feat(auth,dashboard): 2FA mobile session persistence and sparkline cards
- Persist 2FA state in sessionStorage to survive mobile page reloads - Reuse existing valid OTP on re-login to avoid rate limiting and duplicate emails - Add embedded sparkline charts to SolduriCompactCard with expand toggle - Mobile dashboard redesigned: 2 pages with enriched compact cards + cashflow type - Login UI simplified: remove gradient bg, subtitle, icon; use design tokens - Focus OTP input when session is restored from 2FA state Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -406,34 +406,45 @@ def create_auth_router(
|
||||
|
||||
# Pas 4: Dacă are email → trimitem OTP (2FA)
|
||||
if user_email:
|
||||
code = await create_otp(user_email, actual_username, login_data.server_id)
|
||||
# Check for existing valid OTP (mobile page reload scenario)
|
||||
existing_entry = get_otp_entry(user_email)
|
||||
|
||||
if code is None:
|
||||
# Rate limited
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail="Prea multe cereri de cod. Așteptați 10 minute și încercați din nou."
|
||||
if existing_entry:
|
||||
# OTP already exists and is valid — skip generation and email
|
||||
logger.info(
|
||||
f"[2FA] Reusing existing OTP for {user_email[:3]}*** "
|
||||
f"(user='{actual_username}', skipping email)"
|
||||
)
|
||||
else:
|
||||
# Generate new OTP
|
||||
code = await create_otp(user_email, actual_username, login_data.server_id)
|
||||
|
||||
# Trimitem emailul
|
||||
try:
|
||||
from backend.modules.telegram.utils.email_service import get_email_service
|
||||
email_service = get_email_service()
|
||||
email_sent = await email_service.send_auth_code(user_email, code, actual_username)
|
||||
|
||||
if not email_sent:
|
||||
logger.error(f"[2FA] Failed to send OTP email to {user_email[:3]}***")
|
||||
if code is None:
|
||||
# Rate limited
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Nu s-a putut trimite codul de verificare. Încercați din nou."
|
||||
status_code=status.HTTP_429_TOO_MANY_REQUESTS,
|
||||
detail="Prea multe cereri de cod. Așteptați 10 minute și încercați din nou."
|
||||
)
|
||||
|
||||
logger.info(f"[2FA] OTP sent to {user_email[:3]}*** for user '{actual_username}'")
|
||||
# Trimitem emailul
|
||||
try:
|
||||
from backend.modules.telegram.utils.email_service import get_email_service
|
||||
email_service = get_email_service()
|
||||
email_sent = await email_service.send_auth_code(user_email, code, actual_username)
|
||||
|
||||
except ImportError:
|
||||
# Email service nu e disponibil — fallback la login direct
|
||||
logger.warning("[2FA] Email service not available, falling back to direct login")
|
||||
user_email = None
|
||||
if not email_sent:
|
||||
logger.error(f"[2FA] Failed to send OTP email to {user_email[:3]}***")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="Nu s-a putut trimite codul de verificare. Încercați din nou."
|
||||
)
|
||||
|
||||
logger.info(f"[2FA] OTP sent to {user_email[:3]}*** for user '{actual_username}'")
|
||||
|
||||
except ImportError:
|
||||
# Email service nu e disponibil — fallback la login direct
|
||||
logger.warning("[2FA] Email service not available, falling back to direct login")
|
||||
user_email = None
|
||||
|
||||
# Pas 5: Dacă 2FA activ → returnăm cerere de cod
|
||||
if user_email:
|
||||
|
||||
Reference in New Issue
Block a user