Add ops scripts to decrypt/re-encrypt the master xprv, and document them

decrypt_master_key.py: prints the existing master xprv after an explicit
confirmation prompt, for disaster-recovery backups. Falls back to
./data/keys/master.xprv.enc (the docker-compose.yml bind-mount path) when
.env's configured MASTER_KEY_PATH doesn't exist locally.

encrypt_master_key.py: the reverse direction — takes an externally-generated
xprv (e.g. created offline/air-gapped) via a hidden getpass prompt, validates
it parses as a private extended key, and encrypts it with the same Fernet
scheme generate_master_key.py uses. Refuses to overwrite an existing key file
unless --overwrite is passed.

Neither script is reachable via any API endpoint or the admin panel, by
design — this is the one secret the entire custodial wallet derives from.
Documented in docs/setup.md (new "Recuperare o portare una xprv esistente"
section) and CLAUDE.md's Commands block.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 16:20:03 +02:00
co-authored by Claude Sonnet 5
parent 9e7b726df7
commit 1941f30b10
4 changed files with 150 additions and 0 deletions
+21
View File
@@ -52,6 +52,27 @@ file insieme a `XPRV_ENCRYPTION_KEY`** — uno dei due da solo è inutile, ma
perderli entrambi insieme significa perdere i fondi di tutti gli utenti senza
possibilità di recupero.
### Recuperare o portare una xprv esistente
Due script, entrambi manuali/una tantum, per lo scenario di disaster recovery
o per usare una xprv generata altrove (es. offline/air-gapped) invece di
farla generare al server:
- **`scripts/decrypt_master_key.py`**: decifra e stampa a schermo la xprv
già presente in `MASTER_KEY_PATH` (con fallback automatico su
`./data/keys/master.xprv.enc` se il path di `.env` non esiste in locale).
Chiede conferma esplicita prima di stampare.
- **`scripts/encrypt_master_key.py`**: cifra una xprv esterna e la scrive in
`MASTER_KEY_PATH` con lo stesso identico schema (Fernet +
`XPRV_ENCRYPTION_KEY`) usato da `generate_master_key.py`. La xprv va
incollata con input nascosto (non appare a schermo). Si rifiuta di
sovrascrivere un file esistente a meno di passare `--overwrite`.
Entrambi vanno eseguiti localmente (o dentro il container via
`docker compose run --rm app ...`), mai esposti da un endpoint API o dal
pannello admin: chi ottiene questa xprv ottiene il controllo dei fondi di
tutti gli utenti e del pool.
## 4. Installare le dipendenze (solo workflow locale/venv)
Salta questo passaggio se usi solo Docker — l'immagine installa le proprie