feat(deps): add require_verified_email_after_grace guard
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -289,3 +289,47 @@ async def require_active_subscription(
|
||||
)
|
||||
|
||||
return sub
|
||||
|
||||
|
||||
_EMAIL_VERIFICATION_ALLOWLIST = {
|
||||
"/api/v1/auth/me",
|
||||
"/api/v1/auth/logout",
|
||||
"/api/v1/auth/email/send-verification",
|
||||
"/api/v1/auth/email/verify",
|
||||
"/api/v1/auth/password/change",
|
||||
"/api/v1/users/me",
|
||||
"/api/v1/billing/state",
|
||||
"/api/v1/billing/checkout-session",
|
||||
"/api/v1/billing/portal-session",
|
||||
}
|
||||
|
||||
VERIFICATION_GRACE_DAYS = 7
|
||||
|
||||
|
||||
async def require_verified_email_after_grace(
|
||||
request: Request,
|
||||
current_user: Annotated[User, Depends(get_current_active_user)],
|
||||
):
|
||||
"""Enforces 'this user has verified email OR is still in 7-day grace.'
|
||||
OAuth signups bypass cleanly because /auth/{google,microsoft}/callback
|
||||
sets users.email_verified_at = now() (provider-attested)."""
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
if request.url.path in _EMAIL_VERIFICATION_ALLOWLIST:
|
||||
return
|
||||
|
||||
if current_user.email_verified_at is not None:
|
||||
return
|
||||
|
||||
grace_ends = current_user.created_at + timedelta(days=VERIFICATION_GRACE_DAYS)
|
||||
if datetime.now(timezone.utc) < grace_ends:
|
||||
return
|
||||
|
||||
raise HTTPException(
|
||||
status_code=403,
|
||||
detail={
|
||||
"error": "email_not_verified",
|
||||
"grace_ended_at": grace_ends.isoformat(),
|
||||
"resend_url": "/api/v1/auth/email/send-verification",
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user