From 65b8868c369dd315b5abd240dc2881535bafbabd Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 12 Mar 2024 15:31:40 +0200 Subject: [PATCH] fix: enforce order of payments (#2313) * fix: enforce order of payments * fix: do not return wallet by key if the wallet is deleted --- lnbits/core/crud.py | 4 +++- lnbits/core/views/api.py | 5 +---- lnbits/decorators.py | 2 +- tests/core/test_db.py | 3 +-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 317488189..00fca5172 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -554,7 +554,8 @@ async def get_wallet_for_key( row = await (conn or db).fetchone( """ SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) - AS balance_msat FROM wallets WHERE adminkey = ? OR inkey = ? + AS balance_msat FROM wallets + WHERE (adminkey = ? OR inkey = ?) AND deleted = false """, (key, key), ) @@ -602,6 +603,7 @@ async def get_standalone_payment( SELECT * FROM apipayments WHERE {clause} + ORDER BY amount LIMIT 1 """, tuple(values), diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index c6d80253e..ba80e792e 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -539,10 +539,7 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)): # We use X_Api_Key here because we want this call to work with and without keys # If a valid key is given, we also return the field "details", otherwise not wallet = await get_wallet_for_key(X_Api_Key) if isinstance(X_Api_Key, str) else None - wallet = wallet if wallet and not wallet.deleted else None - # we have to specify the wallet id here, because postgres and sqlite return - # internal payments in different order and get_standalone_payment otherwise - # just fetches the first one, causing unpredictable results + payment = await get_standalone_payment( payment_hash, wallet_id=wallet.id if wallet else None ) diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 51c573a53..17eacef1b 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -62,7 +62,7 @@ class KeyChecker(SecurityBase): # avoided here. Also, we should not return the wallet here - thats # silly. Possibly store it in a Redis DB wallet = await get_wallet_for_key(key_value, self._key_type) - if not wallet or wallet.deleted: + if not wallet: raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, detail="Invalid key or wallet.", diff --git a/tests/core/test_db.py b/tests/core/test_db.py index b10a20638..97cebb22e 100644 --- a/tests/core/test_db.py +++ b/tests/core/test_db.py @@ -34,5 +34,4 @@ async def test_create_wallet_and_delete_wallet(app, to_user): assert del_wallet.deleted is True del_wallet = await get_wallet_for_key(wallet.inkey) - assert del_wallet is not None - assert del_wallet.deleted is True + assert del_wallet is None