Files
backrest/internal/api/syncapi/permissions/permissions.go
Gareth 6e0c201025
Some checks failed
Build Snapshot Release / build (push) Has been cancelled
Release Please / release-please (push) Has been cancelled
Test / test-nix (push) Has been cancelled
Test / test-win (push) Has been cancelled
feat: multihost sync ui (#825)
2025-06-29 17:34:02 -07:00

138 lines
3.0 KiB
Go

package permissions
import (
"fmt"
"strings"
v1 "github.com/garethgeorge/backrest/gen/go/v1"
)
type ScopeSet struct {
plans map[string]struct{}
repos map[string]struct{}
excludedPlans map[string]struct{}
excludedRepos map[string]struct{}
wildcard bool
}
func NewScopeSet(scopes []string) (*ScopeSet, error) {
scopeSet := &ScopeSet{
plans: make(map[string]struct{}),
repos: make(map[string]struct{}),
excludedPlans: make(map[string]struct{}),
excludedRepos: make(map[string]struct{}),
wildcard: false,
}
for _, scope := range scopes {
if scope == "*" {
scopeSet.wildcard = true
} else if len(scope) > 5 && strings.HasPrefix(scope, "repo:") {
scopeSet.repos[scope[len("repo:"):]] = struct{}{}
} else if len(scope) > 5 && strings.HasPrefix(scope, "plan:") {
scopeSet.plans[scope[len("plan:"):]] = struct{}{}
} else if len(scope) > 6 && strings.HasPrefix(scope, "!repo:") {
scopeSet.excludedRepos[scope[len("!repo:"):]] = struct{}{}
} else if len(scope) > 6 && strings.HasPrefix(scope, "!plan:") {
scopeSet.excludedPlans[scope[len("!plan:"):]] = struct{}{}
} else {
return nil, fmt.Errorf("invalid scope format: %s", scope)
}
}
return scopeSet, nil
}
func (s *ScopeSet) ContainsPlan(planID string) bool {
if _, ok := s.excludedPlans[planID]; ok {
return false
}
if s.wildcard {
return true
}
if _, ok := s.plans[planID]; ok {
return true
}
return false
}
func (s *ScopeSet) ContainsRepo(repoID string) bool {
if _, ok := s.excludedRepos[repoID]; ok {
return false
}
if s.wildcard {
return true
}
if _, ok := s.repos[repoID]; ok {
return true
}
return false
}
func (s *ScopeSet) Merge(other *ScopeSet) {
if other.wildcard {
s.wildcard = true
return
}
for planID := range other.plans {
s.plans[planID] = struct{}{}
}
for repoID := range other.repos {
s.repos[repoID] = struct{}{}
}
for planID := range other.excludedPlans {
s.excludedPlans[planID] = struct{}{}
}
for repoID := range other.excludedRepos {
s.excludedRepos[repoID] = struct{}{}
}
}
type PermissionSet struct {
perms map[v1.Multihost_Permission_Type]ScopeSet
}
func NewPermissionSet(perms []*v1.Multihost_Permission) (*PermissionSet, error) {
permSet := &PermissionSet{
perms: make(map[v1.Multihost_Permission_Type]ScopeSet),
}
for _, perm := range perms {
if perm.Scopes == nil {
continue
}
scopeSet, err := NewScopeSet(perm.Scopes)
if err != nil {
return nil, err
}
permSet.perms[perm.Type] = *scopeSet
}
return permSet, nil
}
func (p *PermissionSet) CheckPermissionForPlan(planID string, permType ...v1.Multihost_Permission_Type) bool {
for _, pt := range permType {
if scopeSet, ok := p.perms[pt]; ok {
if scopeSet.ContainsPlan(planID) {
return true
}
}
}
return false
}
func (p *PermissionSet) CheckPermissionForRepo(repoID string, permType ...v1.Multihost_Permission_Type) bool {
for _, pt := range permType {
if scopeSet, ok := p.perms[pt]; ok {
if scopeSet.ContainsRepo(repoID) {
return true
}
}
}
return false
}