diff --git a/Pipfile b/Pipfile index e0edea9..35bcb73 100644 --- a/Pipfile +++ b/Pipfile @@ -28,6 +28,7 @@ stripe = "*" matplotlib = "*" requests = "*" python-dotenv = "*" +bitpay = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 25156ce..3db94ca 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "4f61804f9405ff8f66e41739aeac24a2577f7b64f7d08b93459b568528c4f494" + "sha256": "51691e6158d1c309027d595bc4d26079c368f983223f7a567688dd5a98c865fa" }, "pipfile-spec": 6, "requires": { @@ -24,6 +24,13 @@ "index": "pypi", "version": "==2.4.1" }, + "bitpay": { + "hashes": [ + "sha256:3da21326e5a7e98fae93f7fe4c1b046993cf1d8fba60a6c5049cc15f30026b75" + ], + "index": "pypi", + "version": "==2.6.1910" + }, "blinker": { "hashes": [ "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" @@ -60,6 +67,13 @@ ], "version": "==0.10.0" }, + "ecdsa": { + "hashes": [ + "sha256:867ec9cf6df0b03addc8ef66b56359643cb5d0c1dc329df76ba7ecfe256c8061", + "sha256:8f12ac317f8a1318efa75757ef0a651abe12e51fc1af8838fb91079445227277" + ], + "version": "==0.15" + }, "flask": { "hashes": [ "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060", diff --git a/README.md b/README.md index bedff50..4f94cb4 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,8 @@ Run the app FLASK_APP=capsulflask flask run ``` -Run the app in gunicorn locally +Run the app in gunicorn ``` -pip install gunicorn .venv/bin/gunicorn --bind 127.0.0.1:5000 capsulflask:app ``` @@ -61,3 +60,61 @@ For example, the script named `02_up_xyz.sql` should contain code that migrates **IMPORTANT: if you need to make changes to the schema, make a NEW schema version. DO NOT EDIT the existing schema versions.** In general, for safety, schema version upgrades should not delete data. Schema version downgrades will simply throw an error and exit for now. + + +## how to setup btcpay server + +Generate a private key and the accompanying bitpay SIN for the bitpay API client. + + I used this code as an example: https://github.com/bitpay/bitpay-python/blob/master/bitpay/key_utils.py#L6 + +``` +$ python ./readme/generate_btcpay_keys.py +``` + +It should output something looking like this: + +``` +-----BEGIN EC PRIVATE KEY----- +EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK +oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq +NQ+cpBvPDbyrDk9+Uf/sEaRCma094g== +-----END EC PRIVATE KEY----- + + +EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE +``` + +In order to register the key with the btcpay server, you have to first generate a pairing token using the btcpay server interface. +This requires your btcpay server account to have access to the capsul store. Ask Cass about this. + +Navigate to `Manage store: Access Tokens` at: `https://btcpay.cyberia.club/stores//Tokens` + +![](readme/btcpay_sin_pairing.jpg) + + +Finally, send an http request to the btcpay server to complete the pairing: + +``` +curl -H "Content-Type: application/json" https://btcpay.cyberia.club/tokens -d "{'id': 'EXAMPLEwzAEXAMPLEEXAMPLEURD7EXAMPLE', 'pairingCode': 'XXXXXXX'}" +``` + +It should respond with a token: + +``` +{"data":[{"policies":[],"pairingCode":"XXXXXXX","pairingExpiration":1589473817597,"dateCreated":1589472917597,"facade":"merchant","token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","label":"capsulflask"}]} +``` + +And you should see the token in the btcpay server UI: + +![](readme/paired.jpg) + +Now simply set your BTCPAY_PRIVATE_KEY private key in `.env` + +``` +BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY----- +EXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK +oUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq +NQ+cpBvPDbyrDk9+Uf/sEaRCma094g== +-----END EC PRIVATE KEY-----' +``` \ No newline at end of file diff --git a/capsulflask/__init__.py b/capsulflask/__init__.py index 0503997..8cd5c03 100644 --- a/capsulflask/__init__.py +++ b/capsulflask/__init__.py @@ -28,8 +28,10 @@ app.config.from_mapping( STRIPE_API_VERSION=os.environ.get("STRIPE_API_VERSION", default="2020-03-02"), STRIPE_SECRET_KEY=os.environ.get("STRIPE_SECRET_KEY", default=""), - STRIPE_PUBLISHABLE_KEY=os.environ.get("STRIPE_PUBLISHABLE_KEY", default="") + STRIPE_PUBLISHABLE_KEY=os.environ.get("STRIPE_PUBLISHABLE_KEY", default=""), #STRIPE_WEBHOOK_SECRET=os.environ.get("STRIPE_WEBHOOK_SECRET", default="") + + BTCPAY_PRIVATE_KEY=os.environ.get("BTCPAY_PRIVATE_KEY", default="") ) stripe.api_key = app.config['STRIPE_SECRET_KEY'] diff --git a/readme/btcpay_sin_pairing.jpg b/readme/btcpay_sin_pairing.jpg new file mode 100644 index 0000000..26ef8e3 Binary files /dev/null and b/readme/btcpay_sin_pairing.jpg differ diff --git a/readme/generate_btcpay_keys.py b/readme/generate_btcpay_keys.py new file mode 100644 index 0000000..8c18d1b --- /dev/null +++ b/readme/generate_btcpay_keys.py @@ -0,0 +1,47 @@ +from ecdsa import SigningKey, SECP256k1, VerifyingKey +import binascii +import hashlib + +def sha_digest(hexastring): + return hashlib.sha256(binascii.unhexlify(hexastring)).hexdigest() + +def base58encode(hexastring): + chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + int_val = int(hexastring, 16) + encoded = encode58("", int_val, chars) + return encoded + +def encode58(string, int_val, chars): + if int_val == 0: + return string + else: + new_val, rem = divmod(int_val, 58) + new_string = (chars[rem]) + string + return encode58(new_string, new_val, chars) + +sk = SigningKey.generate(curve=SECP256k1) +pem = sk.to_pem() +pem = pem.decode("utf-8") + +print("") +print(pem) +print("") + +public_key = SigningKey.from_pem(pem).get_verifying_key().to_string() +public_key_hex = binascii.hexlify(public_key) +checksum_int = int(public_key_hex, 16) +if(checksum_int % 2 == 0): + prefix = "02" +else: + prefix = "03" +public_key_compressed = prefix + public_key_hex[0:64].decode("utf-8") +hash_of_public_key = sha_digest(public_key_compressed) +ripe_hash_of_public_key = hashlib.new("ripemd160") +ripe_hash_of_public_key.update(binascii.unhexlify(hash_of_public_key)) +version_hash = "0F02"+ripe_hash_of_public_key.hexdigest() +version_checksum = sha_digest(sha_digest(version_hash))[0:8] +btcpay_sin = base58encode(version_hash+version_checksum) + +print("") +print(btcpay_sin) +print("") diff --git a/readme/paired.jpg b/readme/paired.jpg new file mode 100644 index 0000000..9d16bee Binary files /dev/null and b/readme/paired.jpg differ