#!/usr/bin/env python3 # /// script # dependencies = [] # /// """Classify an atproto handle by what kind of name it actually is. Shared by the candidate sweep and the handle re-validation pass, because the two need the same distinctions and got them wrong independently: invalid the handle does not resolve (AppView returns "handle.invalid") pds issued by a PDS, not owned: *.bsky.social, *.eurosky.social, ... bridged a bridge's rendering of an account elsewhere: *.ap.brid.gy, *.web.brid.gy (a bridged Mastodon account is not a domain its owner controls) subdomain a real domain, but not the apex: nl.esa.int, smb.phys.tue.nl apex the registrable domain itself: rug.nl, businessinsider.nl Why the distinction matters, in two different ways: - For the NL floor, a subdomain is fine. smb.phys.tue.nl is as Dutch as tue.nl, and "is this account Dutch" is the only question being asked. - For binding an account to an ORGANISATION (Sifa's entity DB), only `apex` is safe. Binding nl.esa.int would either mint a wrong entity or quietly steal the parent domain's identity. Sifa's own `isBindableHandleDomain` guard rejects everything but apex, and it rejected 65 of the first 155 orgs we handed over. The apex test uses a small suffix table rather than the full Public Suffix List: this runs offline in feeder scripts, and the list only has to be right for the TLDs Dutch accounts actually use. Unknown multi-label suffixes fall back to "two labels = apex", which is correct for .nl, .com, .org, .dev and the rest of the common cases. """ from __future__ import annotations INVALID = "handle.invalid" # Handles a PDS hands out. Not owned by the account holder, so never bindable. PDS_SUFFIXES = ( ".bsky.social", ".eurosky.social", ".bsky.team", ".blacksky.community", ".pds.witchcraft.systems", ".wsocial.eu", ".kelosocial.eu", ".pds.bowverse.fr", ".pds.sved.be", ".pds.jdkserver.nl", ".forum-hietzing.at", ) # Bridges: the handle describes an account on another network. BRIDGE_SUFFIXES = (".ap.brid.gy", ".web.brid.gy", ".brid.gy") # Two-label public suffixes: a domain under these needs three labels to be an apex. MULTI_LABEL_SUFFIXES = ( "co.uk", "org.uk", "ac.uk", "gov.uk", "com.br", "com.au", "co.nz", "co.za", "com.tr", "co.jp", "or.jp", "ne.jp", ) def classify_handle(handle: str | None) -> str: """Return one of: invalid, pds, bridged, subdomain, apex.""" h = (handle or "").strip().lower().rstrip(".") if not h or h == INVALID: return "invalid" # Bridges before PDS: a bridged handle can carry anything to its left. if h.endswith(BRIDGE_SUFFIXES): return "bridged" if h.endswith(PDS_SUFFIXES): return "pds" labels = h.split(".") if len(labels) < 2: return "invalid" for suffix in MULTI_LABEL_SUFFIXES: if h.endswith("." + suffix): # apex under a two-label suffix means exactly three labels return "apex" if len(labels) == 3 else "subdomain" return "apex" if len(labels) == 2 else "subdomain" def is_bindable(handle: str | None) -> bool: """Can this handle stand for an organisation's own domain? Apex only.""" return classify_handle(handle) == "apex" def is_dutch_domain(handle: str | None, tlds=(".nl", ".amsterdam", ".frl")) -> bool: """Does the handle still carry a clearly-Dutch domain? Applies to subdomains too (smb.phys.tue.nl counts), but never to a PDS-issued or bridged handle, where the trailing domain belongs to the infrastructure and says nothing about the account holder. """ kind = classify_handle(handle) if kind in ("invalid", "pds", "bridged"): return False return (handle or "").strip().lower().rstrip(".").endswith(tlds) def self_test() -> int: cases = { "rug.nl": "apex", "businessinsider.nl": "apex", "example.co.uk": "apex", "nl.esa.int": "subdomain", "smb.phys.tue.nl": "subdomain", "shop.example.co.uk": "subdomain", "someone.bsky.social": "pds", "rotterdam.eurosky.social": "pds", "mastodon.nl.ap.brid.gy": "bridged", "someone.web.brid.gy": "bridged", "handle.invalid": "invalid", "": "invalid", None: "invalid", } for handle, expected in cases.items(): got = classify_handle(handle) assert got == expected, f"{handle!r}: expected {expected}, got {got}" assert is_bindable("rug.nl") assert not is_bindable("nl.esa.int") assert not is_bindable("someone.bsky.social") # Dutch-domain test: subdomains count, infrastructure handles never do. assert is_dutch_domain("smb.phys.tue.nl") assert is_dutch_domain("gemeente.amsterdam") assert not is_dutch_domain("someone.bsky.social") assert not is_dutch_domain("mastodon.nl.ap.brid.gy"), ( "bridge domain is not the holder's" ) assert not is_dutch_domain("example.com") print("self-test ok") return 0 if __name__ == "__main__": raise SystemExit(self_test())