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 isDevEnv bool // true = generate without registering, false = register with PLC 13 plcDirectoryURL string // PLC directory URL (only used when isDevEnv=false) 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 if !g.isDevEnv { 55 // Future: implement PLC registration here 56 // return "", fmt.Errorf("PLC registration not yet implemented") 57 } 58 59 return did, nil 60} 61 62// ValidateDID checks if a DID string is properly formatted 63// Supports did:plc, did:web (for instances) 64func ValidateDID(did string) bool { 65 if !strings.HasPrefix(did, "did:") { 66 return false 67 } 68 69 parts := strings.Split(did, ":") 70 if len(parts) < 3 { 71 return false 72 } 73 74 method := parts[1] 75 identifier := parts[2] 76 77 // Basic validation: method and identifier must not be empty 78 return method != "" && identifier != "" 79}