diff --git a/config/base.py b/config/base.py index cf94022..8735671 100644 --- a/config/base.py +++ b/config/base.py @@ -83,6 +83,7 @@ class BaseConfig: RATELIMIT_AUTH_TOTP_VERIFY = os.getenv("RATELIMIT_AUTH_TOTP_VERIFY", "20 per minute; 100 per hour") RATELIMIT_AUTH_FORGOT_PASSWORD = os.getenv("RATELIMIT_AUTH_FORGOT_PASSWORD", "5 per minute; 20 per hour") RATELIMIT_AUTH_RESET_PASSWORD = os.getenv("RATELIMIT_AUTH_RESET_PASSWORD", "10 per minute; 30 per hour") + RATELIMIT_AUTH_RESEND_VERIFICATION = os.getenv("RATELIMIT_AUTH_RESEND_VERIFICATION", "5 per minute; 20 per hour") # Logging LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") diff --git a/gatehouse_app/api/v1/auth/password.py b/gatehouse_app/api/v1/auth/password.py index 9ca6b2b..111e5df 100644 --- a/gatehouse_app/api/v1/auth/password.py +++ b/gatehouse_app/api/v1/auth/password.py @@ -1,8 +1,9 @@ """Password reset, email verification, and account activation endpoints.""" import logging -from flask import request, current_app +from flask import request, current_app, g from gatehouse_app.api.v1 import api_v1_bp from gatehouse_app.extensions import limiter +from gatehouse_app.utils.decorators import login_required from gatehouse_app.utils.response import api_response from gatehouse_app.services.auth_service import AuthService from gatehouse_app.services.notification_service import NotificationService @@ -151,6 +152,36 @@ def resend_verification(): return api_response(data={}, message="If an account exists for this email and is not yet verified, you will receive a verification link shortly.") + +@api_v1_bp.route("/auth/me/resend-verification", methods=["POST"]) +@limiter.limit(lambda: current_app.config["RATELIMIT_AUTH_RESEND_VERIFICATION"]) +@login_required +def resend_verification_authenticated(): + from gatehouse_app.models import EmailVerificationToken + + user = g.current_user + if not user.email_verified: + try: + verify_token = EmailVerificationToken.generate(user_id=user.id) + app_url = current_app.config.get("APP_URL", "http://localhost:8080") + verify_link = f"{app_url}/verify-email?token={verify_token.token}" + email_body = build_email_verification_html( + user_name=user.full_name or user.email, + verify_link=verify_link, + expiry_hours=24, + ) + NotificationService._send_email_async( + to_address=user.email, + subject="Verify your Secuird email address", + body=f"Verify your Secuird email: {verify_link}", + html_body=email_body, + ) + _logger.info(f"Verification email sent for authenticated user {user.id}") + except Exception as exc: + _logger.exception(f"Error sending verification email: {exc}") + + return api_response(data={}, message="If your email is not yet verified, you will receive a verification link shortly.") + @api_v1_bp.route("/auth/activate", methods=["POST"]) def activate_account(): import secrets