Summary
- Hollo 0.9.0 (
ghcr.io/fedify-dev/hollo:0.9.0)
- Docker Compose, PostgreSQL 17, Caddy
HANDLE_HOST=campegg.com, WEB_ORIGIN=https://ap.campegg.com
Querying Hollo's WebFinger endpoint at WEB_ORIGIN for the WEB_ORIGIN-based acct (i.e. the reciprocal lookup Mastodon performs to verify a split-domain identity after fetching an actor object) returns a subject that echoes back exactly what was asked, instead of the canonical HANDLE_HOST identity; i.e. in my case, it returns cam@ap.campegg.com rather than cam@campegg.com (the canonical identity is present, but in a secondary aliases entry).
It looks like Mastodon's account resolution stops as soon as the subject matches the requested resource, so it never gets to aliases. So any server that discovers this account by fetching the actor object first (which appears to be the common path) settles on WEB_ORIGIN as canonical rather than HANDLE_HOST. Confirmed with a live search from a Mastodon account that had never previously resolved this account or domain, so it's not cached or stale results.
Steps to reproduce
Query WebFinger at the account domain directly (this works correctly):
curl -s "https://campegg.com/.well-known/webfinger?resource=acct:cam@campegg.com"
{"subject":"acct:cam@campegg.com","aliases":["https://ap.campegg.com/@cam"],"links":[...]}
Query WebFinger at WEB_ORIGIN for the WEB_ORIGIN-based acct... this is the reciprocal check that a remote server runs after fetching the actor (note: you won't be able to reproduce this now because of the workaround I'm using—see below):
curl -s "https://ap.campegg.com/.well-known/webfinger?resource=acct:cam@ap.campegg.com"
{"subject":"acct:cam@ap.campegg.com","aliases":["https://ap.campegg.com/@cam","acct:cam@campegg.com"],"links":[...]}
Expected behavior
The second response should have subject set to acct:cam@campegg.com regardless of which valid acct variant was queried, which matches how Mastodon's own LOCAL_DOMAIN/WEB_DOMAIN split handles the identical case.
Actual behavior
The subject mirrors the query verbatim; the canonical identity only shows up as an alias.
Impact
Remote search and mention resolution display and store the account under the WEB_ORIGIN domain instead of HANDLE_HOST for any discovery path that starts from the actor object. This includes direct account search, on at least one tested Mastodon instance.
Workaround
I'm currently using a rule in my Caddyfile to serve a corrected response, but it's not ideal (I'd have to remember to update it if I change my avatar image, etc).
@reciprocalcheck {
path /.well-known/webfinger
query resource=acct:cam@ap.campegg.com
}
handle @reciprocalcheck {
header Content-Type "application/jrd+json"
respond `{"subject":"acct:cam@campegg.com","aliases":["https://ap.campegg.com/@cam"],"links":[{"rel":"self","href":"https://ap.campegg.com/@cam","type":"application/activity+json"},{"rel":"http://webfinger.net/rel/profile-page","href":"https://ap.campegg.com/@cam"},{"rel":"http://webfinger.net/rel/avatar","href":"https://ap.campegg.com/assets/avatars/d358e7d2-bc2e-453a-8dca-4c9041b9b00b/d3b1dbca-6f33-4b17-90d3-27e9424bbc56.png"}]}` 200
}
Summary
ghcr.io/fedify-dev/hollo:0.9.0)HANDLE_HOST=campegg.com,WEB_ORIGIN=https://ap.campegg.comQuerying Hollo's WebFinger endpoint at
WEB_ORIGINfor theWEB_ORIGIN-based acct (i.e. the reciprocal lookup Mastodon performs to verify a split-domain identity after fetching an actor object) returns asubjectthat echoes back exactly what was asked, instead of the canonicalHANDLE_HOSTidentity; i.e. in my case, it returnscam@ap.campegg.comrather thancam@campegg.com(the canonical identity is present, but in a secondaryaliasesentry).It looks like Mastodon's account resolution stops as soon as the
subjectmatches the requested resource, so it never gets toaliases. So any server that discovers this account by fetching the actor object first (which appears to be the common path) settles onWEB_ORIGINas canonical rather thanHANDLE_HOST. Confirmed with a live search from a Mastodon account that had never previously resolved this account or domain, so it's not cached or stale results.Steps to reproduce
Query WebFinger at the account domain directly (this works correctly):
{"subject":"acct:cam@campegg.com","aliases":["https://ap.campegg.com/@cam"],"links":[...]}Query WebFinger at
WEB_ORIGINfor theWEB_ORIGIN-based acct... this is the reciprocal check that a remote server runs after fetching the actor (note: you won't be able to reproduce this now because of the workaround I'm using—see below):{"subject":"acct:cam@ap.campegg.com","aliases":["https://ap.campegg.com/@cam","acct:cam@campegg.com"],"links":[...]}Expected behavior
The second response should have
subjectset toacct:cam@campegg.comregardless of which valid acct variant was queried, which matches how Mastodon's ownLOCAL_DOMAIN/WEB_DOMAINsplit handles the identical case.Actual behavior
The
subjectmirrors the query verbatim; the canonical identity only shows up as an alias.Impact
Remote search and mention resolution display and store the account under the
WEB_ORIGINdomain instead ofHANDLE_HOSTfor any discovery path that starts from the actor object. This includes direct account search, on at least one tested Mastodon instance.Workaround
I'm currently using a rule in my
Caddyfileto serve a corrected response, but it's not ideal (I'd have to remember to update it if I change my avatar image, etc).