import uuid import base64 import io from captcha.image import ImageCaptcha from app.core.cache import redis_client from app.core.config import settings class CaptchaService: @staticmethod def generate_captcha() -> dict: """ Generates a captcha image, stores the code in Redis, and returns ID + B64 Image. """ image = ImageCaptcha(width=280, height=90) # Generate 4 character code import random import string code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4)) data = image.generate(code) # Create a unique ID captcha_id = str(uuid.uuid4()) # Store in Redis: CAPTCHA:{uuid} -> code key = f"CAPTCHA:{captcha_id}" redis_client.setex(key, settings.CAPTCHA_EXPIRE_SECONDS, code) # Encode image to base64 base64_image = base64.b64encode(data.getvalue()).decode('utf-8') return { "captcha_id": captcha_id, "image": f"data:image/png;base64,{base64_image}", "expire_seconds": settings.CAPTCHA_EXPIRE_SECONDS } @staticmethod def verify_captcha(captcha_id: str, code: str) -> bool: """ Verifies the captcha code. Deletes the key after check (one-time use). """ if not captcha_id or not code: return False key = f"CAPTCHA:{captcha_id}" stored_code = redis_client.get(key) if not stored_code: return False # Delete immediately to prevent replay redis_client.delete(key) return stored_code.upper() == code.upper()