import os import random import aiosmtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from datetime import datetime, timedelta from dotenv import load_dotenv load_dotenv() # In-memory storage for verification codes (in production, use Redis or database) verification_codes = {} password_reset_tokens = {} def generate_verification_code(): """Generate a 6-digit verification code""" return str(random.randint(100000, 999999)) async def send_verification_email(email: str, code: str, purpose: str = "password_change"): """Send verification code via email""" smtp_host = os.getenv("SMTP_HOST", "smtp.gmail.com") smtp_port = int(os.getenv("SMTP_PORT", "587")) smtp_user = os.getenv("SMTP_USER") smtp_password = os.getenv("SMTP_PASSWORD") smtp_from = os.getenv("SMTP_FROM", smtp_user) if not smtp_user or not smtp_password: raise Exception("SMTP credentials not configured") # Create message message = MIMEMultipart("alternative") message["Subject"] = "קוד אימות - מתכונים שלי" message["From"] = smtp_from message["To"] = email # Email content if purpose == "password_change": text = f""" שלום, קוד האימות שלך לשינוי סיסמה הוא: {code} הקוד תקף ל-10 דקות. אם לא ביקשת לשנות את הסיסמה, התעלם מהודעה זו. בברכה, צוות מתכונים שלי """ html = f"""

שינוי סיסמה

קוד האימות שלך הוא:

{code}

הקוד תקף ל-10 דקות.


אם לא ביקשת לשנות את הסיסמה, התעלם מהודעה זו.

""" part1 = MIMEText(text, "plain") part2 = MIMEText(html, "html") message.attach(part1) message.attach(part2) # Send email await aiosmtplib.send( message, hostname=smtp_host, port=smtp_port, username=smtp_user, password=smtp_password, start_tls=True, ) def store_verification_code(user_id: int, code: str): """Store verification code with expiry""" expiry = datetime.now() + timedelta(minutes=10) verification_codes[user_id] = { "code": code, "expiry": expiry } def verify_code(user_id: int, code: str) -> bool: """Verify if code is correct and not expired""" if user_id not in verification_codes: return False stored = verification_codes[user_id] # Check if expired if datetime.now() > stored["expiry"]: del verification_codes[user_id] return False # Check if code matches if stored["code"] != code: return False # Code is valid, remove it del verification_codes[user_id] return True async def send_password_reset_email(email: str, token: str, frontend_url: str): """Send password reset link via email""" smtp_host = os.getenv("SMTP_HOST", "smtp.gmail.com") smtp_port = int(os.getenv("SMTP_PORT", "587")) smtp_user = os.getenv("SMTP_USER") smtp_password = os.getenv("SMTP_PASSWORD") smtp_from = os.getenv("SMTP_FROM", smtp_user) if not smtp_user or not smtp_password: raise Exception("SMTP credentials not configured") reset_link = f"{frontend_url}?reset_token={token}" # Create message message = MIMEMultipart("alternative") message["Subject"] = "איפוס סיסמה - מתכונים שלי" message["From"] = smtp_from message["To"] = email text = f""" שלום, קיבלנו בקשה לאיפוס הסיסמה שלך. לחץ על הקישור הבא כדי לאפס את הסיסמה (תקף ל-30 דקות): {reset_link} אם לא ביקשת לאפס את הסיסמה, התעלם מהודעה זו. בברכה, צוות מתכונים שלי """ html = f"""

איפוס סיסמה

קיבלנו בקשה לאיפוס הסיסמה שלך.

לחץ על הכפתור למטה כדי לאפס את הסיסמה:

איפוס סיסמה

הקישור תקף ל-30 דקות.


אם לא ביקשת לאפס את הסיסמה, התעלם מהודעה זו.

""" part1 = MIMEText(text, "plain") part2 = MIMEText(html, "html") message.attach(part1) message.attach(part2) # Send email await aiosmtplib.send( message, hostname=smtp_host, port=smtp_port, username=smtp_user, password=smtp_password, start_tls=True, ) def store_password_reset_token(email: str, token: str): """Store password reset token with expiry""" expiry = datetime.now() + timedelta(minutes=30) password_reset_tokens[token] = { "email": email, "expiry": expiry } def verify_reset_token(token: str) -> str: """Verify reset token and return email if valid""" if token not in password_reset_tokens: return None stored = password_reset_tokens[token] # Check if expired if datetime.now() > stored["expiry"]: del password_reset_tokens[token] return None return stored["email"] def consume_reset_token(token: str): """Remove token after use""" if token in password_reset_tokens: del password_reset_tokens[token]