A community based topic aggregation platform built on atproto

feat(server): integrate did:web verification with configuration

Integrates hostedBy verification into the server with environment-based
configuration for development and production use.

Changes:
- Added SKIP_DID_WEB_VERIFICATION env var for dev mode bypass
- Updated consumer initialization with instance DID and skip flag
- Added warning logs when verification is disabled
- Configured .env.dev with skip flag enabled for local development

Server logs will now show:
- "⚠️ WARNING: did:web verification DISABLED (dev mode)" when skipped
- "🚨 SECURITY: Rejecting community" when domain mismatch detected

Production Deployment:
- Set SKIP_DID_WEB_VERIFICATION=false or leave unset
- Ensure .well-known/did.json is properly configured

Co-Authored-By: Claude <noreply@anthropic.com>

Changed files
+17 -7
cmd
server
+6
.env.dev
···
# Always true for local development (use PLC_DIRECTORY_URL to control registration)
IS_DEV_ENV=true
+
# Security: Skip did:web domain verification for local development
+
# IMPORTANT: Set to false in production to prevent domain spoofing attacks
+
# When true, communities can claim any hostedByDID without verification
+
# When false, hostedByDID must match the community handle domain
+
SKIP_DID_WEB_VERIFICATION=true
+
# Logging
LOG_LEVEL=debug
LOG_ENABLED=true
+11 -7
cmd/server/main.go
···
// We cannot allow arbitrary domains to prevent impersonation attacks
// Example attack: !leagueoflegends@riotgames.com on a non-Riot instance
//
-
// TODO (Security - V2.1): Implement did:web domain verification
-
// Currently, any self-hoster can set INSTANCE_DID=did:web:nintendo.com without
-
// actually owning nintendo.com. This allows domain impersonation attacks.
-
// Solution: Verify domain ownership by fetching https://domain/.well-known/did.json
-
// and ensuring it matches the claimed DID. See: https://atproto.com/specs/did-web
-
// Alternatively, switch to did:plc for instance DIDs (cryptographically unique).
+
// SECURITY: did:web domain verification is implemented in the Jetstream consumer
+
// See: internal/atproto/jetstream/community_consumer.go - verifyHostedByClaim()
+
// Communities with mismatched hostedBy domains are rejected during indexing
var instanceDomain string
if strings.HasPrefix(instanceDID, "did:web:") {
// Extract domain from did:web (this is the authoritative source)
···
communityJetstreamURL = "ws://localhost:6008/subscribe?wantedCollections=social.coves.community.profile&wantedCollections=social.coves.community.subscription"
}
-
communityEventConsumer := jetstream.NewCommunityEventConsumer(communityRepo)
+
// Initialize community event consumer with did:web verification
+
skipDIDWebVerification := os.Getenv("SKIP_DID_WEB_VERIFICATION") == "true"
+
if skipDIDWebVerification {
+
log.Println("⚠️ WARNING: did:web domain verification is DISABLED (dev mode)")
+
log.Println(" Set SKIP_DID_WEB_VERIFICATION=false for production")
+
}
+
+
communityEventConsumer := jetstream.NewCommunityEventConsumer(communityRepo, instanceDID, skipDIDWebVerification)
communityJetstreamConnector := jetstream.NewCommunityJetstreamConnector(communityEventConsumer, communityJetstreamURL)
go func() {