storj/cmd/uplinkng/access_permissions.go
Qweder93 b5194762f2 cmd/uplinkng: share command added
In uplink we have command uplink share and we need
to port it to uplinkng to have command with same functionality.

Command could be executed with parameter or without.
without any flags we share as readonly.

Change-Id: I973b11d00da237358834acf5a863ebab37e684cc
2021-12-02 13:02:14 +00:00

149 lines
4.4 KiB
Go

// 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/uplinkng/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 // implies disallowWrites and disallowDeletes
writeonly bool // implies disallowReads and disallowLists
disallowDeletes bool
disallowLists bool
disallowReads bool
disallowWrites bool
notBefore time.Time
notAfter time.Time
}
func (ap *accessPermissions) Setup(params clingy.Parameters) {
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)
ap.readonly = params.Flag("readonly", "Implies --disallow-writes and --disallow-deletes", true,
clingy.Transform(strconv.ParseBool)).(bool)
ap.writeonly = params.Flag("writeonly", "Implies --disallow-reads and --disallow-lists", false,
clingy.Transform(strconv.ParseBool)).(bool)
ap.disallowDeletes = params.Flag("disallow-deletes", "Disallow deletes with the access", false,
clingy.Transform(strconv.ParseBool)).(bool)
ap.disallowLists = params.Flag("disallow-lists", "Disallow lists with the access", false,
clingy.Transform(strconv.ParseBool)).(bool)
ap.disallowReads = params.Flag("disallow-reads", "Disallow reasd with the access", false,
clingy.Transform(strconv.ParseBool)).(bool)
ap.disallowWrites = params.Flag("disallow-writes", "Disallow writes with the access", false,
clingy.Transform(strconv.ParseBool)).(bool)
now := time.Now()
transformHumanDate := clingy.Transform(func(date string) (time.Time, error) {
switch {
case date == "none":
return time.Time{}, nil
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)
}
})
ap.notBefore = params.Flag("not-before",
"Disallow access before this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700')",
time.Time{}, transformHumanDate, clingy.Type("relative_date")).(time.Time)
ap.notAfter = params.Flag("not-after",
"Disallow access after this time (e.g. '+2h', 'now', '2020-01-02T15:04:05Z0700')",
time.Time{}, transformHumanDate, clingy.Type("relative_date")).(time.Time)
}
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
}
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,
}
// 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 (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
}