mirror of https://github.com/Xhofe/alist
				
				
				
			fix(aliyundriver):x-device-id error code (#3390)
* fix(aliyundriver):x-drvice-id error code * fix(aliyunpan):session signature error * fix typo --------- Co-authored-by: Andy Hsu <i@nn.ci>pull/3395/head
							parent
							
								
									22843ffc70
								
							
						
					
					
						commit
						46b2ed2507
					
				| 
						 | 
				
			
			@ -3,6 +3,7 @@ package aliyundrive
 | 
			
		|||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +32,12 @@ type AliDrive struct {
 | 
			
		|||
	AccessToken string
 | 
			
		||||
	cron        *cron.Cron
 | 
			
		||||
	DriveId     string
 | 
			
		||||
	UserID      string
 | 
			
		||||
 | 
			
		||||
	signature  string
 | 
			
		||||
	nonce      int
 | 
			
		||||
	privateKey *ecdsa.PrivateKey
 | 
			
		||||
	cron2      *cron.Cron
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *AliDrive) Config() driver.Config {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +61,7 @@ func (d *AliDrive) Init(ctx context.Context) error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	d.DriveId = utils.Json.Get(res, "default_drive_id").ToString()
 | 
			
		||||
	d.UserID = utils.Json.Get(res, "user_id").ToString()
 | 
			
		||||
	d.cron = cron.NewCron(time.Hour * 2)
 | 
			
		||||
	d.cron.Do(func() {
 | 
			
		||||
		err := d.refreshToken()
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +69,29 @@ func (d *AliDrive) Init(ctx context.Context) error {
 | 
			
		|||
			log.Errorf("%+v", err)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// init deviceID
 | 
			
		||||
	if len(d.DeviceID) < 64 {
 | 
			
		||||
		d.DeviceID = utils.GetSHA256Encode(d.DeviceID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// init privateKey
 | 
			
		||||
	d.privateKey, _ = NewPrivateKey()
 | 
			
		||||
 | 
			
		||||
	// init signature
 | 
			
		||||
	d.sign()
 | 
			
		||||
	d.createSession()
 | 
			
		||||
	d.cron2 = cron.NewCron(time.Minute * 5)
 | 
			
		||||
	d.cron2.Do(func() {
 | 
			
		||||
		d.nonce++
 | 
			
		||||
		d.sign()
 | 
			
		||||
		err := d.renewSession()
 | 
			
		||||
		if d.nonce >= 1073741823 || (err != nil && err.Error() == "device session signature error") {
 | 
			
		||||
			d.nonce = 0
 | 
			
		||||
			d.sign()
 | 
			
		||||
			d.createSession()
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +99,9 @@ func (d *AliDrive) Drop(ctx context.Context) error {
 | 
			
		|||
	if d.cron != nil {
 | 
			
		||||
		d.cron.Stop()
 | 
			
		||||
	}
 | 
			
		||||
	if d.cron2 != nil {
 | 
			
		||||
		d.cron2.Stop()
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
package aliyundrive
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/ecdsa"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"math/big"
 | 
			
		||||
 | 
			
		||||
	"github.com/dustinxie/ecc"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func NewPrivateKey() (*ecdsa.PrivateKey, error) {
 | 
			
		||||
	p256k1 := ecc.P256k1()
 | 
			
		||||
	return ecdsa.GenerateKey(p256k1, rand.Reader)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPrivateKeyFromHex(hex_ string) (*ecdsa.PrivateKey, error) {
 | 
			
		||||
	data, err := hex.DecodeString(hex_)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return NewPrivateKeyFromBytes(data), nil
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewPrivateKeyFromBytes(priv []byte) *ecdsa.PrivateKey {
 | 
			
		||||
	p256k1 := ecc.P256k1()
 | 
			
		||||
	x, y := p256k1.ScalarBaseMult(priv)
 | 
			
		||||
	return &ecdsa.PrivateKey{
 | 
			
		||||
		PublicKey: ecdsa.PublicKey{
 | 
			
		||||
			Curve: p256k1,
 | 
			
		||||
			X:     x,
 | 
			
		||||
			Y:     y,
 | 
			
		||||
		},
 | 
			
		||||
		D: new(big.Int).SetBytes(priv),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PrivateKeyToHex(private *ecdsa.PrivateKey) string {
 | 
			
		||||
	return hex.EncodeToString(PrivateKeyToBytes(private))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PrivateKeyToBytes(private *ecdsa.PrivateKey) []byte {
 | 
			
		||||
	return private.D.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PublicKeyToHex(public *ecdsa.PublicKey) string {
 | 
			
		||||
	return hex.EncodeToString(PublicKeyToBytes(public))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func PublicKeyToBytes(public *ecdsa.PublicKey) []byte {
 | 
			
		||||
	x := public.X.Bytes()
 | 
			
		||||
	if len(x) < 32 {
 | 
			
		||||
		for i := 0; i < 32-len(x); i++ {
 | 
			
		||||
			x = append([]byte{0}, x...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	y := public.Y.Bytes()
 | 
			
		||||
	if len(y) < 32 {
 | 
			
		||||
		for i := 0; i < 32-len(y); i++ {
 | 
			
		||||
			y = append([]byte{0}, y...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return append(x, y...)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ import (
 | 
			
		|||
type Addition struct {
 | 
			
		||||
	driver.RootID
 | 
			
		||||
	RefreshToken   string `json:"refresh_token" required:"true"`
 | 
			
		||||
	DeviceID       string `json:"device_id" required:"true"`
 | 
			
		||||
	OrderBy        string `json:"order_by" type:"select" options:"name,size,updated_at,created_at"`
 | 
			
		||||
	OrderDirection string `json:"order_direction" type:"select" options:"ASC,DESC"`
 | 
			
		||||
	RapidUpload    bool   `json:"rapid_upload"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
package aliyundrive
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
| 
						 | 
				
			
			@ -8,9 +10,37 @@ import (
 | 
			
		|||
	"github.com/alist-org/alist/v3/drivers/base"
 | 
			
		||||
	"github.com/alist-org/alist/v3/internal/op"
 | 
			
		||||
	"github.com/alist-org/alist/v3/pkg/utils"
 | 
			
		||||
	"github.com/dustinxie/ecc"
 | 
			
		||||
	"github.com/go-resty/resty/v2"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *AliDrive) createSession() error {
 | 
			
		||||
	_, err, _ := d.request("https://api.aliyundrive.com/users/v1/users/device/create_session", http.MethodPost, func(req *resty.Request) {
 | 
			
		||||
		req.SetBody(base.Json{
 | 
			
		||||
			"deviceName":   "samsung",
 | 
			
		||||
			"modelName":    "SM-G9810",
 | 
			
		||||
			"nonce":        d.nonce,
 | 
			
		||||
			"pubKey":       PublicKeyToHex(&d.privateKey.PublicKey),
 | 
			
		||||
			"refreshToken": d.RefreshToken,
 | 
			
		||||
		})
 | 
			
		||||
	}, nil)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *AliDrive) renewSession() error {
 | 
			
		||||
	_, err, _ := d.request("https://api.aliyundrive.com/users/v1/users/device/renew_session", http.MethodPost, nil, nil)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *AliDrive) sign() {
 | 
			
		||||
	secpAppID := "5dde4e1bdf9e4966b387ba58f4b3fdc3"
 | 
			
		||||
	singdata := fmt.Sprintf("%s:%s:%s:%d", secpAppID, d.DeviceID, d.UserID, d.nonce)
 | 
			
		||||
	hash := sha256.Sum256([]byte(singdata))
 | 
			
		||||
	data, _ := ecc.SignBytes(d.privateKey, hash[:], ecc.RecID|ecc.LowerS)
 | 
			
		||||
	d.signature = hex.EncodeToString(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// do others that not defined in Driver interface
 | 
			
		||||
 | 
			
		||||
func (d *AliDrive) refreshToken() error {
 | 
			
		||||
| 
						 | 
				
			
			@ -39,9 +69,16 @@ func (d *AliDrive) refreshToken() error {
 | 
			
		|||
 | 
			
		||||
func (d *AliDrive) request(url, method string, callback base.ReqCallback, resp interface{}) ([]byte, error, RespErr) {
 | 
			
		||||
	req := base.RestyClient.R()
 | 
			
		||||
	req.SetHeader("Authorization", "Bearer\t"+d.AccessToken)
 | 
			
		||||
	req.SetHeader("content-type", "application/json")
 | 
			
		||||
	req.SetHeader("origin", "https://www.aliyundrive.com")
 | 
			
		||||
	req.SetHeaders(map[string]string{
 | 
			
		||||
		"Authorization": "Bearer\t" + d.AccessToken,
 | 
			
		||||
		"content-type":  "application/json",
 | 
			
		||||
		"origin":        "https://www.aliyundrive.com",
 | 
			
		||||
		"Referer":       "https://aliyundrive.com/",
 | 
			
		||||
		"X-Signature":   d.signature,
 | 
			
		||||
		"x-request-id":  uuid.NewString(),
 | 
			
		||||
		"X-Canary":      "client=Android,app=adrive,version=v4.1.0",
 | 
			
		||||
		"X-Device-Id":   d.DeviceID,
 | 
			
		||||
	})
 | 
			
		||||
	if callback != nil {
 | 
			
		||||
		callback(req)
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -62,6 +62,7 @@ require (
 | 
			
		|||
	github.com/blevesearch/zapx/v15 v15.3.8 // indirect
 | 
			
		||||
	github.com/bluele/gcache v0.0.2 // indirect
 | 
			
		||||
	github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
 | 
			
		||||
	github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 // indirect
 | 
			
		||||
	github.com/gaoyb7/115drive-webdav v0.1.8 // indirect
 | 
			
		||||
	github.com/geoffgarside/ber v1.1.0 // indirect
 | 
			
		||||
	github.com/gin-contrib/sse v0.1.0 // indirect
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										2
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -63,6 +63,8 @@ github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6
 | 
			
		|||
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
 | 
			
		||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
 | 
			
		||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
 | 
			
		||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 h1:I6KUy4CI6hHjqnyJLNCEi7YHVMkwwtfSr2k9splgdSM=
 | 
			
		||||
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564/go.mod h1:yekO+3ZShy19S+bsmnERmznGy9Rfg6dWWWpiGJjNAz8=
 | 
			
		||||
github.com/gaoyb7/115drive-webdav v0.1.8 h1:EJt4PSmcbvBY4KUh2zSo5p6fN9LZFNkIzuKejipubVw=
 | 
			
		||||
github.com/gaoyb7/115drive-webdav v0.1.8/go.mod h1:BKbeY6j8SKs3+rzBFFALznGxbPmefEm3vA+dGhqgOGU=
 | 
			
		||||
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ package utils
 | 
			
		|||
import (
 | 
			
		||||
	"crypto/md5"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"strings"
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,12 @@ func GetSHA1Encode(data string) string {
 | 
			
		|||
	return hex.EncodeToString(h.Sum(nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetSHA256Encode(data string) string {
 | 
			
		||||
	h := sha256.New()
 | 
			
		||||
	h.Write([]byte(data))
 | 
			
		||||
	return hex.EncodeToString(h.Sum(nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetMD5Encode(data string) string {
 | 
			
		||||
	h := md5.New()
 | 
			
		||||
	h.Write([]byte(data))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue