website for the Dark.Fi's hardware webshop.
python-based website integrating a webshop (Stripe, NOWPayments) and git-based workflow to update website content:
as the content repository is tracked with git, we're using git-annex to handle binary files. to setup this integration:
git annex (see https://git-annex.branchable.com/install/)
add a .gitattributes file with the following:
* annex.largefiles=nothing
*.png filter=annex annex.largefiles=anything
*.jpg filter=annex annex.largefiles=anything
*.pdf filter=annex annex.largefiles=anything
*.epub filter=annex annex.largefiles=anything
add more file type as needed. after this, we don't need to track binary files with git annex add but we can simply use git add.
git init, git annex initgit add, git mv, git rm, etc)git annex sync --content; this syncs both from your computer to the remote server and vice-versa (eg it does a pull and then a push)git annex findgit annex get <filepath> (or without filepath to get all listed files)git annex drop --force <filepath> (or without <filepath> to remove all listed files)
--force because by default git-annex tries to keep at least 1 more copy of the file in another repo, before deleting the file; in eg, it acts as an archive-focused system. since we might not care about that, passing --force bypasses the normal mechanismgit rm <filepath> will not remove the file from the repo, only the symlink git-annex created for it; we can check this by doing ls -l ./git/annex/objects/ and count how many items are in thererename settings.sample.toml to settings.toml and fill out fields:
git_repo: set the path to the content folder (it can also be a relative path)document_match: list of file extension to matchdocument_exclude: list of files to excludeblock_types: set necessary block types (for the content document); for starting, the default ones should be enough; the website's parser read from this list of block types to validate if a given block is "allowed"local_db.filepath: path to local DB, eg file that contains the ordersorder_upload.filepath: path to folder where new XLSX file order are exported to (these files are used to upload a shipping order on the Swiss Post website)currency.default: default currency for Stripecurrency.now_payments: default currency for NOWPaymentscopy the file env.sample and rename it .env. then update its content accordingly:
ENV: set if environment is development or production (it affects some of the code logic)CACHE: set enable or disable to cache CSS, JS and font filesCSRF_SECRET_KEY: generate a secret (a random string of characters) for the CSRF protection, see https://stackoverflow.com/a/54433731; for example:
python
>>> import secrets
>>> secrets.token_hex(16)
SESSION_SECRET_KEY: see item above for how to generate a random string
STRIPE_SECRET_KEY: Stripe API key for production
STRIPE_TEST_SECRET_KEY: Stripe API key for dev environment. Put here your TEST API key. Beware that data in test environment differs from production
STRIPE_ENDPOINT_SECRET: Stripe webhook secret
NOWPAYMENTS_API_KEY: NOWPayments API key
NOWPAYMENTS_SANDBOX_IPN: NOWPayments IPN
NOWPAYMENTS_SANDBOX_API_KEY: NOWPayments Sandbox API key
NOWPAYMENTS_SANDBOX_IPN: NOWPayments Sandbox IPN
MAIL_USERNAME: email address
MAIL_PASSWORD: email password
MAIL_FROM: email sender address
MAIL_FROM_NAME: email sender name
MAIL_PORT: email port
MAIL_SERVER: email server
MAIL_STARTTLS: True|False
MAIL_SSL_TLS: True|False
MAIL_USE_CREDENTIALS: True|False
MAIL_VALIDATE_CERTS: True|False
CPU_CORE: set computer's number of CPU cores, on Linux run nproc --all; this is used by the build_image_cache.py command to generate images of various sizes for the frontend.
python -m venv envsource env/bin/activatepip install -r requirements.txtwhenever installing a new package, save it to requirements.txt by doing:
pip freeze > requirements.txt
to run the local web-server, type:
./dev-server.sh
to run the production server, do:
./server.sh
we display images in various sizes so that the browser can pick the best image in terms of quality / size ratio — for instance by not downloading a high-res image prepared for a big screen if the browser request comes from a small screen device (eg. a phone). to deal with this, there a CLI script called build_image_cache.py at the root of the repo. it offers two commands:
before generating images make sure that the cache folder exists in static/images, otherwise images won't get written
build-all-images: this build all images across the content repo. if an image exists already in the ./static/images/cache/ folder, it will skip it. you can either remove it from the cache folder or rename the image to a new name to force-recreate it. run this command like so: python build_image_cache.py build-all-images '<path/to/content-repo>build-images: this command is used in the git post-receive hook in the git bare repo (on the VPS). it checks if the last pushed commit contains also image files, and if so it creates the necessary sizes of each image for the website. check the post-receive files for the detailsexample:
python build_image_cache.py build-all-images <path/to/content-folder>
unlike with NOWPayments, we can locally test that the Stripe webhook works as intended — for instance that it triggers the order status update, the product inventory update, and the email confirmation.
to do so:
then open a new shell and run:
stripe listen --load-from-webhooks-api --forward-to http://127.0.0.1:5014
where http://127.0.0.1:5014 is your local server port (which is the one set in dev-server.sh). this command listen to our "online" Stripe webhook for any event, and redirects them all to our local environment.
when you run Stripe CLI locally, it might print the webhook signature valid for our local environment — make sure to add it or replace it to the field STRIPE_TEST_ENDPOINT_SECRET in the .env file.
some refs:
aftewards, run whatever you need to test.
sudo adduser)~/.ssh/authorized_keys, set permissions (https://superuser.com/a/925859)sudo group (sudo adduser <user> sudo)update /etc/ssh/ssh_config by changing or adding values to the following:
# disable ssh login for root user
PermitRootLogin no
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no
# remove password-based login for any user
AuthenticationMethods publickey
PubkeyAuthentication yes
# limit ssh access to specified users (IMPORTANT: this will block any other previously authorized user to login via ssh)
AllowUsers <user-1> <user-2>
# disable empty password
PermitEmptyPasswords no
# disable X11Forwarding
X11Forwarding no
then restart sshd with sudo systemctl restart sshd
pyenv (https://bgasparotto.com/install-pyenv-ubuntu-debian):
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-devcurl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bashpyenv install 3.12make git bare repo for source code and add post-receive hook:
#!/bin/bash
GIT_WORK_TREE=/var/www/hardware.darkfi git checkout -f main
chmod +x hooks/post-receivemake folder for website at /var/www/hardware.darkfi; create a new git remote pointing to <user>@<server-ip>:www-code.git and then push to this remote (it should copy all files over to /var/www/darkfi-webshop)
install nginx and copy sample file to /etc/nginx/site-available/; enable nginx site by making a symbolic link of it to /etc/nginx/site-enabled/: sudo ln -s /etc/nginx/site-available/hardware.darkfi.nginx /etc/nginx/site-enabled/hardware.darkfi.nginx
install git-annex:
sudo apt-get install neurodebiansudo apt-get updatesudo apt install git-annexmake new file /etc/systemd/system/darkfi.service and copy sample
sudo systemctl enable darkfi, sudo systemctl start darkfi
setup git user info for current user:
git config --global user.email "you@example.com"git config --global user.name "Your Name"make git bare repo for content:
mkdir www-datacd www-data && git init --bare www-data.gitgit clone www-data.git contentcd content && git annex initpost-receive script to ~/www-data/www-data.git/hooks/chmod +x ~/www-data/www-data.git/hooks/post-receive.this will synchronize the git checkout folder (at ~/www-data/content) with the git bare repo we use for actual synchronization (at ~/www-data/www-data.git).