Fix some access logic

This commit is contained in:
Jon Staab
2025-10-21 17:13:36 -07:00
parent 2381654d90
commit 45716de712
4 changed files with 117 additions and 104 deletions
+4 -4
View File
@@ -57,7 +57,7 @@ func (bl *BlossomStore) Enable(instance *Instance) {
return true, "file too large", 413
}
if auth == nil || !instance.Management.IsPubkeyAllowed(auth.PubKey) {
if auth == nil || !instance.Management.HasAccess(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.Management.IsPubkeyAllowed(auth.PubKey) {
if auth == nil || !instance.Management.HasAccess(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.Management.IsPubkeyAllowed(auth.PubKey) {
if auth == nil || !instance.Management.HasAccess(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.Management.IsPubkeyAllowed(auth.PubKey) {
if auth == nil || !instance.Management.HasAccess(auth.PubKey) {
return true, "unauthorized", 403
}
+25 -20
View File
@@ -95,13 +95,13 @@ func (config *Config) IsOwner(pubkey nostr.PubKey) bool {
return pubkey.Hex() == config.Info.Pubkey
}
func (config *Config) GetRolesForPubkey(pubkey nostr.PubKey) []Role {
roles := make([]Role, 0)
for name, role := range config.Roles {
if name == "member" {
roles = append(roles, role)
}
func (config *Config) IsAdmin(pubkey nostr.PubKey) bool {
return config.IsOwner(pubkey) || config.IsSelf(pubkey)
}
func (config *Config) GetAssignedRoles(pubkey nostr.PubKey) []Role {
roles := make([]Role, 0)
for _, role := range config.Roles {
if slices.Contains(role.Pubkeys, pubkey.Hex()) {
roles = append(roles, role)
}
@@ -110,18 +110,25 @@ func (config *Config) GetRolesForPubkey(pubkey nostr.PubKey) []Role {
return roles
}
func (config *Config) CanManage(pubkey nostr.PubKey) bool {
for _, role := range config.GetRolesForPubkey(pubkey) {
if role.CanManage {
return true
func (config *Config) GetAllRoles(pubkey nostr.PubKey) []Role {
roles := make([]Role, 0)
for name, role := range config.Roles {
if name == "member" {
roles = append(roles, role)
} else if slices.Contains(role.Pubkeys, pubkey.Hex()) {
roles = append(roles, role)
}
}
return false
return roles
}
func (config *Config) CanInvite(pubkey nostr.PubKey) bool {
for _, role := range config.GetRolesForPubkey(pubkey) {
if config.IsAdmin(pubkey) {
return true
}
for _, role := range config.GetAllRoles(pubkey) {
if role.CanInvite {
return true
}
@@ -130,17 +137,15 @@ func (config *Config) CanInvite(pubkey nostr.PubKey) bool {
return false
}
func (config *Config) IsAdmin(pubkey nostr.PubKey) bool {
if config.IsOwner(pubkey) {
func (config *Config) CanManage(pubkey nostr.PubKey) bool {
if config.IsAdmin(pubkey) {
return true
}
if config.IsSelf(pubkey) {
return true
}
if config.CanManage(pubkey) {
return true
for _, role := range config.GetAllRoles(pubkey) {
if role.CanManage {
return true
}
}
return false
+66 -66
View File
@@ -137,7 +137,7 @@ func (instance *Instance) Cleanup() {
func (instance *Instance) StripSignature(ctx context.Context, event nostr.Event) nostr.Event {
pubkey, _ := khatru.GetAuthed(ctx)
if instance.Config.Policy.StripSignatures && !instance.Config.IsAdmin(pubkey) {
if instance.Config.Policy.StripSignatures && !instance.Config.CanManage(pubkey) {
var zeroSig [64]byte
event.Sig = zeroSig
}
@@ -159,7 +159,7 @@ func (instance *Instance) AllowRecipientEvent(event nostr.Event) bool {
if recipientTag != nil {
pubkey, err := nostr.PubKeyFromHex(recipientTag[1])
if err == nil && instance.Management.IsPubkeyAllowed(pubkey) {
if err == nil && instance.Management.HasAccess(pubkey) {
return true
}
}
@@ -251,6 +251,68 @@ func (instance *Instance) DeleteEvent(ctx context.Context, id nostr.ID) error {
return instance.Events.DeleteEvent(id)
}
// Requests
func (instance *Instance) OnRequest(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
pubkey, ok := khatru.GetAuthed(ctx)
if !ok {
return true, "auth-required: authentication is required for access"
}
if !instance.Management.HasAccess(pubkey) {
return true, "restricted: you are not a member of this relay"
}
return false, ""
}
func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter) iter.Seq[nostr.Event] {
return func(yield func(nostr.Event) bool) {
if khatru.IsInternalCall(ctx) {
for event := range instance.Events.QueryEvents(filter, 0) {
if !yield(event) {
return
}
}
} else {
pubkey, _ := khatru.GetAuthed(ctx)
if slices.Contains(filter.Kinds, RELAY_INVITE) && instance.Config.CanInvite(pubkey) {
if !yield(instance.StripSignature(ctx, instance.GenerateInviteEvent(pubkey))) {
return
}
}
for event := range instance.Events.QueryEvents(filter, 1000) {
if instance.IsWriteOnlyEvent(event) {
continue
}
h := GetGroupIDFromEvent(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
}
if !yield(instance.StripSignature(ctx, event)) {
return
}
}
}
}
}
// Event publishing
func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (reject bool, msg string) {
@@ -270,7 +332,7 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
return instance.Management.ValidateJoinRequest(event)
}
if !instance.Management.IsPubkeyAllowed(pubkey) {
if !instance.Management.HasAccess(pubkey) {
return true, "restricted: you are not a member of this relay"
}
@@ -282,7 +344,7 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
return true, "invalid: group metadata cannot be set directly"
}
if slices.Contains(nip29.ModerationEventKinds, event.Kind) && !instance.Config.IsAdmin(event.PubKey) {
if slices.Contains(nip29.ModerationEventKinds, event.Kind) && !instance.Config.CanManage(event.PubKey) {
return true, "restricted: you are not authorized to manage groups"
}
@@ -369,65 +431,3 @@ func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
instance.Groups.DeleteGroup(GetGroupIDFromEvent(event))
}
}
// Requests
func (instance *Instance) OnRequest(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
pubkey, ok := khatru.GetAuthed(ctx)
if !ok {
return true, "auth-required: authentication is required for access"
}
if !instance.Management.IsPubkeyAllowed(pubkey) {
return true, "restricted: you are not a member of this relay"
}
return false, ""
}
func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter) iter.Seq[nostr.Event] {
return func(yield func(nostr.Event) bool) {
if khatru.IsInternalCall(ctx) {
for event := range instance.Events.QueryEvents(filter, 0) {
if !yield(event) {
return
}
}
} else {
pubkey, _ := khatru.GetAuthed(ctx)
if slices.Contains(filter.Kinds, RELAY_INVITE) && instance.Config.CanInvite(pubkey) {
if !yield(instance.StripSignature(ctx, instance.GenerateInviteEvent(pubkey))) {
return
}
}
for event := range instance.Events.QueryEvents(filter, 1000) {
if instance.IsWriteOnlyEvent(event) {
continue
}
h := GetGroupIDFromEvent(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
}
if !yield(instance.StripSignature(ctx, event)) {
return
}
}
}
}
}
+22 -14
View File
@@ -259,20 +259,8 @@ func (m *ManagementStore) GetAllowedPubkeyItems() []nip86.PubKeyReason {
return reasons
}
func (m *ManagementStore) IsPubkeyAllowed(pubkey nostr.PubKey) bool {
if m.Config.IsOwner(pubkey) || m.Config.IsSelf(pubkey) {
return true
}
for range m.Config.GetRolesForPubkey(pubkey) {
return true
}
return m.IsMember(pubkey)
}
func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey) error {
if m.IsPubkeyAllowed(pubkey) {
if m.HasAccess(pubkey) {
return nil
}
@@ -287,6 +275,18 @@ func (m *ManagementStore) AllowPubkey(pubkey nostr.PubKey) error {
return nil
}
func (m *ManagementStore) HasAccess(pubkey nostr.PubKey) bool {
if m.Config.IsAdmin(pubkey) {
return true
}
for range m.Config.GetAssignedRoles(pubkey) {
return true
}
return m.IsMember(pubkey)
}
// Joining
func (m *ManagementStore) ValidateJoinRequest(event nostr.Event) (reject bool, err string) {
@@ -319,7 +319,15 @@ func (m *ManagementStore) Enable(instance *Instance) {
instance.Relay.ManagementAPI.OnAPICall = func(ctx context.Context, mp nip86.MethodParams) (reject bool, msg string) {
pubkey, ok := khatru.GetAuthed(ctx)
if ok && m.Config.CanManage(pubkey) {
if !ok {
return true, "blocked: please authenticate in order to manage this relay"
}
if !m.HasAccess(pubkey) {
return true, "blocked: you are not a member of this relay"
}
if !m.Config.CanManage(pubkey) {
return true, "blocked: only relay admins can manage this relay."
}