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"
|
|
|
|
|
|
|
|
"storj.io/storj/cmd/uplinkng/ulloc"
|
|
|
|
"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
|
|
|
|
|
|
|
readonly bool // implies disallowWrites and disallowDeletes
|
|
|
|
writeonly bool // implies disallowReads and disallowLists
|
|
|
|
|
|
|
|
disallowDeletes bool
|
|
|
|
disallowLists bool
|
|
|
|
disallowReads bool
|
|
|
|
disallowWrites bool
|
|
|
|
|
|
|
|
notBefore time.Time
|
|
|
|
notAfter time.Time
|
|
|
|
}
|
|
|
|
|
2021-05-25 00:11:50 +01:00
|
|
|
func (ap *accessPermissions) Setup(params clingy.Parameters) {
|
2021-06-22 23:41:22 +01:00
|
|
|
ap.prefixes = params.Flag("prefix", "Key prefix access will be restricted to", []ulloc.Location{},
|
|
|
|
clingy.Transform(ulloc.Parse),
|
|
|
|
clingy.Transform(transformSharePrefix),
|
|
|
|
clingy.Repeated,
|
|
|
|
).([]uplink.SharePrefix)
|
|
|
|
|
2021-11-03 13:51:47 +00:00
|
|
|
ap.readonly = params.Flag("readonly", "Implies --disallow-writes and --disallow-deletes", true,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.writeonly = params.Flag("writeonly", "Implies --disallow-reads and --disallow-lists", false,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
|
|
|
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.disallowDeletes = params.Flag("disallow-deletes", "Disallow deletes with the access", false,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.disallowLists = params.Flag("disallow-lists", "Disallow lists with the access", false,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.disallowReads = params.Flag("disallow-reads", "Disallow reasd with the access", false,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.disallowWrites = params.Flag("disallow-writes", "Disallow writes with the access", false,
|
2021-03-31 16:56:34 +01:00
|
|
|
clingy.Transform(strconv.ParseBool)).(bool)
|
|
|
|
|
2021-06-22 23:41:22 +01:00
|
|
|
now := time.Now()
|
|
|
|
transformHumanDate := clingy.Transform(func(date string) (time.Time, error) {
|
|
|
|
switch {
|
2021-11-03 13:51:47 +00:00
|
|
|
case date == "none":
|
|
|
|
return time.Time{}, nil
|
2021-06-22 23:41:22 +01:00
|
|
|
case date == "":
|
|
|
|
return time.Time{}, nil
|
|
|
|
case date == "now":
|
|
|
|
return now, nil
|
|
|
|
case date[0] == '+' || date[0] == '-':
|
|
|
|
d, err := time.ParseDuration(date)
|
|
|
|
return now.Add(d), errs.Wrap(err)
|
|
|
|
default:
|
|
|
|
t, err := time.Parse(time.RFC3339, date)
|
|
|
|
return t, errs.Wrap(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.notBefore = params.Flag("not-before",
|
2021-06-22 23:41:22 +01:00
|
|
|
"Disallow access before this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700')",
|
|
|
|
time.Time{}, transformHumanDate, clingy.Type("relative_date")).(time.Time)
|
2021-05-25 00:11:50 +01:00
|
|
|
ap.notAfter = params.Flag("not-after",
|
2021-06-22 23:41:22 +01:00
|
|
|
"Disallow access after this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700')",
|
|
|
|
time.Time{}, transformHumanDate, clingy.Type("relative_date")).(time.Time)
|
2021-03-31 16:56:34 +01:00
|
|
|
}
|
|
|
|
|
2021-11-03 13:51:47 +00:00
|
|
|
func (ap *accessPermissions) SetupWithPrefixArg(params clingy.Parameters) {
|
|
|
|
ap.Setup(params)
|
|
|
|
|
|
|
|
argPrefixes := params.Arg("prefix", "Key prefix access will be restricted to",
|
|
|
|
clingy.Transform(ulloc.Parse),
|
|
|
|
clingy.Transform(transformSharePrefix),
|
|
|
|
clingy.Repeated,
|
|
|
|
).([]uplink.SharePrefix)
|
|
|
|
|
|
|
|
if argPrefixes != nil {
|
|
|
|
ap.prefixes = argPrefixes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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(),
|
2021-06-22 23:41:22 +01: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
|
|
|
|
|
|
|
func (ap *accessPermissions) AllowDelete() bool {
|
|
|
|
return !ap.disallowDeletes && !ap.readonly
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ap *accessPermissions) AllowList() bool {
|
|
|
|
return !ap.disallowLists && !ap.writeonly
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ap *accessPermissions) AllowDownload() bool {
|
|
|
|
return !ap.disallowReads && !ap.writeonly
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ap *accessPermissions) AllowUpload() bool {
|
|
|
|
return !ap.disallowWrites && !ap.readonly
|
|
|
|
}
|