mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 18:44:20 +01:00
* clean up db * db: table lock * db.table_with_schema * fix encrypt.py * postgres nowait * add timeout to lock * melt quote state in db * kinda working * kinda working with postgres * remove dispose * getting there * porperly clean up db for tests * faster tests * configure connection pooling * try github with connection pool * invoice dispatcher does not lock db * fakewallet: pay_if_regtest waits * pay fakewallet invoices * add more * faster * slower * pay_if_regtest async * do not lock the invoice dispatcher * test: do I get disk I/O errors if we disable the invoice_callback_dispatcher? * fix fake so it workss without a callback dispatchert * test on github * readd tasks * refactor * increase time for lock invoice disatcher * try avoiding a race * remove task * github actions: test regtest with postgres * mint per module * no connection pool for testing * enable pool * do not resend paid event * reuse connection * close db connections * sessions * enable debug * dispose engine * disable connection pool for tests * enable connection pool for postgres only * clean up shutdown routine * remove wait for lightning fakewallet lightning invoice * cancel invoice listener tasks on shutdown * fakewallet conftest: decrease outgoing delay * delay payment and set postgres only if needed * disable fail fast for regtest * clean up regtest.yml * change order of tests_db.py * row-specific mint_quote locking * refactor * fix lock statement * refactor swap * refactor * remove psycopg2 * add connection string example to .env.example * remove unnecessary pay * shorter sleep in test_wallet_subscription_swap
165 lines
5.5 KiB
Python
165 lines
5.5 KiB
Python
import click
|
|
|
|
try:
|
|
from ..core.crypto.aes import AESCipher
|
|
except ImportError:
|
|
# for the CLI to work
|
|
from cashu.core.crypto.aes import AESCipher
|
|
import asyncio
|
|
from functools import wraps
|
|
|
|
from cashu.core.db import Database
|
|
from cashu.core.migrations import migrate_databases
|
|
from cashu.core.settings import settings
|
|
from cashu.mint import migrations
|
|
from cashu.mint.crud import LedgerCrudSqlite
|
|
from cashu.mint.ledger import Ledger
|
|
|
|
|
|
# https://github.com/pallets/click/issues/85#issuecomment-503464628
|
|
def coro(f):
|
|
@wraps(f)
|
|
def wrapper(*args, **kwargs):
|
|
return asyncio.run(f(*args, **kwargs))
|
|
|
|
return wrapper
|
|
|
|
|
|
@click.group()
|
|
def cli():
|
|
"""Ledger Decrypt CLI"""
|
|
pass
|
|
|
|
|
|
@cli.command()
|
|
@click.option("--message", prompt=True, help="The message to encrypt.")
|
|
@click.option(
|
|
"--key",
|
|
prompt=True,
|
|
hide_input=True,
|
|
confirmation_prompt=True,
|
|
help="The encryption key.",
|
|
)
|
|
def encrypt(message, key):
|
|
"""Encrypt a message."""
|
|
aes = AESCipher(key)
|
|
encrypted_message = aes.encrypt(message.encode())
|
|
click.echo(f"Encrypted message: {encrypted_message}")
|
|
|
|
|
|
@cli.command()
|
|
@click.option("--encrypted", prompt=True, help="The encrypted message to decrypt.")
|
|
@click.option(
|
|
"--key",
|
|
prompt=True,
|
|
hide_input=True,
|
|
help="The decryption key.",
|
|
)
|
|
def decrypt(encrypted, key):
|
|
"""Decrypt a message."""
|
|
aes = AESCipher(key)
|
|
decrypted_message = aes.decrypt(encrypted)
|
|
click.echo(f"Decrypted message: {decrypted_message}")
|
|
|
|
|
|
# command to migrate the database to encrypted seeds
|
|
@cli.command()
|
|
@coro
|
|
@click.option("--no-dry-run", is_flag=True, help="Dry run.", default=False)
|
|
async def migrate(no_dry_run):
|
|
"""Migrate the database to encrypted seeds."""
|
|
click.echo(f"Database: directory: {settings.mint_database}")
|
|
assert settings.mint_seed_decryption_key, "MINT_SEED_DECRYPTION_KEY not set."
|
|
assert (
|
|
len(settings.mint_seed_decryption_key) > 12
|
|
), "MINT_SEED_DECRYPTION_KEY is too short, must be at least 12 characters."
|
|
click.echo(
|
|
"Decryption key:"
|
|
f" {settings.mint_seed_decryption_key[0]}{'*'*10}{settings.mint_seed_decryption_key[-1]}"
|
|
)
|
|
click.echo(
|
|
f"Seed: {settings.mint_private_key[0]}{'*'*10}{settings.mint_private_key[-1]}"
|
|
)
|
|
ledger = Ledger(
|
|
db=Database("mint", settings.mint_database),
|
|
seed=settings.mint_private_key,
|
|
derivation_path=settings.mint_derivation_path,
|
|
backends={},
|
|
crud=LedgerCrudSqlite(),
|
|
)
|
|
aes = AESCipher(settings.mint_seed_decryption_key)
|
|
|
|
click.echo("Making sure that db is migrated to latest version first.")
|
|
await migrate_databases(ledger.db, migrations)
|
|
|
|
# get all keysets
|
|
async with ledger.db.connect() as conn:
|
|
rows = await conn.fetchall(
|
|
f"SELECT * FROM {ledger.db.table_with_schema('keysets')} WHERE seed IS NOT"
|
|
" NULL"
|
|
)
|
|
click.echo(f"Found {len(rows)} keysets in database.")
|
|
keysets_all = [dict(**row) for row in rows]
|
|
keysets_migrate = []
|
|
# encrypt the seeds
|
|
for keyset_dict in keysets_all:
|
|
if keyset_dict["seed"] and not keyset_dict["encrypted_seed"]:
|
|
keyset_dict["encrypted_seed"] = aes.encrypt(keyset_dict["seed"].encode())
|
|
keyset_dict["seed_encryption_method"] = "aes"
|
|
keysets_migrate.append(keyset_dict)
|
|
else:
|
|
click.echo(f"Skipping keyset {keyset_dict['id']}: already migrated.")
|
|
|
|
click.echo(f"There are {len(keysets_migrate)} keysets to migrate.")
|
|
|
|
for keyset_dict in keysets_migrate:
|
|
click.echo(f"Keyset {keyset_dict['id']}")
|
|
click.echo(f" Encrypted seed: {keyset_dict['encrypted_seed']}")
|
|
click.echo(f" Encryption method: {keyset_dict['seed_encryption_method']}")
|
|
decryption_success_str = (
|
|
"✅"
|
|
if aes.decrypt(keyset_dict["encrypted_seed"]) == keyset_dict["seed"]
|
|
else "❌"
|
|
)
|
|
click.echo(f" Seed decryption test: {decryption_success_str}")
|
|
|
|
if not no_dry_run:
|
|
click.echo(
|
|
"This was a dry run. Use --no-dry-run to apply the changes to the database."
|
|
)
|
|
if no_dry_run and keysets_migrate:
|
|
click.confirm(
|
|
"Are you sure you want to continue? Before you continue, make sure to have"
|
|
" a backup of your keysets database table.",
|
|
abort=True,
|
|
)
|
|
click.echo("Updating keysets in the database.")
|
|
async with ledger.db.connect() as conn:
|
|
for keyset_dict in keysets_migrate:
|
|
click.echo(f"Updating keyset {keyset_dict['id']}")
|
|
await conn.execute(
|
|
f"UPDATE {ledger.db.table_with_schema('keysets')} SET seed='',"
|
|
" encrypted_seed = ?, seed_encryption_method = ? WHERE id = ?",
|
|
(
|
|
keyset_dict["encrypted_seed"],
|
|
keyset_dict["seed_encryption_method"],
|
|
keyset_dict["id"],
|
|
),
|
|
)
|
|
|
|
click.echo("Initializing mint with encrypted seeds.")
|
|
encrypted_mint_private_key = aes.encrypt(settings.mint_private_key.encode())
|
|
ledger = Ledger(
|
|
db=Database("mint", settings.mint_database),
|
|
seed=encrypted_mint_private_key,
|
|
seed_decryption_key=settings.mint_seed_decryption_key,
|
|
derivation_path=settings.mint_derivation_path,
|
|
backends={},
|
|
crud=LedgerCrudSqlite(),
|
|
)
|
|
click.echo("✅ Migration complete.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
cli()
|