package dgraph import ( "encoding/json" "fmt" "time" "next.orly.dev/pkg/database" "git.mleku.dev/mleku/nostr/encoders/hex" ) // NIP-43 Invite-based ACL methods // Simplified implementation using marker-based storage // AddNIP43Member adds a member using an invite code func (d *D) AddNIP43Member(pubkey []byte, inviteCode string) error { key := "nip43_" + hex.Enc(pubkey) member := database.NIP43Membership{ InviteCode: inviteCode, AddedAt: time.Now(), } copy(member.Pubkey[:], pubkey) data, err := json.Marshal(member) if err != nil { return fmt.Errorf("failed to marshal membership: %w", err) } // Also add to members list if err := d.addToMembersList(pubkey); err != nil { return err } return d.SetMarker(key, data) } // RemoveNIP43Member removes a member func (d *D) RemoveNIP43Member(pubkey []byte) error { key := "nip43_" + hex.Enc(pubkey) // Remove from members list if err := d.removeFromMembersList(pubkey); err != nil { return err } return d.DeleteMarker(key) } // IsNIP43Member checks if a pubkey is a member func (d *D) IsNIP43Member(pubkey []byte) (isMember bool, err error) { _, err = d.GetNIP43Membership(pubkey) return err == nil, nil } // GetNIP43Membership retrieves membership information func (d *D) GetNIP43Membership(pubkey []byte) (*database.NIP43Membership, error) { key := "nip43_" + hex.Enc(pubkey) data, err := d.GetMarker(key) if err != nil { return nil, err } var member database.NIP43Membership if err := json.Unmarshal(data, &member); err != nil { return nil, fmt.Errorf("failed to unmarshal membership: %w", err) } return &member, nil } // GetAllNIP43Members retrieves all member pubkeys func (d *D) GetAllNIP43Members() ([][]byte, error) { data, err := d.GetMarker("nip43_members_list") if err != nil { return nil, nil // No members = empty list } var members []string if err := json.Unmarshal(data, &members); err != nil { return nil, fmt.Errorf("failed to unmarshal members list: %w", err) } result := make([][]byte, 0, len(members)) for _, hexPubkey := range members { pubkey, err := hex.Dec(hexPubkey) if err != nil { continue } result = append(result, pubkey) } return result, nil } // StoreInviteCode stores an invite code with expiration func (d *D) StoreInviteCode(code string, expiresAt time.Time) error { key := "invite_" + code inviteData := map[string]interface{}{ "code": code, "expiresAt": expiresAt, } data, err := json.Marshal(inviteData) if err != nil { return fmt.Errorf("failed to marshal invite: %w", err) } return d.SetMarker(key, data) } // ValidateInviteCode checks if an invite code is valid func (d *D) ValidateInviteCode(code string) (valid bool, err error) { key := "invite_" + code data, err := d.GetMarker(key) if err != nil { return false, nil // Code doesn't exist } var inviteData map[string]interface{} if err := json.Unmarshal(data, &inviteData); err != nil { return false, fmt.Errorf("failed to unmarshal invite: %w", err) } // Check expiration if expiresStr, ok := inviteData["expiresAt"].(string); ok { expiresAt, err := time.Parse(time.RFC3339, expiresStr) if err == nil && time.Now().After(expiresAt) { return false, nil // Expired } } return true, nil } // DeleteInviteCode removes an invite code func (d *D) DeleteInviteCode(code string) error { key := "invite_" + code return d.DeleteMarker(key) } // PublishNIP43MembershipEvent publishes a membership event func (d *D) PublishNIP43MembershipEvent(kind int, pubkey []byte) error { // This would require publishing an actual Nostr event // For now, just log it d.Logger.Infof("would publish NIP-43 event kind %d for %s", kind, hex.Enc(pubkey)) return nil } // Helper functions func (d *D) addToMembersList(pubkey []byte) error { data, err := d.GetMarker("nip43_members_list") var members []string if err == nil { if err := json.Unmarshal(data, &members); err != nil { return fmt.Errorf("failed to unmarshal members list: %w", err) } } hexPubkey := hex.Enc(pubkey) // Check if already in list for _, member := range members { if member == hexPubkey { return nil // Already in list } } members = append(members, hexPubkey) data, err = json.Marshal(members) if err != nil { return fmt.Errorf("failed to marshal members list: %w", err) } return d.SetMarker("nip43_members_list", data) } func (d *D) removeFromMembersList(pubkey []byte) error { data, err := d.GetMarker("nip43_members_list") if err != nil { return nil // List doesn't exist } var members []string if err := json.Unmarshal(data, &members); err != nil { return fmt.Errorf("failed to unmarshal members list: %w", err) } hexPubkey := hex.Enc(pubkey) // Remove from list newMembers := make([]string, 0, len(members)) for _, member := range members { if member != hexPubkey { newMembers = append(newMembers, member) } } data, err = json.Marshal(newMembers) if err != nil { return fmt.Errorf("failed to marshal members list: %w", err) } return d.SetMarker("nip43_members_list", data) }