Simple Private Payment Gateway
Switch branches/tags
Nothing to show
Clone or download
acidsploit set editable=false in payment uri
set editable=false in payment uri
plus fixed some uncaught default events in react-pos
Latest commit 6588435 Mar 13, 2018

README.md

pyxpub - Private Payment Gateway

Pyxpub is a simple webapp that generates unique payment requests for Bitcoin Cash. It exposes the needed features of a receive-only wallet through a JSON API to enable quick development of Point-of-Sale systems. This without the developer having to worry to much about the sensitive bits. Pyxpub makes it easy to follow Bitcoin best practices and future-proofs your application in order to scale towards future needs.

Pyxpub also includes a Point-of-Sale app by default.

Check out the live demo at demo.pyxpub.io (github repo/screenshots: acidsploit/react-pos)

Introduction

As per Bitcoin best practices it is preferred to use a new receiving address for each payment. This for security and privacy implications for both you and your customers or donators. Also, we do not want any private keys on the server generating the receiving address, nor would we want them on any PoS system. This can easily be achieved by using an hd-wallet as described in BIP32. This is the default wallet type when you create a new wallet with Electron Cash.

pyxpub

Pyxpub exposes the needed features of that wallet through an easy to use JSON API, this to enable quick Point-of-Sale developement, without having to worry about the sensitive bits. Pyxpub handles the generation of new unique addresses for payment requests and keeps track of those, monitor payments requests for incoming transactions, and keeps a sales ledger. All you need to do is call the right api endpoints to get it all in your app.

All generated Bitcoin Cash addresses are derived from a pre-defined (Electron Cash) xpub key. Address re-use is prevented by keeping track of used addresses.

xpub (Electron Cash)

First, when you create a new wallet with Electron Cash, it is very important to properly backup and safely store your mnemonic seed. This Electron wallet is your full (send & receive) wallet, make sure it is password protected and also stored safely. You will use it later to retrieve payments. The webapp will use the xpub key to generate receive only addresses on the server, corresponding to the addresses from your Electron wallet. This way we don't need private keys on the server. You can find your wallet's master public key or xpub key through the 'Wallet -> Information' menu.

Installation (built-in server)

clone repo

git clone https://github.com/acidsploit/pyxpub.git pyxpub

setup environment

cd pyxpub/
bash setup.sh

set xpub key

Copy your xpub key from an Electron Cash wallet and paste it in the key.list file.

echo 'xpub...' > key.list

run

cd pyxpub/
bash pyxpub.sh

access locally

Browse to http://localhost:8080

Raspbian Quick Install (uWSGI + NGINX)

A simple script (raspbian.sh) to deploy pyxpub on a fresh Raspbian installation. Gets you up and running in no time on a Raspberry Pi.

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git
sudo reboot

sudo mkdir /srv/wsgi
cd /srv/wsgi
sudo git clone https://github.com/acidsploit/pyxpub.git
cd pyxpub/
echo 'xpub...' > key.list
sudo bash raspbian.sh

Access pyxpub through your raspberry pi ip address. Example: http://192.168.1.15

Monitor the process:

sudo tail -f /var/log/uwsgi/app/pyxpub.log

Installation Linux (uWSGI + NGINX)

install nginx, uwsgi and uwsgi python plugin

Follow your distribution's directions to install these packages.

insall pyxpub in appropriate location

cd /srv/http/
git clone https://github.com/acidsploit/pyxpub.git pyxpub

mkdir /srv/http/public_html/
mv pyxpub/react/ public_html/
cd pyxpub/
bash setup.sh
echo 'xpub...' > key.list
sudo chown http:http -R /srv/http/pyxpub

uWSGI config

Create: /etc/uwsgi/pyxpub.ini

[uwsgi]
socket = /run/uwsgi/%n.sock
processes = 4
chdir = /srv/http/pyxpub/
master = true
plugins = python
file = xpub.py
uid = http
gid = http
virtualenv = /srv/http/pyxpub/env/

uWSGI start & enable at startup

sudo systemctl start uwsgi@pyxpub.service
sudo systemctl enable uwsgi@pyxpub.service

setup nginx vhost to reverse proxy uWSGI

Set up a vhost (preferably with ssl) with following locations and uwsgi_pass:

upstream _pyxpub {
    server unix:/run/uwsgi/pyxpub.sock;
}

server {
    server_name yourserver.com;
    listen 80;

    root /srv/http/pyxpub/public_html;
    
    rewrite ^/$ /react permanent;

    location /react {
        index index.html;
    }
    
    location /qr {
        try_files $uri @uwsgi;
    }

    location /api {
        try_files $uri @uwsgi;
    }

    location /embed {
        return 403;
    }

    location @uwsgi {
            include uwsgi_params;
            uwsgi_pass _pyxpub;
    }
}

