A community based topic aggregation platform built on atproto
1package did 2 3import ( 4 "crypto/rand" 5 "encoding/base32" 6 "fmt" 7 "strings" 8) 9 10// Generator creates DIDs for Coves entities 11type Generator struct { 12 plcDirectoryURL string 13 isDevEnv bool 14} 15 16// NewGenerator creates a new DID generator 17// isDevEnv: true for local development (no PLC registration), false for production (register with PLC) 18// plcDirectoryURL: URL for PLC directory (e.g., "https://plc.directory") 19func NewGenerator(isDevEnv bool, plcDirectoryURL string) *Generator { 20 return &Generator{ 21 isDevEnv: isDevEnv, 22 plcDirectoryURL: plcDirectoryURL, 23 } 24} 25 26// GenerateCommunityDID creates a new random DID for a community 27// Format: did:plc:{base32-random} 28// 29// Dev mode (isDevEnv=true): Generates did:plc:xxx without registering to PLC 30// Prod mode (isDevEnv=false): Generates did:plc:xxx AND registers with PLC directory 31// 32// See: https://github.com/bluesky-social/did-method-plc 33func (g *Generator) GenerateCommunityDID() (string, error) { 34 // Generate 16 random bytes for the DID identifier 35 randomBytes := make([]byte, 16) 36 if _, err := rand.Read(randomBytes); err != nil { 37 return "", fmt.Errorf("failed to generate random DID: %w", err) 38 } 39 40 // Encode as base32 (lowercase, no padding) - matches PLC format 41 encoded := base32.StdEncoding.EncodeToString(randomBytes) 42 encoded = strings.ToLower(strings.TrimRight(encoded, "=")) 43 44 did := fmt.Sprintf("did:plc:%s", encoded) 45 46 // TODO: In production (isDevEnv=false), register this DID with PLC directory 47 // This would involve: 48 // 1. Generate signing keypair for the DID 49 // 2. Create DID document with service endpoints 50 // 3. POST to plcDirectoryURL to register 51 // 4. Store keypair securely for future DID updates 52 // 53 // For now, we just generate the identifier (works fine for local dev) 54 // Production PLC registration is not yet implemented - DIDs are generated 55 // locally but not registered with the PLC directory. This is acceptable 56 // for development and private instances, but production deployments should 57 // implement full PLC registration to ensure DIDs are globally resolvable. 58 _ = g.isDevEnv // Acknowledge that isDevEnv will be used when PLC registration is implemented 59 60 return did, nil 61} 62 63// ValidateDID checks if a DID string is properly formatted 64// Supports did:plc, did:web (for instances) 65func ValidateDID(did string) bool { 66 if !strings.HasPrefix(did, "did:") { 67 return false 68 } 69 70 parts := strings.Split(did, ":") 71 if len(parts) < 3 { 72 return false 73 } 74 75 method := parts[1] 76 identifier := parts[2] 77 78 // Basic validation: method and identifier must not be empty 79 return method != "" && identifier != "" 80}