cmd/uplink: adds register, url, and dns flags to uplink share
and replaces access grant with access uplink share <path> --> creates access grant uplink share --register <path> --> registers access grant uplink share --url <path> --> creates URL, implies register and public uplink share --dns <hostname> <path> --> creates dns info, implies register and public Change-Id: I7930c4973a602d3d721ec6f77170f90957dad8c0
This commit is contained in:
parent
9fe477899b
commit
adb2c83e09
@ -153,71 +153,74 @@ func registerAccess(cmd *cobra.Command, args []string) (err error) {
|
|||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return errs.New("no access specified")
|
return errs.New("no access specified")
|
||||||
}
|
}
|
||||||
|
_, err = register(args[0], registerCfg.AuthService, registerCfg.Public)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if registerCfg.AuthService == "" {
|
func register(accessRaw, authService string, public bool) (accessKey string, err error) {
|
||||||
return errs.New("no auth service address provided")
|
if authService == "" {
|
||||||
|
return "", errs.New("no auth service address provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessRaw := args[0]
|
|
||||||
|
|
||||||
// try assuming that accessRaw is a named access
|
// try assuming that accessRaw is a named access
|
||||||
access, err := registerCfg.GetNamedAccess(accessRaw)
|
access, err := registerCfg.GetNamedAccess(accessRaw)
|
||||||
if err == nil && access != nil {
|
if err == nil && access != nil {
|
||||||
accessRaw, err = access.Serialize()
|
accessRaw, err = access.Serialize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.New("error serializing named access '%s': %w", accessRaw, err)
|
return "", errs.New("error serializing named access '%s': %w", accessRaw, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
postData, err := json.Marshal(map[string]interface{}{
|
postData, err := json.Marshal(map[string]interface{}{
|
||||||
"access_grant": accessRaw,
|
"access_grant": accessRaw,
|
||||||
"public": registerCfg.Public,
|
"public": public,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errs.Wrap(err)
|
return accessKey, errs.Wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.Post(fmt.Sprintf("%s/v1/access", registerCfg.AuthService), "application/json", bytes.NewReader(postData))
|
resp, err := http.Post(fmt.Sprintf("%s/v1/access", authService), "application/json", bytes.NewReader(postData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
defer func() { err = errs.Combine(err, resp.Body.Close()) }()
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
respBody := make(map[string]string)
|
respBody := make(map[string]string)
|
||||||
if err := json.Unmarshal(body, &respBody); err != nil {
|
if err := json.Unmarshal(body, &respBody); err != nil {
|
||||||
return errs.New("unexpected response from auth service: %s", string(body))
|
return "", errs.New("unexpected response from auth service: %s", string(body))
|
||||||
}
|
}
|
||||||
|
|
||||||
accessKey, ok := respBody["access_key_id"]
|
accessKey, ok := respBody["access_key_id"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errs.New("access_key_id missing in response")
|
return "", errs.New("access_key_id missing in response")
|
||||||
}
|
}
|
||||||
secretKey, ok := respBody["secret_key"]
|
secretKey, ok := respBody["secret_key"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errs.New("secret_key missing in response")
|
return "", errs.New("secret_key missing in response")
|
||||||
}
|
}
|
||||||
fmt.Println("=========== CREDENTIALS =========================================================")
|
|
||||||
|
fmt.Println("========== CREDENTIALS ===================================================================")
|
||||||
fmt.Println("Access Key ID: ", accessKey)
|
fmt.Println("Access Key ID: ", accessKey)
|
||||||
fmt.Println("Secret Key: ", secretKey)
|
fmt.Println("Secret Key : ", secretKey)
|
||||||
fmt.Println("Endpoint: ", respBody["endpoint"])
|
fmt.Println("Endpoint : ", respBody["endpoint"])
|
||||||
|
|
||||||
// update AWS credential file if requested
|
// update AWS credential file if requested
|
||||||
if registerCfg.AWSProfile != "" {
|
if registerCfg.AWSProfile != "" {
|
||||||
credentialsPath, err := getAwsCredentialsPath()
|
credentialsPath, err := getAwsCredentialsPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
err = writeAWSCredentials(credentialsPath, registerCfg.AWSProfile, accessKey, secretKey)
|
err = writeAWSCredentials(credentialsPath, registerCfg.AWSProfile, accessKey, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return accessKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAwsCredentialsPath returns the expected AWS credentials path.
|
// getAwsCredentialsPath returns the expected AWS credentials path.
|
||||||
|
@ -7,8 +7,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -31,7 +33,13 @@ var shareCfg struct {
|
|||||||
NotAfter string `help:"disallow access after this time (e.g. '+2h', '2020-01-02T15:01:01-01:00')" basic-help:"true"`
|
NotAfter string `help:"disallow access after this time (e.g. '+2h', '2020-01-02T15:01:01-01:00')" basic-help:"true"`
|
||||||
AllowedPathPrefix []string `help:"whitelist of path prefixes to require, overrides the [allowed-path-prefix] arguments"`
|
AllowedPathPrefix []string `help:"whitelist of path prefixes to require, overrides the [allowed-path-prefix] arguments"`
|
||||||
ExportTo string `default:"" help:"path to export the shared access to" basic-help:"true"`
|
ExportTo string `default:"" help:"path to export the shared access to" basic-help:"true"`
|
||||||
BaseURL string `default:"https://link.tardigradeshare.io" help:"the base url for link sharing"`
|
BaseURL string `default:"https://link.tardigradeshare.io" help:"the base url for link sharing" basic-help:"true"`
|
||||||
|
|
||||||
|
Register bool `default:"false" help:"if true, creates and registers access grant" basic-help:"true"`
|
||||||
|
URL bool `default:"false" help:"if true, returns a url for the shared path. implies --register and --public" basic-help:"true"`
|
||||||
|
DNS string `default:"" help:"specify your custom hostname. if set, returns dns settings for web hosting. implies --register and --public" basic-help:"true"`
|
||||||
|
AuthService string `default:"https://auth.tardigradeshare.io" help:"url for shared auth service" basic-help:"true"`
|
||||||
|
Public bool `default:"false" help:"if true, the access will be public. --dns and --url override this" basic-help:"true"`
|
||||||
|
|
||||||
// Share requires information about the current access
|
// Share requires information about the current access
|
||||||
AccessConfig
|
AccessConfig
|
||||||
@ -46,11 +54,195 @@ func init() {
|
|||||||
Short: "Shares restricted access to objects.",
|
Short: "Shares restricted access to objects.",
|
||||||
RunE: shareMain,
|
RunE: shareMain,
|
||||||
}
|
}
|
||||||
|
|
||||||
RootCmd.AddCommand(shareCmd)
|
RootCmd.AddCommand(shareCmd)
|
||||||
|
|
||||||
process.Bind(shareCmd, &shareCfg, defaults, cfgstruct.ConfDir(getConfDir()))
|
process.Bind(shareCmd, &shareCfg, defaults, cfgstruct.ConfDir(getConfDir()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shareMain(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
newAccessData, sharePrefixes, permission, err := createAccessGrant(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accessKey string
|
||||||
|
|
||||||
|
if shareCfg.Register || shareCfg.URL || shareCfg.DNS != "" {
|
||||||
|
isPublic := (shareCfg.Public || shareCfg.URL || shareCfg.DNS != "")
|
||||||
|
accessKey, err = register(newAccessData, shareCfg.AuthService, isPublic)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("Public Access: ", isPublic)
|
||||||
|
|
||||||
|
if len(shareCfg.AllowedPathPrefix) == 1 && !permission.AllowUpload && !permission.AllowDelete {
|
||||||
|
if shareCfg.URL {
|
||||||
|
if err = createURL(accessKey, sharePrefixes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if shareCfg.DNS != "" {
|
||||||
|
if err = createDNS(accessKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if shareCfg.ExportTo != "" {
|
||||||
|
// convert to an absolute path, mostly for output purposes.
|
||||||
|
exportTo, err := filepath.Abs(shareCfg.ExportTo)
|
||||||
|
if err != nil {
|
||||||
|
return Error.Wrap(err)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(exportTo, []byte(newAccessData+"\n"), 0600); err != nil {
|
||||||
|
return Error.Wrap(err)
|
||||||
|
}
|
||||||
|
fmt.Println("Exported to:", exportTo)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates access grant for allowed path prefixes.
|
||||||
|
func createAccessGrant(args []string) (newAccessData string, sharePrefixes []sharePrefixExtension, permission uplink.Permission, err error) {
|
||||||
|
now := time.Now()
|
||||||
|
notBefore, err := parseHumanDate(shareCfg.NotBefore, now)
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
notAfter, err := parseHumanDate(shareCfg.NotAfter, now)
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(shareCfg.AllowedPathPrefix) == 0 {
|
||||||
|
// if the --allowed-path-prefix flag is not set,
|
||||||
|
// use any arguments as allowed path prefixes
|
||||||
|
for _, arg := range args {
|
||||||
|
shareCfg.AllowedPathPrefix = append(shareCfg.AllowedPathPrefix, strings.Split(arg, ",")...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var uplinkSharePrefixes []uplink.SharePrefix
|
||||||
|
for _, path := range shareCfg.AllowedPathPrefix {
|
||||||
|
p, err := fpath.New(path)
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
if p.IsLocal() {
|
||||||
|
return newAccessData, sharePrefixes, permission, errs.New("required path must be remote: %q", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
uplinkSharePrefix := uplink.SharePrefix{
|
||||||
|
Bucket: p.Bucket(),
|
||||||
|
Prefix: p.Path(),
|
||||||
|
}
|
||||||
|
sharePrefixes = append(sharePrefixes, sharePrefixExtension{
|
||||||
|
uplinkSharePrefix: uplinkSharePrefix,
|
||||||
|
hasTrailingSlash: strings.HasSuffix(path, "/"),
|
||||||
|
})
|
||||||
|
uplinkSharePrefixes = append(uplinkSharePrefixes, uplinkSharePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
access, err := shareCfg.GetAccess()
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
permission = uplink.Permission{}
|
||||||
|
permission.AllowDelete = !shareCfg.DisallowDeletes && !shareCfg.Readonly
|
||||||
|
permission.AllowList = !shareCfg.DisallowLists && !shareCfg.Writeonly
|
||||||
|
permission.AllowDownload = !shareCfg.DisallowReads && !shareCfg.Writeonly
|
||||||
|
permission.AllowUpload = !shareCfg.DisallowWrites && !shareCfg.Readonly
|
||||||
|
permission.NotBefore = notBefore
|
||||||
|
permission.NotAfter = notAfter
|
||||||
|
|
||||||
|
newAccess, err := access.Share(permission, uplinkSharePrefixes...)
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newAccessData, err = newAccess.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
satelliteAddr, _, _, err := parseAccess(newAccessData)
|
||||||
|
if err != nil {
|
||||||
|
return newAccessData, sharePrefixes, permission, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Sharing access to satellite", satelliteAddr)
|
||||||
|
fmt.Println("=========== ACCESS RESTRICTIONS ==========================================================")
|
||||||
|
fmt.Println("Download :", formatPermission(permission.AllowDownload))
|
||||||
|
fmt.Println("Upload :", formatPermission(permission.AllowUpload))
|
||||||
|
fmt.Println("Lists :", formatPermission(permission.AllowList))
|
||||||
|
fmt.Println("Deletes :", formatPermission(permission.AllowDelete))
|
||||||
|
fmt.Println("NotBefore :", formatTimeRestriction(permission.NotBefore))
|
||||||
|
fmt.Println("NotAfter :", formatTimeRestriction(permission.NotAfter))
|
||||||
|
fmt.Println("Paths :", formatPaths(sharePrefixes))
|
||||||
|
fmt.Println("=========== SERIALIZED ACCESS WITH THE ABOVE RESTRICTIONS TO SHARE WITH OTHERS ===========")
|
||||||
|
fmt.Println("Access :", newAccessData)
|
||||||
|
|
||||||
|
return newAccessData, sharePrefixes, permission, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates linksharing url for allowed path prefixes.
|
||||||
|
func createURL(newAccessData string, sharePrefixes []sharePrefixExtension) (err error) {
|
||||||
|
p, err := fpath.New(shareCfg.AllowedPathPrefix[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("=========== BROWSER URL ==================================================================")
|
||||||
|
fmt.Println("REMINDER : Object key must end in '/' when trying to share recursively")
|
||||||
|
|
||||||
|
var printFormat string
|
||||||
|
if p.Path() == "" || !sharePrefixes[0].hasTrailingSlash { // Check if the path is empty (aka sharing the entire bucket) or the path is not a directory or an object that ends in "/".
|
||||||
|
printFormat = "URL : %s/%s/%s/%s\n"
|
||||||
|
} else {
|
||||||
|
printFormat = "URL : %s/%s/%s/%s/\n"
|
||||||
|
}
|
||||||
|
fmt.Printf(printFormat, shareCfg.BaseURL, url.PathEscape(newAccessData), p.Bucket(), p.Path())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates dns record info for allowed path prefixes.
|
||||||
|
func createDNS(accessKey string) (err error) {
|
||||||
|
p, err := fpath.New(shareCfg.AllowedPathPrefix[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
CNAME, err := url.Parse(shareCfg.BaseURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
minWidth := len(shareCfg.DNS) + 5 // add 5 spaces to account for "txt-"
|
||||||
|
w := new(tabwriter.Writer)
|
||||||
|
w.Init(os.Stdout, minWidth, minWidth, 0, '\t', 0)
|
||||||
|
defer func() {
|
||||||
|
err = errs.Combine(err, w.Flush())
|
||||||
|
}()
|
||||||
|
|
||||||
|
var printStorjRoot string
|
||||||
|
if p.Path() == "" {
|
||||||
|
printStorjRoot = fmt.Sprintf("txt-%s\tIN\tTXT \tstorj-root:%s", shareCfg.DNS, p.Bucket())
|
||||||
|
} else {
|
||||||
|
printStorjRoot = fmt.Sprintf("txt-%s\tIN\tTXT \tstorj-root:%s/%s", shareCfg.DNS, p.Bucket(), p.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("=========== DNS INFO =====================================================================")
|
||||||
|
fmt.Println("Remember to update the $ORIGIN with your domain name. You may also change the $TTL.")
|
||||||
|
fmt.Fprintln(w, "$ORIGIN example.com.")
|
||||||
|
fmt.Fprintln(w, "$TTL 3600")
|
||||||
|
fmt.Fprintf(w, "%s \tIN\tCNAME\t%s.\n", shareCfg.DNS, CNAME.Host)
|
||||||
|
fmt.Fprintln(w, printStorjRoot)
|
||||||
|
fmt.Fprintf(w, "txt-%s\tIN\tTXT \tstorj-access:%s\n", shareCfg.DNS, accessKey)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseHumanDate(date string, now time.Time) (time.Time, error) {
|
func parseHumanDate(date string, now time.Time) (time.Time, error) {
|
||||||
switch {
|
switch {
|
||||||
case date == "":
|
case date == "":
|
||||||
@ -71,105 +263,10 @@ func parseHumanDate(date string, now time.Time) (time.Time, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shareMain is the function executed when shareCmd is called.
|
// sharePrefixExtension is a temporary struct type. We might want to add hasTrailingSlash bool to `uplink.SharePrefix` directly.
|
||||||
func shareMain(cmd *cobra.Command, args []string) (err error) {
|
type sharePrefixExtension struct {
|
||||||
now := time.Now()
|
uplinkSharePrefix uplink.SharePrefix
|
||||||
notBefore, err := parseHumanDate(shareCfg.NotBefore, now)
|
hasTrailingSlash bool
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
notAfter, err := parseHumanDate(shareCfg.NotAfter, now)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(shareCfg.AllowedPathPrefix) == 0 {
|
|
||||||
// if the --allowed-path-prefix flag is not set,
|
|
||||||
// use any arguments as allowed path prefixes
|
|
||||||
for _, arg := range args {
|
|
||||||
shareCfg.AllowedPathPrefix = append(shareCfg.AllowedPathPrefix, strings.Split(arg, ",")...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sharePrefixes []uplink.SharePrefix
|
|
||||||
for _, path := range shareCfg.AllowedPathPrefix {
|
|
||||||
p, err := fpath.New(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if p.IsLocal() {
|
|
||||||
return errs.New("required path must be remote: %q", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
sharePrefixes = append(sharePrefixes, uplink.SharePrefix{
|
|
||||||
Bucket: p.Bucket(),
|
|
||||||
Prefix: p.Path(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
access, err := shareCfg.GetAccess()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
permission := uplink.Permission{}
|
|
||||||
permission.AllowDelete = !shareCfg.DisallowDeletes && !shareCfg.Readonly
|
|
||||||
permission.AllowList = !shareCfg.DisallowLists && !shareCfg.Writeonly
|
|
||||||
permission.AllowDownload = !shareCfg.DisallowReads && !shareCfg.Writeonly
|
|
||||||
permission.AllowUpload = !shareCfg.DisallowWrites && !shareCfg.Readonly
|
|
||||||
permission.NotBefore = notBefore
|
|
||||||
permission.NotAfter = notAfter
|
|
||||||
|
|
||||||
newAccess, err := access.Share(permission, sharePrefixes...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newAccessData, err := newAccess.Serialize()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
satelliteAddr, _, _, err := parseAccess(newAccessData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("Sharing access to satellite", satelliteAddr)
|
|
||||||
fmt.Println("=========== ACCESS RESTRICTIONS ==========================================================")
|
|
||||||
fmt.Println("Download :", formatPermission(permission.AllowDownload))
|
|
||||||
fmt.Println("Upload :", formatPermission(permission.AllowUpload))
|
|
||||||
fmt.Println("Lists :", formatPermission(permission.AllowList))
|
|
||||||
fmt.Println("Deletes :", formatPermission(permission.AllowDelete))
|
|
||||||
fmt.Println("NotBefore :", formatTimeRestriction(permission.NotBefore))
|
|
||||||
fmt.Println("NotAfter :", formatTimeRestriction(permission.NotAfter))
|
|
||||||
fmt.Println("Paths :", formatPaths(sharePrefixes))
|
|
||||||
fmt.Println("=========== SERIALIZED ACCESS WITH THE ABOVE RESTRICTIONS TO SHARE WITH OTHERS ===========")
|
|
||||||
fmt.Println("Access :", newAccessData)
|
|
||||||
|
|
||||||
if len(shareCfg.AllowedPathPrefix) == 1 && !permission.AllowUpload && !permission.AllowDelete {
|
|
||||||
fmt.Println("=========== BROWSER URL ==================================================================")
|
|
||||||
p, err := fpath.New(shareCfg.AllowedPathPrefix[0])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println("URL :", fmt.Sprintf("%s/%s/%s/%s", shareCfg.BaseURL,
|
|
||||||
url.PathEscape(newAccessData),
|
|
||||||
url.PathEscape(p.Bucket()),
|
|
||||||
url.PathEscape(p.Path())))
|
|
||||||
}
|
|
||||||
|
|
||||||
if shareCfg.ExportTo != "" {
|
|
||||||
// convert to an absolute path, mostly for output purposes.
|
|
||||||
exportTo, err := filepath.Abs(shareCfg.ExportTo)
|
|
||||||
if err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
if err := ioutil.WriteFile(exportTo, []byte(newAccessData+"\n"), 0600); err != nil {
|
|
||||||
return Error.Wrap(err)
|
|
||||||
}
|
|
||||||
fmt.Println("Exported to:", exportTo)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatPermission(allowed bool) string {
|
func formatPermission(allowed bool) string {
|
||||||
@ -186,19 +283,23 @@ func formatTimeRestriction(t time.Time) string {
|
|||||||
return formatTime(t)
|
return formatTime(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatPaths(sharePrefixes []uplink.SharePrefix) string {
|
func formatPaths(sharePrefixes []sharePrefixExtension) string {
|
||||||
if len(sharePrefixes) == 0 {
|
if len(sharePrefixes) == 0 {
|
||||||
return "WARNING! The entire project is shared!"
|
return "WARNING! The entire project is shared!"
|
||||||
}
|
}
|
||||||
|
|
||||||
var paths []string
|
var paths []string
|
||||||
for _, prefix := range sharePrefixes {
|
for _, prefix := range sharePrefixes {
|
||||||
path := "sj://" + prefix.Bucket
|
path := "sj://" + prefix.uplinkSharePrefix.Bucket
|
||||||
if len(prefix.Prefix) == 0 {
|
if len(prefix.uplinkSharePrefix.Prefix) == 0 {
|
||||||
path += " (entire bucket)"
|
path += "/ (entire bucket)"
|
||||||
} else {
|
} else {
|
||||||
path += "/" + prefix.Prefix
|
path += "/" + prefix.uplinkSharePrefix.Prefix
|
||||||
|
if prefix.hasTrailingSlash {
|
||||||
|
path += "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user