password_valid()/name_valid() ended in `return re.match(...)`, which yields a Match object or None. The setup router tests them with `is False`, and `None is False` is False, so the charset check never rejected anything -- only the length and space rules were doing any work. The validators now return real booleans, and use fullmatch: with re.match the trailing `$` also matches just before a final newline. Impact is bounded, and this is a correctness bug rather than a vulnerability. These call sites are reachable only while the node is in `state=waitsetup`, and that same endpoint hands the caller a signed admin JWT by design, on a device where blitzapi has passwordless sudo. A malformed hostname reaching the setup file -- which provisioning sources as bash -- therefore grants nothing the caller does not already have, and in practice the value comes from the operator's own setup form. What it does cost: a hostname containing a quote or `$` corrupts the setup file and breaks provisioning, and the charset gate would not hold as a defence if the setup flow ever gains operator binding. Also in this change: - Gate /setup-start-done and /setup-start-info on setupPhase != "done", as /setup/shutdown already does. `state` lives in the unauthenticated key-value store, so a local process could flip it back to "waitsetup" on a fully provisioned node and be handed an admin JWT. Unlike the above, that is a real escalation, because setup is supposed to be closed at that point. - raise HTTPException instead of returning it (18 sites). FastAPI serialised the returned object as a 200 body, so rejections looked like successes; the WebUI stored that body as its access token. - Fix the status.status.HTTP_405_METHOD_NOT_ALLOWED typo (3 sites) that raised AttributeError and surfaced as an unhandled 500. - Create the setup file 0600. It holds passwords A/B/C in cleartext and provisioning appends the wallet seed words, on a tmpfs mounted mode=0777. Regression tests in tests/test_setup_input_validation.py; all nine fail before this change and pass after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .github | ||
| .vscode | ||
| app | ||
| docs/superpowers | ||
| modules | ||
| scripts | ||
| tests | ||
| .$calls.drawio.bkp | ||
| .coveragerc | ||
| .env_sample | ||
| .envrc | ||
| .gitignore | ||
| .wakatime-project | ||
| _typos.toml | ||
| calls.drawio | ||
| conftest.py | ||
| devenv.lock | ||
| devenv.nix | ||
| devenv.yaml | ||
| flake.lock | ||
| flake.nix | ||
| gen_client_libs.py | ||
| LICENSE | ||
| Makefile | ||
| openapi.json | ||
| openapitools.json | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
| uv.lock | ||
Blitz API
A management backend for bitcoin and lightning node operators written in Python with FastAPI.
Beta Disclaimer
This software is still considered BETA and may contain bugs. Don't expose it to the open internet or use with a lot of funds.
- Blitz API
- Beta Disclaimer
- Configuration
- Installation
- Run the application
- Development
- Acknowledgements
Configuration
Create a .env file with your bitcoind and lnd configuration. See the .env_sample file for all configuration options.
The .env file is expected to be at the project root folder by default.
To use a custom path, set the BAPI_ENV_PATH env variable to the .env file path.
Dependencies
- Python in version 3.11 or 3.12
- uv for dependency management
- Redis
- Polar If you need an easy option to run a simple bitcoind & lnd client
Installation
⚠️ To setup a development environment for BlitzAPI skip to the Development section.
Linux / macOS
make install
or
python -m pip install -r requirements.txt
Windows
py -m pip install -r requirements.txt
Run the application
Linux / macOS
make run
or
python -m uvicorn app.main:app --reload
Windows
py -m uvicorn app.main:app --reload
Development
Dependencies are managed with uv. Install it by following the uv installation guide.
uv creates and manages a local .venv for you. Prefix commands with uv run (e.g. uv run pytest) to run them inside the project environment, or activate the venv manually via source .venv/bin/activate.
Using the nix package manager
Blitz API provides a Nix Flake file to create a development environment. Execute nix develop (make sure you have flakes enabled) to enter the environment.
In this environment a hidden folder .venv is created to install the python dependencies locally. If pyright can't find these dependencies create the following file in the root
folder of the project:
{
"venvPath": ".",
"venv": ".venv"
}
Installation
make install-dev
or
uv sync
This reads pyproject.toml and installs all dependencies (main + dev) into .venv.
If python dependencies have been changed it's necessary to freeze all requirements to requirements.txt:
make update-requirements-file
or
uv pip compile --all-extras --universal --output-file requirements.txt pyproject.toml
ℹ️ The final deployment installs via pip from
requirements.txt(seemake install) to avoid having to install uv on the target machine, so keep this file in sync when dependencies change.
Sync changes to a RaspiBlitz
Create a file /script/sync_to_blitz.personal.sh (will be ignored by github) the SSH connection data to your RaspiBlitz.
localIP="192.168.178.61" sshPort="22" passwordA=""
Then you can run always make sync-to-blitz to copy your latest code over to your RaspiBlitz. The script automatically restarts the backend API with the new code on your RaspiBlitz and shows you the logs.
To test the backend API then call the SwaggerUI: http://[LOCALIP]/api/v1/docs - to call protected endpoints run the /system/login endpoint first with HTTP POST body:
{
"password": "[PASSWORDA]"
}
and then copy the JWT Auth string returned to Authorize in the top section of the SwaggerUI.
You can also now test the RaspiBlitz WebUI against the API by running it locally on your dev laptop when you configure it to use the backend API of your RaspiBlitz.
Debugging code running on a remote machine via VSCode
To debug Python code that is running on another machine, like a RaspiBlitz, follow these steps.
Prepare local machine
- run
make install-dev. - open the
.vscode/launch.jsonfile and change the host to your remote machines IP-
"connect": { "host": "192.168.1.49", "port": 5678 }
-
- open your
.env_samplefile and replace the line# remote_debugging=falsewithremote_debugging=trueThis is necessary because we're going to synchronize the local source with the remote node. The blitz_api service will be restarted on the remote node. Any changes to the `.env' file will be overwritten by the setup script on the Blitz. This script will use the `.env_sample` file as a base and fill it with data. This way we can trick the Blitz into enabling this setting every time we change something without the Blitz explicitly supporting it. - make sure you follow the steps in the Sync changes to a RaspiBlitz section
- execute
make sync-to-blitz - Make sure to chose
Attachin the RUN AND DEBUG windows of VSCode - Hit F5 and voila you should be connected to your RaspiBlitz and debug code remotely
Prepare the RaspiBlitz
- SSH into the Blitz, and run
sudo -i -u blitzapi cd blitz_api- Finally run
make enable-remote-debugging
Refer to this documentation to learn how to setup VSCode correctly.
Unit / Integration testing
Make sure to include tests for important pieces of submitted code.
Run the tests with pytest
make test
Run tests and generate a coverage
make coverage
This will run tests and generate a coverage html file in this folder: ./htmlcov
Client libraries
ℹ️ The client libraries live in an extra repository: https://github.com/fusion44/blitz_api_client_libraries
Generating client libraries
Install OpenAPI Generator and Java:
npm install @openapitools/openapi-generator-cli -g
sudo apt install default-jre
Clone https://github.com/fusion44/blitz_api_client_libraries next to the blitz_api folder.
make generate-client-libs
⚠️ The first run requires
sudoas it must download a Java .jar file to the system npm package folder.
Swagger / OpenAPI
Once the API is running swagger docs can be found here:
http://127.0.0.1:8000/latest/docs
Useful cURL commands to test the API
curl -N -H "Authorization: Bearer JWT_TOKEN_HERE" http://127.0.0.1:8000/sse/subscribe
curl -N -H "Authorization: Bearer JWT_TOKEN_HERE" http://127.0.0.1:8000/v1/bitcoin/getblockchaininfo
curl -X POST -N http://127.0.0.1:8000/v1/setup/type/1
curl --header "Content-Type: application/json" \
--request POST \
--data '{"password":"12345678"}' \
http://127.0.0.1:8000/system/login
Acknowledgements
Integrated Libraries: