From e951d02c3dd128d16b397173c171ac326af28d12 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 29 Jan 2026 14:13:21 +0200 Subject: [PATCH] feat: clear cache on user deactivation --- lnbits/core/crud/users.py | 21 ++++++++++++++++++++- lnbits/core/crud/wallets.py | 14 ++++++++++---- lnbits/core/views/wallet_api.py | 6 ++---- lnbits/decorators.py | 1 + 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lnbits/core/crud/users.py b/lnbits/core/crud/users.py index 450617d02..a05064a12 100644 --- a/lnbits/core/crud/users.py +++ b/lnbits/core/crud/users.py @@ -4,10 +4,12 @@ from typing import Any from uuid import uuid4 from lnbits.core.crud.extensions import get_user_active_extensions_ids -from lnbits.core.crud.wallets import create_wallet, get_wallets +from lnbits.core.crud.wallets import clear_wallet_cache, create_wallet, get_wallets from lnbits.core.db import db from lnbits.core.models import UserAcls from lnbits.db import Connection, Filters, Page +from lnbits.helpers import sha256s +from lnbits.utils.cache import cache from ..models import ( Account, @@ -51,6 +53,7 @@ async def update_account_activation( "user_id": user_id, }, ) + await clear_user_id_cache(user_id) async def delete_account(user_id: str, conn: Connection | None = None) -> None: @@ -282,6 +285,22 @@ async def get_user_access_control_lists( return user_acls or UserAcls(id=user_id) +async def clear_user_id_cache(user_id: str): + user = await get_user(user_id, activated=None) + if user: + clear_user_cache(user) + + +def clear_user_cache(user: User): + user_cache_key: str | None = cache.pop( + f"auth:user:cache_key:{sha256s(user.id)}", None + ) + if user_cache_key: + cache.pop(user_cache_key) + for wallet in user.wallets: + clear_wallet_cache(wallet) + + def _activated_clause(activated: bool | None) -> str: if activated is None: return "" diff --git a/lnbits/core/crud/wallets.py b/lnbits/core/crud/wallets.py index 21ccd141c..066ddd7b3 100644 --- a/lnbits/core/crud/wallets.py +++ b/lnbits/core/crud/wallets.py @@ -50,7 +50,7 @@ async def delete_wallet( deleted: bool = True, conn: Connection | None = None, ) -> None: - _clear_wallet_cache(wallet_id) + clear_wallet_id_cache(wallet_id) now = int(time()) await (conn or db).execute( @@ -65,7 +65,7 @@ async def delete_wallet( async def force_delete_wallet(wallet_id: str, conn: Connection | None = None) -> None: - _clear_wallet_cache(wallet_id) + clear_wallet_id_cache(wallet_id) await (conn or db).execute( "DELETE FROM wallets WHERE id = :wallet", {"wallet": wallet_id}, @@ -75,7 +75,7 @@ async def force_delete_wallet(wallet_id: str, conn: Connection | None = None) -> async def delete_wallet_by_id( wallet_id: str, conn: Connection | None = None ) -> int | None: - _clear_wallet_cache(wallet_id) + clear_wallet_id_cache(wallet_id) now = int(time()) result = await (conn or db).execute( # Timestamp placeholder is safe from SQL injection (not user input) @@ -294,8 +294,14 @@ async def get_total_balance(conn: Connection | None = None): return row.get("balance", 0) or 0 -def _clear_wallet_cache(wallet_id): +def clear_wallet_id_cache(wallet_id: str): cached_wallet: BaseWallet | None = cache.pop(f"auth:wallet:{wallet_id}") if cached_wallet: cache.pop(f"auth:x-api-key:{cached_wallet.adminkey}") cache.pop(f"auth:x-api-key:{cached_wallet.inkey}") + + +def clear_wallet_cache(wallet: Wallet): + cache.pop(f"auth:wallet:{wallet.id}") + cache.pop(f"auth:x-api-key:{wallet.adminkey}") + cache.pop(f"auth:x-api-key:{wallet.inkey}") diff --git a/lnbits/core/views/wallet_api.py b/lnbits/core/views/wallet_api.py index d93d405c9..3aa7b9934 100644 --- a/lnbits/core/views/wallet_api.py +++ b/lnbits/core/views/wallet_api.py @@ -9,6 +9,7 @@ from fastapi import ( ) from lnbits.core.crud.wallets import ( + clear_wallet_cache, create_wallet, get_wallets_paginated, ) @@ -37,7 +38,6 @@ from lnbits.decorators import ( require_invoice_key, ) from lnbits.helpers import generate_filter_params_openapi -from lnbits.utils.cache import cache from ..crud import ( delete_wallet, @@ -134,9 +134,7 @@ async def api_reset_wallet_keys( if not wallet or wallet.user != account_id.id: raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Wallet not found") - cache.pop(f"auth:wallet:{wallet.id}") - cache.pop(f"auth:x-api-key:{wallet.adminkey}") - cache.pop(f"auth:x-api-key:{wallet.inkey}") + clear_wallet_cache(wallet) wallet.adminkey = uuid4().hex wallet.inkey = uuid4().hex diff --git a/lnbits/decorators.py b/lnbits/decorators.py index d483f7d9b..1673b860f 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -261,6 +261,7 @@ async def check_account_id_exists( account_id, expiry=settings.auth_authentication_cache_minutes * 60, ) + cache.set(f"auth:user:cache_key:{sha256s(account.id)}", cache_key) return account_id