forked from coracle/zooid
Refactor group access, implement hidden/private/closed
This commit is contained in:
@@ -44,7 +44,6 @@ Configures NIP 29 support.
|
|||||||
|
|
||||||
- `enabled` - whether NIP 29 is enabled.
|
- `enabled` - whether NIP 29 is enabled.
|
||||||
- `auto_join` - whether relay members can join `open` groups without approval. Defaults to `true`.
|
- `auto_join` - whether relay members can join `open` groups without approval. Defaults to `true`.
|
||||||
- `auto_leave` - whether relay members can leave groups without approval. Defaults to `true`.
|
|
||||||
|
|
||||||
### `[management]`
|
### `[management]`
|
||||||
|
|
||||||
@@ -90,7 +89,6 @@ strip_signatures = false
|
|||||||
[groups]
|
[groups]
|
||||||
enabled = true
|
enabled = true
|
||||||
auto_join = false
|
auto_join = false
|
||||||
auto_leave = true
|
|
||||||
|
|
||||||
[management]
|
[management]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ type Config struct {
|
|||||||
Groups struct {
|
Groups struct {
|
||||||
Enabled bool `toml:"enabled"`
|
Enabled bool `toml:"enabled"`
|
||||||
AutoJoin bool `toml:"auto_join"`
|
AutoJoin bool `toml:"auto_join"`
|
||||||
AutoLeave bool `toml:"auto_leave"`
|
|
||||||
} `toml:"groups"`
|
} `toml:"groups"`
|
||||||
|
|
||||||
Management struct {
|
Management struct {
|
||||||
|
|||||||
+76
-7
@@ -223,25 +223,94 @@ func (g *GroupStore) UpdateMembersList(h string) error {
|
|||||||
// Other stuff
|
// Other stuff
|
||||||
|
|
||||||
func (g *GroupStore) HasAccess(h string, pubkey nostr.PubKey) bool {
|
func (g *GroupStore) HasAccess(h string, pubkey nostr.PubKey) bool {
|
||||||
|
return g.IsAdmin(h, pubkey) || g.IsMember(h, pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) IsGroupEvent(event nostr.Event) bool {
|
||||||
|
if slices.Contains(nip29.MetadataEventKinds, event.Kind) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(nip29.ModerationEventKinds, event.Kind) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
joinKinds := []nostr.Kind{
|
||||||
|
nostr.KindSimpleGroupJoinRequest,
|
||||||
|
nostr.KindSimpleGroupLeaveRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(joinKinds, event.Kind) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetGroupIDFromEvent(event) != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) CanRead(pubkey nostr.PubKey, event nostr.Event) bool {
|
||||||
|
if !g.Config.Groups.Enabled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
h := GetGroupIDFromEvent(event)
|
||||||
meta, found := g.GetMetadata(h)
|
meta, found := g.GetMetadata(h)
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !HasTag(meta.Tags, "closed") {
|
if HasTag(meta.Tags, "hidden") && !g.HasAccess(h, pubkey) {
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.IsAdmin(h, pubkey) {
|
if HasTag(meta.Tags, "private") && !g.HasAccess(h, pubkey) {
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.IsMember(h, pubkey) {
|
return true
|
||||||
return true
|
}
|
||||||
|
|
||||||
|
func (g *GroupStore) CheckWrite(event nostr.Event) string {
|
||||||
|
if !g.Config.Groups.Enabled {
|
||||||
|
return "invalid: groups are not enabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
if slices.Contains(nip29.MetadataEventKinds, event.Kind) {
|
||||||
|
return "invalid: group metadata cannot be set directly"
|
||||||
|
}
|
||||||
|
|
||||||
|
h := GetGroupIDFromEvent(event)
|
||||||
|
meta, found := g.GetMetadata(h)
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupCreateGroup {
|
||||||
|
if found {
|
||||||
|
return "invalid: that group already exists"
|
||||||
|
}
|
||||||
|
} else if !found {
|
||||||
|
return "invalid: group not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupJoinRequest && g.IsMember(h, event.PubKey) {
|
||||||
|
return "duplicate: already a member"
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupLeaveRequest && !g.IsMember(h, event.PubKey) {
|
||||||
|
return "duplicate: not currently a member"
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(nip29.ModerationEventKinds, event.Kind) && !g.Config.CanManage(event.PubKey) {
|
||||||
|
return "restricted: you are not authorized to manage groups"
|
||||||
|
}
|
||||||
|
|
||||||
|
if HasTag(meta.Tags, "hidden") && !g.HasAccess(h, event.PubKey) {
|
||||||
|
return "invalid: group not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
if HasTag(meta.Tags, "closed") && !g.HasAccess(h, event.PubKey) {
|
||||||
|
return "restricted: you are not a member of that group"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
|
|||||||
+5
-66
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
"fiatjaf.com/nostr/khatru"
|
"fiatjaf.com/nostr/khatru"
|
||||||
"fiatjaf.com/nostr/nip29"
|
|
||||||
"github.com/gosimple/slug"
|
"github.com/gosimple/slug"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -317,19 +316,7 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
h := GetGroupIDFromEvent(event)
|
if instance.Groups.IsGroupEvent(event) && !instance.Groups.CanRead(pubkey, event) {
|
||||||
|
|
||||||
if h != "" {
|
|
||||||
if !instance.Config.Groups.Enabled {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !instance.Groups.HasAccess(h, pubkey) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !instance.Config.Groups.Enabled && slices.Contains(nip29.MetadataEventKinds, event.Kind) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,57 +359,9 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
|||||||
return true, "invalid: this event's kind is not accepted"
|
return true, "invalid: this event's kind is not accepted"
|
||||||
}
|
}
|
||||||
|
|
||||||
if slices.Contains(nip29.MetadataEventKinds, event.Kind) {
|
if instance.Groups.IsGroupEvent(event) {
|
||||||
return true, "invalid: group metadata cannot be set directly"
|
if err := instance.Groups.CheckWrite(event); err != "" {
|
||||||
}
|
return true, err
|
||||||
|
|
||||||
if slices.Contains(nip29.ModerationEventKinds, event.Kind) && !instance.Config.CanManage(event.PubKey) {
|
|
||||||
return true, "restricted: you are not authorized to manage groups"
|
|
||||||
}
|
|
||||||
|
|
||||||
allGroupKinds := append(
|
|
||||||
nip29.ModerationEventKinds,
|
|
||||||
nostr.KindSimpleGroupJoinRequest,
|
|
||||||
nostr.KindSimpleGroupLeaveRequest,
|
|
||||||
)
|
|
||||||
|
|
||||||
h := GetGroupIDFromEvent(event)
|
|
||||||
|
|
||||||
if slices.Contains(allGroupKinds, event.Kind) {
|
|
||||||
if !instance.Config.Groups.Enabled {
|
|
||||||
return true, "invalid: group events not accepted on this relay"
|
|
||||||
}
|
|
||||||
|
|
||||||
if h == "" {
|
|
||||||
return true, "invalid: h tag is required"
|
|
||||||
}
|
|
||||||
|
|
||||||
_, found := instance.Groups.GetMetadata(h)
|
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupCreateGroup {
|
|
||||||
if found {
|
|
||||||
return true, "invalid: that group already exists"
|
|
||||||
}
|
|
||||||
} else if !found {
|
|
||||||
return true, "invalid: no such group exists"
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Groups.IsMember(h, event.PubKey) {
|
|
||||||
return true, "duplicate: already a member"
|
|
||||||
}
|
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && !instance.Groups.IsMember(h, event.PubKey) {
|
|
||||||
return true, "duplicate: not currently a member"
|
|
||||||
}
|
|
||||||
} else if h != "" {
|
|
||||||
_, found := instance.Groups.GetMetadata(h)
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return true, "invalid: no such group exists"
|
|
||||||
}
|
|
||||||
|
|
||||||
if !instance.Groups.HasAccess(h, pubkey) {
|
|
||||||
return true, "restricted: you are not a member of that group"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +394,7 @@ func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && instance.Config.Groups.AutoLeave {
|
if event.Kind == nostr.KindSimpleGroupLeaveRequest {
|
||||||
instance.Groups.RemoveMember(h, event.PubKey)
|
instance.Groups.RemoveMember(h, event.PubKey)
|
||||||
instance.Groups.UpdateMembersList(h)
|
instance.Groups.UpdateMembersList(h)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user