From 5537c7a34317cdcab5a793a7b19a32a72c1a6e9e Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Fri, 23 Oct 2026 02:37:12 +0200 Subject: [PATCH] claim verification state atomically and reject expired ones Co-Authored-By: Claude Opus 5.5 --- verification_server/src/server.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/verification_server/src/server.py b/verification_server/src/server.py index 5ab4ffd..b33f632 100644 --- a/verification_server/src/server.py +++ b/verification_server/src/server.py @@ -47,11 +47,12 @@ async def index(): @app.get("/callback") async def callback(request: Request, code: str, state: str): - # Check if user is pending verification + # Claim the pending verification. Deleting it up front makes the state single use verification = await app.state.pool.fetchrow( """ - SELECT discord_id, challenge, state - FROM galtinn_verification WHERE state = $1 + DELETE FROM galtinn_verification + WHERE state = $1 AND expires > NOW() + RETURNING discord_id, challenge """, state, ) @@ -65,7 +66,7 @@ async def callback(request: Request, code: str, state: str): status_code=400, ) - discord_id, code_challenge, state = list(verification.values()) + discord_id, code_challenge = list(verification.values()) # Get auth_token from code payload = { @@ -122,15 +123,6 @@ async def callback(request: Request, code: str, state: str): status_code=502, ) - # Delete verification entry - await app.state.pool.execute( - """ - DELETE FROM galtinn_verification - WHERE discord_id = $1 - """, - discord_id, - ) - # Notify bot that user is verified # asyncpg does not allow for arguments in NOTIFY queries, hence we use f-strings notify_query = f"NOTIFY galtinn_auth_complete, '{discord_id} {user['sub']}'"