From 8a15810b46b9a2fa86355639d8c2da4ae0d6e3c0 Mon Sep 17 00:00:00 2001 From: YangXu <2945065490@qq.com> Date: Sat, 20 Jul 2024 09:38:15 +0800 Subject: [PATCH] fix(aliyundrive_open): add aliyundrive_tv auth --- drivers/aliyundrive_open/driver.go | 12 ++++ drivers/aliyundrive_open/meta.go | 4 +- drivers/aliyundrive_open/types.go | 27 +++++++++ drivers/aliyundrive_open/util.go | 92 +++++++++++++++++++++++++++++- 4 files changed, 133 insertions(+), 2 deletions(-) diff --git a/drivers/aliyundrive_open/driver.go b/drivers/aliyundrive_open/driver.go index 4029ad57c37..e4e2e4d903b 100644 --- a/drivers/aliyundrive_open/driver.go +++ b/drivers/aliyundrive_open/driver.go @@ -42,6 +42,18 @@ func (d *AliyundriveOpen) Init(ctx context.Context) error { if d.DriveType == "" { d.DriveType = "default" } + if d.UseTVAuth && d.RefreshToken == "" { + if d.SID != "" { + // 查询 对应的 authCode --> 获取 access_token refresh_token + err := d.getRefreshTokenBySID() + if err != nil { + return err + } + } else { + // 发送 qcode 请求 获取 sid + return d.getSID() + } + } res, err := d.request("/adrive/v1.0/user/getDriveInfo", http.MethodPost, nil) if err != nil { return err diff --git a/drivers/aliyundrive_open/meta.go b/drivers/aliyundrive_open/meta.go index de9b45e01d6..31115417a69 100644 --- a/drivers/aliyundrive_open/meta.go +++ b/drivers/aliyundrive_open/meta.go @@ -8,7 +8,7 @@ import ( type Addition struct { DriveType string `json:"drive_type" type:"select" options:"default,resource,backup" default:"default"` driver.RootID - RefreshToken string `json:"refresh_token" required:"true"` + RefreshToken string `json:"refresh_token"` OrderBy string `json:"order_by" type:"select" options:"name,size,updated_at,created_at"` OrderDirection string `json:"order_direction" type:"select" options:"ASC,DESC"` OauthTokenURL string `json:"oauth_token_url" default:"https://api.nn.ci/alist/ali_open/token"` @@ -19,6 +19,8 @@ type Addition struct { InternalUpload bool `json:"internal_upload" help:"If you are using Aliyun ECS is located in Beijing, you can turn it on to boost the upload speed"` LIVPDownloadFormat string `json:"livp_download_format" type:"select" options:"jpeg,mov" default:"jpeg"` AccessToken string + UseTVAuth bool `json:"use_tv_auth"` + SID string `json:"sid"` } var config = driver.Config{ diff --git a/drivers/aliyundrive_open/types.go b/drivers/aliyundrive_open/types.go index 46830a51336..9a45737d06a 100644 --- a/drivers/aliyundrive_open/types.go +++ b/drivers/aliyundrive_open/types.go @@ -82,3 +82,30 @@ type MoveOrCopyResp struct { DriveID string `json:"drive_id"` FileID string `json:"file_id"` } + +type SIDResp struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + QRCodeURL string `json:"qrCodeUrl"` + SID string `json:"sid"` + } `json:"data"` +} + +type RefreshTokenSIDResp struct { + Status string `json:"status"` + AuthCode string `json:"authCode"` +} + +type RefreshTokenAuthResp struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + Code string `json:"code"` + Message string `json:"message"` + TokenType string `json:"token_type"` + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIN int `json:"expires_in"` + } +} diff --git a/drivers/aliyundrive_open/util.go b/drivers/aliyundrive_open/util.go index 331e6400c97..29bcf134672 100644 --- a/drivers/aliyundrive_open/util.go +++ b/drivers/aliyundrive_open/util.go @@ -119,7 +119,11 @@ func (d *AliyundriveOpen) requestReturnErrResp(uri, method string, callback base isRetry := len(retry) > 0 && retry[0] if e.Code != "" { if !isRetry && (utils.SliceContains([]string{"AccessTokenInvalid", "AccessTokenExpired", "I400JD"}, e.Code) || d.AccessToken == "") { - err = d.refreshToken() + if d.UseTVAuth { + err = d.getRefreshTokenByTV(d.RefreshToken, true) + } else { + err = d.refreshToken() + } if err != nil { return nil, err, nil } @@ -176,3 +180,89 @@ func getNowTime() (time.Time, string) { nowTimeStr := nowTime.Format("2006-01-02T15:04:05.000Z") return nowTime, nowTimeStr } + +func (d *AliyundriveOpen) getSID() error { + url := "http://api.extscreen.com/aliyundrive/qrcode" + var resp SIDResp + _, err := base.RestyClient.R(). + SetBody(base.Json{ + "scopes": "user:base,file:all:read,file:all:write", + "width": 500, + "height": 500, + }). + SetResult(&resp). + Post(url) + if err != nil { + return err + } + d.SID = resp.Data.SID + op.MustSaveDriverStorage(d) + authURL := fmt.Sprintf("https://www.aliyundrive.com/o/oauth/authorize?sid=%s", resp.Data.SID) + return fmt.Errorf(`need verify: Click Here`, authURL) +} + +func (d *AliyundriveOpen) getRefreshTokenBySID() error { + // 获取 authCode + authCode := "" + url := "https://openapi.alipan.com/oauth/qrcode/" + d.SID + "/status" + time.Sleep(time.Second) // 等待 阿里云盘那边更新SID状态 + var resp RefreshTokenSIDResp + _, err := base.RestyClient.R(). + SetResult(&resp). + Get(url) + if err != nil { + return err + } + if resp.Status != "LoginSuccess" { + return fmt.Errorf("failed to get auth code: %s", resp.Status) + + } else { + authCode = resp.AuthCode + } + return d.getRefreshTokenByTV(authCode, false) +} + +func (d *AliyundriveOpen) getRefreshTokenByTV(code string, isRefresh bool) error { + refresh, access, err := d._getRefreshTokenByTV(code, isRefresh) + for i := 0; i < 3; i++ { + if err == nil { + break + } else { + log.Errorf("[ali_open] failed to refresh token: %s", err) + } + refresh, access, err = d._getRefreshTokenByTV(code, isRefresh) + } + if err != nil { + return err + } + log.Infof("[ali_open] token exchange: %s -> %s", d.RefreshToken, refresh) + d.RefreshToken, d.AccessToken = refresh, access + op.MustSaveDriverStorage(d) + return nil +} + +func (d *AliyundriveOpen) _getRefreshTokenByTV(code string, isRefresh bool) (refreshToken, accessToken string, err error) { + url := "http://api.extscreen.com/aliyundrive/token" + var resp RefreshTokenAuthResp + body := "" + if isRefresh { + body = fmt.Sprintf("refresh_token=%s", code) + } else { + body = fmt.Sprintf("code=%s", code) + } + + res, err := base.RestyClient.R(). + SetHeader("Content-Type", "application/x-www-form-urlencoded"). + SetBody(body). + SetResult(&resp). + Post(url) + if err != nil { + return "", "", err + } + + refresh, access := resp.Data.RefreshToken, resp.Data.AccessToken + if refresh == "" { + return "", "", fmt.Errorf("failed to refresh token: refresh token is empty, resp: %s", res.String()) + } + return refresh, access, nil +}