From 285c28e7c8da1ad9ce705f8588b999b7a21d4129 Mon Sep 17 00:00:00 2001 From: public_host Date: Tue, 1 Dec 2020 13:26:36 +0800 Subject: [PATCH] init --- .gitignore | 6 +- README.md | 15 +++ build/init.bat | 2 + build/make-key.bat | 2 + build/upload.bat | 2 + main.go | 325 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 build/init.bat create mode 100644 build/make-key.bat create mode 100644 build/upload.bat create mode 100644 main.go diff --git a/.gitignore b/.gitignore index 9a3a8d8..d1baad6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# ---> Go # Binaries for programs and plugins *.exe *.exe~ @@ -6,9 +5,12 @@ *.so *.dylib -# Test binary, build with `go test -c` +# Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Dependency directories (remove the comment below to include it) +# vendor/ +.idea \ No newline at end of file diff --git a/README.md b/README.md index ccdf040..f240e5f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ # qcloudcos +```sh + +# 生成key +> qcloudcos -op make-key + +# 设置key +> qcloudcos -op set-key + +# 上传文件夹 +> qcloudcos -op upload -path ./foo + +# 查看文件夹信息 +> qcloudcos -op list + +``` \ No newline at end of file diff --git a/build/init.bat b/build/init.bat new file mode 100644 index 0000000..cf4fd77 --- /dev/null +++ b/build/init.bat @@ -0,0 +1,2 @@ + %~dp0qcloudcos -op set-key + pause \ No newline at end of file diff --git a/build/make-key.bat b/build/make-key.bat new file mode 100644 index 0000000..c00cbc5 --- /dev/null +++ b/build/make-key.bat @@ -0,0 +1,2 @@ + %~dp0qcloudcos -op make-key + pause \ No newline at end of file diff --git a/build/upload.bat b/build/upload.bat new file mode 100644 index 0000000..6b6e428 --- /dev/null +++ b/build/upload.bat @@ -0,0 +1,2 @@ + %~dp0qcloudcos -op upload -path %1 +pause \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..6afdeb0 --- /dev/null +++ b/main.go @@ -0,0 +1,325 @@ +package main + +import ( + "bytes" + "context" + "encoding/base64" + "encoding/json" + "errors" + "flag" + "fmt" + "github.com/AlecAivazis/survey" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/wailovet/osmanthuswine/src/helper" + "io/ioutil" + "net/http" + "net/url" + "os" + "os/exec" + "os/user" + "path/filepath" + "runtime" + "strings" +) + +var config TencentYunConfig + +var op string +var path string +var key string + +func loadKey() { + homePath, err := home() + if err != nil { + fmt.Println("错误 102: ", err) + return + } + keyFile := filepath.Join(homePath, ".qcloud-key") + data, _ := ioutil.ReadFile(keyFile) + if string(data) == "" { + fmt.Println("错误 204 找不到key,请使用使用set-key进行初始化.") + return + } + key = string(data) +} + +func initKey() { + + if key == "" { + fmt.Println("key is empty!") + os.Exit(1) + } + var err error + var dekey []byte + dekey, err = base64.StdEncoding.DecodeString(key) + if err != nil { + fmt.Println("错误 201:", err) + os.Exit(1) + } + + dekey, err = helper.DefaultAesDecrypt(dekey) + if err != nil { + fmt.Println("错误 202:", err) + os.Exit(1) + } + err = json.Unmarshal(dekey, &config) + if err != nil { + fmt.Println("错误 203:", err) + os.Exit(1) + } +} + +func main() { + + helper.AesKey = []byte("3136352472abcdef") + flag.StringVar(&op, "op", "", "操作:make-key[生成密钥] | set-key[设置密钥] | upload [上传文件] | list [获取文件]") + flag.StringVar(&path, "path", "", "上传目录") + flag.StringVar(&key, "key", "", "key") + flag.Parse() + + switch op { + case "set-key": + key = askText("输入key") + initKey() + _, err := getTencentYunCosFiles("") + if err != nil { + fmt.Println("key error 101:", err) + return + } + + homePath, err := home() + if err != nil { + fmt.Println("错误 102:", err) + return + } + keyFile := filepath.Join(homePath, ".qcloud-key") + err = ioutil.WriteFile(keyFile, []byte(key), 0644) + if err != nil { + fmt.Println("错误 103:", err) + return + } + + fmt.Println("完成!") + case "make-key": + config.SecretID = askText("输入SecretID") + config.SecretKey = askText("输入SecretKey") + config.BucketURL = askText("输入BucketURL") + config.Root = askText("输入Root") + + mkey, err := helper.DefaultAesEncrypt([]byte(helper.JsonEncode(config))) + if err != nil { + fmt.Println("错误 104:", err) + return + } + mkey = []byte(base64.StdEncoding.EncodeToString(mkey)) + fmt.Println("key:", string(mkey), " ==> ", "key.txt") + _ = ioutil.WriteFile("key.txt", mkey, 0644) + os.Exit(0) + case "upload": + loadKey() + initKey() + + if path != "" { + url := UploadDir(path) + fmt.Println("url:", url) + } else { + flag.Usage() + } + case "list": + loadKey() + initKey() + for { + data, err := getTencentYunCosFiles(path) + if err != nil { + fmt.Println("错误 106:", err) + return + } + //for e := range data.CommonPrefixes { + // fmt.Println(data.CommonPrefixes[e]) + //} + var files []string + for e := range data.Contents { + files = append(files, data.Contents[e].Key) + } + _, menu := askSelect("Path:"+path, append([]string{".."}, append(data.CommonPrefixes, files...)...)...) + if menu == ".." { + pathSplit := strings.Split(path, "/") + if len(pathSplit) > 1 { + path = strings.Join(pathSplit[0:len(pathSplit)-1], "/") + } else { + path = "" + } + } else { + path = menu + } + } + + default: + flag.Usage() + } +} + +type TencentYunConfig struct { + SecretID string + SecretKey string + SessionToken string + BucketURL string + Root string +} + +var client *cos.Client + +func getTencentYunConf(c *TencentYunConfig) *cos.Client { + if client == nil { + BucketURL, _ := url.Parse(c.BucketURL) + b := &cos.BaseURL{ + BucketURL: BucketURL, + } + // 1.永久密钥 + client = cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: c.SecretID, + SecretKey: c.SecretKey, + }, + }) + } + + return client +} + +func getTencentYunCosFiles(prefix string) (*cos.BucketGetResult, error) { + + // 1.永久密钥 + client := getTencentYunConf(&config) + + res, _, err := client.Bucket.Get(context.Background(), &cos.BucketGetOptions{ + Prefix: prefix, + Delimiter: "/", + }) + if err != nil { + return nil, err + } + return res, nil +} + +func UploadDir(fpath string, qpaths ...string) string { + qpath := "" + if len(qpaths) > 0 { + qpath = qpaths[0] + } else { + separator := "/" + if runtime.GOOS == "windows" { + separator = `\` + } + separatordir := strings.Split(fpath, separator) + if len(separatordir) > 0 { + qpath = separatordir[len(separatordir)-1] + } + } + client := getTencentYunConf(&config) + + files, _ := ioutil.ReadDir(fpath) + for _, f := range files { + if f.Name()[0] == '.' { + continue + } + if f.IsDir() { + UploadDir(filepath.Join(fpath, f.Name()), filepath.Join(qpath, f.Name())) + } else { + filename := filepath.Join(fpath, f.Name()) + fmt.Print("上传:", filename, " ==> ", filepath.Join(config.Root, filename), " ") + _, err := client.Object.PutFromFile(context.Background(), strings.Replace(filepath.Join(config.Root, qpath, f.Name()), `\`, `/`, -1), filename, nil) + if err != nil { + fmt.Println("错误 105:", err) + } else { + fmt.Println("完成") + } + } + } + + return config.BucketURL + "/" + strings.Replace(filepath.Join(config.Root, qpath), `\`, `/`, -1) +} + +func askSelect(title string, v ...string) (int, string) { + + result := -1 + prompt := &survey.Select{ + Message: title, + Options: v, + } + + err := survey.AskOne(prompt, &result) + if err != nil { + return 0, "" + } + + if result == -1 { + return askSelect(title, v...) + } + return result, v[result] +} + +func askText(title string) string { + result := "" + prompt := &survey.Input{ + Message: title, + } + survey.AskOne(prompt, &result) + + if result == "" { + fmt.Println("不允许为空") + return askText(title) + } + return result +} +func home() (string, error) { + user, err := user.Current() + if nil == err { + return user.HomeDir, nil + } + + // cross compile support + + if "windows" == runtime.GOOS { + return homeWindows() + } + + // Unix-like system, so just assume Unix + return homeUnix() +} + +func homeUnix() (string, error) { + // First prefer the HOME environmental variable + if home := os.Getenv("HOME"); home != "" { + return home, nil + } + + // If that fails, try the shell + var stdout bytes.Buffer + cmd := exec.Command("sh", "-c", "eval echo ~$USER") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return "", err + } + + result := strings.TrimSpace(stdout.String()) + if result == "" { + return "", errors.New("blank output when reading home directory") + } + + return result, nil +} + +func homeWindows() (string, error) { + drive := os.Getenv("HOMEDRIVE") + path := os.Getenv("HOMEPATH") + home := drive + path + if drive == "" || path == "" { + home = os.Getenv("USERPROFILE") + } + if home == "" { + return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") + } + + return home, nil +}