mirror of https://github.com/Xhofe/alist
parent
544a7ea022
commit
d0ee90cd11
|
@ -45,26 +45,29 @@ func (x *Thunder) Init(ctx context.Context) (err error) {
|
||||||
Common: &Common{
|
Common: &Common{
|
||||||
client: base.NewRestyClient(),
|
client: base.NewRestyClient(),
|
||||||
Algorithms: []string{
|
Algorithms: []string{
|
||||||
"HPxr4BVygTQVtQkIMwQH33ywbgYG5l4JoR",
|
"9uJNVj/wLmdwKrJaVj/omlQ",
|
||||||
"GzhNkZ8pOBsCY+7",
|
"Oz64Lp0GigmChHMf/6TNfxx7O9PyopcczMsnf",
|
||||||
"v+l0ImTpG7c7/",
|
"Eb+L7Ce+Ej48u",
|
||||||
"e5ztohgVXNP",
|
"jKY0",
|
||||||
"t",
|
"ASr0zCl6v8W4aidjPK5KHd1Lq3t+vBFf41dqv5+fnOd",
|
||||||
"EbXUWyVVqQbQX39Mbjn2geok3/0WEkAVxeqhtx857++kjJiRheP8l77gO",
|
"wQlozdg6r1qxh0eRmt3QgNXOvSZO6q/GXK",
|
||||||
"o7dvYgbRMOpHXxCs",
|
"gmirk+ciAvIgA/cxUUCema47jr/YToixTT+Q6O",
|
||||||
"6MW8TD8DphmakaxCqVrfv7NReRRN7ck3KLnXBculD58MvxjFRqT+",
|
"5IiCoM9B1/788ntB",
|
||||||
"kmo0HxCKVfmxoZswLB4bVA/dwqbVAYghSb",
|
"P07JH0h6qoM6TSUAK2aL9T5s2QBVeY9JWvalf",
|
||||||
"j",
|
"+oK0AN",
|
||||||
"4scKJNdd7F27Hv7tbt",
|
|
||||||
},
|
},
|
||||||
DeviceID: utils.GetMD5EncodeStr(x.Username + x.Password),
|
DeviceID: func() string {
|
||||||
|
if len(x.DeviceID) != 32 {
|
||||||
|
return utils.GetMD5EncodeStr(x.DeviceID)
|
||||||
|
}
|
||||||
|
return x.DeviceID
|
||||||
|
}(),
|
||||||
ClientID: "Xp6vsxz_7IYVw2BB",
|
ClientID: "Xp6vsxz_7IYVw2BB",
|
||||||
ClientSecret: "Xp6vsy4tN9toTVdMSpomVdXpRmES",
|
ClientSecret: "Xp6vsy4tN9toTVdMSpomVdXpRmES",
|
||||||
ClientVersion: "7.51.0.8196",
|
ClientVersion: "8.31.0.9726",
|
||||||
PackageName: "com.xunlei.downloadprovider",
|
PackageName: "com.xunlei.downloadprovider",
|
||||||
UserAgent: "ANDROID-com.xunlei.downloadprovider/7.51.0.8196 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/220200 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)",
|
UserAgent: "ANDROID-com.xunlei.downloadprovider/8.31.0.9726 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/512000 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)",
|
||||||
DownloadUserAgent: "Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)",
|
DownloadUserAgent: "Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)",
|
||||||
|
|
||||||
refreshCTokenCk: func(token string) {
|
refreshCTokenCk: func(token string) {
|
||||||
x.CaptchaToken = token
|
x.CaptchaToken = token
|
||||||
op.MustSaveDriverStorage(x)
|
op.MustSaveDriverStorage(x)
|
||||||
|
@ -80,6 +83,8 @@ func (x *Thunder) Init(ctx context.Context) (err error) {
|
||||||
x.GetStorage().SetStatus(fmt.Sprintf("%+v", err.Error()))
|
x.GetStorage().SetStatus(fmt.Sprintf("%+v", err.Error()))
|
||||||
op.MustSaveDriverStorage(x)
|
op.MustSaveDriverStorage(x)
|
||||||
}
|
}
|
||||||
|
// 清空 信任密钥
|
||||||
|
x.Addition.CreditKey = ""
|
||||||
}
|
}
|
||||||
x.SetTokenResp(token)
|
x.SetTokenResp(token)
|
||||||
return err
|
return err
|
||||||
|
@ -93,6 +98,17 @@ func (x *Thunder) Init(ctx context.Context) (err error) {
|
||||||
x.SetCaptchaToken(ctoekn)
|
x.SetCaptchaToken(ctoekn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if x.Addition.CreditKey != "" {
|
||||||
|
x.SetCreditKey(x.Addition.CreditKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.Addition.DeviceID != "" {
|
||||||
|
x.Common.DeviceID = x.Addition.DeviceID
|
||||||
|
} else {
|
||||||
|
x.Addition.DeviceID = x.Common.DeviceID
|
||||||
|
op.MustSaveDriverStorage(x)
|
||||||
|
}
|
||||||
|
|
||||||
// 防止重复登录
|
// 防止重复登录
|
||||||
identity := x.GetIdentity()
|
identity := x.GetIdentity()
|
||||||
if x.identity != identity || !x.IsLogin() {
|
if x.identity != identity || !x.IsLogin() {
|
||||||
|
@ -102,6 +118,8 @@ func (x *Thunder) Init(ctx context.Context) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// 清空 信任密钥
|
||||||
|
x.Addition.CreditKey = ""
|
||||||
x.SetTokenResp(token)
|
x.SetTokenResp(token)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -161,6 +179,17 @@ func (x *ThunderExpert) Init(ctx context.Context) (err error) {
|
||||||
x.SetCaptchaToken(x.CaptchaToken)
|
x.SetCaptchaToken(x.CaptchaToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if x.ExpertAddition.CreditKey != "" {
|
||||||
|
x.SetCreditKey(x.ExpertAddition.CreditKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x.ExpertAddition.DeviceID != "" {
|
||||||
|
x.Common.DeviceID = x.ExpertAddition.DeviceID
|
||||||
|
} else {
|
||||||
|
x.ExpertAddition.DeviceID = x.Common.DeviceID
|
||||||
|
op.MustSaveDriverStorage(x)
|
||||||
|
}
|
||||||
|
|
||||||
// 签名方法
|
// 签名方法
|
||||||
if x.SignType == "captcha_sign" {
|
if x.SignType == "captcha_sign" {
|
||||||
x.Common.Timestamp = x.Timestamp
|
x.Common.Timestamp = x.Timestamp
|
||||||
|
@ -194,6 +223,8 @@ func (x *ThunderExpert) Init(ctx context.Context) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// 清空 信任密钥
|
||||||
|
x.ExpertAddition.CreditKey = ""
|
||||||
x.SetTokenResp(token)
|
x.SetTokenResp(token)
|
||||||
x.SetRefreshTokenFunc(func() error {
|
x.SetRefreshTokenFunc(func() error {
|
||||||
token, err := x.XunLeiCommon.RefreshToken(x.TokenResp.RefreshToken)
|
token, err := x.XunLeiCommon.RefreshToken(x.TokenResp.RefreshToken)
|
||||||
|
@ -202,6 +233,8 @@ func (x *ThunderExpert) Init(ctx context.Context) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
x.GetStorage().SetStatus(fmt.Sprintf("%+v", err.Error()))
|
x.GetStorage().SetStatus(fmt.Sprintf("%+v", err.Error()))
|
||||||
}
|
}
|
||||||
|
// 清空 信任密钥
|
||||||
|
x.ExpertAddition.CreditKey = ""
|
||||||
}
|
}
|
||||||
x.SetTokenResp(token)
|
x.SetTokenResp(token)
|
||||||
op.MustSaveDriverStorage(x)
|
op.MustSaveDriverStorage(x)
|
||||||
|
@ -233,7 +266,8 @@ func (x *ThunderExpert) SetTokenResp(token *TokenResp) {
|
||||||
|
|
||||||
type XunLeiCommon struct {
|
type XunLeiCommon struct {
|
||||||
*Common
|
*Common
|
||||||
*TokenResp // 登录信息
|
*TokenResp // 登录信息
|
||||||
|
*CoreLoginResp // core登录信息
|
||||||
|
|
||||||
refreshTokenFunc func() error
|
refreshTokenFunc func() error
|
||||||
}
|
}
|
||||||
|
@ -433,6 +467,10 @@ func (xc *XunLeiCommon) SetTokenResp(tr *TokenResp) {
|
||||||
xc.TokenResp = tr
|
xc.TokenResp = tr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (xc *XunLeiCommon) SetCoreTokenResp(tr *CoreLoginResp) {
|
||||||
|
xc.CoreLoginResp = tr
|
||||||
|
}
|
||||||
|
|
||||||
// 携带Authorization和CaptchaToken的请求
|
// 携带Authorization和CaptchaToken的请求
|
||||||
func (xc *XunLeiCommon) Request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
func (xc *XunLeiCommon) Request(url string, method string, callback base.ReqCallback, resp interface{}) ([]byte, error) {
|
||||||
data, err := xc.Common.Request(url, method, func(req *resty.Request) {
|
data, err := xc.Common.Request(url, method, func(req *resty.Request) {
|
||||||
|
@ -461,7 +499,7 @@ func (xc *XunLeiCommon) Request(url string, method string, callback base.ReqCall
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
case 9: // 验证码token过期
|
case 9: // 验证码token过期
|
||||||
if err = xc.RefreshCaptchaTokenAtLogin(GetAction(method, url), xc.UserID); err != nil {
|
if err = xc.RefreshCaptchaTokenAtLogin(GetAction(method, url), xc.TokenResp.UserID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -493,20 +531,25 @@ func (xc *XunLeiCommon) RefreshToken(refreshToken string) (*TokenResp, error) {
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
func (xc *XunLeiCommon) Login(username, password string) (*TokenResp, error) {
|
func (xc *XunLeiCommon) Login(username, password string) (*TokenResp, error) {
|
||||||
url := XLUSER_API_URL + "/auth/signin"
|
//v3 login拿到 sessionID
|
||||||
err := xc.RefreshCaptchaTokenInLogin(GetAction(http.MethodPost, url), username)
|
sessionID, err := xc.CoreLogin(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
//v1 login拿到令牌
|
||||||
|
url := XLUSER_API_URL + "/auth/signin/token"
|
||||||
|
if err = xc.RefreshCaptchaTokenInLogin(GetAction(http.MethodPost, url), username); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var resp TokenResp
|
var resp TokenResp
|
||||||
_, err = xc.Common.Request(url, http.MethodPost, func(req *resty.Request) {
|
_, err = xc.Common.Request(url, http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetPathParam("client_id", xc.ClientID)
|
||||||
req.SetBody(&SignInRequest{
|
req.SetBody(&SignInRequest{
|
||||||
CaptchaToken: xc.GetCaptchaToken(),
|
|
||||||
ClientID: xc.ClientID,
|
ClientID: xc.ClientID,
|
||||||
ClientSecret: xc.ClientSecret,
|
ClientSecret: xc.ClientSecret,
|
||||||
Username: username,
|
Provider: SignProvider,
|
||||||
Password: password,
|
SigninToken: sessionID,
|
||||||
})
|
})
|
||||||
}, &resp)
|
}, &resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -582,3 +625,48 @@ func (xc *XunLeiCommon) DeleteOfflineTasks(ctx context.Context, taskIDs []string
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (xc *XunLeiCommon) CoreLogin(username string, password string) (sessionID string, err error) {
|
||||||
|
url := XLUSER_API_BASE_URL + "/xluser.core.login/v3/login"
|
||||||
|
var resp CoreLoginResp
|
||||||
|
res, err := xc.Common.Request(url, http.MethodPost, func(req *resty.Request) {
|
||||||
|
req.SetHeader("User-Agent", "android-ok-http-client/xl-acc-sdk/version-5.0.12.512000")
|
||||||
|
req.SetBody(&CoreLoginRequest{
|
||||||
|
ProtocolVersion: "301",
|
||||||
|
SequenceNo: "1000012",
|
||||||
|
PlatformVersion: "10",
|
||||||
|
IsCompressed: "0",
|
||||||
|
Appid: APPID,
|
||||||
|
ClientVersion: "8.31.0.9726",
|
||||||
|
PeerID: "00000000000000000000000000000000",
|
||||||
|
AppName: "ANDROID-com.xunlei.downloadprovider",
|
||||||
|
SdkVersion: "512000",
|
||||||
|
Devicesign: generateDeviceSign(xc.DeviceID, xc.PackageName),
|
||||||
|
NetWorkType: "WIFI",
|
||||||
|
ProviderName: "NONE",
|
||||||
|
DeviceModel: "M2004J7AC",
|
||||||
|
DeviceName: "Xiaomi_M2004j7ac",
|
||||||
|
OSVersion: "12",
|
||||||
|
Creditkey: xc.GetCreditKey(),
|
||||||
|
Hl: "zh-CN",
|
||||||
|
UserName: username,
|
||||||
|
PassWord: password,
|
||||||
|
VerifyKey: "",
|
||||||
|
VerifyCode: "",
|
||||||
|
IsMd5Pwd: "0",
|
||||||
|
})
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = utils.Json.Unmarshal(res, &resp); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
xc.SetCoreTokenResp(&resp)
|
||||||
|
|
||||||
|
sessionID = resp.SessionID
|
||||||
|
|
||||||
|
return sessionID, nil
|
||||||
|
}
|
||||||
|
|
|
@ -23,23 +23,25 @@ type ExpertAddition struct {
|
||||||
RefreshToken string `json:"refresh_token" required:"true" help:"login type is refresh_token,this is required"`
|
RefreshToken string `json:"refresh_token" required:"true" help:"login type is refresh_token,this is required"`
|
||||||
|
|
||||||
// 签名方法1
|
// 签名方法1
|
||||||
Algorithms string `json:"algorithms" required:"true" help:"sign type is algorithms,this is required" default:"HPxr4BVygTQVtQkIMwQH33ywbgYG5l4JoR,GzhNkZ8pOBsCY+7,v+l0ImTpG7c7/,e5ztohgVXNP,t,EbXUWyVVqQbQX39Mbjn2geok3/0WEkAVxeqhtx857++kjJiRheP8l77gO,o7dvYgbRMOpHXxCs,6MW8TD8DphmakaxCqVrfv7NReRRN7ck3KLnXBculD58MvxjFRqT+,kmo0HxCKVfmxoZswLB4bVA/dwqbVAYghSb,j,4scKJNdd7F27Hv7tbt"`
|
Algorithms string `json:"algorithms" required:"true" help:"sign type is algorithms,this is required" default:"9uJNVj/wLmdwKrJaVj/omlQ,Oz64Lp0GigmChHMf/6TNfxx7O9PyopcczMsnf,Eb+L7Ce+Ej48u,jKY0,ASr0zCl6v8W4aidjPK5KHd1Lq3t+vBFf41dqv5+fnOd,wQlozdg6r1qxh0eRmt3QgNXOvSZO6q/GXK,gmirk+ciAvIgA/cxUUCema47jr/YToixTT+Q6O,5IiCoM9B1/788ntB,P07JH0h6qoM6TSUAK2aL9T5s2QBVeY9JWvalf,+oK0AN"`
|
||||||
// 签名方法2
|
// 签名方法2
|
||||||
CaptchaSign string `json:"captcha_sign" required:"true" help:"sign type is captcha_sign,this is required"`
|
CaptchaSign string `json:"captcha_sign" required:"true" help:"sign type is captcha_sign,this is required"`
|
||||||
Timestamp string `json:"timestamp" required:"true" help:"sign type is captcha_sign,this is required"`
|
Timestamp string `json:"timestamp" required:"true" help:"sign type is captcha_sign,this is required"`
|
||||||
|
|
||||||
// 验证码
|
// 验证码
|
||||||
CaptchaToken string `json:"captcha_token"`
|
CaptchaToken string `json:"captcha_token"`
|
||||||
|
// 信任密钥
|
||||||
|
CreditKey string `json:"credit_key" help:"credit key,used for login"`
|
||||||
|
|
||||||
// 必要且影响登录,由签名决定
|
// 必要且影响登录,由签名决定
|
||||||
DeviceID string `json:"device_id" required:"true" default:"9aa5c268e7bcfc197a9ad88e2fb330e5"`
|
DeviceID string `json:"device_id" default:""`
|
||||||
ClientID string `json:"client_id" required:"true" default:"Xp6vsxz_7IYVw2BB"`
|
ClientID string `json:"client_id" required:"true" default:"Xp6vsxz_7IYVw2BB"`
|
||||||
ClientSecret string `json:"client_secret" required:"true" default:"Xp6vsy4tN9toTVdMSpomVdXpRmES"`
|
ClientSecret string `json:"client_secret" required:"true" default:"Xp6vsy4tN9toTVdMSpomVdXpRmES"`
|
||||||
ClientVersion string `json:"client_version" required:"true" default:"7.51.0.8196"`
|
ClientVersion string `json:"client_version" required:"true" default:"8.31.0.9726"`
|
||||||
PackageName string `json:"package_name" required:"true" default:"com.xunlei.downloadprovider"`
|
PackageName string `json:"package_name" required:"true" default:"com.xunlei.downloadprovider"`
|
||||||
|
|
||||||
//不影响登录,影响下载速度
|
//不影响登录,影响下载速度
|
||||||
UserAgent string `json:"user_agent" required:"true" default:"ANDROID-com.xunlei.downloadprovider/7.51.0.8196 netWorkType/4G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/220200 Oauth2Client/0.9 (Linux 4_14_186-perf-gdcf98eab238b) (JAVA 0)"`
|
UserAgent string `json:"user_agent" required:"true" default:"ANDROID-com.xunlei.downloadprovider/8.31.0.9726 netWorkType/5G appid/40 deviceName/Xiaomi_M2004j7ac deviceModel/M2004J7AC OSVersion/12 protocolVersion/301 platformVersion/10 sdkVersion/512000 Oauth2Client/0.9 (Linux 4_14_186-perf-gddfs8vbb238b) (JAVA 0)"`
|
||||||
DownloadUserAgent string `json:"download_user_agent" required:"true" default:"Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)"`
|
DownloadUserAgent string `json:"download_user_agent" required:"true" default:"Dalvik/2.1.0 (Linux; U; Android 12; M2004J7AC Build/SP1A.210812.016)"`
|
||||||
|
|
||||||
//优先使用视频链接代替下载链接
|
//优先使用视频链接代替下载链接
|
||||||
|
@ -74,6 +76,10 @@ type Addition struct {
|
||||||
Username string `json:"username" required:"true"`
|
Username string `json:"username" required:"true"`
|
||||||
Password string `json:"password" required:"true"`
|
Password string `json:"password" required:"true"`
|
||||||
CaptchaToken string `json:"captcha_token"`
|
CaptchaToken string `json:"captcha_token"`
|
||||||
|
// 信任密钥
|
||||||
|
CreditKey string `json:"credit_key" help:"credit key,used for login"`
|
||||||
|
// 登录设备ID
|
||||||
|
DeviceID string `json:"device_id" default:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录特征,用于判断是否重新登录
|
// 登录特征,用于判断是否重新登录
|
||||||
|
|
|
@ -18,6 +18,10 @@ type ErrResp struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ErrResp) IsError() bool {
|
func (e *ErrResp) IsError() bool {
|
||||||
|
if e.ErrorMsg == "success" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return e.ErrorCode != 0 || e.ErrorMsg != "" || e.ErrorDescription != ""
|
return e.ErrorCode != 0 || e.ErrorMsg != "" || e.ErrorDescription != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,13 +65,79 @@ func (t *TokenResp) Token() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignInRequest struct {
|
type SignInRequest struct {
|
||||||
CaptchaToken string `json:"captcha_token"`
|
|
||||||
|
|
||||||
ClientID string `json:"client_id"`
|
ClientID string `json:"client_id"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
|
|
||||||
Username string `json:"username"`
|
Provider string `json:"provider"`
|
||||||
Password string `json:"password"`
|
SigninToken string `json:"signin_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CoreLoginRequest struct {
|
||||||
|
ProtocolVersion string `json:"protocolVersion"`
|
||||||
|
SequenceNo string `json:"sequenceNo"`
|
||||||
|
PlatformVersion string `json:"platformVersion"`
|
||||||
|
IsCompressed string `json:"isCompressed"`
|
||||||
|
Appid string `json:"appid"`
|
||||||
|
ClientVersion string `json:"clientVersion"`
|
||||||
|
PeerID string `json:"peerID"`
|
||||||
|
AppName string `json:"appName"`
|
||||||
|
SdkVersion string `json:"sdkVersion"`
|
||||||
|
Devicesign string `json:"devicesign"`
|
||||||
|
NetWorkType string `json:"netWorkType"`
|
||||||
|
ProviderName string `json:"providerName"`
|
||||||
|
DeviceModel string `json:"deviceModel"`
|
||||||
|
DeviceName string `json:"deviceName"`
|
||||||
|
OSVersion string `json:"OSVersion"`
|
||||||
|
Creditkey string `json:"creditkey"`
|
||||||
|
Hl string `json:"hl"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
PassWord string `json:"passWord"`
|
||||||
|
VerifyKey string `json:"verifyKey"`
|
||||||
|
VerifyCode string `json:"verifyCode"`
|
||||||
|
IsMd5Pwd string `json:"isMd5Pwd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CoreLoginResp struct {
|
||||||
|
Account string `json:"account"`
|
||||||
|
Creditkey string `json:"creditkey"`
|
||||||
|
/* Error string `json:"error"`
|
||||||
|
ErrorCode string `json:"errorCode"`
|
||||||
|
ErrorDescription string `json:"error_description"`*/
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
IsCompressed string `json:"isCompressed"`
|
||||||
|
IsSetPassWord string `json:"isSetPassWord"`
|
||||||
|
KeepAliveMinPeriod string `json:"keepAliveMinPeriod"`
|
||||||
|
KeepAlivePeriod string `json:"keepAlivePeriod"`
|
||||||
|
LoginKey string `json:"loginKey"`
|
||||||
|
NickName string `json:"nickName"`
|
||||||
|
PlatformVersion string `json:"platformVersion"`
|
||||||
|
ProtocolVersion string `json:"protocolVersion"`
|
||||||
|
SecureKey string `json:"secureKey"`
|
||||||
|
SequenceNo string `json:"sequenceNo"`
|
||||||
|
SessionID string `json:"sessionID"`
|
||||||
|
Timestamp string `json:"timestamp"`
|
||||||
|
UserID string `json:"userID"`
|
||||||
|
UserName string `json:"userName"`
|
||||||
|
UserNewNo string `json:"userNewNo"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
/* VipList []struct {
|
||||||
|
ExpireDate string `json:"expireDate"`
|
||||||
|
IsAutoDeduct string `json:"isAutoDeduct"`
|
||||||
|
IsVip string `json:"isVip"`
|
||||||
|
IsYear string `json:"isYear"`
|
||||||
|
PayID string `json:"payId"`
|
||||||
|
PayName string `json:"payName"`
|
||||||
|
Register string `json:"register"`
|
||||||
|
Vasid string `json:"vasid"`
|
||||||
|
VasType string `json:"vasType"`
|
||||||
|
VipDayGrow string `json:"vipDayGrow"`
|
||||||
|
VipGrow string `json:"vipGrow"`
|
||||||
|
VipLevel string `json:"vipLevel"`
|
||||||
|
Icon struct {
|
||||||
|
General string `json:"general"`
|
||||||
|
Small string `json:"small"`
|
||||||
|
} `json:"icon"`
|
||||||
|
} `json:"vipList"`*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -251,3 +321,29 @@ type Params struct {
|
||||||
PredictSpeed string `json:"predict_speed"`
|
PredictSpeed string `json:"predict_speed"`
|
||||||
PredictType string `json:"predict_type"`
|
PredictType string `json:"predict_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoginReviewResp 登录验证响应
|
||||||
|
type LoginReviewResp struct {
|
||||||
|
Creditkey string `json:"creditkey"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
ErrorCode string `json:"errorCode"`
|
||||||
|
ErrorDesc string `json:"errorDesc"`
|
||||||
|
ErrorDescURL string `json:"errorDescUrl"`
|
||||||
|
ErrorIsRetry int `json:"errorIsRetry"`
|
||||||
|
ErrorDescription string `json:"error_description"`
|
||||||
|
IsCompressed string `json:"isCompressed"`
|
||||||
|
PlatformVersion string `json:"platformVersion"`
|
||||||
|
ProtocolVersion string `json:"protocolVersion"`
|
||||||
|
Reviewurl string `json:"reviewurl"`
|
||||||
|
SequenceNo string `json:"sequenceNo"`
|
||||||
|
UserID string `json:"userID"`
|
||||||
|
VerifyType string `json:"verifyType"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReviewData 验证数据
|
||||||
|
type ReviewData struct {
|
||||||
|
Creditkey string `json:"creditkey"`
|
||||||
|
Reviewurl string `json:"reviewurl"`
|
||||||
|
Deviceid string `json:"deviceid"`
|
||||||
|
Devicesign string `json:"devicesign"`
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package thunder
|
package thunder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -15,10 +17,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
API_URL = "https://api-pan.xunlei.com/drive/v1"
|
API_URL = "https://api-pan.xunlei.com/drive/v1"
|
||||||
FILE_API_URL = API_URL + "/files"
|
FILE_API_URL = API_URL + "/files"
|
||||||
TASK_API_URL = API_URL + "/tasks"
|
TASK_API_URL = API_URL + "/tasks"
|
||||||
XLUSER_API_URL = "https://xluser-ssl.xunlei.com/v1"
|
XLUSER_API_BASE_URL = "https://xluser-ssl.xunlei.com"
|
||||||
|
XLUSER_API_URL = XLUSER_API_BASE_URL + "/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -34,6 +37,12 @@ const (
|
||||||
UPLOAD_TYPE_URL = "UPLOAD_TYPE_URL"
|
UPLOAD_TYPE_URL = "UPLOAD_TYPE_URL"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SignProvider = "access_end_point_token"
|
||||||
|
APPID = "40"
|
||||||
|
APPKey = "34a062aaa22f906fca4fefe9fb3a3021"
|
||||||
|
)
|
||||||
|
|
||||||
func GetAction(method string, url string) string {
|
func GetAction(method string, url string) string {
|
||||||
urlpath := regexp.MustCompile(`://[^/]+((/[^/\s?#]+)*)`).FindStringSubmatch(url)[1]
|
urlpath := regexp.MustCompile(`://[^/]+((/[^/\s?#]+)*)`).FindStringSubmatch(url)[1]
|
||||||
return method + ":" + urlpath
|
return method + ":" + urlpath
|
||||||
|
@ -44,6 +53,8 @@ type Common struct {
|
||||||
|
|
||||||
captchaToken string
|
captchaToken string
|
||||||
|
|
||||||
|
creditKey string
|
||||||
|
|
||||||
// 签名相关,二选一
|
// 签名相关,二选一
|
||||||
Algorithms []string
|
Algorithms []string
|
||||||
Timestamp, CaptchaSign string
|
Timestamp, CaptchaSign string
|
||||||
|
@ -69,6 +80,13 @@ func (c *Common) GetCaptchaToken() string {
|
||||||
return c.captchaToken
|
return c.captchaToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Common) SetCreditKey(creditKey string) {
|
||||||
|
c.creditKey = creditKey
|
||||||
|
}
|
||||||
|
func (c *Common) GetCreditKey() string {
|
||||||
|
return c.creditKey
|
||||||
|
}
|
||||||
|
|
||||||
// 刷新验证码token(登录后)
|
// 刷新验证码token(登录后)
|
||||||
func (c *Common) RefreshCaptchaTokenAtLogin(action, userID string) error {
|
func (c *Common) RefreshCaptchaTokenAtLogin(action, userID string) error {
|
||||||
metas := map[string]string{
|
metas := map[string]string{
|
||||||
|
@ -170,12 +188,53 @@ func (c *Common) Request(url, method string, callback base.ReqCallback, resp int
|
||||||
var erron ErrResp
|
var erron ErrResp
|
||||||
utils.Json.Unmarshal(res.Body(), &erron)
|
utils.Json.Unmarshal(res.Body(), &erron)
|
||||||
if erron.IsError() {
|
if erron.IsError() {
|
||||||
|
// review_panel 表示需要短信验证码进行验证
|
||||||
|
if erron.ErrorMsg == "review_panel" {
|
||||||
|
return nil, c.getReviewData(res)
|
||||||
|
}
|
||||||
|
|
||||||
return nil, &erron
|
return nil, &erron
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.Body(), nil
|
return res.Body(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取验证所需内容
|
||||||
|
func (c *Common) getReviewData(res *resty.Response) error {
|
||||||
|
var reviewResp LoginReviewResp
|
||||||
|
var reviewData ReviewData
|
||||||
|
|
||||||
|
if err := utils.Json.Unmarshal(res.Body(), &reviewResp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceSign := generateDeviceSign(c.DeviceID, c.PackageName)
|
||||||
|
|
||||||
|
reviewData = ReviewData{
|
||||||
|
Creditkey: reviewResp.Creditkey,
|
||||||
|
Reviewurl: reviewResp.Reviewurl + "&deviceid=" + deviceSign,
|
||||||
|
Deviceid: deviceSign,
|
||||||
|
Devicesign: deviceSign,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将reviewData转为JSON字符串
|
||||||
|
reviewDataJSON, _ := json.MarshalIndent(reviewData, "", " ")
|
||||||
|
//reviewDataJSON, _ := json.Marshal(reviewData)
|
||||||
|
|
||||||
|
return fmt.Errorf(`
|
||||||
|
<div style="font-family: Arial, sans-serif; padding: 15px; border-radius: 5px; border: 1px solid #e0e0e0;>
|
||||||
|
<h3 style="color: #d9534f; margin-top: 0;">
|
||||||
|
<span style="font-size: 16px;">🔒 本次登录需要验证</span><br>
|
||||||
|
<span style="font-size: 14px; font-weight: normal; color: #666;">This login requires verification</span>
|
||||||
|
</h3>
|
||||||
|
<p style="font-size: 14px; margin-bottom: 15px;">下面是验证所需要的数据,具体使用方法请参照对应的驱动文档<br>
|
||||||
|
<span style="color: #666; font-size: 13px;">Below are the relevant verification data. For specific usage methods, please refer to the corresponding driver documentation.</span></p>
|
||||||
|
<div style="border: 1px solid #ddd; border-radius: 4px; padding: 10px; overflow-x: auto; font-family: 'Courier New', monospace; font-size: 13px;">
|
||||||
|
<pre style="margin: 0; white-space: pre-wrap;"><code>%s</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>`, string(reviewDataJSON))
|
||||||
|
}
|
||||||
|
|
||||||
// 计算文件Gcid
|
// 计算文件Gcid
|
||||||
func getGcid(r io.Reader, size int64) (string, error) {
|
func getGcid(r io.Reader, size int64) (string, error) {
|
||||||
calcBlockSize := func(j int64) int64 {
|
calcBlockSize := func(j int64) int64 {
|
||||||
|
@ -201,3 +260,24 @@ func getGcid(r io.Reader, size int64) (string, error) {
|
||||||
}
|
}
|
||||||
return hex.EncodeToString(hash1.Sum(nil)), nil
|
return hex.EncodeToString(hash1.Sum(nil)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateDeviceSign(deviceID, packageName string) string {
|
||||||
|
|
||||||
|
signatureBase := fmt.Sprintf("%s%s%s%s", deviceID, packageName, APPID, APPKey)
|
||||||
|
|
||||||
|
sha1Hash := sha1.New()
|
||||||
|
sha1Hash.Write([]byte(signatureBase))
|
||||||
|
sha1Result := sha1Hash.Sum(nil)
|
||||||
|
|
||||||
|
sha1String := hex.EncodeToString(sha1Result)
|
||||||
|
|
||||||
|
md5Hash := md5.New()
|
||||||
|
md5Hash.Write([]byte(sha1String))
|
||||||
|
md5Result := md5Hash.Sum(nil)
|
||||||
|
|
||||||
|
md5String := hex.EncodeToString(md5Result)
|
||||||
|
|
||||||
|
deviceSign := fmt.Sprintf("div101.%s%s", deviceID, md5String)
|
||||||
|
|
||||||
|
return deviceSign
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue