package auth import ( "sync" "forge.cadoles.com/Cadoles/guesstimate/internal/model" "github.com/antonmedv/expr" "github.com/antonmedv/expr/vm" "github.com/pkg/errors" ) var ( ErrUnexpectedRuleResult = errors.New("unexpected rule result") ) type Service struct { rules []*vm.Program mutex sync.RWMutex } func (s *Service) LoadRules(rawRules ...string) error { rules := make([]*vm.Program, 0, len(rawRules)) for _, rr := range rawRules { r, err := expr.Compile(rr) if err != nil { return errors.WithStack(err) } rules = append(rules, r) } s.mutex.Lock() s.rules = rules s.mutex.Unlock() return nil } func (s *Service) Authorize(user *model.User) (bool, error) { s.mutex.RLock() defer s.mutex.RUnlock() env := map[string]interface{}{ "user": user, } for _, r := range s.rules { result, err := expr.Run(r, env) if err != nil { return false, errors.WithStack(err) } authorized, ok := result.(bool) if !ok { return false, errors.WithStack(ErrUnexpectedRuleResult) } if !authorized { return false, nil } } return true, nil } func NewService() *Service { return &Service{ rules: make([]*vm.Program, 0), } }