NGINX start & enable at startup

sudo systemctl start nginx.service
sudo systemctl enable nginx.service

Usage

Direct browser access

http://localhost:8080 This will open the React Point-of-Sale app.

JSON

payment request /api/payment

Generate new payment request.

Options:

  • amount

  • label

      curl 'http://localhost:8080/api/payment?amount=0.0023&label=SHOP:1Wed2B44'
    
      {
      "payment": {
        "amount": "0.0023", 
        "addr": "bitcoincash:qpej4uw429m9m0wawcphw9v4sch2ymd6qsqh7jx9gl", 
        "legacy_addr": "1BVx9uf5UGJDt1eMqjut8qh1K4mmEeDSFQ", 
        "label": "SHOP:1Wed2B44", 
        "qr_img": "/qr?addr=bitcoincash:qpej4uw429m9m0wawcphw9v4sch2ymd6qsqh7jx9gl&amount=0.0023&label=SHOP:1Wed2B44", 
        "payment_uri": "bitcoincash:qpej4uw429m9m0wawcphw9v4sch2ymd6qsqh7jx9gl?amount=0.0023&message=SHOP:1Wed2B44"
        }
      }
    

payment verification request /api/verify

Verify payment of payment request

Options:

  • addr
  • amount

or

  • label

    curl 'http://localhost:8080/api/verify?addr=bitcoincash:qpemxfnepk9f0g2yzgsyk4ynnklaaunr7g99rrwas9&amount=0.0023'
    
    {"received": 0}
    or 
    {"received": 1}
    

sales ledger request /api/ledger

Fetch sales ledger.

curl 'http://localhost:8080/api/ledger'
  
  {
   "1":{
      "id":1,
      "timestamp":1519152761.0008476,
      "addr":"bitcoincash:qzwdulf49wfmalj6a36gn2h5ncvrxmw98ydzhxe7gz",
      "amount":"0.00040650",
      "label":"DEVZERO.BE:5cc4f403-9351-42f1-8850-a50735f921fd",
      "received":1,
      "confirmations":0,
      "txid":"5bae0304eb76e78167af30fe6b98f83462828ae974b9c7bc236ebb5b7a9d9e26"
   },
   "2":{
      "id":2,
      "timestamp":1519159704.388939,
      "addr":"bitcoincash:qpej4uw429m9m0wawcphw9v4sch2ymd6qsqh7jx9gl",
      "amount":"0.00976920",
      "label":"DEVZERO.BE:7d2cc3a5-9a6b-4112-b8ac-c60f89d28408",
      "received":0,
      "confirmations":0,
      "txid":"NoTX"
   },
   "3":{
      "id":3,
      "timestamp":1519220076.8360977,
      "addr":"bitcoincash:qpemxfnepk9f0g2yzgsyk4ynnklaaunr7g99rrwas9",
      "amount":"0.0023",
      "label":"SHOP:1Wed2B44",
      "received":0,
      "confirmations":0,
      "txid":"NoTX"
   }
}

exchange rate request /api/rate

Fetch exchange rate or list supported currencies for specified source.

Options:

  • source (cryptocompate, kraken, coinbase)
  • currency

=> Returns exchange rate for requested source and currency

or

  • source (cryptocompate, kraken, coinbase)

=> Returns array of supported currencies for specified source

curl 'http://localhost:8080/api/rate?source=cryptocompare'

{
  "currencies": ["EUR", 
                 "USD", 
                 "GBP", 
                 "AUD", 
                 "BRL", 
                 "CAD", 
                 "CHF", 
                 "CLP", 
                 "CNY", 
                 "CZK", 
                 "DKK", 
                 "HKD", 
                 "HUF", 
                 "IDR", 
                 "ILS", 
                 "INR", 
                 "JPY", 
                 "KRW", 
                 "MXN", 
                 "MYR", 
                 "NOK", 
                 "NZD", 
                 "PHP", 
                 "PKR", 
                 "PLN", 
                 "RUB", 
                 "SEK", 
                 "SGD", 
                 "THB", 
                 "TRY", 
                 "TWD", 
                 "ZAR"]
}

curl 'http://localhost:8080/api/rate?source=kraken'

{
  "currencies": ["EUR", 
                 "USD"]
}

curl 'http://localhost:8080/api/rate?source=kraken&currency=EUR'

{
  "currency": "EUR", 
  "price": 953.8
}

QR image only

http://localhost:8080/qr?addr=bitcoincash:qpej4uw429m9m0wawcphw9v4sch2ymd6qsqh7jx9gl&amount=0.0023&label=SHOP:PAYM123