Skip to content

Commit

Permalink
fix(pikpak): modify the processing logic of CaptchaToken
Browse files Browse the repository at this point in the history
  • Loading branch information
Three-taile-dragon committed Aug 17, 2024
1 parent 51c95ee commit a4d133d
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 62 deletions.
62 changes: 55 additions & 7 deletions drivers/pikpak/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/json"
"fmt"
"github.com/alist-org/alist/v3/internal/op"
"golang.org/x/oauth2"
"io"
"net/http"
"strconv"
"strings"
Expand All @@ -28,6 +30,7 @@ type PikPak struct {
*Common
RefreshToken string
AccessToken string
oauth2Token oauth2.TokenSource
}

func (d *PikPak) Config() driver.Config {
Expand Down Expand Up @@ -62,25 +65,60 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
d.SetCaptchaToken(d.Addition.CaptchaToken)
}

// 如果已经有RefreshToken,直接刷新AccessToken
if d.Addition.DeviceID != "" {
d.SetDeviceID(d.Addition.DeviceID)
} else {
d.Addition.DeviceID = d.Common.DeviceID
op.MustSaveDriverStorage(d)
}
// 初始化 oauth2Config
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,
},
}

// 如果已经有RefreshToken,直接获取AccessToken
if d.Addition.RefreshToken != "" {
d.RefreshToken = d.Addition.RefreshToken
if err := d.refreshToken(); err != nil {
// 使用 oauth2 刷新令牌
// 初始化 oauth2Token
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
return oauth2Config.TokenSource(ctx, &oauth2.Token{
RefreshToken: d.Addition.RefreshToken,
}).Token()
}))
token, err := d.oauth2Token.Token()
if err != nil {
return err
}
d.RefreshToken = token.RefreshToken
d.AccessToken = token.AccessToken
} else {
// 如果没有填写RefreshToken,尝试登录 获取 refreshToken
if err := d.login(); err != nil {
return err
}
}

// 获取CaptchaToken
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)

// 保存 有效的 RefreshToken
d.Addition.RefreshToken = d.RefreshToken
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) {
return oauth2Config.TokenSource(ctx, &oauth2.Token{
RefreshToken: d.Addition.RefreshToken,
}).Token()
}))
op.MustSaveDriverStorage(d)
return nil
}

Expand All @@ -100,8 +138,18 @@ 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.request(fmt.Sprintf("https://api-drive.mypikpak.com/drive/v1/files/%s?_magic=2021&thumbnail_size=SIZE_LARGE", file.GetID()),
http.MethodGet, nil, &resp)
queryParams := map[string]string{
"_magic": "2021",
"usage": "FETCH",
"thumbnail_size": "SIZE_LARGE",
}
if !d.DisableMediaLink {
queryParams["usage"] = "CACHE"
}
_, err := d.request(fmt.Sprintf("https://api-drive.mypikpak.com/drive/v1/files/%s", file.GetID()),
http.MethodGet, func(req *resty.Request) {
req.SetQueryParams(queryParams)
}, &resp)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -224,7 +272,7 @@ func (d *PikPak) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
input := &s3manager.UploadInput{
Bucket: &params.Bucket,
Key: &params.Key,
Body: stream,
Body: io.TeeReader(stream, driver.NewProgress(stream.GetSize(), up)),
}
_, err = uploader.UploadWithContext(ctx, input)
return err
Expand Down
3 changes: 2 additions & 1 deletion drivers/pikpak/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ type Addition struct {
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"`
DeviceID string `json:"device_id" required:"false" default:""`
DisableMediaLink bool `json:"disable_media_link" default:"true"`
}

var config = driver.Config{
Expand Down
124 changes: 70 additions & 54 deletions drivers/pikpak/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ const (

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
// 使用 用户填写的 CaptchaToken —————— (验证后的captcha_token)
if d.GetCaptchaToken() == "" {
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{
res, err := base.RestyClient.SetRetryCount(1).R().SetError(&e).SetBody(base.Json{
"captcha_token": d.GetCaptchaToken(),
"client_id": ClientID,
"client_secret": ClientSecret,
Expand All @@ -69,53 +73,60 @@ func (d *PikPak) login() error {
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) refreshToken() error {
// url := "https://user.mypikpak.com/v1/auth/token"
// var e ErrResp
// res, err := base.RestyClient.SetRetryCount(1).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()
req.SetHeaders(map[string]string{
"Authorization": "Bearer " + d.AccessToken,
//"Authorization": "Bearer " + d.AccessToken,
"User-Agent": d.GetUserAgent(),
"X-Device-ID": d.GetDeviceID(),
"X-Captcha-Token": d.GetCaptchaToken(),
})
if d.oauth2Token != nil {
// 使用oauth2 获取 access_token
token, err := d.oauth2Token.Token()
if err != nil {
return nil, err
}
req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken)
}

if callback != nil {
callback(req)
}
Expand All @@ -132,18 +143,31 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
switch e.ErrorCode {
case 0:
return res.Body(), nil
case 4122, 4121, 10, 16:
if err1 := d.refreshToken(); err1 != nil {
return nil, err1
case 4122, 4121, 16:
// access_token 过期

//if err1 := d.refreshToken(); err1 != nil {
// return nil, err1
//}
t, err := d.oauth2Token.Token()
if err != nil {
return nil, err
}
d.AccessToken = t.AccessToken
d.RefreshToken = t.RefreshToken
d.Addition.RefreshToken = t.RefreshToken
op.MustSaveDriverStorage(d)

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)
case 10: // 操作频繁
return nil, errors.New(e.ErrorDescription)
default:
return nil, err
return nil, errors.New(e.Error())
}
}

Expand Down Expand Up @@ -311,9 +335,9 @@ func (c *Common) GetCaptchaSign() (timestamp, sign string) {
func (d *PikPak) refreshCaptchaToken(action string, metas map[string]string) error {
param := CaptchaTokenRequest{
Action: action,
CaptchaToken: d.Common.CaptchaToken,
CaptchaToken: d.GetCaptchaToken(),
ClientID: ClientID,
DeviceID: d.Common.DeviceID,
DeviceID: d.GetDeviceID(),
Meta: metas,
RedirectUri: "xlaccsdk01://xbase.cloud/callback?state=harbor",
}
Expand All @@ -328,15 +352,7 @@ func (d *PikPak) refreshCaptchaToken(action string, metas map[string]string) err
}

if e.IsError() {
return &e
}

if resp.CaptchaToken == "" {
return fmt.Errorf("empty captchaToken")
} else {
// 对 被风控的情况 进行处理
d.Addition.CaptchaToken = resp.CaptchaToken
op.MustSaveDriverStorage(d)
return errors.New(e.Error())
}

if resp.Url != "" {
Expand Down

0 comments on commit a4d133d

Please sign in to comment.