You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.7 KiB
156 lines
3.7 KiB
package acl |
|
|
|
import ( |
|
"git.mleku.dev/mleku/nostr/encoders/event" |
|
acliface "next.orly.dev/pkg/interfaces/acl" |
|
"next.orly.dev/pkg/mode" |
|
"next.orly.dev/pkg/utils/atomic" |
|
) |
|
|
|
var Registry = &S{} |
|
|
|
// SetMode sets the active ACL mode and syncs it to the mode package for |
|
// packages that need to check the mode without importing acl (to avoid cycles). |
|
func (s *S) SetMode(m string) { |
|
s.active.Store(m) |
|
mode.ACLMode.Store(m) |
|
} |
|
|
|
type S struct { |
|
// acl holds registered ACL implementations. |
|
// Use ACLs(), GetACLByType(), or ListRegisteredACLs() to access. |
|
acl []acliface.I |
|
// active holds the name of the currently active ACL mode. |
|
// Use GetMode() to read the current mode. |
|
active atomic.String |
|
} |
|
|
|
// GetMode returns the currently active ACL mode name. |
|
func (s *S) GetMode() string { |
|
return s.active.Load() |
|
} |
|
|
|
// GetACLByType returns the ACL implementation with the given type name, or nil if not found. |
|
func (s *S) GetACLByType(typ string) acliface.I { |
|
for _, i := range s.acl { |
|
if i.Type() == typ { |
|
return i |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
// GetActiveACL returns the currently active ACL implementation, or nil if none is active. |
|
func (s *S) GetActiveACL() acliface.I { |
|
return s.GetACLByType(s.active.Load()) |
|
} |
|
|
|
// ListRegisteredACLs returns the type names of all registered ACL implementations. |
|
func (s *S) ListRegisteredACLs() []string { |
|
types := make([]string, 0, len(s.acl)) |
|
for _, i := range s.acl { |
|
types = append(types, i.Type()) |
|
} |
|
return types |
|
} |
|
|
|
// ACLs returns the registered ACL implementations for iteration. |
|
// Prefer using GetActiveACL() or GetACLByType() when possible. |
|
func (s *S) ACLs() []acliface.I { |
|
return s.acl |
|
} |
|
|
|
// IsRegistered returns true if an ACL with the given type is registered. |
|
func (s *S) IsRegistered(typ string) bool { |
|
return s.GetACLByType(typ) != nil |
|
} |
|
|
|
type A struct{ S } |
|
|
|
func (s *S) Register(i acliface.I) { |
|
(*s).acl = append((*s).acl, i) |
|
} |
|
|
|
// RegisterAndActivate registers an ACL implementation and sets it as the active one. |
|
// This is used for gRPC clients where the mode is determined by the remote server. |
|
func (s *S) RegisterAndActivate(i acliface.I) { |
|
s.acl = []acliface.I{i} |
|
s.SetMode(i.Type()) |
|
} |
|
|
|
func (s *S) Configure(cfg ...any) (err error) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
err = i.Configure(cfg...) |
|
return |
|
} |
|
} |
|
return err |
|
} |
|
|
|
func (s *S) GetAccessLevel(pub []byte, address string) (level string) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
level = i.GetAccessLevel(pub, address) |
|
break |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *S) GetACLInfo() (name, description, documentation string) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
name, description, documentation = i.GetACLInfo() |
|
break |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *S) Syncer() { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
i.Syncer() |
|
break |
|
} |
|
} |
|
} |
|
|
|
func (s *S) Type() (typ string) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
typ = i.Type() |
|
break |
|
} |
|
} |
|
return |
|
} |
|
|
|
// AddFollow forwards a pubkey to the active ACL if it supports dynamic follows |
|
func (s *S) AddFollow(pub []byte) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
if f, ok := i.(*Follows); ok { |
|
f.AddFollow(pub) |
|
} |
|
break |
|
} |
|
} |
|
} |
|
|
|
// CheckPolicy checks if an event is allowed by the active ACL policy |
|
func (s *S) CheckPolicy(ev *event.E) (allowed bool, err error) { |
|
for _, i := range s.acl { |
|
if i.Type() == s.active.Load() { |
|
// Check if the ACL implementation has a CheckPolicy method |
|
if policyChecker, ok := i.(acliface.PolicyChecker); ok { |
|
return policyChecker.CheckPolicy(ev) |
|
} |
|
// If no CheckPolicy method, default to allowing |
|
return true, nil |
|
} |
|
} |
|
// If no active ACL, default to allowing |
|
return true, nil |
|
}
|
|
|