domain migration
This commit is contained in:
parent
192b810eb4
commit
c04a6ce6fe
26 changed files with 777 additions and 125 deletions
|
|
@ -5,6 +5,8 @@ from __future__ import annotations
|
|||
import dns.exception
|
||||
import dns.resolver
|
||||
|
||||
OWNERSHIP_PREFIX = "agmail-verify="
|
||||
|
||||
|
||||
def _normalize_txt(value: str) -> str:
|
||||
return " ".join(value.split()).strip().lower()
|
||||
|
|
@ -51,6 +53,29 @@ def _lookup_mx(domain_name: str) -> list[tuple[int, str]]:
|
|||
return hosts
|
||||
|
||||
|
||||
def ownership_record_value(token: str) -> str:
|
||||
return f"{OWNERSHIP_PREFIX}{token}"
|
||||
|
||||
|
||||
def ownership_token_from_value(value: str) -> str:
|
||||
normalized = value.strip()
|
||||
if normalized.lower().startswith(OWNERSHIP_PREFIX):
|
||||
return normalized[len(OWNERSHIP_PREFIX) :]
|
||||
return normalized
|
||||
|
||||
|
||||
def verify_ownership(domain_name: str, verification_token: str) -> tuple[bool, str]:
|
||||
name = f"_agmail-verify.{domain_name}"
|
||||
expected = _normalize_txt(ownership_record_value(verification_token))
|
||||
records = [_normalize_txt(record) for record in _lookup_txt(name)]
|
||||
if expected in records:
|
||||
return True, "Domain ownership verified via TXT record."
|
||||
return (
|
||||
False,
|
||||
f"Add TXT at _agmail-verify.{domain_name} with value {ownership_record_value(verification_token)}",
|
||||
)
|
||||
|
||||
|
||||
def verify_mx(domain_name: str, expected_host: str) -> tuple[bool, str]:
|
||||
expected = expected_host.rstrip(".").lower()
|
||||
hosts = _lookup_mx(domain_name)
|
||||
|
|
@ -96,7 +121,7 @@ def verify_platform_spf(platform_spf_host: str, mail_host: str) -> tuple[bool, s
|
|||
if not spf_records:
|
||||
return (
|
||||
False,
|
||||
f"No SPF TXT at {platform_spf_host}. On getall.help add Host _spf with "
|
||||
f"No SPF TXT at {platform_spf_host}. On the platform domain add Host _spf with "
|
||||
f"v=spf1 ip4:<mail-server-ip> ~all.",
|
||||
)
|
||||
|
||||
|
|
@ -138,10 +163,13 @@ def verify_dmarc(domain_name: str, expected_value: str) -> tuple[bool, str]:
|
|||
return False, f"No DMARC TXT record found at {name}."
|
||||
expected = _normalize_txt(expected_value)
|
||||
for record in records:
|
||||
if record == expected or record.startswith("v=dmarc1"):
|
||||
if "v=dmarc1" in record:
|
||||
return True, "DMARC record is present."
|
||||
return False, "DMARC TXT record is missing or incomplete."
|
||||
if record == expected:
|
||||
return True, "DMARC record matches the expected value."
|
||||
return (
|
||||
False,
|
||||
"DMARC TXT must match the value shown in setup exactly "
|
||||
"(do not rely on an existing third-party DMARC record).",
|
||||
)
|
||||
|
||||
|
||||
def verify_company_dns(
|
||||
|
|
@ -151,15 +179,14 @@ def verify_company_dns(
|
|||
dkim_selector: str,
|
||||
dkim_public_key: str,
|
||||
platform_spf_include: str,
|
||||
verification_token: str,
|
||||
) -> list[dict]:
|
||||
"""Customer-domain checks only (ownership + mail authentication)."""
|
||||
dmarc_expected = f"v=DMARC1; p=quarantine; rua=mailto:dmarc@{domain_name}"
|
||||
checks = [
|
||||
("ownership", *verify_ownership(domain_name, verification_token)),
|
||||
("mx", *verify_mx(domain_name, shared_mail_host)),
|
||||
("spf", *verify_spf(domain_name, platform_spf_include)),
|
||||
(
|
||||
"platform_spf",
|
||||
*verify_platform_spf(platform_spf_include, shared_mail_host),
|
||||
),
|
||||
(
|
||||
"dkim",
|
||||
*verify_dkim(domain_name, dkim_selector, dkim_public_key),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue