forked from 3wordchant/capsul-flask
Split README up into separate files
This commit is contained in:
26
docs/architecture.md
Normal file
26
docs/architecture.md
Normal file
@ -0,0 +1,26 @@
|
||||
# hub-and-spoke architecture
|
||||
|
||||

|
||||
|
||||
This diagram was created with https://app.diagrams.net/.
|
||||
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
||||
|
||||
right now I have 2 types of operations, immediate mode and async.
|
||||
|
||||
both types of operations do assignment synchronously. so if the system cant assign the operation to one or more hosts (spokes),
|
||||
or whatever the operation requires, then it will fail.
|
||||
|
||||
some operations tolerate partial failures, like, `capacity_avaliable` will succeed if at least one spoke succeeds.
|
||||
for immediate mode requests (like `list`, `capacity_avaliable`, `destroy`), assignment and completion of the operation are the same thing.
|
||||
|
||||
for async ones, they can be assigned without knowing whether or not they succeeded (`create`).
|
||||
|
||||

|
||||
|
||||
This diagram was created with https://app.diagrams.net/.
|
||||
To edit it, download the <a download href="readme/hub-and-spoke.xml">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
||||
|
||||
if you issue a create, and it technically could go to any number of hosts, but only one host responds, it will succeed
|
||||
but if you issue a create and somehow 2 hosts both think they own that task, it will fail and throw a big error. cuz it expects exactly 1 to own the create task
|
||||
|
||||
currently its not set up to do any polling. its not really like a queue at all. It's all immediate for the most part
|
68
docs/btcpay.md
Normal file
68
docs/btcpay.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Receiving cryptocurrency payments with BTCPay
|
||||
|
||||
Generate a private key and the accompanying bitpay SIN for the btcpay API client.
|
||||
|
||||
I used this code as an example: https://github.com/bitpay/bitpay-python/blob/master/bitpay/key_utils.py#L6
|
||||
|
||||
```
|
||||
$ pipenv run 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/<store-id>/Tokens`
|
||||
|
||||

