2021-03-31 16:56:34 +01:00
|
|
|
// Copyright (C) 2021 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/zeebo/clingy"
|
2021-06-22 23:41:22 +01:00
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
2022-01-06 19:55:46 +00:00
|
|
|
"storj.io/storj/cmd/uplink/ulloc"
|
2021-06-22 23:41:22 +01:00
|
|
|
"storj.io/uplink"
|
2021-03-31 16:56:34 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// accessPermissions holds flags and provides a Setup method for commands that
|
|
|
|
// have to modify permissions on access grants.
|
|
|
|
type accessPermissions struct {
|
2021-06-22 23:41:22 +01:00
|
|
|
prefixes []uplink.SharePrefix // prefixes is the set of path prefixes that the grant will be limited to
|
2021-03-31 16:56:34 +01:00
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
readonly bool
|
|
|
|
writeonly bool
|
2021-03-31 16:56:34 +01:00
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
disallowDeletes *bool
|
|
|
|
disallowLists *bool
|
|
|
|
disallowReads *bool
|
|
|
|
disallowWrites *bool
|
2021-03-31 16:56:34 +01:00
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
notBefore *time.Time
|
|
|
|
notAfter *time.Time
|
2021-03-31 16:56:34 +01:00
|
|
|
}
|
|
|
|
|
2022-01-25 23:39:26 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-06-22 23:41:22 +01:00
|
|
|
|
2021-11-03 13:51:47 +00:00
|
|
|
ap.readonly = params.Flag("readonly", "Implies --disallow-writes and --disallow-deletes", true,
|
2021-12-09 19:21:52 +00:00
|
|
|
clingy.Transform(strconv.ParseBool), clingy.Boolean).(bool)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.writeonly = params.Flag("writeonly", "Implies --disallow-reads and --disallow-lists", false,
|
2021-12-09 19:21:52 +00:00
|
|
|
clingy.Transform(strconv.ParseBool), clingy.Boolean).(bool)
|
2021-03-31 16:56:34 +01:00
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
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()
|
2021-03-31 16:56:34 +01:00
|
|
|
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.notBefore = params.Flag("not-before",
|
2022-12-05 16:08:28 +00:00
|
|
|
"Disallow access before this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700', 'none')",
|
|
|
|
nil, clingy.Transform(parseHumanDate), clingy.Type("relative_date"), clingy.Optional).(*time.Time)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.notAfter = params.Flag("not-after",
|
2022-12-05 16:08:28 +00:00
|
|
|
"Disallow access after this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700', 'none')",
|
|
|
|
nil, clingy.Transform(parseHumanDate), clingy.Type("relative_date"), clingy.Optional).(*time.Time)
|
2021-11-03 13:51:47 +00:00
|
|
|
|
2022-01-25 23:39:26 +00:00
|
|
|
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)
|
2021-11-03 13:51:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2021-06-22 23:41:22 +01:00
|
|
|
func (ap *accessPermissions) Apply(access *uplink.Access) (*uplink.Access, error) {
|
|
|
|
permission := uplink.Permission{
|
2021-11-03 13:51:47 +00:00
|
|
|
AllowDelete: ap.AllowDelete(),
|
|
|
|
AllowList: ap.AllowList(),
|
|
|
|
AllowDownload: ap.AllowDownload(),
|
|
|
|
AllowUpload: ap.AllowUpload(),
|
2022-12-05 16:08:28 +00:00
|
|
|
NotBefore: ap.NotBefore(),
|
|
|
|
NotAfter: ap.NotAfter(),
|
2021-03-31 16:56:34 +01:00
|
|
|
}
|
2021-06-22 23:41:22 +01:00
|
|
|
|
2021-08-13 20:31:04 +01:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2021-06-22 23:41:22 +01:00
|
|
|
access, err := access.Share(permission, ap.prefixes...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return access, nil
|
2021-03-31 16:56:34 +01:00
|
|
|
}
|
2021-11-03 13:51:47 +00:00
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
func defaulted[T any](val *T, def T) T {
|
|
|
|
if val != nil {
|
|
|
|
return *val
|
|
|
|
}
|
|
|
|
return def
|
2021-11-03 13:51:47 +00:00
|
|
|
}
|
|
|
|
|
2022-12-05 16:08:28 +00:00
|
|
|
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) }
|