-
Notifications
You must be signed in to change notification settings - Fork 385
/
access_permissions.go
138 lines (113 loc) · 4.81 KB
/
access_permissions.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
// Copyright (C) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
package main
import (
"strconv"
"time"
"github.com/zeebo/clingy"
"github.com/zeebo/errs"
"storj.io/storj/cmd/uplink/ulloc"
"storj.io/uplink"
)
// accessPermissions holds flags and provides a Setup method for commands that
// have to modify permissions on access grants.
type accessPermissions struct {
prefixes []uplink.SharePrefix // prefixes is the set of path prefixes that the grant will be limited to
readonly bool
writeonly bool
disallowDeletes *bool
disallowLists *bool
disallowReads *bool
disallowWrites *bool
notBefore *time.Time
notAfter *time.Time
maxObjectTTL *time.Duration
}
func (ap *accessPermissions) Setup(params clingy.Parameters, prefixFlags bool) {
if prefixFlags {
ap.prefixes = params.Flag("prefix", "Key prefix access will be restricted to", []uplink.SharePrefix{},
clingy.Transform(ulloc.Parse),
clingy.Transform(transformSharePrefix),
clingy.Repeated,
).([]uplink.SharePrefix)
}
ap.readonly = params.Flag("readonly", "Implies --disallow-writes and --disallow-deletes", true,
clingy.Transform(strconv.ParseBool), clingy.Boolean).(bool)
ap.writeonly = params.Flag("writeonly", "Implies --disallow-reads and --disallow-lists", false,
clingy.Transform(strconv.ParseBool), clingy.Boolean).(bool)
params.Break()
ap.disallowDeletes = params.Flag("disallow-deletes", "Disallow deletes with the access", nil,
clingy.Transform(strconv.ParseBool), clingy.Boolean, clingy.Optional).(*bool)
ap.disallowLists = params.Flag("disallow-lists", "Disallow lists with the access", nil,
clingy.Transform(strconv.ParseBool), clingy.Boolean, clingy.Optional).(*bool)
ap.disallowReads = params.Flag("disallow-reads", "Disallow reads with the access", nil,
clingy.Transform(strconv.ParseBool), clingy.Boolean, clingy.Optional).(*bool)
ap.disallowWrites = params.Flag("disallow-writes", "Disallow writes with the access", nil,
clingy.Transform(strconv.ParseBool), clingy.Boolean, clingy.Optional).(*bool)
params.Break()
ap.notBefore = params.Flag("not-before",
"Disallow access before this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700', 'none')",
nil, clingy.Transform(parseHumanDateNotBefore), clingy.Type("relative_date"), clingy.Optional).(*time.Time)
ap.notAfter = params.Flag("not-after",
"Disallow access after this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700', 'none')",
nil, clingy.Transform(parseHumanDateNotAfter), clingy.Type("relative_date"), clingy.Optional).(*time.Time)
params.Break()
ap.maxObjectTTL = params.Flag("max-object-ttl",
"The object is automatically deleted after this period. (e.g. '1h30m', '24h', '720h')",
nil, clingy.Transform(time.ParseDuration), clingy.Type("period"), clingy.Optional).(*time.Duration)
if !prefixFlags {
ap.prefixes = params.Arg("prefix", "Key prefix access will be restricted to",
clingy.Transform(ulloc.Parse),
clingy.Transform(transformSharePrefix),
clingy.Repeated,
).([]uplink.SharePrefix)
}
}
func transformSharePrefix(loc ulloc.Location) (uplink.SharePrefix, error) {
bucket, key, ok := loc.RemoteParts()
if !ok {
return uplink.SharePrefix{}, errs.New("invalid prefix: must be remote: %q", loc)
}
return uplink.SharePrefix{
Bucket: bucket,
Prefix: key,
}, nil
}
func (ap *accessPermissions) Apply(access *uplink.Access) (*uplink.Access, error) {
permission := uplink.Permission{
AllowDelete: ap.AllowDelete(),
AllowList: ap.AllowList(),
AllowDownload: ap.AllowDownload(),
AllowUpload: ap.AllowUpload(),
NotBefore: ap.NotBefore(),
NotAfter: ap.NotAfter(),
MaxObjectTTL: ap.MaxObjectTTL(),
}
// if we aren't actually restricting anything, then we don't need to Share.
if permission == (uplink.Permission{
AllowDelete: true,
AllowList: true,
AllowDownload: true,
AllowUpload: true,
}) && len(ap.prefixes) == 0 {
return access, nil
}
access, err := access.Share(permission, ap.prefixes...)
if err != nil {
return nil, errs.Wrap(err)
}
return access, nil
}
func defaulted[T any](val *T, def T) T {
if val != nil {
return *val
}
return def
}
func (ap *accessPermissions) NotBefore() time.Time { return defaulted(ap.notBefore, time.Time{}) }
func (ap *accessPermissions) NotAfter() time.Time { return defaulted(ap.notAfter, time.Time{}) }
func (ap *accessPermissions) AllowDelete() bool { return !defaulted(ap.disallowDeletes, ap.readonly) }
func (ap *accessPermissions) AllowList() bool { return !defaulted(ap.disallowLists, ap.writeonly) }
func (ap *accessPermissions) AllowDownload() bool { return !defaulted(ap.disallowReads, ap.writeonly) }
func (ap *accessPermissions) AllowUpload() bool { return !defaulted(ap.disallowWrites, ap.readonly) }
func (ap *accessPermissions) MaxObjectTTL() *time.Duration { return ap.maxObjectTTL }