diff --git a/backend/app/services/auth/verification.py b/backend/app/services/auth/verification.py index cbfa156c..48cdafe5 100644 --- a/backend/app/services/auth/verification.py +++ b/backend/app/services/auth/verification.py @@ -1,5 +1,5 @@ import uuid -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Optional, Dict, Tuple from app.database.supabase.client import get_supabase_client from app.models.database.supabase import User @@ -16,7 +16,7 @@ def _cleanup_expired_sessions(): """ Remove expired verification sessions. """ - current_time = datetime.now() + current_time = datetime.now(timezone.utc) expired_sessions = [ session_id for session_id, (discord_id, expiry_time) in _verification_sessions.items() if current_time > expiry_time @@ -36,17 +36,18 @@ async def create_verification_session(discord_id: str) -> Optional[str]: """ supabase = get_supabase_client() + await cleanup_expired_tokens() _cleanup_expired_sessions() token = str(uuid.uuid4()) session_id = str(uuid.uuid4()) - expiry_time = datetime.now() + timedelta(minutes=SESSION_EXPIRY_MINUTES) + expiry_time = datetime.now(timezone.utc) + timedelta(minutes=SESSION_EXPIRY_MINUTES) try: update_res = await supabase.table("users").update({ "verification_token": token, "verification_token_expires_at": expiry_time.isoformat(), - "updated_at": datetime.now().isoformat() + "updated_at": datetime.now(timezone.utc).isoformat() }).eq("discord_id", discord_id).execute() if update_res.data: @@ -79,7 +80,7 @@ async def find_user_by_session_and_verify( discord_id, expiry_time = session_data - current_time = datetime.now().isoformat() + current_time = datetime.now(timezone.utc).isoformat() user_res = await supabase.table("users").select("*").eq( "discord_id", discord_id ).neq( @@ -106,7 +107,7 @@ async def find_user_by_session_and_verify( await supabase.table("users").update({ "verification_token": None, "verification_token_expires_at": None, - "updated_at": datetime.now().isoformat() + "updated_at": datetime.now(timezone.utc).isoformat() }).eq("id", user_to_verify['id']).execute() raise Exception(f"GitHub account {github_username} is already linked to another Discord user") @@ -115,7 +116,7 @@ async def find_user_by_session_and_verify( "github_username": github_username, "email": user_to_verify.get('email') or email, "is_verified": True, - "verified_at": datetime.now().isoformat(), + "verified_at": datetime.now(timezone.utc).isoformat(), "verification_token": None, "verification_token_expires_at": None, "updated_at": datetime.now().isoformat() @@ -139,7 +140,7 @@ async def cleanup_expired_tokens(): Clean up expired verification tokens from database. """ supabase = get_supabase_client() - current_time = datetime.now().isoformat() + current_time = datetime.now(timezone.utc).isoformat() try: cleanup_res = await supabase.table("users").update({ @@ -165,12 +166,12 @@ async def get_verification_session_info(session_id: str) -> Optional[Dict[str, s discord_id, expiry_time = session_data - if datetime.now() > expiry_time: + if datetime.now(timezone.utc) > expiry_time: del _verification_sessions[session_id] return None return { "discord_id": discord_id, "expiry_time": expiry_time.isoformat(), - "time_remaining": str(expiry_time - datetime.now()) + "time_remaining": str(expiry_time - datetime.now(timezone.utc)) } diff --git a/backend/integrations/discord/cogs.py b/backend/integrations/discord/cogs.py index 64fd0b7f..34c51a97 100644 --- a/backend/integrations/discord/cogs.py +++ b/backend/integrations/discord/cogs.py @@ -3,6 +3,7 @@ import discord from discord import app_commands from discord.ext import commands, tasks +from datetime import datetime, timezone from app.agents.devrel.onboarding.messages import ( build_encourage_verification_message, @@ -129,18 +130,36 @@ async def verify_github(self, interaction: discord.Interaction): return if user_profile.verification_token: - embed = discord.Embed( - title="⏳ Verification Pending", - description="You already have a verification in progress.", - color=discord.Color.orange() - ) - embed.add_field( - name="What to do", - value="Please complete the existing verification or wait for it to expire (5 minutes).", - inline=False - ) - await interaction.followup.send(embed=embed, ephemeral=True) - return + expires_at = user_profile.verification_token_expires_at + is_expired = False + + if expires_at: + if isinstance(expires_at, str): + expires_at_dt = datetime.fromisoformat(expires_at) + else: + expires_at_dt = expires_at + + if expires_at_dt.tzinfo is None: + expires_at_dt = expires_at_dt.replace(tzinfo=timezone.utc) + + now_utc = datetime.now(timezone.utc) + + if expires_at_dt < now_utc: + is_expired = True + + if not is_expired: + embed = discord.Embed( + title="⏳ Verification Pending", + description="You already have a verification in progress.", + color=discord.Color.orange() + ) + embed.add_field( + name="What to do", + value="Please complete the existing verification or wait for it to expire (5 minutes).", + inline=False + ) + await interaction.followup.send(embed=embed, ephemeral=True) + return session_id = await create_verification_session(str(interaction.user.id)) if not session_id: