proxy-pool/internal/domain/clientpolicy/policy.go

99 lines
2.7 KiB
Go

// Package clientpolicy defines fixed credential-level limits that can be
// enforced before an extraction reaches the activity-pool store.
package clientpolicy
import (
"errors"
"strings"
)
var ErrInvalidPolicy = errors.New("invalid client policy")
// Policy limits an authenticated client's permitted Distribution extraction or
// Gateway routing. Zero values preserve the existing unrestricted behavior.
type Policy struct {
MaxExtractCount int `yaml:"maxExtractCount"`
AllowedUpstreams []string `yaml:"allowedUpstreams"`
AllowedRegions []string `yaml:"allowedRegions"`
AllowedRoutings []string `yaml:"allowedRoutings"`
}
func (policy Policy) IsZero() bool {
return policy.MaxExtractCount == 0 && len(policy.AllowedUpstreams) == 0 &&
len(policy.AllowedRegions) == 0 && len(policy.AllowedRoutings) == 0
}
func (policy Policy) Validate() error {
if policy.MaxExtractCount < 0 ||
!validUniqueValues(policy.AllowedUpstreams) ||
!validUniqueValues(policy.AllowedRegions) ||
!validUniqueValues(policy.AllowedRoutings) {
return ErrInvalidPolicy
}
return nil
}
func (policy Policy) Clone() Policy {
policy.AllowedUpstreams = append([]string(nil), policy.AllowedUpstreams...)
policy.AllowedRegions = append([]string(nil), policy.AllowedRegions...)
policy.AllowedRoutings = append([]string(nil), policy.AllowedRoutings...)
return policy
}
func (policy Policy) AllowsExtractCount(count int) bool {
return policy.MaxExtractCount == 0 || count <= policy.MaxExtractCount
}
func (policy Policy) RestrictUpstreams(requested []string) ([]string, bool) {
return restrict(requested, policy.AllowedUpstreams)
}
func (policy Policy) RestrictRegions(requested []string) ([]string, bool) {
return restrict(requested, policy.AllowedRegions)
}
func (policy Policy) AllowsRouting(routing string) bool {
if len(policy.AllowedRoutings) == 0 {
return true
}
for _, allowed := range policy.AllowedRoutings {
if routing == allowed {
return true
}
}
return false
}
func restrict(requested, allowed []string) ([]string, bool) {
if len(allowed) == 0 {
return append([]string(nil), requested...), true
}
if len(requested) == 0 {
return append([]string(nil), allowed...), true
}
allowedSet := make(map[string]struct{}, len(allowed))
for _, value := range allowed {
allowedSet[value] = struct{}{}
}
for _, value := range requested {
if _, ok := allowedSet[value]; !ok {
return nil, false
}
}
return append([]string(nil), requested...), true
}
func validUniqueValues(values []string) bool {
seen := make(map[string]struct{}, len(values))
for _, value := range values {
if value == "" || strings.TrimSpace(value) != value {
return false
}
if _, exists := seen[value]; exists {
return false
}
seen[value] = struct{}{}
}
return true
}