forked from coracle/zooid
Clean up groups stuff
This commit is contained in:
+4
-4
@@ -57,7 +57,7 @@ func (bl *BlossomStore) Enable(instance *Instance) {
|
||||
return true, "file too large", 413
|
||||
}
|
||||
|
||||
if auth == nil || !instance.HasAccess(auth.PubKey) {
|
||||
if auth == nil || !instance.Management.IsPubkeyAllowed(auth.PubKey) {
|
||||
return true, "unauthorized", 403
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (bl *BlossomStore) Enable(instance *Instance) {
|
||||
}
|
||||
|
||||
backend.RejectGet = func(ctx context.Context, auth *nostr.Event, sha256 string, ext string) (bool, string, int) {
|
||||
if auth == nil || !instance.HasAccess(auth.PubKey) {
|
||||
if auth == nil || !instance.Management.IsPubkeyAllowed(auth.PubKey) {
|
||||
return true, "unauthorized", 403
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func (bl *BlossomStore) Enable(instance *Instance) {
|
||||
}
|
||||
|
||||
backend.RejectList = func(ctx context.Context, auth *nostr.Event, pubkey nostr.PubKey) (bool, string, int) {
|
||||
if auth == nil || !instance.HasAccess(auth.PubKey) {
|
||||
if auth == nil || !instance.Management.IsPubkeyAllowed(auth.PubKey) {
|
||||
return true, "unauthorized", 403
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (bl *BlossomStore) Enable(instance *Instance) {
|
||||
}
|
||||
|
||||
backend.RejectDelete = func(ctx context.Context, auth *nostr.Event, sha256 string, ext string) (bool, string, int) {
|
||||
if auth == nil || !instance.HasAccess(auth.PubKey) {
|
||||
if auth == nil || !instance.Management.IsPubkeyAllowed(auth.PubKey) {
|
||||
return true, "unauthorized", 403
|
||||
}
|
||||
|
||||
|
||||
+75
-48
@@ -1,8 +1,6 @@
|
||||
package zooid
|
||||
|
||||
import (
|
||||
"iter"
|
||||
|
||||
"fiatjaf.com/nostr"
|
||||
)
|
||||
|
||||
@@ -16,17 +14,74 @@ func GetGroupIDFromEvent(event nostr.Event) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func MakeGroupMetadataFilter(h string) nostr.Filter {
|
||||
return nostr.Filter{
|
||||
type GroupStore struct {
|
||||
Config *Config
|
||||
Events *EventStore
|
||||
}
|
||||
|
||||
func (g *GroupStore) GetMetadata(h string) nostr.Event {
|
||||
filter := nostr.Filter{
|
||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupMetadata},
|
||||
Tags: nostr.TagMap{
|
||||
"d": []string{h},
|
||||
},
|
||||
}
|
||||
|
||||
for event := range g.Events.QueryEvents(filter, 1) {
|
||||
return event
|
||||
}
|
||||
|
||||
return nostr.Event{}
|
||||
}
|
||||
|
||||
func MakeGroupEventFilters(h string) []nostr.Filter {
|
||||
return []nostr.Filter{
|
||||
func (g *GroupStore) AddMember(h string, pubkey nostr.PubKey) error {
|
||||
event := nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupPutUser,
|
||||
CreatedAt: nostr.Now(),
|
||||
Tags: nostr.Tags{
|
||||
nostr.Tag{"p", pubkey.Hex()},
|
||||
nostr.Tag{"h", h},
|
||||
},
|
||||
}
|
||||
|
||||
return g.Events.SignAndSaveEvent(event, true)
|
||||
}
|
||||
|
||||
func (g *GroupStore) RemoveMember(h string, pubkey nostr.PubKey) error {
|
||||
event := nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupRemoveUser,
|
||||
CreatedAt: nostr.Now(),
|
||||
Tags: nostr.Tags{
|
||||
nostr.Tag{"p", pubkey.Hex()},
|
||||
nostr.Tag{"h", h},
|
||||
},
|
||||
}
|
||||
|
||||
return g.Events.SignAndSaveEvent(event, true)
|
||||
}
|
||||
|
||||
func (g *GroupStore) SetMetadataFromEvent(event nostr.Event) error {
|
||||
tags := nostr.Tags{}
|
||||
|
||||
for _, tag := range event.Tags {
|
||||
if len(tag) >= 2 && tag[0] == "h" {
|
||||
tags = append(tags, nostr.Tag{"d", tag[1]})
|
||||
} else {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
metadataEvent := nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupMetadata,
|
||||
CreatedAt: event.CreatedAt,
|
||||
Tags: tags,
|
||||
}
|
||||
|
||||
return g.Events.SignAndSaveEvent(metadataEvent, true)
|
||||
}
|
||||
|
||||
func (g *GroupStore) DeleteGroup(h string) {
|
||||
filters := []nostr.Filter{
|
||||
{
|
||||
Tags: nostr.TagMap{
|
||||
"d": []string{h},
|
||||
@@ -38,20 +93,24 @@ func MakeGroupEventFilters(h string) []nostr.Filter {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, filter := range filters {
|
||||
for event := range g.Events.QueryEvents(filter, 0) {
|
||||
g.Events.DeleteEvent(event.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MakeGroupMembershipCheckFilter(h string, pubkey nostr.PubKey) nostr.Filter {
|
||||
return nostr.Filter{
|
||||
func (g *GroupStore) IsMember(h string, pubkey nostr.PubKey) bool {
|
||||
filter := nostr.Filter{
|
||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupPutUser, nostr.KindSimpleGroupRemoveUser},
|
||||
Tags: nostr.TagMap{
|
||||
"p": []string{pubkey.Hex()},
|
||||
"h": []string{h},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func CheckGroupMembership(events iter.Seq[nostr.Event]) bool {
|
||||
for event := range events {
|
||||
for event := range g.Events.QueryEvents(filter, 1) {
|
||||
if event.Kind == nostr.KindSimpleGroupPutUser {
|
||||
return true
|
||||
}
|
||||
@@ -64,42 +123,10 @@ func CheckGroupMembership(events iter.Seq[nostr.Event]) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func MakePutUserEvent(h string, pubkey nostr.PubKey) nostr.Event {
|
||||
return nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupPutUser,
|
||||
CreatedAt: nostr.Now(),
|
||||
Tags: nostr.Tags{
|
||||
nostr.Tag{"p", pubkey.Hex()},
|
||||
nostr.Tag{"h", h},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeRemoveUserEvent(h string, pubkey nostr.PubKey) nostr.Event {
|
||||
return nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupRemoveUser,
|
||||
CreatedAt: nostr.Now(),
|
||||
Tags: nostr.Tags{
|
||||
nostr.Tag{"p", pubkey.Hex()},
|
||||
nostr.Tag{"h", h},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeMetadataEvent(event nostr.Event) nostr.Event {
|
||||
tags := nostr.Tags{}
|
||||
|
||||
for _, tag := range event.Tags {
|
||||
if len(tag) >= 2 && tag[0] == "h" {
|
||||
tags = append(tags, nostr.Tag{"d", tag[1]})
|
||||
} else {
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
return nostr.Event{
|
||||
Kind: nostr.KindSimpleGroupMetadata,
|
||||
CreatedAt: event.CreatedAt,
|
||||
Tags: tags,
|
||||
func (g *GroupStore) HasAccess(h string, pubkey nostr.PubKey) bool {
|
||||
if !HasTag(g.GetMetadata(h).Tags, "closed") {
|
||||
return true
|
||||
}
|
||||
|
||||
return g.IsMember(h, pubkey)
|
||||
}
|
||||
|
||||
+88
-131
@@ -20,6 +20,7 @@ type Instance struct {
|
||||
Events *EventStore
|
||||
Blossom *BlossomStore
|
||||
Management *ManagementStore
|
||||
Groups *GroupStore
|
||||
}
|
||||
|
||||
func MakeInstance(filename string) (*Instance, error) {
|
||||
@@ -48,12 +49,18 @@ func MakeInstance(filename string) (*Instance, error) {
|
||||
Events: events,
|
||||
}
|
||||
|
||||
groups := &GroupStore{
|
||||
Config: config,
|
||||
Events: events,
|
||||
}
|
||||
|
||||
instance := &Instance{
|
||||
Relay: relay,
|
||||
Config: config,
|
||||
Events: events,
|
||||
Blossom: blossom,
|
||||
Management: management,
|
||||
Groups: groups,
|
||||
}
|
||||
|
||||
// NIP 11 info
|
||||
@@ -82,16 +89,14 @@ func MakeInstance(filename string) (*Instance, error) {
|
||||
// Handlers
|
||||
|
||||
instance.Relay.OnConnect = instance.OnConnect
|
||||
instance.Relay.OnEvent = instance.OnEvent
|
||||
instance.Relay.PreventBroadcast = instance.PreventBroadcast
|
||||
instance.Relay.StoreEvent = instance.StoreEvent
|
||||
instance.Relay.ReplaceEvent = instance.ReplaceEvent
|
||||
instance.Relay.DeleteEvent = instance.DeleteEvent
|
||||
instance.Relay.OnEvent = instance.OnEvent
|
||||
instance.Relay.OnEventSaved = instance.OnEventSaved
|
||||
instance.Relay.OnEphemeralEvent = instance.OnEphemeralEvent
|
||||
instance.Relay.OnRequest = instance.OnRequest
|
||||
instance.Relay.QueryStored = instance.QueryStored
|
||||
instance.Relay.RejectConnection = instance.RejectConnection
|
||||
instance.Relay.PreventBroadcast = instance.PreventBroadcast
|
||||
|
||||
// Todo: when there's a new version of khatru
|
||||
// instance.Relay.StartExpirationManager()
|
||||
@@ -129,36 +134,15 @@ func (instance *Instance) Cleanup() {
|
||||
|
||||
// Utility methods
|
||||
|
||||
func (instance *Instance) IsGroupMember(id string, pubkey nostr.PubKey) bool {
|
||||
filter := MakeGroupMembershipCheckFilter(id, pubkey)
|
||||
events := instance.Events.QueryEvents(filter, 0)
|
||||
isMember := CheckGroupMembership(events)
|
||||
func (instance *Instance) StripSignature(ctx context.Context, event nostr.Event) nostr.Event {
|
||||
pubkey, _ := khatru.GetAuthed(ctx)
|
||||
|
||||
return isMember
|
||||
}
|
||||
|
||||
func (instance *Instance) HasGroupAccess(id string, pubkey nostr.PubKey) bool {
|
||||
filter := MakeGroupMetadataFilter(id)
|
||||
|
||||
for event := range instance.Events.QueryEvents(filter, 1) {
|
||||
if !HasTag(event.Tags, "closed") {
|
||||
return true
|
||||
}
|
||||
if instance.Config.Policy.StripSignatures && !instance.Config.IsAdmin(pubkey) {
|
||||
var zeroSig [64]byte
|
||||
event.Sig = zeroSig
|
||||
}
|
||||
|
||||
return instance.IsGroupMember(id, pubkey)
|
||||
}
|
||||
|
||||
func (instance *Instance) IsInternalEvent(event nostr.Event) bool {
|
||||
if event.Kind == nostr.KindApplicationSpecificData {
|
||||
tag := event.Tags.Find("d")
|
||||
|
||||
if tag != nil && strings.HasPrefix(tag[1], "zooid/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return event
|
||||
}
|
||||
|
||||
func (instance *Instance) AllowRecipientEvent(event nostr.Event) bool {
|
||||
@@ -184,6 +168,41 @@ func (instance *Instance) AllowRecipientEvent(event nostr.Event) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (instance *Instance) IsInternalEvent(event nostr.Event) bool {
|
||||
if event.Kind == nostr.KindApplicationSpecificData {
|
||||
tag := event.Tags.Find("d")
|
||||
|
||||
if tag != nil && strings.HasPrefix(tag[1], "zooid/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (instance *Instance) IsReadOnlyEvent(event nostr.Event) bool {
|
||||
if instance.IsInternalEvent(event) {
|
||||
return true
|
||||
}
|
||||
|
||||
readOnlyEventKinds := []nostr.Kind{
|
||||
RELAY_ADD_MEMBER,
|
||||
RELAY_REMOVE_MEMBER,
|
||||
RELAY_MEMBERS,
|
||||
}
|
||||
|
||||
return slices.Contains(readOnlyEventKinds, event.Kind)
|
||||
}
|
||||
|
||||
func (instance *Instance) IsWriteOnlyEvent(event nostr.Event) bool {
|
||||
writeOnlyEventKinds := []nostr.Kind{
|
||||
RELAY_JOIN,
|
||||
RELAY_LEAVE,
|
||||
}
|
||||
|
||||
return slices.Contains(writeOnlyEventKinds, event.Kind)
|
||||
}
|
||||
|
||||
func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event {
|
||||
filter := nostr.Filter{
|
||||
Kinds: []nostr.Kind{RELAY_INVITE},
|
||||
@@ -210,40 +229,30 @@ func (instance *Instance) GenerateInviteEvent(pubkey nostr.PubKey) nostr.Event {
|
||||
return event
|
||||
}
|
||||
|
||||
func (instance *Instance) OnJoinEvent(event nostr.Event) (reject bool, msg string) {
|
||||
claimTag := event.Tags.Find("claim")
|
||||
|
||||
if claimTag == nil {
|
||||
return true, "invalid: no claim tag"
|
||||
}
|
||||
|
||||
filter := nostr.Filter{
|
||||
Kinds: []nostr.Kind{RELAY_INVITE},
|
||||
}
|
||||
|
||||
for event := range instance.Events.QueryEvents(filter, 0) {
|
||||
if event.Tags.FindWithValue("claim", claimTag[1]) != nil {
|
||||
return false, ""
|
||||
}
|
||||
}
|
||||
|
||||
return true, "invalid: failed to validate invite code"
|
||||
}
|
||||
|
||||
func (instance *Instance) GetGroupMetadataEvent(h string) nostr.Event {
|
||||
for event := range instance.Events.QueryEvents(MakeGroupMetadataFilter(h), 1) {
|
||||
return event
|
||||
}
|
||||
|
||||
return nostr.Event{}
|
||||
}
|
||||
|
||||
// Handlers
|
||||
|
||||
func (instance *Instance) OnConnect(ctx context.Context) {
|
||||
khatru.RequestAuth(ctx)
|
||||
}
|
||||
|
||||
func (instance *Instance) PreventBroadcast(ws *khatru.WebSocket, event nostr.Event) bool {
|
||||
return instance.IsWriteOnlyEvent(event)
|
||||
}
|
||||
|
||||
func (instance *Instance) StoreEvent(ctx context.Context, event nostr.Event) error {
|
||||
return instance.Events.SaveEvent(event)
|
||||
}
|
||||
|
||||
func (instance *Instance) ReplaceEvent(ctx context.Context, event nostr.Event) error {
|
||||
return instance.Events.ReplaceEvent(event)
|
||||
}
|
||||
|
||||
func (instance *Instance) DeleteEvent(ctx context.Context, id nostr.ID) error {
|
||||
return instance.Events.DeleteEvent(id)
|
||||
}
|
||||
|
||||
// Event publishing
|
||||
|
||||
func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (reject bool, msg string) {
|
||||
if instance.AllowRecipientEvent(event) {
|
||||
return false, ""
|
||||
@@ -258,15 +267,15 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
||||
}
|
||||
|
||||
if event.Kind == RELAY_JOIN {
|
||||
return instance.OnJoinEvent(event)
|
||||
return instance.Management.ValidateJoinRequest(event)
|
||||
}
|
||||
|
||||
if !instance.Management.IsPubkeyAllowed(pubkey) {
|
||||
return true, "restricted: you are not a member of this relay"
|
||||
}
|
||||
|
||||
if instance.IsInternalEvent(event) {
|
||||
return true, "invalid: this event is not accepted"
|
||||
if instance.IsReadOnlyEvent(event) {
|
||||
return true, "invalid: this event's kind is not accepted"
|
||||
}
|
||||
|
||||
if slices.Contains(nip29.MetadataEventKinds, event.Kind) {
|
||||
@@ -294,7 +303,7 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
||||
return true, "invalid: h tag is required"
|
||||
}
|
||||
|
||||
meta := instance.GetGroupMetadataEvent(h)
|
||||
meta := instance.Groups.GetMetadata(h)
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupCreateGroup {
|
||||
if !IsEmptyEvent(meta) {
|
||||
@@ -304,21 +313,21 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
||||
return true, "invalid: no such group exists"
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.IsGroupMember(h, event.PubKey) {
|
||||
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Groups.IsMember(h, event.PubKey) {
|
||||
return true, "duplicate: already a member"
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && !instance.IsGroupMember(h, event.PubKey) {
|
||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && !instance.Groups.IsMember(h, event.PubKey) {
|
||||
return true, "duplicate: not currently a member"
|
||||
}
|
||||
} else if h != "" {
|
||||
meta := instance.GetGroupMetadataEvent(h)
|
||||
meta := instance.Groups.GetMetadata(h)
|
||||
|
||||
if IsEmptyEvent(meta) {
|
||||
return true, "invalid: no such group exists"
|
||||
}
|
||||
|
||||
if HasTag(meta.Tags, "closed") && !instance.IsGroupMember(h, pubkey) {
|
||||
if HasTag(meta.Tags, "closed") && !instance.Groups.IsMember(h, pubkey) {
|
||||
return true, "restricted: you are not a member of that group"
|
||||
}
|
||||
}
|
||||
@@ -330,25 +339,7 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (instance *Instance) StoreEvent(ctx context.Context, event nostr.Event) error {
|
||||
return instance.Events.SaveEvent(event)
|
||||
}
|
||||
|
||||
func (instance *Instance) ReplaceEvent(ctx context.Context, event nostr.Event) error {
|
||||
return instance.Events.ReplaceEvent(event)
|
||||
}
|
||||
|
||||
func (instance *Instance) DeleteEvent(ctx context.Context, id nostr.ID) error {
|
||||
return instance.Events.DeleteEvent(id)
|
||||
}
|
||||
|
||||
func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
|
||||
addEvent := func(newEvent nostr.Event) {
|
||||
if err := instance.Events.SignAndSaveEvent(newEvent, true); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
if event.Kind == RELAY_JOIN {
|
||||
instance.Management.AllowPubkey(event.PubKey)
|
||||
}
|
||||
@@ -359,39 +350,27 @@ func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Config.Groups.AutoJoin {
|
||||
h := GetGroupIDFromEvent(event)
|
||||
meta := instance.GetGroupMetadataEvent(h)
|
||||
meta := instance.Groups.GetMetadata(h)
|
||||
|
||||
if !HasTag(meta.Tags, "closed") {
|
||||
addEvent(MakePutUserEvent(h, event.PubKey))
|
||||
instance.Groups.AddMember(h, event.PubKey)
|
||||
}
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && instance.Config.Groups.AutoLeave {
|
||||
addEvent(MakeRemoveUserEvent(GetGroupIDFromEvent(event), event.PubKey))
|
||||
instance.Groups.RemoveMember(GetGroupIDFromEvent(event), event.PubKey)
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupCreateGroup {
|
||||
addEvent(MakeMetadataEvent(event))
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupEditMetadata {
|
||||
addEvent(MakeMetadataEvent(event))
|
||||
if event.Kind == nostr.KindSimpleGroupCreateGroup || event.Kind == nostr.KindSimpleGroupEditMetadata {
|
||||
instance.Groups.SetMetadataFromEvent(event)
|
||||
}
|
||||
|
||||
if event.Kind == nostr.KindSimpleGroupDeleteGroup {
|
||||
for _, filter := range MakeGroupEventFilters(GetGroupIDFromEvent(event)) {
|
||||
for event := range instance.Events.QueryEvents(filter, 0) {
|
||||
instance.Events.DeleteEvent(event.ID)
|
||||
}
|
||||
}
|
||||
instance.Groups.DeleteGroup(GetGroupIDFromEvent(event))
|
||||
}
|
||||
}
|
||||
|
||||
func (instance *Instance) OnEphemeralEvent(ctx context.Context, event nostr.Event) {
|
||||
if slices.Contains([]nostr.Kind{RELAY_INVITE, RELAY_JOIN}, event.Kind) {
|
||||
instance.Events.SaveEvent(event)
|
||||
}
|
||||
}
|
||||
// Requests
|
||||
|
||||
func (instance *Instance) OnRequest(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
|
||||
pubkey, ok := khatru.GetAuthed(ctx)
|
||||
@@ -416,30 +395,16 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pubkey, isAuthed := khatru.GetAuthed(ctx)
|
||||
|
||||
if !isAuthed {
|
||||
log.Panic("Unauthorized user was allowed to query events")
|
||||
}
|
||||
|
||||
stripSignature := func(event nostr.Event) nostr.Event {
|
||||
if instance.Config.Policy.StripSignatures && !instance.Config.IsAdmin(pubkey) {
|
||||
var zeroSig [64]byte
|
||||
event.Sig = zeroSig
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
pubkey, _ := khatru.GetAuthed(ctx)
|
||||
|
||||
if slices.Contains(filter.Kinds, RELAY_INVITE) && instance.Config.CanInvite(pubkey) {
|
||||
if !yield(stripSignature(instance.GenerateInviteEvent(pubkey))) {
|
||||
if !yield(instance.StripSignature(ctx, instance.GenerateInviteEvent(pubkey))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for event := range instance.Events.QueryEvents(filter, 1000) {
|
||||
// We save some ephemeral events for bookkeeping, don't return them
|
||||
if event.Kind.IsEphemeral() {
|
||||
if instance.IsWriteOnlyEvent(event) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -450,7 +415,7 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
|
||||
continue
|
||||
}
|
||||
|
||||
if !instance.HasGroupAccess(h, pubkey) {
|
||||
if !instance.Groups.HasAccess(h, pubkey) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -459,18 +424,10 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
|
||||
continue
|
||||
}
|
||||
|
||||
if !yield(stripSignature(event)) {
|
||||
if !yield(instance.StripSignature(ctx, event)) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (instance *Instance) RejectConnection(r *http.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (instance *Instance) PreventBroadcast(ws *khatru.WebSocket, event nostr.Event) bool {
|
||||
return event.Kind == RELAY_JOIN
|
||||
}
|
||||
|
||||
+64
-32
@@ -22,11 +22,51 @@ import (
|
||||
// All actions are idempotent, and won't do anything if conditions are already correct.
|
||||
|
||||
type ManagementStore struct {
|
||||
Relay *khatru.Relay
|
||||
Config *Config
|
||||
Events *EventStore
|
||||
}
|
||||
|
||||
// Banned events
|
||||
|
||||
func (m *ManagementStore) GetBannedEventItems() []nip86.IDReason {
|
||||
items := make([]nip86.IDReason, 0)
|
||||
for tag := range m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS).Tags.FindAll("event") {
|
||||
items = append(items, nip86.IDReason{
|
||||
ID: tag[1],
|
||||
Reason: tag[2],
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
func (m *ManagementStore) BanEvent(id nostr.ID, reason string) error {
|
||||
if err := m.Events.DeleteEvent(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
event.Tags = append(event.Tags, nostr.Tag{"event", id.Hex(), reason})
|
||||
|
||||
return m.Events.SignAndSaveEvent(event, false)
|
||||
}
|
||||
|
||||
func (m *ManagementStore) AllowEvent(id nostr.ID, reason string) error {
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
event.Tags = Filter(event.Tags, func(t nostr.Tag) bool {
|
||||
return t[1] == id.Hex()
|
||||
})
|
||||
|
||||
return m.Events.SignAndSaveEvent(event, false)
|
||||
}
|
||||
|
||||
func (m *ManagementStore) EventIsBanned(id nostr.ID) bool {
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
tag := event.Tags.FindWithValue("event", id.Hex())
|
||||
|
||||
return tag != nil
|
||||
}
|
||||
|
||||
// Internal banned pubkeys list
|
||||
|
||||
func (m *ManagementStore) GetBannedPubkeyItems() []nip86.PubKeyReason {
|
||||
@@ -73,6 +113,13 @@ func (m *ManagementStore) RemoveBannedPubkey(pubkey nostr.PubKey) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ManagementStore) PubkeyIsBanned(pubkey nostr.PubKey) bool {
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_PUBKEYS)
|
||||
tag := event.Tags.FindWithValue("pubkey", pubkey.Hex())
|
||||
|
||||
return tag != nil
|
||||
}
|
||||
|
||||
// Membership
|
||||
|
||||
func (m *ManagementStore) GetMembers() []nostr.PubKey {
|
||||
@@ -240,45 +287,30 @@ func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Banned events
|
||||
// Joining
|
||||
|
||||
func (m *ManagementStore) GetBannedEventItems() []nip86.IDReason {
|
||||
items := make([]nip86.IDReason, 0)
|
||||
for tag := range m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS).Tags.FindAll("event") {
|
||||
items = append(items, nip86.IDReason{
|
||||
ID: tag[1],
|
||||
Reason: tag[2],
|
||||
})
|
||||
func (m *ManagementStore) ValidateJoinRequest(event nostr.Event) (reject bool, err string) {
|
||||
if m.PubkeyIsBanned(event.PubKey) {
|
||||
return true, "invalid: you have been banned from this relay"
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
claimTag := event.Tags.Find("claim")
|
||||
|
||||
func (m *ManagementStore) BanEvent(id nostr.ID, reason string) error {
|
||||
if err := m.Events.DeleteEvent(id); err != nil {
|
||||
return err
|
||||
if claimTag == nil {
|
||||
return true, "invalid: no claim tag"
|
||||
}
|
||||
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
event.Tags = append(event.Tags, nostr.Tag{"event", id.Hex(), reason})
|
||||
filter := nostr.Filter{
|
||||
Kinds: []nostr.Kind{RELAY_INVITE},
|
||||
}
|
||||
|
||||
return m.Events.SignAndSaveEvent(event, false)
|
||||
}
|
||||
for event := range m.Events.QueryEvents(filter, 0) {
|
||||
if event.Tags.FindWithValue("claim", claimTag[1]) != nil {
|
||||
return false, ""
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ManagementStore) AllowEvent(id nostr.ID, reason string) error {
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
event.Tags = Filter(event.Tags, func(t nostr.Tag) bool {
|
||||
return t[1] == id.Hex()
|
||||
})
|
||||
|
||||
return m.Events.SignAndSaveEvent(event, false)
|
||||
}
|
||||
|
||||
func (m *ManagementStore) EventIsBanned(id nostr.ID) bool {
|
||||
event := m.Events.GetOrCreateApplicationSpecificData(BANNED_EVENTS)
|
||||
tag := event.Tags.FindWithValue("event", id.Hex())
|
||||
|
||||
return tag != nil
|
||||
return true, "invalid: failed to validate invite code"
|
||||
}
|
||||
|
||||
// Middleware
|
||||
|
||||
Reference in New Issue
Block a user