commit 4155770e7164c82c3f5f390a2253f2157587b399
parent 6437afe627b929242232921ae881fb3d6c3309d3
Author: NicholasFarrow <nicholas.w.farrow@gmail.com>
Date: Sat, 16 Jan 2021 19:56:43 +1100
fix readme conflict
Diffstat:
10 files changed, 599 insertions(+), 50 deletions(-)
diff --git a/README.md b/README.md
@@ -10,15 +10,16 @@ BTCPyment currently serves as
BTCPyment makes donation buttons simple; using Python and Javascript to talk to your own Bitcoin node, with an easy iframe embed install. BTCPyment uses RPC to generate new addresses from your Bitcoin node, and monitors the payment status with your own copy of the blockchain.
# Features
-* Lightweight, Python and Javascript talk to your own Bitcoin node via websockets and SSH.
-* Direct peer-to-peer payments without any middleman. No KYC, and greater privacy than donation systems with reused Bitcoin addresses.
+* Talk to your own Bitcoin node via RPC and SSH. Bitcoin core, or any other node software that supports RPC calls.
+* Lightweight - Python and Javascript websockets.
+* Direct peer-to-peer payments without any middleman. No KYC, and greater privacy than donation systems wher Bitcoin addresses are reused multiple times.
* Natively supports all bitcoind node features (e.g. segwit) through RPC.
* QR codes, user chooses the minimum payment confirmations and payment expiry duration.
* Highly extendable, just take a look at the code! Optional code execution upon payment.
* No shitcoin bloat. Bitcoin only.
# Installation (short!)
-BTCPyment requires you to have a server host on, and a connection to a Bitcoin node. If you don't have one, you should [install one](https://bitcoincore.org/en/download/).
+You require a server to host an instance of BTCPyment on, and a connection to a Bitcoin node. If you don't have a Bitcoin node, you should [install one](https://bitcoincore.org/en/download/).
### Install
Clone and install dependencies
```
@@ -52,9 +53,13 @@ Now embed the donation button into your website:
```html
<iframe src="http://YOUR_SERVER_IP:8000/" style="margin: 0 auto;display:block;height:320px;border:none;overflow:hidden;" scrolling="no"></iframe>
```
+Changing `YOUR_SERVER_IP` to the IP address of the machine you're running BTCPyment through. Optionally, you can redirect a domain to that IP and use that instead.
-## Using HTTPS
-Embedded iframes are easy if your site only uses HTTP. But if your site uses HTTPS, then you will be able to see your donation button at `http://YOUR_SERVER_IP:8000/` but not in the embeded iframe. See [HTTPS instructions](docs/HTTPS.md).
+## Security
+For maximum security, we recommend hosting on a machine where your node only has access to a **watch-only** wallet.
+
+## Using HTTPS & Domains
+Embedded iframes are easy if your site only uses HTTP. But if your site uses HTTPS, then you can see your donation button at `http://YOUR_SERVER_IP:8000/` but will not be able to in an embedded iframe. See [HTTPS instructions](docs/HTTPS.md).
# Developers
### You only need a little python!
diff --git a/config.py b/config.py
@@ -1,11 +1,14 @@
# Bitcoin node connection settings
+# Connecting through local host, or via forwarded ssh port
host = "127.0.0.1"
rpcport = "8332"
+# From ~/.bitcoin/bitcoin.conf
username = "bitcoinrpc"
password = "RPAPASSWORD"
# SSH tunnel to node (raspberry pi!)
# Make sure this command works `ssh HOST@IP -q -N -L 8332:localhost:8332`
+# This forwards the ports required to talk to the node via RPC (or gRPC in the case of lightning)
tunnel_host = "HOST@IP"
# Check for payment every xx seconds
@@ -19,3 +22,9 @@ required_confirmations = 2
# Global connection attempts
connection_attempts = 3
+
+# Payment method
+pay_method = "bitcoind"
+# Switch payment_method to lnd if you want to use lightning payments instead. And uncomment lnd_dir.
+#pay_method = "lnd"
+#lnd_dir = "~/.lnd/"
diff --git a/gateways/btcpyment.js b/gateways/btcpyment.js
@@ -0,0 +1,35 @@
+var successCallback = function(data) {
+
+ var checkout_form = $( 'form.woocommerce-checkout' );
+
+ // add a token to our hidden input field
+ // console.log(data) to find the token
+ checkout_form.find('#btcpyment_token').val(data.token);
+
+ // deactivate the tokenRequest function event
+ checkout_form.off( 'checkout_place_order', tokenRequest );
+
+ // submit the form now
+ checkout_form.submit();
+
+};
+
+var errorCallback = function(data) {
+ console.log(data);
+};
+
+var tokenRequest = function() {
+
+ // here will be a payment gateway function that process all the card data from your form,
+ // maybe it will need your Publishable API key which is misha_params.publishableKey
+ // and fires successCallback() on success and errorCallback on failure
+ return false;
+
+};
+
+jQuery(function($){
+
+ var checkout_form = $( 'form.woocommerce-checkout' );
+ checkout_form.on( 'checkout_place_order', tokenRequest );
+
+});
diff --git a/gateways/woo_btcpyment.php b/gateways/woo_btcpyment.php
@@ -0,0 +1,234 @@
+<?php
+/*
+ * Plugin Name: BTCPyment
+ * Plugin URI: https://github.com/nickfarrow/BTCPyment
+ * Description: Take credit card payments on your store.
+ * Author: Nick Farrow
+ * Author URI: https://nickfarrow.com
+ * Version: 1.0.1
+ *
+*/
+
+/* Based.
+* Based on https://rudrastyh.com/woocommerce/payment-gateway-plugin.html */
+
+/*
+ * This action hook registers our PHP class as a WooCommerce payment gateway
+ */
+
+//Debugging helper
+ if (!function_exists('write_log')) {
+ function write_log($log) {
+ if (true === WP_DEBUG) {
+ if (is_array($log) || is_object($log)) {
+ error_log(print_r($log, true));
+ } else {
+ error_log($log);
+ }
+ }
+ }
+ }
+
+// BTCPyment class
+add_filter( 'woocommerce_payment_gateways', 'btcpyment_add_gateway_class' );
+function btcpyment_add_gateway_class( $gateways ) {
+ $gateways[] = 'WC_Btcpyment_Gateway';
+ return $gateways;
+}
+
+// Extend existing payment gateway
+add_action( 'plugins_loaded', 'btcpyment_init_gateway_class' );
+function btcpyment_init_gateway_class() {
+
+ class WC_Btcpyment_Gateway extends WC_Payment_Gateway {
+
+ /**
+ * Class constructor
+ */
+ public function __construct() {
+
+ $this->id = 'BTCPyment'; // payment gateway plugin ID
+ $this->icon = ''; // URL of the icon that will be displayed on checkout page near your gateway name
+ $this->has_fields = true; // in case you need a custom credit card form
+ $this->method_title = 'BTCPyment Gateway';
+ $this->method_description = 'Description of btcpyment payment gateway'; // will be displayed on the options page
+
+ $this->supports = array(
+ 'products'
+ );
+
+ // Method with all the options fields
+ $this->init_form_fields();
+
+ // Load the settings.
+ $this->init_settings();
+ $this->title = $this->get_option( 'title' );
+ $this->description = $this->get_option( 'description' );
+ $this->enabled = $this->get_option( 'enabled' );
+ $this->btcpyment_server_url = $this->get_option( 'btcpyment_server_url' );
+ $this->redirect_url = $this->get_option( 'redirect_url' );
+ $this->testmode = 'yes' === $this->get_option( 'testmode' );
+ $this->private_key = $this->testmode ? $this->get_option( 'test_private_key' ) : $this->get_option( 'private_key' );
+ $this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' );
+ $this->callback_URL = str_replace( 'https:', 'http:', add_query_arg( 'wc-api', 'wc_btcpyment_gateway', home_url( '/' ) ) );
+ // $this->callback_URL = home_url( '/' ) . 'wc-api/' . 'WC_Btcpyment_Gateway/';
+
+ // This action hook saves the settings
+ add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
+
+ // We need custom JavaScript to obtain a token
+ // add_action( 'wp_enqueue_scri6pts', array( $this, 'payment_scripts' ) );
+
+ // You can also register a webhook here
+ add_action( 'woocommerce_api_wc_btcpyment_gateway', array( $this, 'webhook' ) );
+ }
+
+ /**
+ * Plugin options
+ */
+ public function init_form_fields(){
+
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => 'Enable/Disable',
+ 'label' => 'Enable btcpyment Gateway',
+ 'type' => 'checkbox',
+ 'description' => '',
+ 'default' => 'no'
+ ),
+ 'title' => array(
+ 'title' => 'Title',
+ 'type' => 'text',
+ 'description' => 'This controls the title which the user sees during checkout.',
+ 'default' => 'Bitcoin',
+ 'desc_tip' => true,
+ ),
+ 'description' => array(
+ 'title' => 'Description',
+ 'type' => 'textarea',
+ 'description' => 'This controls the description which the user sees during checkout.',
+ 'default' => 'Pay with Bitcoin via BTCPyment',
+ ),
+ 'btcpyment_server_url' => array(
+ 'title' => 'BTCPyment URL',
+ 'type' => 'text',
+ 'description' => 'Points towards your instance of BTCPyment, should be IP or https://SERVER.com'
+ ),
+ 'redirect_url' => array(
+ 'title' => 'Redirect URL',
+ 'type' => 'text',
+ 'description' => 'URL the user is redirected to after payment.'
+ ),
+ 'testmode' => array(
+ 'title' => 'Test mode',
+ 'label' => 'Enable Test Mode',
+ 'type' => 'checkbox',
+ 'description' => 'Place the payment gateway in test mode using test API keys.',
+ 'default' => 'yes',
+ 'desc_tip' => true,
+ ),
+ 'test_publishable_key' => array(
+ 'title' => 'Test Publishable Key',
+ 'type' => 'text'
+ ),
+ 'test_private_key' => array(
+ 'title' => 'Test Private Key',
+ 'type' => 'password',
+ ),
+ 'publishable_key' => array(
+ 'title' => 'Live Publishable Key',
+ 'type' => 'text'
+ ),
+ 'private_key' => array(
+ 'title' => 'Live Private Key',
+ 'type' => 'password'
+ )
+ );
+ }
+
+
+ /*
+ * Custom CSS and JS, in most cases required only when you decided to go with a custom credit card form
+ */
+ public function payment_scripts() {
+
+ // we need JavaScript to process a token only on cart/checkout pages, right?
+ if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) {
+ return;
+ }
+
+ // if our payment gateway is disabled, we do not have to enqueue JS too
+ if ( 'no' === $this->enabled ) {
+ return;
+ }
+
+ // no reason to enqueue JavaScript if API keys are not set
+ if ( empty( $this->private_key ) || empty( $this->publishable_key ) ) {
+ return;
+ }
+
+ // do not work with card detailes without SSL unless your website is in a test mode
+ if ( ! $this->testmode && ! is_ssl() ) {
+ return;
+ }
+ //
+ // // let's suppose it is our payment processor JavaScript that allows to obtain a token
+ // wp_enqueue_script( 'btcpyment_js', 'https://btcpyment.nickfarrow.com' );
+ //
+ // // and this is our custom JS in your plugin directory that works with token.js
+ // wp_register_script( 'woocommerce_btcpyment', plugins_url( 'btcpyment.js', __FILE__ ), array( 'jquery', 'btcpyment_js' ) );
+ //
+ // // in most payment processors you have to use PUBLIC KEY to obtain a token
+ // wp_localize_script( 'woocommerce_btcpyment', 'btcpyment_params', array(
+ // 'publishableKey' => $this->publishable_key
+ // ) );
+
+ wp_enqueue_script( 'woocommerce_btcpyment' );
+
+ }
+
+
+ /*
+ * Processing the payments
+ */
+ public function process_payment( $order_id ) {
+
+ global $woocommerce;
+
+ // we need it to get any order detailes
+ $order = wc_get_order( $order_id );
+
+ /*
+ * Array with parameters for API interaction
+ */
+ $args = array(
+ 'amount' => $order->get_total(),
+ 'id' => $order->get_id(),
+ 'w_url' => $this->callback_URL );
+ // HASH??? FOR SECURE PAYMENTS?
+
+ $payment_url = add_query_arg(
+ $args,
+ $this->btcpyment_server_url . "/pay"
+ );
+
+ // Redirect to BTCPyment
+ return [
+ 'result' => 'success',
+ 'redirect' => $payment_url
+ ];
+ }
+
+ /*
+ * Webhook to confirm payment
+ */
+ public function webhook() {
+ header( 'HTTP/1.1 200 OK' );
+ $order = wc_get_order( $_GET['id'] );
+ $order->payment_complete();
+ $order->reduce_order_stock();
+
+ update_option('webhook_debug', $_GET);
+ }
+ }
+}
diff --git a/pay/bitcoind.py b/pay/bitcoind.py
@@ -1,7 +1,10 @@
-import config
+import time
import subprocess
+import time
+import config
from invoice.payment_invoice import invoice
+
class btcd(invoice):
def __init__(self, dollar_value, currency, label):
super().__init__(dollar_value, currency, label)
@@ -17,6 +20,7 @@ class btcd(invoice):
try:
self.rpc = AuthServiceProxy(connection_str)
info = self.rpc.getblockchaininfo()
+ print(info)
print("Successfully contacted bitcoind.")
break
diff --git a/pay/lnd.py b/pay/lnd.py
@@ -0,0 +1,108 @@
+import config
+import subprocess
+import time
+import os
+import json
+from base64 import b64decode
+from google.protobuf.json_format import MessageToJson
+
+from invoice.payment_invoice import invoice
+
+class lnd(invoice):
+ def __init__(self, dollar_value, currency, label):
+ super().__init__(dollar_value, currency, label)
+ print(self.__dict__)
+
+ from lnd_grpc import Client
+
+ # Copy admin macaroon and tls cert to local machine
+ try:
+ tls_file = os.path.join(config.lnd_dir, "tls.cert")
+ macaroon_file = os.path.join(config.lnd_dir, "data/chain/bitcoin/mainnet/admin.macaroon")
+ subprocess.run(["scp", "{}:{}".format(config.tunnel_host, tls_file), "."])
+ subprocess.run(["scp", "-r", "{}:{}".format(config.tunnel_host, macaroon_file), "."])
+
+ except Exception as e:
+ print(e)
+ print("Failed to copy tls and macaroon files to local machine.")
+
+ connection_str = "{}:{}".format(config.host, config.rpcport)
+ print("Attempting to connect to {}. This may take a few minutes...".format(connection_str))
+
+ for i in range(config.connection_attempts):
+ try:
+ # Require admin=True for creating invoices
+ print("Attempting to initialise lnd rpc client...")
+ self.lnd = Client(grpc_host=config.host,
+ grpc_port=config.rpcport,
+ macaroon_path="admin.macaroon",
+ tls_cert_path="tls.cert")
+
+ # print("Getting lnd info...")
+ # info = self.lnd.get_info()
+ # print(info)
+
+ print("Successfully contacted lnd.")
+ break
+
+ except Exception as e:
+ print(e)
+ time.sleep(config.pollrate)
+ print("Attempting again... {}/{}...".format(i+1, config.connection_attempts))
+ else:
+ raise Exception("Could not connect to lnd. Check your gRPC / port tunneling settings and try again.")
+
+
+ def create_lnd_invoice(self, btc_amount):
+ # Multiplying by 10^8 to convert to satoshi units
+ sats_amount = int(btc_amount*10**8)
+ res = self.lnd.add_invoice(value=sats_amount)
+ self.lnd_invoice = json.loads(MessageToJson(res))
+ self.hash = res.r_hash #self.lnd_invoice['r_hash']
+ print("Create invoice response:")
+ print(res)
+ return self.lnd_invoice['payment_request']
+
+ # self.lnd_invoice = json.loads(MessageToJson(self.lnd.add_invoice(sats_amount)))
+ # print(self.lnd_invoice)
+ # print("printed")
+ #
+ # self.hash = str(b64decode(self.lnd_invoice['r_hash']).hex())
+ # # self.hash = str(b64decode(self.lnd_invoice['rHash']).hex())
+ #
+ # print("Created invoice: {}".format(self.hash))
+ # return self.lnd_invoice['payment_request']
+ # return self.lnd_invoice['paymentRequest']
+
+
+ def get_address(self):
+ self.address = self.create_lnd_invoice(self.value)
+
+ # for i in range(config.connection_attempts):
+ # try:
+ # self.address = self.create_lnd_invoice(self.value)
+ # except Exception as e:
+ # print(e)
+ # print("Attempting again... {}/{}...".format(i+1, config.connection_attempts))
+
+ return
+
+ def check_payment(self):
+ print("Looking up invoice")
+ # For some reason this does not work, I think lookup_invoice() may be broken
+ # as it does not return the correct response that includes the amount paid among other fields.
+ print(self.lnd.list_invoices())
+ print(self.lnd.lookup_invoice(r_hash=self.hash))
+ print("Invoice ^")
+ print(type(self.hash))
+ print(str(self.hash.hex()))
+
+ # print(str(b64decode(self.hash.strip('\\'))))
+ # invoice_status = json.loads(MessageToJson(self.lnd.lookup_invoice(self.hash)))
+ # print(invoice_status)
+ # print(self.lnd.lookup_invoice("8893044a07c2c5e2a50252f044224f297487242e05758a970d5ba28ece75f66d"))
+ # subprocess.run([""])
+
+ conf_paid = 0 #invoice_status['amt_paid']
+ unconf_paid = 0
+ return conf_paid, unconf_paid
diff --git a/server.py b/server.py
@@ -1,35 +1,48 @@
-from flask import Flask, render_template, session
+from flask import Flask, render_template, session, request
from flask_socketio import SocketIO, emit, disconnect
from markupsafe import escape
import time
+import os
+import requests
import ssh_tunnel
import config
import invoice
from pay import bitcoind
+from pay import lnd
# Begin websocket
async_mode = None
app = Flask(__name__)
-app.config['SECRET_KEY'] = 'secret!'
+app.config['SECRET_KEY'] = os.urandom(24).hex()
+print("Initialised Flask with secret key: {}".format(app.config['SECRET_KEY']))
socket_ = SocketIO(app, async_mode=async_mode, cors_allowed_origins="*")
-# Render html
+# Render index pages
+# To-do, this will be a donation form page that submits to /pay
@app.route('/')
def index():
- return render_template('index.html', async_mode=socket_.async_mode)
+ return render_template('donate.html', async_mode=socket_.async_mode)
+
+@app.route('/pay')
+def payment_page():
+ #
+ # # Label is blank if not supplied
+ # params = {'label':''}
+ # for key, value in dict(request.args).items():
+ # params[key] = value
+ params = dict(request.args)
+ return render_template('index.html', params=params, async_mode=socket_.async_mode)
# Basic return on initialisation
-@socket_.on('initialise', namespace='/pay')
+@socket_.on('initialise')
def test_message(message):
emit('payresponse', {'time_left': -1, 'response': message['data']})
# Main payment method for websocket
# Recieves form amount and initiates invoice and payment processing.
-@socket_.on('payment', namespace='/pay')
+@socket_.on('make_payment')
def make_payment(payload):
- print("Requesting payment for {}".format(payload['amount']))
-
# Check the amount is a float
amount = payload['amount']
try:
@@ -45,11 +58,15 @@ def make_payment(payload):
amount = None
return
- # Need to check this is safe!
- label = payload['label']
+ # Return if label missing
+ if 'id' not in payload.keys():
+ return
+ # label = payload['label']
+ # else:
+ # label = "undefined"
# Initialise this payment
- payment = create_invoice(amount, "USD", label)
+ payment = create_invoice(amount, "USD", payload['id'])
process_payment(payment)
@@ -58,7 +75,22 @@ def make_payment(payload):
payment.response = 'Payment finalised. Thankyou!'
update_status(payment)
- invoice.success.success()
+ # Call webhook
+ if config.gateway is not None and config.gateway:
+ response = requests.get(
+ payload['w_url'], params={'id' : payload['id']},
+ headers={'Content-Type': 'application/json'}
+ )
+ if response.status_code != 200:
+ print('Failed to confirm payment via webhook {}, the response is: {}'.format(response.status_code, response.text))
+ payment.status = response.text
+ payment.response = response.text
+ else:
+ print("Successfully confirmed payment via webhook.")
+ payment.status = 'Payment confirmed.'
+ payment.response = 'Payment confirmed.'
+
+ update_status(payment)
### DO SOMETHING
# Depends on config
@@ -69,7 +101,16 @@ def make_payment(payload):
# Initialise the payment via the payment method (bitcoind / lightningc / etc),
# create qr code for the payment.
def create_invoice(dollar_amount, currency, label):
- payment = bitcoind.btcd(dollar_amount, currency, label)
+ if config.pay_method == "bitcoind":
+ print("AHHHHHhhhhhhh")
+ payment = bitcoind.btcd(dollar_amount, currency, label)
+ elif config.pay_method == "lnd":
+ payment = lnd.lnd(dollar_amount, currency, label)
+ else:
+ # There probably should be config checking code within main.py
+ print("Invalid payment method")
+ return
+
payment.get_address()
payment.create_qr()
return payment
@@ -91,8 +132,8 @@ def update_status(payment, console_status=True):
# Payment processing function.
# Handle payment logic.
def process_payment(payment):
- payment.status = 'Awaiting payment.'
- payment.response = 'Awaiting payment.'
+ payment.status = 'Payment intialised, awaiting payment.'
+ payment.response = 'Payment intialised, awaiting payment.'
update_status(payment)
# Track start_time for payment timeouts
@@ -120,8 +161,8 @@ def process_payment(payment):
update_status(payment, console_status=False)
socket_.sleep(config.pollrate)
else:
- payment.status = "Awaiting payment...".format(payment.value)
- payment.response = "Awaiting payment...".format(payment.value)
+ payment.status = "Waiting for payment...".format(payment.value)
+ payment.response = "Waiting for payment...".format(payment.value)
update_status(payment)
socket_.sleep(config.pollrate)
else:
@@ -133,9 +174,12 @@ def process_payment(payment):
# Test Bitcoind connection on startup:
print("Checking node connectivity...")
-bitcoind.btcd(1, 'USD', 'Init test.')
+if config.pay_method == "bitcoind":
+ bitcoind.btcd(1, 'USD', 'Init test.')
+elif config.pay_method == "lnd":
+ lnd.lnd(1, 'USD', 'Init test')
print("Connection successful.")
if __name__ == '__main__':
- socket_.run(app, debug=True)
+ socket_.run(app, debug=False)
diff --git a/static/server_connection.js b/static/server_connection.js
@@ -1,6 +1,6 @@
// Websocket logic, talks to server.py pay
-$(document).ready(function() {
- namespace = '/pay';
+function initiate(payment_data) {
+ namespace = '/';
var socket = io(namespace);
socket.on('connect', function() {
@@ -21,19 +21,17 @@ $(document).ready(function() {
cb();
});
- $('form#pay').submit(function(event) {
- socket.emit('payment', {'amount': $('#pay_data').val(), 'label' : null});
- return false;
- });
-});
+ socket.emit('make_payment', payment_data);
+ return false
+}
// Additional steps to take when giving a response to the webpage
// Update qr code, and hide timer
function conditionalPageLogic(msg) {
if (msg.address != null) {
- document.getElementById('logo').classList.add("qr");
+ // document.getElementById('logo').classList.add("qr");
// document.getElementById('logo').src = "static/qr_codes/" + msg.uuid + ".png";
- document.getElementById('logo').style.display = "none";
+ // document.getElementById('logo').style.display = "none";
document.getElementById('qrImage').style.display = "block";
document.getElementById('qrClick').href = "/static/qr_codes/" + msg.uuid + ".png";
document.getElementById('qrImage').src = "/static/qr_codes/" + msg.uuid + ".png";
diff --git a/templates/donate.html b/templates/donate.html
@@ -0,0 +1,116 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>BTCPyment</title>
+ <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
+
+ <script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js"></script>
+ <!-- <script src="{{ url_for('static', filename='server_connection.js') }}"></script> -->
+
+ <style>
+ html, body {
+ display: flex;
+ /* height:auto;
+ width:260px; */
+ }
+ body{
+ background-color: inherit;
+ overflow: hidden;
+ }
+ p {
+ /* display: inline-block; */
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ margin: 0;
+ padding: 5px;
+ }
+ h1 {
+ font-size: 2em;
+ }
+ #paybox {
+ background-color: #f7931a;
+ border-radius: 25px;
+ padding-left: 30px;
+ padding-right: 30px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ font-size: 16px
+
+ /* height:auto; */
+ height: 275px;
+ width:220px;
+ }
+ #row {
+ display: flex;
+ }
+ #left {
+ width: 60%;
+ padding: 0 10px 0 0;
+ float: left;
+ }
+ #right {
+ width: 40%;
+ padding: 0 10px 0 0;
+ float: right;
+ }
+ #address {
+ overflow-wrap: break-word;
+ text-align: right;
+ }
+ #about {
+ color:#000;
+ }
+ .qr {
+ transition: transform .2s;
+ object-fit: cover;
+ }
+ .qr:hover {
+ -ms-transform: scale(2.5); /* IE 9 */
+ -webkit-transform: scale(2.5); /* Safari 3-8 */
+ transform: scale(3);
+ }
+ </style>
+
+</head>
+
+
+<body>
+ <div id="paybox">
+ <div id="row" height="50px">
+ <div id="left" style="display:inline-block;" height="75px">
+ <h1>Donate Bitcoin</h>
+ </div>
+ <div id="right">
+ <a id="logo" target="_blank"><img id="logo" style="padding-top:25px;padding-left:30px;" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a>
+ <a id="qrClick" target="_blank"><img class="qr" id="qrImage" style="padding-top:25px;display:none" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a>
+ </div>
+ </div>
+
+ <div id="paymentForm">
+ <center>
+ <form id="pay" action='/pay' style="margin:0;padding0;">
+ <h2 style="margin:0;padding0;">Amount:
+ <input style="display:inline" size="4" type="float" name="amount" id="amount" placeholder="USD">
+ </h2>
+ <br>
+ <input style="width:100%" type="submit" value="Pay" onclick="hideAmountShowPayment()">
+ </form>
+ </center>
+ </div>
+
+ <!-- <div id="paymentDetails" style="display:none; padding: 0;">
+ <p style="padding:0;">Send: <b><span id="amount"></span></b> BTC</p>
+ <p style="padding:0;">To: </p><b><p id="address" onclick="copyTextFromElement('address')"></p></b>
+ <p style="padding:0;"><span id="status"></span></p>
+ <p id="timerContainer" style="padding:0;"><span id="timer"></span> seconds remaining.</p>
+ </div>
+
+ <div id="information" style="text-align: right; padding: 0;">
+ <small><a id="about" href="https://github.com/nickfarrow/BTCPyment" target="_blank">BTCPyment</a></small>
+ </div> -->
+
+ <div id="paybutton"></div>
+ </div>
+</body>
+</html>
diff --git a/templates/index.html b/templates/index.html
@@ -3,11 +3,18 @@
<head>
<title>BTCPyment</title>
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
-
+
<script src="//code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js"></script>
<script src="{{ url_for('static', filename='server_connection.js') }}"></script>
+ <!-- Initate the payment websocket -->
+ <script type="text/javascript">
+ payment_data = {{ params|tojson }};
+ console.log(payment_data);
+ initiate(payment_data);
+ </script>
+
<style>
html, body {
@@ -80,27 +87,16 @@
<div id="paybox">
<div id="row" height="50px">
<div id="left" style="display:inline-block;" height="75px">
- <h1>Donate Bitcoin</h>
+ <h1>Pay Bitcoin</h>
</div>
<div id="right">
- <a id="logo" target="_blank"><img id="logo" style="padding-top:25px;padding-left:30px;" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a>
- <a id="qrClick" target="_blank"><img class="qr" id="qrImage" style="padding-top:25px;display:none" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a>
+ <!-- <a id="logo" target="_blank"><img id="logo" style="padding-top:25px;padding-left:30px;" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a> -->
+ <a id="qrClick" target="_blank"><img class="qr" id="qrImage" style="padding-top:25px;display:block" width="65px" src="https://i.pinimg.com/originals/3a/dd/40/3add4023fa9b435e7da3c09156b88015.png"></a>
</div>
</div>
- <div id="paymentForm">
- <center>
- <form id="pay" method="POST" action='#' style="margin:0;padding0;">
- <h2 style="margin:0;padding0;">Amount:
- <input style="display:inline" size="4" type="float" name="pay_data" id="pay_data" placeholder="USD">
- </h2>
- <br>
- <input style="width:100%" type="submit" value="Pay" onclick="hideAmountShowPayment()">
- </form>
- </center>
- </div>
- <div id="paymentDetails" style="display:none; padding: 0;">
+ <div id="paymentDetails" style="display:block; padding: 0;">
<p style="padding:0;">Send: <b><span id="amount"></span></b> BTC</p>
<p style="padding:0;">To: </p><b><p id="address" onclick="copyTextFromElement('address')"></p></b>
<p style="padding:0;"><span id="status"></span></p>