Refactor management stuff

This commit is contained in:
Jon Staab
2025-10-21 14:35:25 -07:00
parent 11b900262d
commit 3f9bdf1b3d
5 changed files with 247 additions and 145 deletions
+33 -6
View File
@@ -5,15 +5,16 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"iter" "iter"
"log"
"fiatjaf.com/nostr" "fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore" "fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr/khatru"
"github.com/Masterminds/squirrel" "github.com/Masterminds/squirrel"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
) )
type EventStore struct { type EventStore struct {
Relay *khatru.Relay
Config *Config Config *Config
Schema *Schema Schema *Schema
FTSAvailable bool FTSAvailable bool
@@ -337,6 +338,22 @@ func (events *EventStore) CountEvents(filter nostr.Filter) (uint32, error) {
// Non-eventstore methods // Non-eventstore methods
func (events *EventStore) SignAndSaveEvent(event nostr.Event, broadcast bool) error {
if err := events.Config.Sign(&event); err != nil {
return err
}
if err := events.SaveEvent(event); err != nil {
return err
}
if broadcast {
events.Relay.BroadcastEvent(event)
}
return nil
}
func (events *EventStore) GetOrCreateApplicationSpecificData(d string) nostr.Event { func (events *EventStore) GetOrCreateApplicationSpecificData(d string) nostr.Event {
filter := nostr.Filter{ filter := nostr.Filter{
Kinds: []nostr.Kind{nostr.KindApplicationSpecificData}, Kinds: []nostr.Kind{nostr.KindApplicationSpecificData},
@@ -349,19 +366,29 @@ func (events *EventStore) GetOrCreateApplicationSpecificData(d string) nostr.Eve
return event return event
} }
event := nostr.Event{ return nostr.Event{
Kind: nostr.KindApplicationSpecificData, Kind: nostr.KindApplicationSpecificData,
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
Tags: nostr.Tags{ Tags: nostr.Tags{
[]string{"d", d}, []string{"d", d},
}, },
} }
}
if err := events.Config.Sign(&event); err != nil { func (events *EventStore) GetOrCreateMemberList() nostr.Event {
log.Println("Failed to sign application specific event: %w", err) filter := nostr.Filter{
Kinds: []nostr.Kind{RELAY_MEMBERS},
} }
events.SaveEvent(event) for event := range events.QueryEvents(filter, 1) {
return event
}
return event return nostr.Event{
Kind: nostr.KindApplicationSpecificData,
CreatedAt: nostr.Now(),
Tags: nostr.Tags{
[]string{"-"},
},
}
} }
+26 -30
View File
@@ -9,18 +9,17 @@ import (
"strings" "strings"
"fiatjaf.com/nostr" "fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr/khatru" "fiatjaf.com/nostr/khatru"
"fiatjaf.com/nostr/nip29" "fiatjaf.com/nostr/nip29"
"github.com/gosimple/slug" "github.com/gosimple/slug"
) )
type Instance struct { type Instance struct {
Relay *khatru.Relay
Config *Config Config *Config
Events eventstore.Store Events *EventStore
Blossom *BlossomStore Blossom *BlossomStore
Management *ManagementStore Management *ManagementStore
Relay *khatru.Relay
} }
func MakeInstance(filename string) (*Instance, error) { func MakeInstance(filename string) (*Instance, error) {
@@ -29,7 +28,10 @@ func MakeInstance(filename string) (*Instance, error) {
return nil, err return nil, err
} }
relay := khatru.NewRelay()
events := &EventStore{ events := &EventStore{
Relay: relay,
Config: config, Config: config,
Schema: &Schema{ Schema: &Schema{
Name: slug.Make(config.Schema), Name: slug.Make(config.Schema),
@@ -47,11 +49,11 @@ func MakeInstance(filename string) (*Instance, error) {
} }
instance := &Instance{ instance := &Instance{
Relay: relay,
Config: config, Config: config,
Events: events, Events: events,
Blossom: blossom, Blossom: blossom,
Management: management, Management: management,
Relay: khatru.NewRelay(),
} }
// NIP 11 info // NIP 11 info
@@ -127,10 +129,6 @@ func (instance *Instance) Cleanup() {
// Utility methods // Utility methods
func (instance *Instance) HasAccess(pubkey nostr.PubKey) bool {
return instance.Management.PubkeyIsAllowed(pubkey)
}
func (instance *Instance) IsGroupMember(id string, pubkey nostr.PubKey) bool { func (instance *Instance) IsGroupMember(id string, pubkey nostr.PubKey) bool {
filter := MakeGroupMembershipCheckFilter(id, pubkey) filter := MakeGroupMembershipCheckFilter(id, pubkey)
events := instance.Events.QueryEvents(filter, 0) events := instance.Events.QueryEvents(filter, 0)
@@ -177,7 +175,7 @@ func (instance *Instance) AllowRecipientEvent(event nostr.Event) bool {
if recipientTag != nil { if recipientTag != nil {
pubkey, err := nostr.PubKeyFromHex(recipientTag[1]) pubkey, err := nostr.PubKeyFromHex(recipientTag[1])
if err == nil && instance.HasAccess(pubkey) { if err == nil && instance.Management.IsPubkeyAllowed(pubkey) {
return true return true
} }
} }
@@ -188,7 +186,7 @@ func (instance *Instance) AllowRecipientEvent(event nostr.Event) bool {
func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event { func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event {
filter := nostr.Filter{ filter := nostr.Filter{
Kinds: []nostr.Kind{AUTH_INVITE}, Kinds: []nostr.Kind{RELAY_INVITE},
Authors: []nostr.PubKey{pubkey}, Authors: []nostr.PubKey{pubkey},
} }
@@ -197,7 +195,7 @@ func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event {
} }
event := nostr.Event{ event := nostr.Event{
Kind: AUTH_INVITE, Kind: RELAY_INVITE,
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
Tags: nostr.Tags{ Tags: nostr.Tags{
[]string{"claim", RandomString(8)}, []string{"claim", RandomString(8)},
@@ -205,14 +203,10 @@ func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event {
}, },
} }
if err := instance.Config.Sign(&event); err != nil { if err := instance.Events.SignAndSaveEvent(event, false); err != nil {
log.Printf("Failed to sign invite event: %v", err) log.Printf("Failed to sign invite event: %v", err)
} }
if err := instance.Events.SaveEvent(event); err != nil {
log.Printf("Failed to save invite event: %v", err)
}
return event return event
} }
@@ -224,7 +218,7 @@ func (instance *Instance) OnJoinEvent(event nostr.Event) (reject bool, msg strin
} }
filter := nostr.Filter{ filter := nostr.Filter{
Kinds: []nostr.Kind{AUTH_INVITE}, Kinds: []nostr.Kind{RELAY_INVITE},
} }
for event := range instance.Events.QueryEvents(filter, 0) { for event := range instance.Events.QueryEvents(filter, 0) {
@@ -263,11 +257,11 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
return true, "restricted: you cannot publish events on behalf of others" return true, "restricted: you cannot publish events on behalf of others"
} }
if event.Kind == AUTH_JOIN { if event.Kind == RELAY_JOIN {
return instance.OnJoinEvent(event) return instance.OnJoinEvent(event)
} }
if !instance.HasAccess(pubkey) { if !instance.Management.IsPubkeyAllowed(pubkey) {
return true, "restricted: you are not a member of this relay" return true, "restricted: you are not a member of this relay"
} }
@@ -350,17 +344,19 @@ func (instance *Instance) DeleteEvent(ctx context.Context, id nostr.ID) error {
func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) { func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
addEvent := func(newEvent nostr.Event) { addEvent := func(newEvent nostr.Event) {
if err := instance.Config.Sign(&newEvent); err != nil { if err := instance.Events.SignAndSaveEvent(newEvent, true); err != nil {
log.Println(err) log.Println(err)
} else {
if err := instance.Events.SaveEvent(newEvent); err != nil {
log.Println(err)
} else {
instance.Relay.BroadcastEvent(newEvent)
}
} }
} }
if event.Kind == RELAY_JOIN {
instance.Management.AllowPubkey(event.PubKey)
}
if event.Kind == RELAY_LEAVE {
instance.Management.BanPubkey(event.PubKey, "exited relay")
}
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Config.Groups.AutoJoin { if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Config.Groups.AutoJoin {
h := GetGroupIDFromEvent(event) h := GetGroupIDFromEvent(event)
meta := instance.GetGroupMetadataEvent(h) meta := instance.GetGroupMetadataEvent(h)
@@ -392,7 +388,7 @@ func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
} }
func (instance *Instance) OnEphemeralEvent(ctx context.Context, event nostr.Event) { func (instance *Instance) OnEphemeralEvent(ctx context.Context, event nostr.Event) {
if slices.Contains([]nostr.Kind{AUTH_INVITE, AUTH_JOIN}, event.Kind) { if slices.Contains([]nostr.Kind{RELAY_INVITE, RELAY_JOIN}, event.Kind) {
instance.Events.SaveEvent(event) instance.Events.SaveEvent(event)
} }
} }
@@ -404,7 +400,7 @@ func (instance *Instance) OnRequest(ctx context.Context, filter nostr.Filter) (r
return true, "auth-required: authentication is required for access" return true, "auth-required: authentication is required for access"
} }
if !instance.HasAccess(pubkey) { if !instance.Management.IsPubkeyAllowed(pubkey) {
return true, "restricted: you are not a member of this relay" return true, "restricted: you are not a member of this relay"
} }
@@ -435,7 +431,7 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
return event return event
} }
if slices.Contains(filter.Kinds, AUTH_INVITE) && instance.Config.CanInvite(pubkey) { if slices.Contains(filter.Kinds, RELAY_INVITE) && instance.Config.CanInvite(pubkey) {
if !yield(stripSignature(instance.GenerateInviteEvent(pubkey))) { if !yield(stripSignature(instance.GenerateInviteEvent(pubkey))) {
return return
} }
@@ -476,5 +472,5 @@ func (instance *Instance) RejectConnection(r *http.Request) bool {
} }
func (instance *Instance) PreventBroadcast(ws *khatru.WebSocket, event nostr.Event) bool { func (instance *Instance) PreventBroadcast(ws *khatru.WebSocket, event nostr.Event) bool {
return event.Kind == AUTH_JOIN return event.Kind == RELAY_JOIN
} }
+8 -8
View File
@@ -102,7 +102,7 @@ func TestInstance_HasAccess(t *testing.T) {
// Add a join event for the user (must be signed by the user) // Add a join event for the user (must be signed by the user)
joinEvent := nostr.Event{ joinEvent := nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
PubKey: userPubkey, PubKey: userPubkey,
Tags: nostr.Tags{{"claim", "test"}}, Tags: nostr.Tags{{"claim", "test"}},
@@ -211,7 +211,7 @@ func TestInstance_AllowRecipientEvent(t *testing.T) {
// Add user access // Add user access
joinEvent := nostr.Event{ joinEvent := nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
PubKey: userPubkey, PubKey: userPubkey,
Tags: nostr.Tags{{"claim", "test"}}, Tags: nostr.Tags{{"claim", "test"}},
@@ -285,8 +285,8 @@ func TestInstance_GenerateInviteEvent(t *testing.T) {
inviteEvent := instance.GenerateInviteEvent(userPubkey) inviteEvent := instance.GenerateInviteEvent(userPubkey)
// Test event properties // Test event properties
if inviteEvent.Kind != AUTH_INVITE { if inviteEvent.Kind != RELAY_INVITE {
t.Errorf("GenerateInviteEvent() kind = %v, want %v", inviteEvent.Kind, AUTH_INVITE) t.Errorf("GenerateInviteEvent() kind = %v, want %v", inviteEvent.Kind, RELAY_INVITE)
} }
if inviteEvent.PubKey != instance.Config.Secret.Public() { if inviteEvent.PubKey != instance.Config.Secret.Public() {
@@ -332,7 +332,7 @@ func TestInstance_OnJoinEvent(t *testing.T) {
{ {
name: "valid join event", name: "valid join event",
joinEvent: nostr.Event{ joinEvent: nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
Tags: nostr.Tags{{"claim", claimTag[1]}}, Tags: nostr.Tags{{"claim", claimTag[1]}},
}, },
wantReject: false, wantReject: false,
@@ -341,7 +341,7 @@ func TestInstance_OnJoinEvent(t *testing.T) {
{ {
name: "join event without claim", name: "join event without claim",
joinEvent: nostr.Event{ joinEvent: nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
Tags: nostr.Tags{}, Tags: nostr.Tags{},
}, },
wantReject: true, wantReject: true,
@@ -350,7 +350,7 @@ func TestInstance_OnJoinEvent(t *testing.T) {
{ {
name: "join event with invalid claim", name: "join event with invalid claim",
joinEvent: nostr.Event{ joinEvent: nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
Tags: nostr.Tags{{"claim", "invalid-claim"}}, Tags: nostr.Tags{{"claim", "invalid-claim"}},
}, },
wantReject: true, wantReject: true,
@@ -476,7 +476,7 @@ func TestInstance_HasAccess_WithBannedUser(t *testing.T) {
// Test banned user has no access even with join event // Test banned user has no access even with join event
joinEvent := nostr.Event{ joinEvent := nostr.Event{
Kind: AUTH_JOIN, Kind: RELAY_JOIN,
CreatedAt: nostr.Now(), CreatedAt: nostr.Now(),
PubKey: userPubkey, PubKey: userPubkey,
Tags: nostr.Tags{{"claim", "test"}}, Tags: nostr.Tags{{"claim", "test"}},
+172 -97
View File
@@ -8,12 +8,26 @@ import (
"fmt" "fmt"
) )
// Management store takes care of all nip 86 methods, as well as defining actions for internal use.
//
// The banned pubkeys list is a NIP 78 application-specific event, which keeps track of which pubkeys
// have been banned, independently of the members list. Banned events works the same way.
//
// Membership is implemented as defined here https://github.com/nostr-protocol/nips/pull/1079/files, using
// both membership lists and add/remove events.
//
// Actions like BanPubkey and AllowPubkey synchronize ban and membership lists. These should be called in most
// cases, unless you're trying to do something more advanced.
//
// All actions are idempotent, and won't do anything if conditions are already correct.
type ManagementStore struct { type ManagementStore struct {
Relay *khatru.Relay
Config *Config Config *Config
Events *EventStore Events *EventStore
} }
// Banned pubkeys // Internal banned pubkeys list
func (m *ManagementStore) GetBannedPubkeyItems() []nip86.PubKeyReason { func (m *ManagementStore) GetBannedPubkeyItems() []nip86.PubKeyReason {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS) event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
@@ -29,30 +43,135 @@ func (m *ManagementStore) GetBannedPubkeyItems() []nip86.PubKeyReason {
return items return items
} }
func (m *ManagementStore) GetBannedPubkeys() []nostr.PubKey { func (m *ManagementStore) AddBannedPubkey(pubkey nostr.PubKey, reason string) error {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
if event.Tags.FindWithValue("pubkey", pubkey.Hex()) == nil {
event.Tags = append(event.Tags, nostr.Tag{"pubkey", pubkey.Hex(), reason})
if err := m.Events.SignAndSaveEvent(event, false); err != nil {
return err
}
}
return nil
}
func (m *ManagementStore) RemoveBannedPubkey(pubkey nostr.PubKey) error {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
if event.Tags.FindWithValue("pubkey", pubkey.Hex()) != nil {
event.Tags = Filter(event.Tags, func(t nostr.Tag) bool {
return t[1] != pubkey.Hex()
})
if err := m.Events.SignAndSaveEvent(event, false); err != nil {
return err
}
}
return nil
}
// Membership
func (m *ManagementStore) GetMembers() []nostr.PubKey {
pubkeys := make([]nostr.PubKey, 0) pubkeys := make([]nostr.PubKey, 0)
for _, item := range m.GetBannedPubkeyItems() { for tag := range m.Events.GetOrCreateMemberList().Tags.FindAll("member") {
pubkeys = append(pubkeys, item.PubKey) pubkey, err := nostr.PubKeyFromHex(tag[1])
if err == nil {
pubkeys = append(pubkeys, pubkey)
}
} }
return pubkeys return pubkeys
} }
func (m *ManagementStore) IsMember(pubkey nostr.PubKey) bool {
return m.Events.GetOrCreateMemberList().Tags.FindWithValue("member", pubkey.Hex()) != nil
}
func (m *ManagementStore) AddMember(pubkey nostr.PubKey) error {
membersEvent := m.Events.GetOrCreateMemberList()
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) == nil {
addMemberEvent := nostr.Event{
Kind: RELAY_ADD_MEMBER,
CreatedAt: nostr.Now(),
Tags: nostr.Tags{
[]string{"-"},
[]string{"p", pubkey.Hex()},
},
}
if err := m.Events.SignAndSaveEvent(addMemberEvent, true); err != nil {
return err
}
membersEvent.Tags = append(membersEvent.Tags, nostr.Tag{"pubkey", pubkey.Hex()})
if err := m.Events.SignAndSaveEvent(membersEvent, true); err != nil {
return err
}
}
return nil
}
func (m *ManagementStore) RemoveMember(pubkey nostr.PubKey) error {
membersEvent := m.Events.GetOrCreateMemberList()
if membersEvent.Tags.FindWithValue("member", pubkey.Hex()) != nil {
removeMemberEvent := nostr.Event{
Kind: RELAY_REMOVE_MEMBER,
CreatedAt: nostr.Now(),
Tags: nostr.Tags{
[]string{"-"},
[]string{"p", pubkey.Hex()},
},
}
if err := m.Events.SignAndSaveEvent(removeMemberEvent, true); err != nil {
return err
}
membersEvent.Tags = Filter(membersEvent.Tags, func(t nostr.Tag) bool {
return t[1] != pubkey.Hex()
})
if err := m.Events.SignAndSaveEvent(membersEvent, true); err != nil {
return err
}
}
return nil
}
// Banning
func (m *ManagementStore) BanPubkey(pubkey nostr.PubKey, reason string) error { func (m *ManagementStore) BanPubkey(pubkey nostr.PubKey, reason string) error {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS) if err := m.RemoveMember(pubkey); err != nil {
event.Tags = append(event.Tags, nostr.Tag{"pubkey", pubkey.Hex(), reason}) return err
}
return m.Events.SaveEvent(event) if err := m.AddBannedPubkey(pubkey, reason); err != nil {
return err
}
filter := nostr.Filter{
Authors: []nostr.PubKey{pubkey},
}
for event := range m.Events.QueryEvents(filter, 0) {
m.Events.DeleteEvent(event.ID)
}
return nil
} }
func (m *ManagementStore) PubkeyIsBanned(pubkey nostr.PubKey) bool { // Allowing
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
tag := event.Tags.FindWithValue("pubkey", pubkey.Hex())
return tag != nil
}
// Allowed pubkeys
func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason { func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason {
reasons := make([]nip86.PubKeyReason, 0) reasons := make([]nip86.PubKeyReason, 0)
@@ -71,47 +190,29 @@ func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason {
for _, pubkey := range role.Pubkeys { for _, pubkey := range role.Pubkeys {
reasons = append(reasons, nip86.PubKeyReason{ reasons = append(reasons, nip86.PubKeyReason{
PubKey: nostr.MustPubKeyFromHex(pubkey), PubKey: nostr.MustPubKeyFromHex(pubkey),
Reason: fmt.Sprintf("assigned to role: %s", name), Reason: fmt.Sprintf("assigned to %s role", name),
}) })
} }
} }
filter := nostr.Filter{ for tag := range m.Events.GetOrCreateMemberList().Tags.FindAll("member") {
Kinds: []nostr.Kind{AUTH_JOIN}, pubkey, err := nostr.PubKeyFromHex(tag[1])
}
for event := range m.Events.QueryEvents(filter, 0) { if err != nil {
reasons = append( reasons = append(
reasons, reasons,
nip86.PubKeyReason{ nip86.PubKeyReason{
PubKey: event.PubKey, PubKey: pubkey,
Reason: "joined via invite code", Reason: "relay member",
}, },
) )
}
} }
return reasons return reasons
} }
func (m *ManagementStore) GetAllowedPubkeys() []nostr.PubKey { func (m *ManagementStore) IsPubkeyAllowed(pubkey nostr.PubKey) bool {
pubkeys := make([]nostr.PubKey, 0)
for _, item := range m.GetAllowedPubkeyItems() {
pubkeys = append(pubkeys, item.PubKey)
}
return pubkeys
}
func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey, reason string) error {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
event.Tags = Filter(event.Tags, func(t nostr.Tag) bool {
return t[1] != pubkey.Hex()
})
return m.Events.SaveEvent(event)
}
func (m *ManagementStore) PubkeyIsAllowed(pubkey nostr.PubKey) bool {
if m.Config.IsOwner(pubkey) || m.Config.IsSelf(pubkey) { if m.Config.IsOwner(pubkey) || m.Config.IsSelf(pubkey) {
return true return true
} }
@@ -120,32 +221,32 @@ func (m *ManagementStore) PubkeyIsAllowed(pubkey nostr.PubKey) bool {
return true return true
} }
filter := nostr.Filter{ return m.IsMember(pubkey)
Kinds: []nostr.Kind{AUTH_JOIN}, }
Authors: []nostr.PubKey{pubkey},
func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey) error {
if m.IsPubkeyAllowed(pubkey) {
return nil
} }
for range m.Events.QueryEvents(filter, 1) { if err := m.AddMember(pubkey); err != nil {
return true return err
} }
return false if err := m.RemoveBannedPubkey(pubkey); err != nil {
return err
}
return nil
} }
// Banned events // Banned events
type BannedEventItem struct { func (m *ManagementStore) GetBannedEventItems() []nip86.IDReason {
ID nostr.ID items := make([]nip86.IDReason, 0)
Reason string for tag := range m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS).Tags.FindAll("event") {
} items = append(items, nip86.IDReason{
ID: tag[1],
func (m *ManagementStore) GetBannedEventItems() []BannedEventItem {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
items := make([]BannedEventItem, 0)
for tag := range event.Tags.FindAll("event") {
items = append(items, BannedEventItem{
ID: nostr.MustIDFromHex(tag[1]),
Reason: tag[2], Reason: tag[2],
}) })
} }
@@ -153,20 +254,15 @@ func (m *ManagementStore) GetBannedEventItems() []BannedEventItem {
return items return items
} }
func (m *ManagementStore) GetBannedEvents() []nostr.ID { func (m *ManagementStore) BanEvent(id nostr.ID, reason string) error {
ids := make([]nostr.ID, 0) if err := m.Events.DeleteEvent(id); err != nil {
for _, item := range m.GetBannedEventItems() { return err
ids = append(ids, item.ID)
} }
return ids
}
func (m *ManagementStore) BanEvent(id nostr.ID, reason string) error {
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS) event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
event.Tags = append(event.Tags, nostr.Tag{"event", id.Hex(), reason}) event.Tags = append(event.Tags, nostr.Tag{"event", id.Hex(), reason})
return m.Events.SaveEvent(event) return m.Events.SignAndSaveEvent(event, false)
} }
func (m *ManagementStore) AllowEvent(id nostr.ID, reason string) error { func (m *ManagementStore) AllowEvent(id nostr.ID, reason string) error {
@@ -175,7 +271,7 @@ func (m *ManagementStore) AllowEvent(id nostr.ID, reason string) error {
return t[1] == id.Hex() return t[1] == id.Hex()
}) })
return m.Events.SaveEvent(event) return m.Events.SignAndSaveEvent(event, false)
} }
func (m *ManagementStore) EventIsBanned(id nostr.ID) bool { func (m *ManagementStore) EventIsBanned(id nostr.ID) bool {
@@ -199,19 +295,11 @@ func (m *ManagementStore) Enable(instance *Instance) {
} }
instance.Relay.ManagementAPI.BanPubKey = func(ctx context.Context, pubkey nostr.PubKey, reason string) error { instance.Relay.ManagementAPI.BanPubKey = func(ctx context.Context, pubkey nostr.PubKey, reason string) error {
filter := nostr.Filter{
Authors: []nostr.PubKey{pubkey},
}
for event := range instance.Events.QueryEvents(filter, 0) {
instance.Events.DeleteEvent(event.ID)
}
return m.BanPubkey(pubkey, reason) return m.BanPubkey(pubkey, reason)
} }
instance.Relay.ManagementAPI.AllowPubKey = func(ctx context.Context, pubkey nostr.PubKey, reason string) error { instance.Relay.ManagementAPI.AllowPubKey = func(ctx context.Context, pubkey nostr.PubKey, reason string) error {
return m.AllowPubkey(pubkey, reason) return m.AllowPubkey(pubkey)
} }
instance.Relay.ManagementAPI.ListBannedPubKeys = func(ctx context.Context) ([]nip86.PubKeyReason, error) { instance.Relay.ManagementAPI.ListBannedPubKeys = func(ctx context.Context) ([]nip86.PubKeyReason, error) {
@@ -223,8 +311,6 @@ func (m *ManagementStore) Enable(instance *Instance) {
} }
instance.Relay.ManagementAPI.BanEvent = func(ctx context.Context, id nostr.ID, reason string) error { instance.Relay.ManagementAPI.BanEvent = func(ctx context.Context, id nostr.ID, reason string) error {
instance.Events.DeleteEvent(id)
return m.BanEvent(id, reason) return m.BanEvent(id, reason)
} }
@@ -233,17 +319,6 @@ func (m *ManagementStore) Enable(instance *Instance) {
} }
instance.Relay.ManagementAPI.ListBannedEvents = func(ctx context.Context) ([]nip86.IDReason, error) { instance.Relay.ManagementAPI.ListBannedEvents = func(ctx context.Context) ([]nip86.IDReason, error) {
reasons := make([]nip86.IDReason, 0) return m.GetBannedEventItems(), nil
for _, item := range m.GetBannedEventItems() {
reasons = append(
reasons,
nip86.IDReason{
ID: item.ID.Hex(),
Reason: item.Reason,
},
)
}
return reasons, nil
} }
} }
+8 -4
View File
@@ -7,10 +7,14 @@ import (
) )
const ( const (
AUTH_JOIN = 28934 RELAY_ADD_MEMBER = 8000
AUTH_INVITE = 28935 RELAY_REMOVE_MEMBER = 8001
BANNED_PUBKEYS = "zooid/banned_pubkeys" RELAY_MEMBERS = 13534
BANNED_EVENTS = "zooid/banned_events" RELAY_JOIN = 28934
RELAY_INVITE = 28935
RELAY_LEAVE = 28936
BANNED_PUBKEYS = "zooid/banned_pubkeys"
BANNED_EVENTS = "zooid/banned_events"
) )
func First[T any](s []T) T { func First[T any](s []T) T {