feat(pds): DID-Dokument unter /.well-known/did.json ausliefern

Die AppView soll die Access-Tokens der PDS prüfen können, ohne dass
PDS_JWT_SECRET den PDS-Prozess verlässt. Verifiziert wird ES256 mit dem
*öffentlichen* Teil des P-256-Schlüssels — den veröffentlicht die PDS
jetzt als verificationMethod (Multikey) in ihrem DID-Dokument.

Damit fällt auch die hartkodierte Service-DID: describeServer gab stur
did:web:pds.maarcadetweet.local zurück, unabhängig von PDS_PUBLIC_URL.
Beide Endpoints leiten sie jetzt aus einer Quelle ab
(AppConfig::pds_did(), did:web-Regel mit %3A-kodiertem Port). Der `iss`
des Access-Tokens baute die DID zuvor ohne Port-Kodierung zusammen —
also in einer Form, der kein did:web-Resolver folgen könnte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013HC9HLrUU1LNwkzp8nkDLX
This commit is contained in:
tomdebone
2026-09-09 23:01:16 +02:00
co-authored by Claude Opus 5
parent ec8fe187fe
commit 786a892658
4 changed files with 354 additions and 3 deletions
+7 -1
View File
@@ -39,7 +39,13 @@ pub fn issue_access_jwt(
let now = chrono::Utc::now().timestamp();
let exp = now + 3600;
let claims = JwtClaims {
iss: format!("did:web:{}", cfg.pds_public_url.trim_start_matches("http://").trim_start_matches("https://")),
// Same derivation as `describeServer` and `/.well-known/did.json`
// (`AppConfig::pds_did`), so a verifier can take `iss`, resolve
// the did:web document and arrive at the key this token is
// signed with. The previous inline version dropped the
// percent-encoding of the port, producing an `iss` that no
// did:web resolver could follow.
iss: cfg.pds_did(),
sub: did.to_string(),
aud: "did:web:appview.maarcadetweet.local".into(),
iat: now,