File size: 2,943 Bytes
7404e13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e31f9c2
7404e13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13c846c
7404e13
 
e31f9c2
 
 
 
 
7404e13
13c846c
 
 
 
7404e13
13c846c
 
 
7404e13
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""Validation rules for registration contact details."""

import re


# Keep this intentionally small to avoid rejecting legitimate organization domains.
# These are widely used consumer email services across North America, Europe, and
# Asia. Add domains only when they are observed in registration applications.
COMMON_PERSONAL_EMAIL_DOMAINS = frozenset(
    {
        "126.com",
        "163.com",
        "aol.com",
        "daum.net",
        "gmail.com",
        "gmx.com",
        "hotmail.com",
        "icloud.com",
        "mail.com",
        "mail.ru",
        "naver.com",
        "outlook.com",
        "proton.me",
        "protonmail.com",
        "qq.com",
        "rediffmail.com",
        "yahoo.com",
        "yandex.com",
        "yandex.ru",
        "zoho.com",
    }
)

DOMAIN_LABEL_RE = re.compile(r"^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$")
ASCII_LETTER_RE = re.compile(r"[A-Za-z]")


def email_domain(email: str) -> str | None:
    """Return a normalized domain for a basic, usable email address."""
    email = (email or "").strip()
    if len(email) > 254 or email.count("@") != 1 or any(char.isspace() for char in email):
        return None

    local_part, domain = email.rsplit("@", 1)
    domain = domain.rstrip(".").casefold()
    if not local_part or len(local_part) > 64 or not domain or "." not in domain:
        return None

    try:
        domain = domain.encode("idna").decode("ascii")
    except UnicodeError:
        return None

    labels = domain.split(".")
    if any(not DOMAIN_LABEL_RE.fullmatch(label) for label in labels):
        return None
    return domain


def uses_common_personal_email_service(email: str) -> bool:
    """Whether an address belongs to one of the blocked consumer services."""
    domain = email_domain(email)
    if domain is None:
        return False

    parts = domain.split(".")
    return any(
        ".".join(parts[index:]) in COMMON_PERSONAL_EMAIL_DOMAINS
        for index in range(len(parts) - 1)
    )


def registration_contact_error(
    profile_email: str,
    organization: str,
) -> str | None:
    """Return a user-facing error for the OAuth-provided contact email."""
    if not (organization or "").strip():
        return "Organization / Affiliation is required."
    if not ASCII_LETTER_RE.search(organization):
        return (
            "Organization / Affiliation must include an English or Romanized Latin "
            "name for registration review."
        )

    profile_email = (profile_email or "").strip()
    if email_domain(profile_email) is None:
        return "Your Hugging Face account must provide a valid primary email address."
    if uses_common_personal_email_service(profile_email):
        return (
            "Your Hugging Face primary email must be an academic, company, or "
            "organization address. Addresses from common personal email services "
            "are not accepted."
        )
    return None