From 8e6c1aa78d1f43e7e6f329a7d27b82753ea165da Mon Sep 17 00:00:00 2001
From: YangXu <47767754+Three-taile-dragon@users.noreply.github.com>
Date: Thu, 15 Aug 2024 21:46:55 +0800
Subject: [PATCH] fix(pikpak): refresh_token cannot be obtained (#7017)
---
drivers/pikpak/driver.go | 57 +++++---------
drivers/pikpak/meta.go | 2 +
drivers/pikpak/util.go | 160 +++++++++++++++++++++++++--------------
3 files changed, 126 insertions(+), 93 deletions(-)
diff --git a/drivers/pikpak/driver.go b/drivers/pikpak/driver.go
index 1d086e0a..f0fc57f7 100644
--- a/drivers/pikpak/driver.go
+++ b/drivers/pikpak/driver.go
@@ -20,14 +20,14 @@ import (
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
- "golang.org/x/oauth2"
)
type PikPak struct {
model.Storage
Addition
*Common
- oauth2Token oauth2.TokenSource
+ RefreshToken string
+ AccessToken string
}
func (d *PikPak) Config() driver.Config {
@@ -58,29 +58,27 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
}
}
- oauth2Config := &oauth2.Config{
- ClientID: d.ClientID,
- ClientSecret: d.ClientSecret,
- Endpoint: oauth2.Endpoint{
- AuthURL: "https://user.mypikpak.com/v1/auth/signin",
- TokenURL: "https://user.mypikpak.com/v1/auth/token",
- AuthStyle: oauth2.AuthStyleInParams,
- },
+ if d.Addition.CaptchaToken != "" && d.Addition.RefreshToken == "" {
+ d.SetCaptchaToken(d.Addition.CaptchaToken)
}
- d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
- return oauth2Config.PasswordCredentialsToken(
- context.WithValue(context.Background(), oauth2.HTTPClient, base.HttpClient),
- d.Username,
- d.Password,
- )
- }))
-
- // 获取用户ID
- _ = d.GetUserID()
+ // 如果已经有RefreshToken,直接刷新AccessToken
+ if d.Addition.RefreshToken != "" {
+ d.RefreshToken = d.Addition.RefreshToken
+ if err := d.refreshToken(); err != nil {
+ return err
+ }
+ } else {
+ if err := d.login(); err != nil {
+ return err
+ }
+ }
// 获取CaptchaToken
- _ = d.RefreshCaptchaTokenAtLogin(GetAction(http.MethodGet, "https://api-drive.mypikpak.com/drive/v1/files"), d.Common.UserID)
+ err = d.RefreshCaptchaTokenAtLogin(GetAction(http.MethodGet, "https://api-drive.mypikpak.com/drive/v1/files"), d.Common.UserID)
+ if err != nil {
+ return err
+ }
// 更新UserAgent
d.Common.UserAgent = BuildCustomUserAgent(d.Common.DeviceID, ClientID, PackageName, SdkVersion, ClientVersion, PackageName, d.Common.UserID)
return nil
@@ -102,7 +100,7 @@ func (d *PikPak) List(ctx context.Context, dir model.Obj, args model.ListArgs) (
func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
var resp File
- _, err := d.requestWithCaptchaToken(fmt.Sprintf("https://api-drive.mypikpak.com/drive/v1/files/%s?_magic=2021&thumbnail_size=SIZE_LARGE", file.GetID()),
+ _, err := d.request(fmt.Sprintf("https://api-drive.mypikpak.com/drive/v1/files/%s?_magic=2021&thumbnail_size=SIZE_LARGE", file.GetID()),
http.MethodGet, nil, &resp)
if err != nil {
return nil, err
@@ -320,19 +318,4 @@ func (d *PikPak) DeleteOfflineTasks(ctx context.Context, taskIDs []string, delet
return nil
}
-func (d *PikPak) GetUserID() error {
-
- token, err := d.oauth2Token.Token()
- if err != nil {
- return err
- }
-
- userID := token.Extra("sub").(string)
-
- if userID != "" {
- d.Common.SetUserID(userID)
- }
- return nil
-}
-
var _ driver.Driver = (*PikPak)(nil)
diff --git a/drivers/pikpak/meta.go b/drivers/pikpak/meta.go
index c462ed13..51ba5c46 100644
--- a/drivers/pikpak/meta.go
+++ b/drivers/pikpak/meta.go
@@ -11,6 +11,8 @@ type Addition struct {
Password string `json:"password" required:"true"`
ClientID string `json:"client_id" required:"true" default:"YNxT9w7GMdWvEOKa"`
ClientSecret string `json:"client_secret" required:"true" default:"dbw2OtmVEeuUvIptb1Coyg"`
+ RefreshToken string `json:"refresh_token" required:"true" default:""`
+ CaptchaToken string `json:"captcha_token" default:""`
DisableMediaLink bool `json:"disable_media_link"`
}
diff --git a/drivers/pikpak/util.go b/drivers/pikpak/util.go
index d4cf64f0..7eb2b803 100644
--- a/drivers/pikpak/util.go
+++ b/drivers/pikpak/util.go
@@ -4,8 +4,11 @@ import (
"crypto/md5"
"crypto/sha1"
"encoding/hex"
+ "errors"
"fmt"
+ "github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
+ jsoniter "github.com/json-iterator/go"
"net/http"
"regexp"
"strings"
@@ -18,34 +21,101 @@ import (
// do others that not defined in Driver interface
var Algorithms = []string{
- "PAe56I7WZ6FCSkFy77A96jHWcQA27ui80Qy4",
- "SUbmk67TfdToBAEe2cZyP8vYVeN",
- "1y3yFSZVWiGN95fw/2FQlRuH/Oy6WnO",
- "8amLtHJpGzHPz4m9hGz7r+i+8dqQiAk",
- "tmIEq5yl2g/XWwM3sKZkY4SbL8YUezrvxPksNabUJ",
- "4QvudeJwgJuSf/qb9/wjC21L5aib",
- "D1RJd+FZ+LBbt+dAmaIyYrT9gxJm0BB",
- "1If",
- "iGZr/SJPUFRkwvC174eelKy",
+ "Gez0T9ijiI9WCeTsKSg3SMlx",
+ "zQdbalsolyb1R/",
+ "ftOjr52zt51JD68C3s",
+ "yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
+ "BRJrQZiTQ65WtMvwO",
+ "je8fqxKPdQVJiy1DM6Bc9Nb1",
+ "niV",
+ "9hFCW2R1",
+ "sHKHpe2i96",
+ "p7c5E6AcXQ/IJUuAEC9W6",
+ "",
+ "aRv9hjc9P+Pbn+u3krN6",
+ "BzStcgE8qVdqjEH16l4",
+ "SqgeZvL5j9zoHP95xWHt",
+ "zVof5yaJkPe3VFpadPof",
}
const (
ClientID = "YNxT9w7GMdWvEOKa"
ClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
- ClientVersion = "1.46.2"
+ ClientVersion = "1.47.1"
PackageName = "com.pikcloud.pikpak"
SdkVersion = "2.0.4.204000 "
)
+func (d *PikPak) login() error {
+ url := "https://user.mypikpak.com/v1/auth/signin"
+ if err := d.RefreshCaptchaTokenInLogin(GetAction(http.MethodPost, url), d.Username); err != nil {
+ return err
+ }
+ var e ErrResp
+ res, err := base.RestyClient.R().SetError(&e).SetBody(base.Json{
+ "captcha_token": d.GetCaptchaToken(),
+ "client_id": ClientID,
+ "client_secret": ClientSecret,
+ "username": d.Username,
+ "password": d.Password,
+ }).SetQueryParam("client_id", ClientID).Post(url)
+ if err != nil {
+ return err
+ }
+ if e.ErrorCode != 0 {
+ return &e
+ }
+ data := res.Body()
+ d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
+ d.AccessToken = jsoniter.Get(data, "access_token").ToString()
+ d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
+ d.Addition.RefreshToken = d.RefreshToken
+ op.MustSaveDriverStorage(d)
+ return nil
+}
+
+func (d *PikPak) refreshToken() error {
+ url := "https://user.mypikpak.com/v1/auth/token"
+ var e ErrResp
+ res, err := base.RestyClient.R().SetError(&e).
+ SetHeader("user-agent", "").SetBody(base.Json{
+ "client_id": ClientID,
+ "client_secret": ClientSecret,
+ "grant_type": "refresh_token",
+ "refresh_token": d.RefreshToken,
+ }).SetQueryParam("client_id", ClientID).Post(url)
+ if err != nil {
+ d.Status = err.Error()
+ op.MustSaveDriverStorage(d)
+ return err
+ }
+ if e.ErrorCode != 0 {
+ if e.ErrorCode == 4126 {
+ // refresh_token invalid, re-login
+ return d.login()
+ }
+ d.Status = e.Error()
+ op.MustSaveDriverStorage(d)
+ return errors.New(e.Error())
+ }
+ data := res.Body()
+ d.Status = "work"
+ d.RefreshToken = jsoniter.Get(data, "refresh_token").ToString()
+ d.AccessToken = jsoniter.Get(data, "access_token").ToString()
+ d.Common.SetUserID(jsoniter.Get(data, "sub").ToString())
+ d.Addition.RefreshToken = d.RefreshToken
+ op.MustSaveDriverStorage(d)
+ return nil
+}
+
func (d *PikPak) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
req := base.RestyClient.R()
-
- token, err := d.oauth2Token.Token()
- if err != nil {
- return nil, err
- }
- req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken)
-
+ req.SetHeaders(map[string]string{
+ "Authorization": "Bearer " + d.AccessToken,
+ "User-Agent": d.GetUserAgent(),
+ "X-Device-ID": d.GetDeviceID(),
+ "X-Captcha-Token": d.GetCaptchaToken(),
+ })
if callback != nil {
callback(req)
}
@@ -59,48 +129,22 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
return nil, err
}
- if e.IsError() {
- return nil, &e
- }
- return res.Body(), nil
-}
-
-func (d *PikPak) requestWithCaptchaToken(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
-
- data, err := d.request(url, method, func(req *resty.Request) {
- req.SetHeaders(map[string]string{
- "User-Agent": d.GetUserAgent(),
- "X-Device-ID": d.GetDeviceID(),
- "X-Captcha-Token": d.GetCaptchaToken(),
- })
- if callback != nil {
- callback(req)
- }
- }, resp)
-
- errResp, ok := err.(*ErrResp)
- if !ok {
- return nil, err
- }
-
- switch errResp.ErrorCode {
+ switch e.ErrorCode {
case 0:
- return data, nil
- //case 4122, 4121, 10, 16:
- // if d.refreshTokenFunc != nil {
- // if err = xc.refreshTokenFunc(); err == nil {
- // break
- // }
- // }
- // return nil, err
+ return res.Body(), nil
+ case 4122, 4121, 10, 16:
+ if err1 := d.refreshToken(); err1 != nil {
+ return nil, err1
+ }
+ return d.request(url, method, callback, resp)
case 9: // 验证码token过期
if err = d.RefreshCaptchaTokenAtLogin(GetAction(method, url), d.Common.UserID); err != nil {
return nil, err
}
+ return d.request(url, method, callback, resp)
default:
return nil, err
}
- return d.requestWithCaptchaToken(url, method, callback, resp)
}
func (d *PikPak) getFiles(id string) ([]File, error) {
@@ -276,7 +320,7 @@ func (d *PikPak) refreshCaptchaToken(action string, metas map[string]string) err
var e ErrResp
var resp CaptchaTokenResponse
_, err := d.request("https://user.mypikpak.com/v1/shield/captcha/init", http.MethodPost, func(req *resty.Request) {
- req.SetError(&e).SetBody(param)
+ req.SetError(&e).SetBody(param).SetQueryParam("client_id", ClientID)
}, &resp)
if err != nil {
@@ -287,12 +331,16 @@ func (d *PikPak) refreshCaptchaToken(action string, metas map[string]string) err
return &e
}
- if resp.Url != "" {
- return fmt.Errorf(`need verify: Click Here`, resp.Url)
- }
-
if resp.CaptchaToken == "" {
return fmt.Errorf("empty captchaToken")
+ } else {
+ // 对 被风控的情况 进行处理
+ d.Addition.CaptchaToken = resp.CaptchaToken
+ op.MustSaveDriverStorage(d)
+ }
+
+ if resp.Url != "" {
+ return fmt.Errorf(`need verify: Click Here`, resp.Url)
}
if d.Common.RefreshCTokenCk != nil {