forked from endophage/gotuf
/
roles.go
169 lines (152 loc) · 4.32 KB
/
roles.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package data
import (
"fmt"
"strings"
"github.com/endophage/gotuf/errors"
)
// Canonical base role names
const (
CanonicalRootRole = "root"
CanonicalTargetsRole = "targets"
CanonicalSnapshotRole = "snapshot"
CanonicalTimestampRole = "timestamp"
)
// ValidRoles holds an overrideable mapping of canonical role names
// to any custom roles names a user wants to make use of. This allows
// us to be internally consistent while using different roles in the
// public TUF files.
var ValidRoles = map[string]string{
CanonicalRootRole: CanonicalRootRole,
CanonicalTargetsRole: CanonicalTargetsRole,
CanonicalSnapshotRole: CanonicalSnapshotRole,
CanonicalTimestampRole: CanonicalTimestampRole,
}
// SetValidRoles is a utility function to override some or all of the roles
func SetValidRoles(rs map[string]string) {
// iterate ValidRoles
for k := range ValidRoles {
if v, ok := rs[k]; ok {
ValidRoles[k] = v
}
}
}
// RoleName returns the (possibly overridden) role name for the provided
// canonical role name
func RoleName(canonicalRole string) string {
if r, ok := ValidRoles[canonicalRole]; ok {
return r
}
return canonicalRole
}
// CanonicalRole does a reverse lookup to get the canonical role name
// from the (possibly overridden) role name
func CanonicalRole(role string) string {
name := strings.ToLower(role)
if _, ok := ValidRoles[name]; ok {
// The canonical version is always lower case
// se ensure we return name, not role
return name
}
targetsBase := fmt.Sprintf("%s/", ValidRoles[CanonicalTargetsRole])
if strings.HasPrefix(name, targetsBase) {
role = strings.TrimPrefix(role, targetsBase)
role = fmt.Sprintf("%s/%s", CanonicalTargetsRole, role)
return role
}
for r, v := range ValidRoles {
if role == v {
return r
}
}
return ""
}
// ValidRole only determines the name is semantically
// correct. For target delegated roles, it does NOT check
// the the appropriate parent roles exist.
func ValidRole(name string) bool {
name = strings.ToLower(name)
if v, ok := ValidRoles[name]; ok {
return name == v
}
targetsBase := fmt.Sprintf("%s/", ValidRoles[CanonicalTargetsRole])
if strings.HasPrefix(name, targetsBase) {
return true
}
for _, v := range ValidRoles {
if name == v {
return true
}
}
return false
}
// RootRole is a cut down role as it appears in the root.json
type RootRole struct {
KeyIDs []string `json:"keyids"`
Threshold int `json:"threshold"`
}
// Role is a more verbose role as they appear in targets delegations
type Role struct {
RootRole
Name string `json:"name"`
Paths []string `json:"paths,omitempty"`
PathHashPrefixes []string `json:"path_hash_prefixes,omitempty"`
Email string `json:"email,omitempty"`
}
// NewRole creates a new Role object from the given parameters
func NewRole(name string, threshold int, keyIDs, paths, pathHashPrefixes []string) (*Role, error) {
if len(paths) > 0 && len(pathHashPrefixes) > 0 {
return nil, errors.ErrInvalidRole{}
}
if threshold < 1 {
return nil, errors.ErrInvalidRole{}
}
if !ValidRole(name) {
return nil, errors.ErrInvalidRole{}
}
return &Role{
RootRole: RootRole{
KeyIDs: keyIDs,
Threshold: threshold,
},
Name: name,
Paths: paths,
PathHashPrefixes: pathHashPrefixes,
}, nil
}
// IsValid checks if the role has defined both paths and path hash prefixes,
// having both is invalid
func (r Role) IsValid() bool {
return !(len(r.Paths) > 0 && len(r.PathHashPrefixes) > 0)
}
// ValidKey checks if the given id is a recognized signing key for the role
func (r Role) ValidKey(id string) bool {
for _, key := range r.KeyIDs {
if key == id {
return true
}
}
return false
}
// CheckPaths checks if a given path is valid for the role
func (r Role) CheckPaths(path string) bool {
for _, p := range r.Paths {
if strings.HasPrefix(path, p) {
return true
}
}
return false
}
// CheckPrefixes checks if a given hash matches the prefixes for the role
func (r Role) CheckPrefixes(hash string) bool {
for _, p := range r.PathHashPrefixes {
if strings.HasPrefix(hash, p) {
return true
}
}
return false
}
// IsDelegation checks if the role is a delegation or a root role
func (r Role) IsDelegation() bool {
targetsBase := fmt.Sprintf("%s/", ValidRoles[CanonicalTargetsRole])
return strings.HasPrefix(r.Name, targetsBase)
}