Skip to content

Add DNS-over-HTTPS TXT and well-known atproto handle-resolution components - #57

Merged
germ-mark merged 5 commits into
mainfrom
llm/doh-wellknown-handle-resolvers
Sep 23, 2026
Merged

germ-mark merged 5 commits into
mainfrom
llm/doh-wellknown-handle-resolvers

Conversation

@germ-mark

Copy link
Copy Markdown
Contributor

Adds two single-purpose atproto handle-resolution components beside the existing DidPlcResolver / DidWebResolver, plus the supporting DNS machinery — all Atproto-namespaced and additive (no changes to existing files):

  • Atproto.DoHTXTFetcher — RFC 8484 DNS-over-HTTPS TXT lookups over the injected HTTPFetcher; DoH servers are parametrizable config (serverURLs, Cloudflare→Google default, per-provider fallback). Backed by a minimal RFC 1035 wire codec (Atproto.DNSWireFormat) behind an Atproto.DNSTXTFetcher seam.
  • Atproto.DnsHandleResolver — resolves a handle to a DID via its _atproto TXT record.
  • Atproto.WellKnownHandleResolver — resolves a handle via https://<handle>/.well-known/atproto-did, mirroring DidWebResolver's hardening: redirect-refusing fetcher, reserved-TLD screen, response-size bound, DID method-form checked on parse.

Portable (no platform DNS APIs) so it builds and tests on Linux/Android; the Darwin dnssd path is intentionally out of scope.

Test notes: ported wire-format fixtures plus new coverage for the parser's out-of-bounds guards (mutation-verified — each new test fails when its guard is neutralized) and the well-known resolver's redirect/size/reserved-TLD behavior. swift test green (91 tests), swift format lint clean. Purely additive → minor changeset.

🤖 Generated with Claude Code

germ-mark and others added 3 commits September 22, 2026 10:14
Ports DNSWireFormat, DNSTXTFetcher, and DoHTXTFetcher (RFC 1035 / RFC
8484), and adds two new public resolvers alongside DidWebResolver and
DidPlcResolver: WellKnownHandleResolver (HTTPS well-known method, over
the injected HTTPFetcher seam) and DnsHandleResolver (DNS TXT method,
defaulting to DoHTXTFetcher). Both refuse redirects and validate their
result through Atproto.DID.init(string:), matching the existing
resolvers' security shape.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- WellKnownHandleResolver now rejects reserved TLDs before building
  the well-known URL, matching DidWebResolver's screen (reuses its
  reservedTLDs set as the shared source of truth).
- Add tests exercising the two untested parser bounds in
  decodeTXTRecords - a short answer header and an RDLENGTH exceeding
  the buffer - both verified to fail (crash) when their guard is
  neutralized.
- Reword the maxBodySize comment: the bound rejects a body before
  parsing, not before it's buffered.
- Reword the changeset to not oversell DID validation.
- Make joinedCharacterStrings private - nothing outside the type uses it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DoHTXTFetcher, DNSWireFormat, DNSTXTFetcher, and DNSTXTFetcherError
move into extension Atproto, matching DnsHandleResolver and
WellKnownHandleResolver. Names and casing unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1b4b358

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@germ-network/atprotoclient Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Three additive helpers on Atproto.XRPC.BskyAppCallable:
relationshipLookup(actor:others:) dedupes/chunks app.bsky.graph.getRelationships
at the lexicon's 30-subject limit and reports not-found subjects rather than
dropping them (not an account-existence check - the AppView returns a
relationship entry for any well-formed DID); bskyProfileIfExists(actor:) maps
getProfile's undeclared not-found shape (400 InvalidRequest, "Profile not
found") to nil; and Atproto.BskyCDN.imageURL(_:did:blob:host:) builds CDN
image URLs from a blob reference with explicit RFC 3986 path-segment encoding
so a crafted DID/CID can't escape its segment.

Also fixes GetRelationships.Parameters.init to accept exactly 30 others (the
lexicon's own maxLength, previously rejected) and makes GetRelationships.Errors
public, since it's already thrown by public API.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add relationshipLookup, bskyProfileIfExists, and BskyCDN read helpers
@germ-mark
germ-mark merged commit 4121c03 into main Sep 23, 2026
22 checks passed
@germ-mark
germ-mark deleted the llm/doh-wellknown-handle-resolvers branch September 23, 2026 23:43
@github-actions github-actions Bot mentioned this pull request Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant