Milestone 3
This commit is contained in:
30
backend/app/api/_validation.py
Normal file
30
backend/app/api/_validation.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""Lightweight email validator that tolerates internal/lab TLDs (.local, .corp, …).
|
||||
|
||||
`pydantic.EmailStr` relies on `email-validator` with `globally_deliverable=True`,
|
||||
which rejects RFC 6761 special-use domains. Red-team and corporate intranet
|
||||
deployments routinely use such suffixes — we accept any RFC-shape email and
|
||||
defer deliverability checks to the operator.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Annotated
|
||||
|
||||
from pydantic import AfterValidator
|
||||
|
||||
# Permissive RFC-shape pattern: local-part 1..64 chars, domain has at least one
|
||||
# dot, each label is 1..63 chars of letters/digits/hyphens, total ≤ 254.
|
||||
_EMAIL_RE = re.compile(
|
||||
r"^(?=.{1,254}$)[A-Za-z0-9._%+\-]{1,64}@[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9\-]{0,61}[A-Za-z0-9])?)+$"
|
||||
)
|
||||
|
||||
|
||||
def _validate_email(value: str) -> str:
|
||||
v = value.strip()
|
||||
if not _EMAIL_RE.match(v):
|
||||
raise ValueError("not a valid email address")
|
||||
return v.lower()
|
||||
|
||||
|
||||
Email = Annotated[str, AfterValidator(_validate_email)]
|
||||
Reference in New Issue
Block a user