|
||||
|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
Now simply set your `BTCPAY_PRIVATE_KEY` variable in `.env`
|
||||
|
||||
NOTE: make sure to use single quotes and replace the new lines with \n.
|
||||
|
||||
```
|
||||
BTCPAY_PRIVATE_KEY='-----BEGIN EC PRIVATE KEY-----\nEXAMPLEIArx/EXAMPLEKH23EXAMPLEsYXEXAMPLE5qdEXAMPLEcFHoAcEXAMPLEK\noUQDQgAEnWs47PT8+ihhzyvXX6/yYMAWWODluRTR2Ix6ZY7Z+MV7v0W1maJzqeqq\nNQ+cpBvPDbyrDk9+Uf/sEaRCma094g==\n-----END EC PRIVATE KEY-----'
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## testing cryptocurrency payments
|
||||
|
||||
I used litecoin to test cryptocurrency payments, because its the simplest & lowest fee cryptocurrency that BTCPay server supports. You can download the easy-to-use litecoin SPV wallet `electrum-ltc` from [github.com/pooler/electrum-ltc](https://github.com/pooler/electrum-ltc) or [electrum-ltc.org](https://electrum-ltc.org/), set up a wallet, and then either purchase some litecoin from an exchange, or ask Forest for some litecoin to use for testing.
|
||||
|
||||
|
||||
## sequence diagram explaining how BTC payment process works
|
||||
|
||||

|
||||
|
||||
This diagram was created with https://app.diagrams.net/.
|
||||
To edit it, download the <a download href="readme/btcpayment_process.drawio">diagram file</a> and edit it with the https://app.diagrams.net/ web application, or you may run the application from [source](https://github.com/jgraph/drawio) if you wish.
|
23
docs/configuration.md
Normal file
23
docs/configuration.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Configuring Capsul-Flask
|
||||
|
||||
Create a `.env` file to set up the application configuration:
|
||||
|
||||
```
|
||||
nano .env
|
||||
```
|
||||
|
||||
You can enter any environment variables referenced in `__init__.py` to this file.
|
||||
|
||||
For example you may enter your SMTP credentials like this:
|
||||
```
|
||||
MAIL_USERNAME=forest@nullhex.com
|
||||
MAIL_DEFAULT_SENDER=forest@nullhex.com
|
||||
MAIL_PASSWORD=**************
|
||||
```
|
||||
|
||||
## Loading variables from files
|
||||
|
||||
To support [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/), you can also load secret values from files – for example, to load `MAIL_PASSWORD` from `/run/secrets/mail_password`, set
|
||||
```sh
|
||||
MAIL_PASSWORD_FILE=/run/secrets/mail_password
|
||||
```
|
46
docs/database.md
Normal file
46
docs/database.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Working with the Capsul database
|
||||
|
||||
## Running manual database queries
|
||||
|
||||
You can manually mess around with the database like this:
|
||||
|
||||
```
|
||||
pipenv run flask cli sql -f test.sql
|
||||
```
|
||||
|
||||
```
|
||||
pipenv run flask cli sql -c 'SELECT * FROM vms'
|
||||
```
|
||||
|
||||
This one selects the vms table with the column name header:
|
||||
|
||||
```
|
||||
pipenv run flask cli sql -c "SELECT string_agg(column_name::text, ', ') from information_schema.columns WHERE table_name='vms'; SELECT * from vms"
|
||||
```
|
||||
|
||||
How to modify a payment manually, like if you get a chargeback or to fix customer payment issues:
|
||||
|
||||
```
|
||||
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
||||
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, FALSE
|
||||
|
||||
$ pipenv run flask cli sql -c "UPDATE payments SET invalidated = True WHERE id = 1"
|
||||
1 rows affected.
|
||||
|
||||
$ pipenv run flask cli sql -c "SELECT id, created, email, dollars, invalidated from payments"
|
||||
1, 2020-05-05T00:00:00, forest.n.johnson@gmail.com, 20.00, TRUE
|
||||
```
|
||||
|
||||
## Database schema management
|
||||
|
||||
capsulflask has a concept of a schema version. When the application starts, it will query the database for a table named `schemaversion` that has one row and one column (`version`). If the `version` it finds is not equal to the `desiredSchemaVersion` variable set in `db.py`, it will run migration scripts from the `schema_migrations` folder one by one until the `schemaversion` table shows the correct version.
|
||||
|
||||
For example, the script named `02_up_xyz.sql` should contain code that migrates the database from schema version 1 to schema version 2. Likewise, the script `02_down_xyz.sql` should contain code that migrates from schema version 2 back to schema version 1.
|
||||
|
||||
**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 view the logs on the database server (legion.cyberia.club)
|
||||
|
||||
`sudo -u postgres pg_dump capsul-flask | gzip -9 > capsul-backup-2021-02-15.gz`
|
68
docs/deployment.md
Normal file
68
docs/deployment.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Deploying Capsul on a server
|
||||
|
||||
## Installing prerequisites for Spoke Mode
|
||||
|
||||
On your spoke (see [Architecture](./architecture.md) You'll need `libvirtd`, `dnsmasq`, and `qemu-kvm`, plus a `/tank` diectory with some operating system images in it:
|
||||
|
||||
```
|
||||
sudo apt install libvirt-daemon-system virtinst git dnsmasq qemu qemu-kvm
|
||||
sudo mkdir -p /var/www /tank/{vm,img,config}
|
||||
sudo mkdir -p /tank/img/debian/10
|
||||
cd !$
|
||||
sudo wget https://cloud.debian.org/images/cloud/buster/20201023-432/debian-10-genericcloud-amd64-20201023-432.qcow2 -O root.img.qcow2
|
||||
```
|
||||
|
||||
TODO: network set-up
|
||||
TODO: cyberia-cloudinit.yml
|
||||
|
||||
## Deploying capsul-flask
|
||||
|
||||
### Extra Manual™
|
||||
|
||||
Follow the [local set-up instructions](./local-set-up.md) on your server.
|
||||
|
||||
Make sure to set `BASE_URL` correctly, generate your own secret tokens, and
|
||||
configure your own daemon management for the capsul-flask server (e.g. writing
|
||||
init scripts, or SystemD unit files).
|
||||
|
||||
Use the suggested `gunicorn` command (with appropriately-set address and port),
|
||||
instead of `flask run`, to launch the server.
|
||||
|
||||
TODO: cron runner
|
||||
|
||||
### Using vanilla Docker Swarm
|
||||
|
||||
Download the Co-op Cloud swarm `compose.yml`:
|
||||
|
||||
```sh
|
||||
wget https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/compose.yml
|
||||
```
|
||||
|
||||
Optionally, download add-on compose files for Stripe, BTCPay, and Spoke Mode:
|
||||
|
||||
```sh
|
||||
wget https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/compose.{stripe,btcpay,spoke}.yml
|
||||
```
|
||||
|
||||
Then, create a `.env` file and configure appropriately -- you probably want to
|
||||
define most settings in [the Co-op Cloud `.envrc.sample`
|
||||
file](https://git.autonomic.zone/coop-cloud/capsul/src/branch/main/.envrc.sample).
|
||||
|
||||
Load the environment variables (using Python `direnv`, or a manual `set -a && source .env && set +a`), insert any necessary secrets, then run the deployment:
|
||||
|
||||
```sh
|
||||
docker stack deploy -c compose.yml -c compose.stripe.yml your_capsul
|
||||
```
|
||||
|
||||
(where you'd add an extra `-c compose.btcpay.yml` for each optional compose file
|
||||
you want, and set `your_capsul` to the "stack name" you want).
|
||||
|
||||
TODO: cron runner
|
||||
|
||||
### Using Co-op Cloud / Docker Swarm
|
||||
|
||||
Follow [the guide in the README for the Co-op Cloud capsul package](https://git.autonomic.zone/coop-cloud/capsul/).
|
||||
|
||||
### Using docker-compose
|
||||
|
||||
TODO
|
BIN
docs/images/btcpay_sin_pairing.jpg
Normal file
BIN
docs/images/btcpay_sin_pairing.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
1
docs/images/btcpayment_process.drawio
Normal file
1
docs/images/btcpayment_process.drawio
Normal file
File diff suppressed because one or more lines are too long
BIN
docs/images/btcpayment_process.png
Normal file
BIN
docs/images/btcpayment_process.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 190 KiB |
47
docs/images/generate_btcpay_keys.py
Normal file
47
docs/images/generate_btcpay_keys.py
Normal file
@ -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("")
|
1
docs/images/hub-and-spoke.xml
Normal file
1
docs/images/hub-and-spoke.xml
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2021-01-03T00:49:24.202Z" agent="5.0 (X11)" etag="bNLCzv8xp0QHJ2iOv8s8" version="14.1.8" type="device"><diagram id="2J8LUWl6CGm-7iVjfT5N" name="Page-1">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</diagram></mxfile>
|
BIN
docs/images/hub-and-spoke1.png
Normal file
BIN
docs/images/hub-and-spoke1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
docs/images/hub-and-spoke2.png
Normal file
BIN
docs/images/hub-and-spoke2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
BIN
docs/images/paired.jpg
Normal file
BIN
docs/images/paired.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
69
docs/local-set-up.md
Normal file
69
docs/local-set-up.md
Normal file
@ -0,0 +1,69 @@
|
||||
# How to run Capsul locally
|
||||
|
||||
## With Docker
|
||||
|
||||
If you have Docker and Docker-Compose installed, you can use the
|
||||
`3wordchant/capsul-flask` Docker image to launch capsul-flask, and a Postgres
|
||||
database server, for you:
|
||||
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
docker-compose will read settings from your `.env` file; you can set any of the
|
||||
options mentioned in the [configuration documentation](./configuration.md).
|
||||
|
||||
## Manually
|
||||
|
||||
Ensure you have the pre-requisites for the psycopg2 Postgres database adapter package:
|
||||
|
||||
```sh
|
||||
sudo apt install python3-dev libpq-dev
|
||||
pg_config --version
|
||||
```
|
||||
|
||||
Ensure you have the wonderful `pipenv` python package management and virtual environment cli:
|
||||
|
||||
```sh
|
||||
sudo apt install pipenv
|
||||
```
|
||||
|
||||
Create python virtual environment and install packages:
|
||||
|
||||
```sh
|
||||
pipenv install
|
||||
```
|
||||
|
||||
Run an instance of Postgres (I used docker for this, you can use whatever you want, point is its listening on `localhost:5432`):
|
||||
|
||||
```sh
|
||||
docker run --rm -it -e POSTGRES_PASSWORD=dev -p 5432:5432 postgres
|
||||
```
|
||||
|
||||
Run the app
|
||||
|
||||
```sh
|
||||
pipenv run flask run
|
||||
```
|
||||
|
||||
or, using Gunicorn:
|
||||
|
||||
```sh
|
||||
pipenv run gunicorn --bind 127.0.0.1:5000 -k gevent --worker-connections 1000 app:app
|
||||
```
|
||||
|
||||
Note that by default when running locally, the `SPOKE_MODEL` is set to `mock`, meaning that it won't actually try to spawn vms.
|
||||
|
||||
## Crediting your account
|
||||
|
||||
Once you log in for the first time, you will want to give yourself some free capsulbux so you can create fake capsuls for testing.
|
||||
|
||||
```sh
|
||||
pipenv run flask cli sql -c "INSERT INTO payments (email, dollars) VALUES ('<your email address here>', 20.00)"
|
||||
```
|
||||
|
||||
## Running scheduled tasks:
|
||||
|
||||
```sh
|
||||
pipenv run flask cli cron-task
|
||||
```
|
Reference in New Issue
Block a user