mirror of
https://github.com/minio/mc.git
synced 2025-11-12 01:02:26 +03:00
165 lines
5.0 KiB
Go
165 lines
5.0 KiB
Go
/*
|
||
* Minio Client (C) 2014, 2015 Minio, Inc.
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
package main
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/json"
|
||
"errors"
|
||
"fmt"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/fatih/color"
|
||
"github.com/minio/cli"
|
||
"github.com/minio/mc/pkg/client"
|
||
"github.com/minio/mc/pkg/console"
|
||
"github.com/minio/minio/pkg/probe"
|
||
)
|
||
|
||
// Help message.
|
||
var shareCmd = cli.Command{
|
||
Name: "share",
|
||
Usage: "Share documents via URL",
|
||
Action: mainShare,
|
||
CustomHelpTemplate: `NAME:
|
||
mc {{.Name}} - {{.Usage}}
|
||
|
||
USAGE:
|
||
mc {{.Name}} TARGET [DURATION=s|m|h|d] {{if .Description}}
|
||
|
||
DESCRIPTION:
|
||
{{.Description}}{{end}}{{if .Flags}}
|
||
|
||
FLAGS:
|
||
{{range .Flags}}{{.}}
|
||
{{end}}{{ end }}
|
||
|
||
EXAMPLES:
|
||
1. Generate URL for sharing, with a default expiry of 7 days.
|
||
$ mc {{.Name}} https://s3.amazonaws.com/backup/2006-Mar-1/backup.tar.gz
|
||
|
||
2. Generate URL for sharing, with an expiry of 10 minutes.
|
||
$ mc {{.Name}} https://s3.amazonaws.com/backup/2006-Mar-1/backup.tar.gz 10m
|
||
|
||
3. Generate list of URLs for sharing a folder recursively, with expiration of 1 hour each.
|
||
$ mc {{.Name}} https://s3.amazonaws.com/backup... 1h
|
||
|
||
`,
|
||
}
|
||
|
||
// mainShare - is a handler for mc share command
|
||
func mainShare(ctx *cli.Context) {
|
||
if !ctx.Args().Present() || ctx.Args().First() == "help" || len(ctx.Args()) > 2 {
|
||
cli.ShowCommandHelpAndExit(ctx, "share", 1) // last argument is exit code
|
||
}
|
||
console.SetCustomTheme(map[string]*color.Color{
|
||
"Share": color.New(color.FgGreen, color.Bold),
|
||
})
|
||
args := ctx.Args()
|
||
config := mustGetMcConfig()
|
||
/// get first and last arguments
|
||
url := args.First() // url to be shared
|
||
// default expiration is 7days
|
||
expires := time.Duration(604800) * time.Second
|
||
if len(args) == 2 {
|
||
var err error
|
||
expires, err = time.ParseDuration(args.Last())
|
||
fatalIf(probe.NewError(err), "Unable to parse time argument.")
|
||
}
|
||
targetURL, err := getCanonicalizedURL(url, config.Aliases)
|
||
fatalIf(err.Trace(url), "Unable to parse argument ‘"+url+"’.")
|
||
|
||
// if recursive strip off the "..."
|
||
err = doShareCmd(stripRecursiveURL(targetURL), isURLRecursive(targetURL), expires)
|
||
fatalIf(err.Trace(targetURL), "Unable generate URL for sharing.")
|
||
}
|
||
|
||
// ShareMessage container for share messages
|
||
type ShareMessage struct {
|
||
Expires time.Duration `json:"expire-seconds"`
|
||
PresignedURL string `json:"presigned-url"`
|
||
}
|
||
|
||
// String string printer for share message
|
||
func (s ShareMessage) String() string {
|
||
if !globalJSONFlag {
|
||
return console.Colorize("Share", fmt.Sprintf("Succesfully generated shared URL with expiry %s, please share: %s", s.Expires, s.PresignedURL))
|
||
}
|
||
shareMessageBytes, err := json.Marshal(s)
|
||
fatalIf(probe.NewError(err), "Failed to marshal into JSON.")
|
||
|
||
// json encoding escapes ampersand into its unicode character which is not usable directly for share
|
||
// and fails with cloud storage. convert them back so that they are usable
|
||
shareMessageBytes = bytes.Replace(shareMessageBytes, []byte("\\u0026"), []byte("&"), -1)
|
||
return string(shareMessageBytes)
|
||
}
|
||
|
||
func getNewTargetURL(targetParser *client.URL, name string) string {
|
||
match, _ := filepath.Match("*.s3*.amazonaws.com", targetParser.Host)
|
||
if match {
|
||
targetParser.Path = string(targetParser.Separator) + name
|
||
} else {
|
||
targetParser.Path = string(targetParser.Separator) + path2Bucket(targetParser) + string(targetParser.Separator) + name
|
||
}
|
||
return targetParser.String()
|
||
}
|
||
|
||
// doShareCmd share files from target
|
||
func doShareCmd(targetURL string, recursive bool, expires time.Duration) *probe.Error {
|
||
clnt, err := target2Client(targetURL)
|
||
if err != nil {
|
||
return err.Trace()
|
||
}
|
||
if expires.Seconds() < 1 {
|
||
return probe.NewError(errors.New("Too low expires, expiration cannot be less than 1 second."))
|
||
}
|
||
if expires.Seconds() > 604800 {
|
||
return probe.NewError(errors.New("Too high expires, expiration cannot be larger than 7 days."))
|
||
}
|
||
for contentCh := range clnt.List(recursive) {
|
||
if contentCh.Err != nil {
|
||
return contentCh.Err.Trace()
|
||
}
|
||
newClnt, err := url2Client(getNewTargetURL(clnt.URL(), contentCh.Content.Name))
|
||
if err != nil {
|
||
return err.Trace()
|
||
}
|
||
presignedURL, err := newClnt.Share(expires)
|
||
if err != nil {
|
||
return err.Trace()
|
||
}
|
||
console.Println(ShareMessage{Expires: expires / time.Second, PresignedURL: presignedURL}.String())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func path2Bucket(u *client.URL) (bucketName string) {
|
||
pathSplits := strings.SplitN(u.Path, "?", 2)
|
||
splits := strings.SplitN(pathSplits[0], string(u.Separator), 3)
|
||
switch len(splits) {
|
||
case 0, 1:
|
||
bucketName = ""
|
||
case 2:
|
||
bucketName = splits[1]
|
||
case 3:
|
||
bucketName = splits[1]
|
||
}
|
||
return bucketName
|
||
}
|