99 lines
2.7 KiB
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
|
|
}
|