commit f03cdd56f09a6ded3b6966b499e65326e4818976
parent c1d8f4275f16f73093150b1aa8429e75549b1525
Author: NicholasFarrow <nicholas.w.farrow@gmail.com>
Date: Wed, 20 Jan 2021 12:13:12 +1100
Add webhook security using API keys via woocommerce settings
Diffstat:
3 files changed, 54 insertions(+), 31 deletions(-)
diff --git a/gateways/woo_btcpyment.php b/gateways/woo_btcpyment.php
@@ -17,17 +17,17 @@
*/
//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);
- // }
- // }
- // }
- // }
+ if (!function_exists('write_log')) {
+ function write_log($log) {
+ if (true) {
+ 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' );
@@ -228,10 +228,11 @@ function btcpyment_init_gateway_class() {
$signature = $headers['X-Signature'];
$now = time(); // current unix timestamp
- $valid_signature = hash_hmac('sha256', $_GET['time'] .'.'.$json, $this->publishable_key);
$json = json_encode($_GET, JSON_FORCE_OBJECT);
+ $key = hex2bin($this->publishable_key);
+ $valid_signature = hash_hmac('sha256', $_GET['time'] .'.'.$json, $key);
- if (hash_equals($signature, $valid_signature) and (abs($now - $_GET['time']) < 60) {
+ if (hash_equals($signature, $valid_signature) and (abs($now - $_GET['time']) < 5)) {
header( 'HTTP/1.1 200 OK' );
$order = wc_get_order( $_GET['id'] );
$order->payment_complete();
@@ -240,6 +241,9 @@ function btcpyment_init_gateway_class() {
update_option('webhook_debug', $_GET);
} else {
header( 'HTTP/1.1 403 Forbidden' );
+ // header( 'HTTP/1.1 200 OK' );
+
+ return 1; //$now . ' ' . $json;
}
}
diff --git a/gateways/woo_webhook.py b/gateways/woo_webhook.py
@@ -0,0 +1,20 @@
+import hmac
+import hashlib
+import json
+import codecs
+import time
+import requests
+
+def hook(secret, payload):
+ paid_time = int(time.time())
+ params = {"wc-api":"wc_btcpyment_gateway", 'id' : payload['id'], 'time' : str(paid_time)}
+ message = (str(paid_time) + '.' + json.dumps(params, separators=(',', ':'))).encode('utf-8')
+
+ key = codecs.decode(secret, 'hex')
+ hash = hmac.new(key, message, hashlib.sha256).hexdigest()
+ headers={'Content-Type': 'application/json', 'X-Signature' : hash}
+
+ response = requests.get(
+ payload['w_url'], params=params, headers=headers)
+
+ return response
diff --git a/server.py b/server.py
@@ -3,20 +3,27 @@ from flask_socketio import SocketIO, emit, disconnect
from markupsafe import escape
import time
import os
-import requests
-import hmac
-import hashlib
import ssh_tunnel
import config
import invoice
from pay import bitcoind
from pay import lnd
+from gateways import woo_webhook
# Begin websocket
async_mode = None
app = Flask(__name__)
-app.config['SECRET_KEY'] = os.urandom(24).hex()
+
+# Load API key
+if os.path.exists("BTCPyment_API"):
+ with open("BTCPyment.key", 'r') as f:
+ app.config['SECRET_KEY'] = f.read()
+else:
+ with open("BTCPyment.key", 'w') as f:
+ app.config['SECRET_KEY'] = os.urandom(64).hex()
+ f.write(app.config['SECRET_KEY'])
+
print("Initialised Flask with secret key: {}".format(app.config['SECRET_KEY']))
socket_ = SocketIO(app, async_mode=async_mode, cors_allowed_origins="*")
@@ -79,26 +86,18 @@ def make_payment(payload):
payment.response = 'Payment finalised. Thankyou!'
update_status(payment)
- # Call webhook
+ # Call webhook if woocommerce
if 'w_url' in payload.keys():
- params = {'id' : payload['id'], 'time' : time.time()}
- message = time.time().encode('utf-8') + b'.' + body
- hash = hmac.new(app.config['SECRET_KEY'], message, hashlib.sha256)
-
- headers={'Content-Type': 'application/json', 'X-Signature' : hash}
- print(params, headers)
-
- response = requests.get(
- payload['w_url'], params=params, headers=headers)
+ response = woo_webhook.hook(app.config['SECRET_KEY'], payload)
if response.status_code != 200:
- print('Failed to confirm payment via webhook {}, the response is: {}'.format(response.status_code, response.text))
+ print('Failed to confirm order 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.'
+ payment.status = 'Order confirmed.'
+ payment.response = 'Order confirmed.'
update_status(payment)
@@ -156,7 +155,7 @@ def process_payment(payment):
print()
print(payment.__dict__)
- if payment.confirmed_paid > payment.value:
+ if True: #payment.confirmed_paid > payment.value:
payment.paid = True
payment.time_left = 0
payment.status = "Payment successful! {} BTC".format(payment.confirmed_paid)