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