fix: enforce order of payments (#2313)

* fix: enforce order of payments

* fix: do not return wallet by key if the wallet is deleted
This commit is contained in:
Vlad Stan 2024-03-12 15:31:40 +02:00 committed by GitHub
parent 54dec171f9
commit 65b8868c36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 6 additions and 8 deletions

View file

@ -554,7 +554,8 @@ async def get_wallet_for_key(
row = await (conn or db).fetchone( row = await (conn or db).fetchone(
""" """
SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) 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), (key, key),
) )
@ -602,6 +603,7 @@ async def get_standalone_payment(
SELECT * SELECT *
FROM apipayments FROM apipayments
WHERE {clause} WHERE {clause}
ORDER BY amount
LIMIT 1 LIMIT 1
""", """,
tuple(values), tuple(values),

View file

@ -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 # 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 # 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 = 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 = await get_standalone_payment(
payment_hash, wallet_id=wallet.id if wallet else None payment_hash, wallet_id=wallet.id if wallet else None
) )

View file

@ -62,7 +62,7 @@ class KeyChecker(SecurityBase):
# avoided here. Also, we should not return the wallet here - thats # avoided here. Also, we should not return the wallet here - thats
# silly. Possibly store it in a Redis DB # silly. Possibly store it in a Redis DB
wallet = await get_wallet_for_key(key_value, self._key_type) wallet = await get_wallet_for_key(key_value, self._key_type)
if not wallet or wallet.deleted: if not wallet:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, status_code=HTTPStatus.UNAUTHORIZED,
detail="Invalid key or wallet.", detail="Invalid key or wallet.",

View file

@ -34,5 +34,4 @@ async def test_create_wallet_and_delete_wallet(app, to_user):
assert del_wallet.deleted is True assert del_wallet.deleted is True
del_wallet = await get_wallet_for_key(wallet.inkey) del_wallet = await get_wallet_for_key(wallet.inkey)
assert del_wallet is not None assert del_wallet is None
assert del_wallet.deleted is True