Something went wrong. Try again.
Central platform for European atproto.<cc> country community websites atproto.eu
community atproto
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148#!/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 needthe 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: thisruns offline in feeder scripts, and the list only has to be right for the TLDs Dutchaccounts 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())