feat: implement Bluesky-compatible bidirectional DID verification
Implements mandatory bidirectional did:web verification matching Bluesky's
security model. This prevents domain impersonation attacks by requiring
DID documents to claim the handle domain in their alsoKnownAs field.
Security Improvements:
- MANDATORY bidirectional verification (hard-fail, not soft-fail)
- Verifies domain matching (handle domain == hostedBy domain)
- Fetches DID document from https://domain/.well-known/did.json
- Verifies DID document ID matches claimed DID
- NEW: Verifies DID document claims handle in alsoKnownAs field
- Rejects communities that fail verification (was: log warning only)
- Cache TTL increased from 1h to 24h (matches Bluesky recommendations)
Implementation:
- Location: internal/atproto/jetstream/community_consumer.go
- Verification runs in AppView Jetstream consumer (not creation API)
- Impact: Controls AppView indexing and federation trust
- Performance: Bounded LRU cache (1000 entries), rate limiting (10 req/s)
Attack Prevention:
✓ Domain impersonation (can't claim did:web:nintendo.com without owning it)
✓ DNS hijacking (bidirectional check fails even with DNS control)
✓ Reputation hijacking (can't point your domain to someone else's DID)
✓ AppView pollution (only legitimate communities indexed)
✓ Federation trust (other instances can verify instance identity)
Tests:
- Updated existing tests to handle mandatory verification
- Added comprehensive bidirectional verification tests with mock HTTP server
- All tests passing ✅
Documentation:
- PRD_BACKLOG.md: Marked did:web verification as COMPLETE
- PRD_ALPHA_GO_LIVE.md: Added production deployment requirements
- Clarified architecture: AppView (coves.social) + PDS (coves.me)
- Added PDS deployment checklist (separate domain required)
- Updated production environment checklist
- Added Jetstream configuration (Bluesky production firehose)
Production Requirements:
- Deploy .well-known/did.json to coves.social with alsoKnownAs field
- Set SKIP_DID_WEB_VERIFICATION=false (production)
- PDS must be on separate domain (coves.me, not coves.social)
- Jetstream connects to wss://jetstream2.us-east.bsky.network/subscribe
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>