fix(pikpak): refresh_token cannot be obtained (#7017)

pull/7025/head
YangXu 2024-08-15 21:46:55 +08:00 committed by GitHub
parent 6bff5b6107
commit 8e6c1aa78d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 126 additions and 93 deletions

View File

@ -20,14 +20,14 @@ import (
"github.com/aws/aws-sdk-go/service/s3/s3manager" "github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
) )
type PikPak struct { type PikPak struct {
model.Storage model.Storage
Addition Addition
*Common *Common
oauth2Token oauth2.TokenSource RefreshToken string
AccessToken string
} }
func (d *PikPak) Config() driver.Config { func (d *PikPak) Config() driver.Config {
@ -58,29 +58,27 @@ func (d *PikPak) Init(ctx context.Context) (err error) {
} }
} }
oauth2Config := &oauth2.Config{ if d.Addition.CaptchaToken != "" && d.Addition.RefreshToken == "" {
ClientID: d.ClientID, d.SetCaptchaToken(d.Addition.CaptchaToken)
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,
},
} }
d.oauth2Token = oauth2.ReuseTokenSource(nil, utils.TokenSource(func() (*oauth2.Token, error) { // 如果已经有RefreshToken直接刷新AccessToken
return oauth2Config.PasswordCredentialsToken( if d.Addition.RefreshToken != "" {
context.WithValue(context.Background(), oauth2.HTTPClient, base.HttpClient), d.RefreshToken = d.Addition.RefreshToken
d.Username, if err := d.refreshToken(); err != nil {
d.Password, return err
) }
})) } else {
if err := d.login(); err != nil {
// 获取用户ID return err
_ = d.GetUserID() }
}
// 获取CaptchaToken // 获取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 // 更新UserAgent
d.Common.UserAgent = BuildCustomUserAgent(d.Common.DeviceID, ClientID, PackageName, SdkVersion, ClientVersion, PackageName, d.Common.UserID) d.Common.UserAgent = BuildCustomUserAgent(d.Common.DeviceID, ClientID, PackageName, SdkVersion, ClientVersion, PackageName, d.Common.UserID)
return nil 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) { func (d *PikPak) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
var resp File 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) http.MethodGet, nil, &resp)
if err != nil { if err != nil {
return nil, err return nil, err
@ -320,19 +318,4 @@ func (d *PikPak) DeleteOfflineTasks(ctx context.Context, taskIDs []string, delet
return nil 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) var _ driver.Driver = (*PikPak)(nil)

View File

@ -11,6 +11,8 @@ type Addition struct {
Password string `json:"password" required:"true"` Password string `json:"password" required:"true"`
ClientID string `json:"client_id" required:"true" default:"YNxT9w7GMdWvEOKa"` ClientID string `json:"client_id" required:"true" default:"YNxT9w7GMdWvEOKa"`
ClientSecret string `json:"client_secret" required:"true" default:"dbw2OtmVEeuUvIptb1Coyg"` 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"` DisableMediaLink bool `json:"disable_media_link"`
} }

View File

@ -4,8 +4,11 @@ import (
"crypto/md5" "crypto/md5"
"crypto/sha1" "crypto/sha1"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils" "github.com/alist-org/alist/v3/pkg/utils"
jsoniter "github.com/json-iterator/go"
"net/http" "net/http"
"regexp" "regexp"
"strings" "strings"
@ -18,34 +21,101 @@ import (
// do others that not defined in Driver interface // do others that not defined in Driver interface
var Algorithms = []string{ var Algorithms = []string{
"PAe56I7WZ6FCSkFy77A96jHWcQA27ui80Qy4", "Gez0T9ijiI9WCeTsKSg3SMlx",
"SUbmk67TfdToBAEe2cZyP8vYVeN", "zQdbalsolyb1R/",
"1y3yFSZVWiGN95fw/2FQlRuH/Oy6WnO", "ftOjr52zt51JD68C3s",
"8amLtHJpGzHPz4m9hGz7r+i+8dqQiAk", "yeOBMH0JkbQdEFNNwQ0RI9T3wU/v",
"tmIEq5yl2g/XWwM3sKZkY4SbL8YUezrvxPksNabUJ", "BRJrQZiTQ65WtMvwO",
"4QvudeJwgJuSf/qb9/wjC21L5aib", "je8fqxKPdQVJiy1DM6Bc9Nb1",
"D1RJd+FZ+LBbt+dAmaIyYrT9gxJm0BB", "niV",
"1If", "9hFCW2R1",
"iGZr/SJPUFRkwvC174eelKy", "sHKHpe2i96",
"p7c5E6AcXQ/IJUuAEC9W6",
"",
"aRv9hjc9P+Pbn+u3krN6",
"BzStcgE8qVdqjEH16l4",
"SqgeZvL5j9zoHP95xWHt",
"zVof5yaJkPe3VFpadPof",
} }
const ( const (
ClientID = "YNxT9w7GMdWvEOKa" ClientID = "YNxT9w7GMdWvEOKa"
ClientSecret = "dbw2OtmVEeuUvIptb1Coyg" ClientSecret = "dbw2OtmVEeuUvIptb1Coyg"
ClientVersion = "1.46.2" ClientVersion = "1.47.1"
PackageName = "com.pikcloud.pikpak" PackageName = "com.pikcloud.pikpak"
SdkVersion = "2.0.4.204000 " 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) { func (d *PikPak) request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
req := base.RestyClient.R() req := base.RestyClient.R()
req.SetHeaders(map[string]string{
token, err := d.oauth2Token.Token() "Authorization": "Bearer " + d.AccessToken,
if err != nil { "User-Agent": d.GetUserAgent(),
return nil, err "X-Device-ID": d.GetDeviceID(),
} "X-Captcha-Token": d.GetCaptchaToken(),
req.SetAuthScheme(token.TokenType).SetAuthToken(token.AccessToken) })
if callback != nil { if callback != nil {
callback(req) callback(req)
} }
@ -59,48 +129,22 @@ func (d *PikPak) request(url string, method string, callback base.ReqCallback, r
return nil, err return nil, err
} }
if e.IsError() { switch e.ErrorCode {
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 {
case 0: case 0:
return data, nil return res.Body(), nil
//case 4122, 4121, 10, 16: case 4122, 4121, 10, 16:
// if d.refreshTokenFunc != nil { if err1 := d.refreshToken(); err1 != nil {
// if err = xc.refreshTokenFunc(); err == nil { return nil, err1
// break }
// } return d.request(url, method, callback, resp)
// }
// return nil, err
case 9: // 验证码token过期 case 9: // 验证码token过期
if err = d.RefreshCaptchaTokenAtLogin(GetAction(method, url), d.Common.UserID); err != nil { if err = d.RefreshCaptchaTokenAtLogin(GetAction(method, url), d.Common.UserID); err != nil {
return nil, err return nil, err
} }
return d.request(url, method, callback, resp)
default: default:
return nil, err return nil, err
} }
return d.requestWithCaptchaToken(url, method, callback, resp)
} }
func (d *PikPak) getFiles(id string) ([]File, error) { 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 e ErrResp
var resp CaptchaTokenResponse var resp CaptchaTokenResponse
_, err := d.request("https://user.mypikpak.com/v1/shield/captcha/init", http.MethodPost, func(req *resty.Request) { _, 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) }, &resp)
if err != nil { if err != nil {
@ -287,12 +331,16 @@ func (d *PikPak) refreshCaptchaToken(action string, metas map[string]string) err
return &e return &e
} }
if resp.Url != "" {
return fmt.Errorf(`need verify: <a target="_blank" href="%s">Click Here</a>`, resp.Url)
}
if resp.CaptchaToken == "" { if resp.CaptchaToken == "" {
return fmt.Errorf("empty captchaToken") return fmt.Errorf("empty captchaToken")
} else {
// 对 被风控的情况 进行处理
d.Addition.CaptchaToken = resp.CaptchaToken
op.MustSaveDriverStorage(d)
}
if resp.Url != "" {
return fmt.Errorf(`need verify: <a target="_blank" href="%s">Click Here</a>`, resp.Url)
} }
if d.Common.RefreshCTokenCk != nil { if d.Common.RefreshCTokenCk != nil {