acl.go raw

   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