2021-10-10 10:48:53 +08:00
|
|
|
|
// Copyright (c) 2020 tickstep.
|
|
|
|
|
//
|
|
|
|
|
// 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 command
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"github.com/tickstep/aliyunpan-api/aliyunpan"
|
2022-12-10 14:07:28 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan-api/aliyunpan/apierror"
|
|
|
|
|
"github.com/tickstep/aliyunpan/cmder/cmdliner"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/internal/config"
|
2022-12-10 14:07:28 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/internal/functions/panlogin"
|
2022-12-07 17:35:03 +08:00
|
|
|
|
"github.com/tickstep/aliyunpan/internal/plugins"
|
|
|
|
|
"github.com/tickstep/aliyunpan/internal/utils"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"github.com/tickstep/library-go/logger"
|
2022-12-10 14:07:28 +08:00
|
|
|
|
"github.com/urfave/cli"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"math/rand"
|
2021-12-29 19:33:46 +08:00
|
|
|
|
"net/url"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"path"
|
2022-10-07 12:11:34 +08:00
|
|
|
|
"path/filepath"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"strings"
|
2022-12-10 14:07:28 +08:00
|
|
|
|
"sync"
|
2021-10-10 10:48:53 +08:00
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
panCommandVerbose = logger.New("PANCOMMAND", config.EnvVerbose)
|
2022-12-10 14:07:28 +08:00
|
|
|
|
|
|
|
|
|
saveConfigMutex *sync.Mutex = new(sync.Mutex)
|
|
|
|
|
|
|
|
|
|
ReloadConfigFunc = func(c *cli.Context) error {
|
|
|
|
|
err := config.Config.Reload()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("重载配置错误: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SaveConfigFunc = func(c *cli.Context) error {
|
|
|
|
|
saveConfigMutex.Lock()
|
|
|
|
|
defer saveConfigMutex.Unlock()
|
|
|
|
|
err := config.Config.Save()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("保存配置错误: %s\n", err)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2021-10-10 10:48:53 +08:00
|
|
|
|
)
|
|
|
|
|
|
2022-12-05 16:56:17 +08:00
|
|
|
|
// RunTestShellPattern 执行测试通配符
|
|
|
|
|
func RunTestShellPattern(driveId string, pattern string) {
|
|
|
|
|
acUser := GetActiveUser()
|
|
|
|
|
files, err := acUser.PanClient().MatchPathByShellPattern(driveId, GetActiveUser().PathJoin(driveId, pattern))
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for _, f := range *files {
|
|
|
|
|
fmt.Printf("%s\n", f.Path)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// matchPathByShellPattern 通配符匹配路径,允许返回多个匹配结果
|
|
|
|
|
func matchPathByShellPattern(driveId string, patterns ...string) (files []*aliyunpan.FileEntity, e error) {
|
|
|
|
|
acUser := GetActiveUser()
|
|
|
|
|
for k := range patterns {
|
|
|
|
|
ps, err := acUser.PanClient().MatchPathByShellPattern(driveId, acUser.PathJoin(driveId, patterns[k]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
files = append(files, *ps...)
|
|
|
|
|
}
|
|
|
|
|
return files, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// makePathAbsolute 拼接路径,确定返回路径为绝对路径
|
|
|
|
|
func makePathAbsolute(driveId string, patterns ...string) (panpaths []string, err error) {
|
2021-10-10 10:48:53 +08:00
|
|
|
|
acUser := GetActiveUser()
|
|
|
|
|
for k := range patterns {
|
|
|
|
|
ps := acUser.PathJoin(driveId, patterns[k])
|
|
|
|
|
panpaths = append(panpaths, ps)
|
|
|
|
|
}
|
|
|
|
|
return panpaths, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func RandomStr(count int) string {
|
|
|
|
|
//STR_SET := "abcdefjhijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ1234567890"
|
|
|
|
|
STR_SET := "abcdefjhijklmnopqrstuvwxyz1234567890"
|
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
|
str := strings.Builder{}
|
2022-06-20 17:28:25 +08:00
|
|
|
|
for i := 0; i < count; i++ {
|
2021-10-10 10:48:53 +08:00
|
|
|
|
str.WriteByte(byte(STR_SET[rand.Intn(len(STR_SET))]))
|
|
|
|
|
}
|
|
|
|
|
return str.String()
|
2021-10-31 15:53:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func GetAllPathFolderByPath(pathStr string) []string {
|
|
|
|
|
dirNames := strings.Split(pathStr, "/")
|
|
|
|
|
dirs := []string{}
|
|
|
|
|
p := "/"
|
|
|
|
|
dirs = append(dirs, p)
|
2022-06-20 17:28:25 +08:00
|
|
|
|
for _, s := range dirNames {
|
2021-10-31 15:53:27 +08:00
|
|
|
|
p = path.Join(p, s)
|
|
|
|
|
dirs = append(dirs, p)
|
|
|
|
|
}
|
|
|
|
|
return dirs
|
2021-12-29 19:33:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EscapeStr 转义字符串
|
|
|
|
|
func EscapeStr(s string) string {
|
|
|
|
|
return url.PathEscape(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnescapeStr 反转义字符串
|
|
|
|
|
func UnescapeStr(s string) string {
|
2022-06-20 17:28:25 +08:00
|
|
|
|
r, _ := url.PathUnescape(s)
|
2021-12-29 19:33:46 +08:00
|
|
|
|
return r
|
2022-01-16 14:21:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RefreshTokenInNeed 刷新refresh token
|
2023-02-16 22:25:09 +08:00
|
|
|
|
func RefreshTokenInNeed(activeUser *config.PanUser, deviceName string) bool {
|
2022-01-16 14:21:20 +08:00
|
|
|
|
if activeUser == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// refresh expired token
|
|
|
|
|
if activeUser.PanClient() != nil {
|
|
|
|
|
if len(activeUser.WebToken.RefreshToken) > 0 {
|
|
|
|
|
cz := time.FixedZone("CST", 8*3600) // 东8区
|
|
|
|
|
expiredTime, _ := time.ParseInLocation("2006-01-02 15:04:05", activeUser.WebToken.ExpireTime, cz)
|
|
|
|
|
now := time.Now()
|
2022-09-24 15:09:31 +08:00
|
|
|
|
if (expiredTime.Unix() - now.Unix()) <= (20 * 60) { // 20min
|
2022-12-13 09:53:29 +08:00
|
|
|
|
pluginManger := plugins.NewPluginManager(config.GetPluginDir())
|
|
|
|
|
plugin, _ := pluginManger.GetPlugin()
|
|
|
|
|
params := &plugins.UserTokenRefreshFinishParams{
|
|
|
|
|
Result: "success",
|
|
|
|
|
Message: "",
|
|
|
|
|
OldToken: "",
|
|
|
|
|
NewToken: "",
|
|
|
|
|
UpdatedAt: utils.NowTimeStr(),
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-16 14:21:20 +08:00
|
|
|
|
// need update refresh token
|
|
|
|
|
logger.Verboseln("access token expired, get new from refresh token")
|
|
|
|
|
if wt, er := aliyunpan.GetAccessTokenFromRefreshToken(activeUser.RefreshToken); er == nil {
|
2022-12-12 14:07:58 +08:00
|
|
|
|
params.Result = "success"
|
|
|
|
|
params.OldToken = activeUser.RefreshToken
|
|
|
|
|
params.NewToken = wt.RefreshToken
|
|
|
|
|
|
2022-12-07 17:09:24 +08:00
|
|
|
|
activeUser.RefreshToken = wt.RefreshToken
|
2022-01-16 14:21:20 +08:00
|
|
|
|
activeUser.WebToken = *wt
|
|
|
|
|
activeUser.PanClient().UpdateToken(*wt)
|
|
|
|
|
logger.Verboseln("get new access token success")
|
2022-12-12 14:07:58 +08:00
|
|
|
|
|
|
|
|
|
// plugin callback
|
|
|
|
|
if er1 := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(activeUser), params); er1 != nil {
|
|
|
|
|
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er1.Error())
|
|
|
|
|
}
|
2023-02-16 22:25:09 +08:00
|
|
|
|
|
2023-02-19 17:36:23 +08:00
|
|
|
|
// create new signature
|
2023-02-16 22:25:09 +08:00
|
|
|
|
_, e := activeUser.PanClient().CreateSession(&aliyunpan.CreateSessionParam{
|
|
|
|
|
DeviceName: deviceName,
|
|
|
|
|
ModelName: "Windows网页版",
|
|
|
|
|
})
|
|
|
|
|
if e != nil {
|
|
|
|
|
logger.Verboseln("call CreateSession error in RefreshTokenInNeed: " + e.Error())
|
|
|
|
|
}
|
2022-01-16 14:21:20 +08:00
|
|
|
|
return true
|
2022-12-07 17:24:02 +08:00
|
|
|
|
} else {
|
|
|
|
|
// token refresh error
|
2022-12-07 17:35:03 +08:00
|
|
|
|
// if token has expired, callback plugin api for notify
|
|
|
|
|
if now.Unix() >= expiredTime.Unix() {
|
2022-12-12 14:07:58 +08:00
|
|
|
|
params.Result = "fail"
|
|
|
|
|
params.Message = er.Error()
|
|
|
|
|
params.OldToken = activeUser.RefreshToken
|
2022-12-07 17:35:03 +08:00
|
|
|
|
if er1 := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(activeUser), params); er1 != nil {
|
|
|
|
|
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er1.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-16 14:21:20 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
2022-06-20 17:28:25 +08:00
|
|
|
|
}
|
2022-09-24 15:09:31 +08:00
|
|
|
|
|
2022-10-07 12:11:34 +08:00
|
|
|
|
func isIncludeFile(pattern string, fileName string) bool {
|
|
|
|
|
b, er := filepath.Match(pattern, fileName)
|
|
|
|
|
if er != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return b
|
|
|
|
|
}
|
2022-10-14 09:16:35 +08:00
|
|
|
|
|
|
|
|
|
// isMatchWildcardPattern 是否是统配符字符串
|
|
|
|
|
func isMatchWildcardPattern(name string) bool {
|
|
|
|
|
return strings.ContainsAny(name, "*") || strings.ContainsAny(name, "?") || strings.ContainsAny(name, "[")
|
|
|
|
|
}
|
2022-12-10 14:07:28 +08:00
|
|
|
|
|
|
|
|
|
// DoLoginHelper 登录助手,使用token进行登录
|
|
|
|
|
func DoLoginHelper(refreshToken string) (refreshTokenStr string, webToken aliyunpan.WebLoginToken, error error) {
|
|
|
|
|
line := cmdliner.NewLiner()
|
|
|
|
|
defer line.Close()
|
|
|
|
|
|
|
|
|
|
if refreshToken == "" {
|
|
|
|
|
refreshToken, error = line.State.Prompt("请输入RefreshToken, 回车键提交 > ")
|
|
|
|
|
if error != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// app login
|
|
|
|
|
atoken, apperr := aliyunpan.GetAccessTokenFromRefreshToken(refreshToken)
|
|
|
|
|
if apperr != nil {
|
|
|
|
|
if apperr.Code == apierror.ApiCodeTokenExpiredCode || apperr.Code == apierror.ApiCodeRefreshTokenExpiredCode {
|
|
|
|
|
fmt.Println("Token过期,需要重新登录")
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println("Token登录失败:", apperr)
|
|
|
|
|
}
|
|
|
|
|
return "", webToken, fmt.Errorf("登录失败")
|
|
|
|
|
}
|
|
|
|
|
refreshTokenStr = refreshToken
|
|
|
|
|
return refreshTokenStr, *atoken, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TryLogin 尝试登录,基础应用支持的各类登录方式进行尝试成功登录
|
|
|
|
|
func TryLogin() *config.PanUser {
|
2022-12-10 14:47:00 +08:00
|
|
|
|
// 获取当前插件
|
|
|
|
|
pluginManger := plugins.NewPluginManager(config.GetPluginDir())
|
|
|
|
|
plugin, _ := pluginManger.GetPlugin()
|
|
|
|
|
params := &plugins.UserTokenRefreshFinishParams{
|
|
|
|
|
Result: "success",
|
|
|
|
|
Message: "",
|
|
|
|
|
OldToken: "",
|
|
|
|
|
NewToken: "",
|
|
|
|
|
UpdatedAt: utils.NowTimeStr(),
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-10 14:07:28 +08:00
|
|
|
|
// can do automatically login?
|
|
|
|
|
for _, u := range config.Config.UserList {
|
|
|
|
|
if u.UserId == config.Config.ActiveUID {
|
|
|
|
|
// login
|
|
|
|
|
_, webToken, err := DoLoginHelper(u.RefreshToken)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Verboseln("automatically login use saved refresh token error ", err)
|
|
|
|
|
if u.TokenId != "" {
|
|
|
|
|
logger.Verboseln("try to login use tokenId")
|
|
|
|
|
h := panlogin.NewLoginHelper(config.DefaultTokenServiceWebHost)
|
|
|
|
|
r, e := h.GetRefreshToken(u.TokenId)
|
|
|
|
|
if e != nil {
|
|
|
|
|
logger.Verboseln("try to login use tokenId error", e)
|
2022-12-10 14:47:00 +08:00
|
|
|
|
// login fail plugin callback
|
|
|
|
|
params.Result = "fail"
|
|
|
|
|
params.OldToken = u.RefreshToken
|
|
|
|
|
params.NewToken = ""
|
|
|
|
|
if er := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(u), params); er != nil {
|
|
|
|
|
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er.Error())
|
|
|
|
|
}
|
2022-12-10 14:07:28 +08:00
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
refreshToken, e := h.ParseSecureRefreshToken("", r.SecureRefreshToken)
|
|
|
|
|
if e != nil {
|
|
|
|
|
logger.Verboseln("try to parse refresh token error", e)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
_, webToken, err = DoLoginHelper(refreshToken)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Verboseln("try to use refresh token from tokenId error", e)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("Token重新自动登录成功")
|
|
|
|
|
// save new refresh token
|
|
|
|
|
u.RefreshToken = refreshToken
|
2022-12-10 14:47:00 +08:00
|
|
|
|
} else {
|
|
|
|
|
// login fail plugin callback
|
|
|
|
|
params.Result = "fail"
|
|
|
|
|
params.OldToken = u.RefreshToken
|
|
|
|
|
params.NewToken = ""
|
|
|
|
|
if er := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(u), params); er != nil {
|
|
|
|
|
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er.Error())
|
|
|
|
|
}
|
2022-12-10 14:07:28 +08:00
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
2022-12-10 14:47:00 +08:00
|
|
|
|
// plugin param
|
|
|
|
|
params.Result = "success"
|
|
|
|
|
params.OldToken = u.RefreshToken
|
|
|
|
|
params.NewToken = webToken.RefreshToken
|
|
|
|
|
|
|
|
|
|
// success login, save new token and access token
|
|
|
|
|
u.RefreshToken = webToken.RefreshToken
|
2022-12-10 14:07:28 +08:00
|
|
|
|
u.WebToken = webToken
|
|
|
|
|
|
|
|
|
|
// save
|
|
|
|
|
SaveConfigFunc(nil)
|
|
|
|
|
// reload
|
|
|
|
|
ReloadConfigFunc(nil)
|
2022-12-10 14:47:00 +08:00
|
|
|
|
|
|
|
|
|
// do plugin callback
|
|
|
|
|
if er := plugin.UserTokenRefreshFinishCallback(plugins.GetContext(u), params); er != nil {
|
|
|
|
|
logger.Verbosef("UserTokenRefreshFinishCallback error: " + er.Error())
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-10 14:07:28 +08:00
|
|
|
|
return config.Config.ActiveUser()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|