clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / internal / policy / access.go
access.go 2.3K
1package policy23import (4 "strings"56 "github.com/FelineStateMachine/tinyrelay/internal/event"7)89type Access struct {10 PubKeys []string11 Role string12 Member bool13 Owner bool14}1516// CanRead applies the read rule, kind blocks, private repository rules and17// recipient addressing to one event.18func CanRead(p Policy, e event.Event, a Access) bool {19 if containsInt(p.BlockedKinds, e.Kind) {20 return false21 }22 if !readRule(p, a) {23 return false24 }25 if IsPrivateRepository(e) && (!p.Features.Grasp08 || p.Reads != "members") {26 return false27 }28 if privateKind(e.Kind) {29 return addressed(e, a)30 }31 return true32}3334// IsPrivateRepository identifies a GRASP repository announcement carrying the35// private=true marker. State events are associated with their announcement by36// owner and identifier at the storage boundary.37func IsPrivateRepository(e event.Event) bool {38 if e.Kind != 30617 {39 return false40 }41 for _, tag := range e.Tags {42 if len(tag) >= 2 && tag[0] == "private" && strings.EqualFold(tag[1], "true") {43 return true44 }45 }46 return false47}4849// CanWrite applies kind blocks, allowlists and the tenant write rule to one50// event.51func CanWrite(p Policy, e event.Event, a Access) bool {52 if containsInt(p.BlockedKinds, e.Kind) {53 return false54 }55 if len(p.AllowedKinds) > 0 && !containsInt(p.AllowedKinds, e.Kind) {56 return false57 }58 switch p.Writes {59 case "open":60 return true61 case "owner":62 return a.Owner || (p.Owner != "" && e.PubKey == p.Owner)63 case "allowlist":64 return a.Member || a.Owner65 case "wot":66 return a.Member || a.Owner67 default:68 return false69 }70}7172func readRule(p Policy, a Access) bool {73 switch p.Reads {74 case "open":75 return true76 case "auth":77 return len(a.PubKeys) > 0 || a.Owner78 case "members":79 return a.Member || a.Owner80 default:81 return false82 }83}8485func privateKind(kind int) bool { return kind == 4 || kind == 1059 }8687func addressed(e event.Event, a Access) bool {88 if hasKey(a, e.PubKey) {89 return true90 }91 for _, tag := range e.Tags {92 if len(tag) >= 2 && strings.EqualFold(tag[0], "p") && hasKey(a, tag[1]) {93 return true94 }95 }96 return false97}9899func hasKey(a Access, key string) bool {100 for _, candidate := range a.PubKeys {101 if candidate == key {102 return true103 }104 }105 return false106}107func containsInt(values []int, wanted int) bool {108 for _, value := range values {109 if value == wanted {110 return true111 }112 }113 return false114}