mirror of https://github.com/Xhofe/alist
fix(pikpak): refresh_token cannot be obtained (#7017)
parent
6bff5b6107
commit
8e6c1aa78d
|
@ -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)
|
||||||
|
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue