1 package acl
2 3 import (
4 "next.orly.dev/pkg/nostr/encoders/event"
5 acliface "next.orly.dev/pkg/interfaces/acl"
6 "next.orly.dev/pkg/mode"
7 "next.orly.dev/pkg/utils/atomic"
8 )
9 10 var Registry = &S{}
11 12 // SetMode sets the active ACL mode and syncs it to the mode package for
13 // packages that need to check the mode without importing acl (to avoid cycles).
14 func (s *S) SetMode(m string) {
15 s.active.Store(m)
16 mode.ACLMode.Store(m)
17 }
18 19 type S struct {
20 // acl holds registered ACL implementations.
21 // Use ACLs(), GetACLByType(), or ListRegisteredACLs() to access.
22 acl []acliface.I
23 // active holds the name of the currently active ACL mode.
24 // Use GetMode() to read the current mode.
25 active atomic.String
26 }
27 28 // GetMode returns the currently active ACL mode name.
29 func (s *S) GetMode() string {
30 return s.active.Load()
31 }
32 33 // GetACLByType returns the ACL implementation with the given type name, or nil if not found.
34 func (s *S) GetACLByType(typ string) acliface.I {
35 for _, i := range s.acl {
36 if i.Type() == typ {
37 return i
38 }
39 }
40 return nil
41 }
42 43 // GetActiveACL returns the currently active ACL implementation, or nil if none is active.
44 func (s *S) GetActiveACL() acliface.I {
45 return s.GetACLByType(s.active.Load())
46 }
47 48 // ListRegisteredACLs returns the type names of all registered ACL implementations.
49 func (s *S) ListRegisteredACLs() []string {
50 types := make([]string, 0, len(s.acl))
51 for _, i := range s.acl {
52 types = append(types, i.Type())
53 }
54 return types
55 }
56 57 // ACLs returns the registered ACL implementations for iteration.
58 // Prefer using GetActiveACL() or GetACLByType() when possible.
59 func (s *S) ACLs() []acliface.I {
60 return s.acl
61 }
62 63 // IsRegistered returns true if an ACL with the given type is registered.
64 func (s *S) IsRegistered(typ string) bool {
65 return s.GetACLByType(typ) != nil
66 }
67 68 type A struct{ S }
69 70 func (s *S) Register(i acliface.I) {
71 (*s).acl = append((*s).acl, i)
72 }
73 74 // RegisterAndActivate registers an ACL implementation and sets it as the active one.
75 // This is used for gRPC clients where the mode is determined by the remote server.
76 func (s *S) RegisterAndActivate(i acliface.I) {
77 s.acl = []acliface.I{i}
78 s.SetMode(i.Type())
79 }
80 81 func (s *S) Configure(cfg ...any) (err error) {
82 for _, i := range s.acl {
83 if i.Type() == s.active.Load() {
84 err = i.Configure(cfg...)
85 return
86 }
87 }
88 return err
89 }
90 91 func (s *S) GetAccessLevel(pub []byte, address string) (level string) {
92 for _, i := range s.acl {
93 if i.Type() == s.active.Load() {
94 level = i.GetAccessLevel(pub, address)
95 break
96 }
97 }
98 return
99 }
100 101 func (s *S) GetACLInfo() (name, description, documentation string) {
102 for _, i := range s.acl {
103 if i.Type() == s.active.Load() {
104 name, description, documentation = i.GetACLInfo()
105 break
106 }
107 }
108 return
109 }
110 111 func (s *S) Syncer() {
112 for _, i := range s.acl {
113 if i.Type() == s.active.Load() {
114 i.Syncer()
115 break
116 }
117 }
118 }
119 120 func (s *S) Type() (typ string) {
121 for _, i := range s.acl {
122 if i.Type() == s.active.Load() {
123 typ = i.Type()
124 break
125 }
126 }
127 return
128 }
129 130 // AddFollow forwards a pubkey to the active ACL if it supports dynamic follows
131 func (s *S) AddFollow(pub []byte) {
132 for _, i := range s.acl {
133 if i.Type() == s.active.Load() {
134 if f, ok := i.(*Follows); ok {
135 f.AddFollow(pub)
136 }
137 break
138 }
139 }
140 }
141 142 // CheckPolicy checks if an event is allowed by the active ACL policy
143 func (s *S) CheckPolicy(ev *event.E) (allowed bool, err error) {
144 for _, i := range s.acl {
145 if i.Type() == s.active.Load() {
146 // Check if the ACL implementation has a CheckPolicy method
147 if policyChecker, ok := i.(acliface.PolicyChecker); ok {
148 return policyChecker.CheckPolicy(ev)
149 }
150 // If no CheckPolicy method, default to allowing
151 return true, nil
152 }
153 }
154 // If no active ACL, default to allowing
155 return true, nil
156 }
157