1package deb 2 3import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 8 "github.com/DisposaBoy/JsonConfigReader" 9 "github.com/aptly-dev/aptly/pgp" 10 "github.com/aptly-dev/aptly/utils" 11) 12 13// UploadersRule is single rule of format: what packages can group or key upload 14type UploadersRule struct { 15 Condition string `json:"condition"` 16 Allow []string `json:"allow"` 17 Deny []string `json:"deny"` 18 CompiledCondition PackageQuery `json:"-" codec:"-"` 19} 20 21func (u UploadersRule) String() string { 22 b, _ := json.Marshal(u) 23 return string(b) 24} 25 26// Uploaders is configuration of restrictions for .changes file importing 27type Uploaders struct { 28 Groups map[string][]string `json:"groups"` 29 Rules []UploadersRule `json:"rules"` 30} 31 32func (u *Uploaders) String() string { 33 b, _ := json.Marshal(u) 34 return string(b) 35} 36 37// NewUploadersFromFile loads Uploaders structue from .json file 38func NewUploadersFromFile(path string) (*Uploaders, error) { 39 uploaders := &Uploaders{} 40 f, err := os.Open(path) 41 if err != nil { 42 return nil, fmt.Errorf("error loading uploaders file: %s", err) 43 } 44 defer f.Close() 45 46 err = json.NewDecoder(JsonConfigReader.New(f)).Decode(&uploaders) 47 if err != nil { 48 return nil, fmt.Errorf("error loading uploaders file: %s", err) 49 } 50 51 return uploaders, nil 52} 53 54func (u *Uploaders) expandGroupsInternal(items []string, trail []string) []string { 55 result := []string{} 56 57 for _, item := range items { 58 // stop infinite recursion 59 if utils.StrSliceHasItem(trail, item) { 60 continue 61 } 62 63 group, ok := u.Groups[item] 64 if !ok { 65 result = append(result, item) 66 } else { 67 newTrail := append([]string(nil), trail...) 68 result = append(result, u.expandGroupsInternal(group, append(newTrail, item))...) 69 } 70 } 71 72 return result 73} 74 75// ExpandGroups expands list of keys/groups into list of keys 76func (u *Uploaders) ExpandGroups(items []string) []string { 77 result := u.expandGroupsInternal(items, []string{}) 78 79 return utils.StrSliceDeduplicate(result) 80} 81 82// IsAllowed checks whether listed keys are allowed to upload given .changes file 83func (u *Uploaders) IsAllowed(changes *Changes) error { 84 for _, rule := range u.Rules { 85 if rule.CompiledCondition.Matches(changes) { 86 deny := u.ExpandGroups(rule.Deny) 87 for _, key := range changes.SignatureKeys { 88 for _, item := range deny { 89 if item == "*" || key.Matches(pgp.Key(item)) { 90 return fmt.Errorf("denied according to rule: %s", rule) 91 } 92 } 93 } 94 95 allow := u.ExpandGroups(rule.Allow) 96 for _, key := range changes.SignatureKeys { 97 for _, item := range allow { 98 if item == "*" || key.Matches(pgp.Key(item)) { 99 return nil 100 } 101 } 102 } 103 } 104 } 105 106 return fmt.Errorf("denied as no rule matches") 107} 108