72 lines
1.1 KiB
Go
72 lines
1.1 KiB
Go
package auth
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"forge.cadoles.com/Cadoles/daddy/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),
|
|
}
|
|
}
|