mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-23 03:34:19 +01:00
Blind authentication (#675)
* auth server * cleaning up * auth ledger class * class variables -> instance variables * annotations * add models and api route * custom amount and api prefix * add auth db * blind auth token working * jwt working * clean up * JWT works * using openid connect server * use oauth server with password flow * new realm * add keycloak docker * hopefully not garbage * auth works * auth kinda working * fix cli * auth works for send and receive * pass auth_db to Wallet * auth in info * refactor * fix supported * cache mint info * fix settings and endpoints * add description to .env.example * track changes for openid connect client * store mint in db * store credentials * clean up v1_api.py * load mint info into auth wallet * fix first login * authenticate if refresh token fails * clear auth also middleware * use regex * add cli command * pw works * persist keyset amounts * add errors.py * do not start auth server if disabled in config * upadte poetry * disvoery url * fix test * support device code flow * adopt latest spec changes * fix code flow * mint max bat dynamic * mypy ignore * fix test * do not serialize amount in authproof * all auth flows working * fix tests * submodule * refactor * test * dont sleep * test * add wallet auth tests * test differently * test only keycloak for now * fix creds * daemon * fix test * install everything * install jinja * delete wallet for every test * auth: use global rate limiter * test auth rate limit * keycloak hostname * move keycloak test data * reactivate all tests * add readme * load proofs * remove unused code * remove unused code * implement change suggestions by ok300 * add error codes * test errors
This commit is contained in:
@@ -75,16 +75,26 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
db_read: DbReadHelper
|
||||
invoice_listener_tasks: List[asyncio.Task] = []
|
||||
disable_melt: bool = False
|
||||
pubkey: PublicKey
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
db: Database,
|
||||
seed: str,
|
||||
backends: Mapping[Method, Mapping[Unit, LightningBackend]],
|
||||
seed_decryption_key: Optional[str] = None,
|
||||
derivation_path="",
|
||||
amounts: Optional[List[int]] = None,
|
||||
backends: Optional[Mapping[Method, Mapping[Unit, LightningBackend]]] = None,
|
||||
seed_decryption_key: Optional[str] = None,
|
||||
crud=LedgerCrudSqlite(),
|
||||
):
|
||||
) -> None:
|
||||
self.keysets: Dict[str, MintKeyset] = {}
|
||||
self.backends: Mapping[Method, Mapping[Unit, LightningBackend]] = {}
|
||||
self.events = LedgerEventManager()
|
||||
self.db_read: DbReadHelper
|
||||
self.locks: Dict[str, asyncio.Lock] = {} # holds multiprocessing locks
|
||||
self.invoice_listener_tasks: List[asyncio.Task] = []
|
||||
|
||||
if not seed:
|
||||
raise Exception("seed not set")
|
||||
|
||||
@@ -103,24 +113,33 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
|
||||
self.db = db
|
||||
self.crud = crud
|
||||
self.backends = backends
|
||||
|
||||
if backends:
|
||||
self.backends = backends
|
||||
|
||||
if amounts:
|
||||
self.amounts = amounts
|
||||
else:
|
||||
self.amounts = [2**n for n in range(settings.max_order)]
|
||||
|
||||
self.pubkey = derive_pubkey(self.seed)
|
||||
self.db_read = DbReadHelper(self.db, self.crud)
|
||||
self.db_write = DbWriteHelper(self.db, self.crud, self.events, self.db_read)
|
||||
|
||||
# ------- STARTUP -------
|
||||
|
||||
async def startup_ledger(self):
|
||||
await self._startup_ledger()
|
||||
async def startup_ledger(self) -> None:
|
||||
await self._startup_keysets()
|
||||
await self._check_backends()
|
||||
await self._check_pending_proofs_and_melt_quotes()
|
||||
self.invoice_listener_tasks = await self.dispatch_listeners()
|
||||
|
||||
async def _startup_ledger(self):
|
||||
async def _startup_keysets(self) -> None:
|
||||
await self.init_keysets()
|
||||
|
||||
for derivation_path in settings.mint_derivation_path_list:
|
||||
await self.activate_keyset(derivation_path=derivation_path)
|
||||
|
||||
async def _check_backends(self) -> None:
|
||||
for method in self.backends:
|
||||
for unit in self.backends[method]:
|
||||
logger.info(
|
||||
@@ -139,7 +158,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
|
||||
logger.info(f"Data dir: {settings.cashu_dir}")
|
||||
|
||||
async def shutdown_ledger(self):
|
||||
async def shutdown_ledger(self) -> None:
|
||||
await self.db.engine.dispose()
|
||||
for task in self.invoice_listener_tasks:
|
||||
task.cancel()
|
||||
@@ -169,57 +188,65 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
|
||||
version: Optional[str] = None,
|
||||
autosave=True,
|
||||
) -> MintKeyset:
|
||||
"""Load the keyset for a derivation path if it already exists. If not generate new one and store in the db.
|
||||
"""
|
||||
Load an existing keyset for the specified derivation path or generate a new one if it doesn't exist.
|
||||
Optionally store the newly created keyset in the database.
|
||||
|
||||
Args:
|
||||
derivation_path (_type_): Derivation path from which the keyset is generated.
|
||||
autosave (bool, optional): Store newly-generated keyset if not already in database. Defaults to True.
|
||||
derivation_path (str): Derivation path for keyset generation.
|
||||
seed (Optional[str], optional): Seed value. Defaults to None.
|
||||
version (Optional[str], optional): Version identifier. Defaults to None.
|
||||
autosave (bool, optional): Whether to store the keyset if newly created. Defaults to True.
|
||||
|
||||
Returns:
|
||||
MintKeyset: Keyset
|
||||
MintKeyset: The activated keyset.
|
||||
"""
|
||||
if not derivation_path:
|
||||
raise Exception("derivation path not set")
|
||||
raise ValueError("Derivation path must be provided.")
|
||||
|
||||
seed = seed or self.seed
|
||||
tmp_keyset_local = MintKeyset(
|
||||
version = version or settings.version
|
||||
# Initialize a temporary keyset to derive the ID
|
||||
temp_keyset = MintKeyset(
|
||||
seed=seed,
|
||||
derivation_path=derivation_path,
|
||||
version=version or settings.version,
|
||||
version=version,
|
||||
amounts=self.amounts,
|
||||
)
|
||||
logger.debug(
|
||||
f"Activating keyset for derivation path {derivation_path} with id"
|
||||
f" {tmp_keyset_local.id}."
|
||||
f"Activating keyset for derivation path '{derivation_path}' with ID '{temp_keyset.id}'."
|
||||
)
|
||||
# load the keyset from db
|
||||
logger.trace(f"crud: loading keyset for {derivation_path}")
|
||||
tmp_keysets_local: List[MintKeyset] = await self.crud.get_keyset(
|
||||
id=tmp_keyset_local.id, db=self.db
|
||||
|
||||
# Attempt to retrieve existing keysets from the database
|
||||
existing_keysets: List[MintKeyset] = await self.crud.get_keyset(
|
||||
id=temp_keyset.id, db=self.db
|
||||
)
|
||||
logger.trace(f"crud: loaded {len(tmp_keysets_local)} keysets")
|
||||
if tmp_keysets_local:
|
||||
# we have a keyset with this derivation path in the database
|
||||
keyset = tmp_keysets_local[0]
|
||||
logger.trace(
|
||||
f"Retrieved {len(existing_keysets)} keyset(s) for derivation path '{derivation_path}'."
|
||||
)
|
||||
|
||||
if existing_keysets:
|
||||
keyset = existing_keysets[0]
|
||||
else:
|
||||
# no keyset for this derivation path yet
|
||||
# we create a new keyset (keys will be generated at instantiation)
|
||||
# Create a new keyset if none exists
|
||||
keyset = MintKeyset(
|
||||
seed=seed or self.seed,
|
||||
seed=seed,
|
||||
derivation_path=derivation_path,
|
||||
version=version or settings.version,
|
||||
amounts=self.amounts,
|
||||
version=version,
|
||||
input_fee_ppk=settings.mint_input_fee_ppk,
|
||||
)
|
||||
logger.debug(f"Generated new keyset {keyset.id}.")
|
||||
logger.debug(f"Generated new keyset with ID '{keyset.id}'.")
|
||||
|
||||
if autosave:
|
||||
logger.debug(f"crud: storing new keyset {keyset.id}.")
|
||||
logger.debug(f"Storing new keyset with ID '{keyset.id}'.")
|
||||
await self.crud.store_keyset(keyset=keyset, db=self.db)
|
||||
logger.trace(f"crud: stored new keyset {keyset.id}.")
|
||||
|
||||
# activate this keyset
|
||||
# Activate the keyset
|
||||
keyset.active = True
|
||||
# load the new keyset in self.keysets
|
||||
self.keysets[keyset.id] = keyset
|
||||
logger.debug(f"Keyset with ID '{keyset.id}' is now active.")
|
||||
|
||||
logger.debug(f"Loaded keyset {keyset.id}")
|
||||
return keyset
|
||||
|
||||
async def init_keysets(self, autosave: bool = True) -> None:
|
||||
|
||||
Reference in New Issue
Block a user