🚧 189 chunk upload
This commit is contained in:
parent
1a69d80489
commit
c6a5ba9b91
@ -2,16 +2,9 @@ package _89
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/aes"
|
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Xhofe/alist/conf"
|
"github.com/Xhofe/alist/conf"
|
||||||
@ -19,7 +12,6 @@ import (
|
|||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/google/uuid"
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
@ -35,6 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var client189Map map[string]*resty.Client
|
var client189Map map[string]*resty.Client
|
||||||
|
var infoMap = make(map[string]Rsa, 0)
|
||||||
|
|
||||||
func (driver Cloud189) getClient(account *model.Account) (*resty.Client, error) {
|
func (driver Cloud189) getClient(account *model.Account) (*resty.Client, error) {
|
||||||
client, ok := client189Map[account.Name]
|
client, ok := client189Map[account.Name]
|
||||||
@ -158,7 +151,7 @@ func (driver Cloud189) Login(account *model.Account) error {
|
|||||||
u := "https://open.e.189.cn/api/logbox/oauth2/picCaptcha.do?token=" + vCodeID + timeStamp
|
u := "https://open.e.189.cn/api/logbox/oauth2/picCaptcha.do?token=" + vCodeID + timeStamp
|
||||||
imgRes, err := client.R().SetHeaders(map[string]string{
|
imgRes, err := client.R().SetHeaders(map[string]string{
|
||||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/76.0",
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/76.0",
|
||||||
"Referer": "https://open.e.pan.cn/",
|
"Referer": "https://open.e.189.cn/api/logbox/oauth2/unifyAccountLogin.do",
|
||||||
"Sec-Fetch-Dest": "image",
|
"Sec-Fetch-Dest": "image",
|
||||||
"Sec-Fetch-Mode": "no-cors",
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
"Sec-Fetch-Site": "same-origin",
|
"Sec-Fetch-Site": "same-origin",
|
||||||
@ -176,9 +169,10 @@ func (driver Cloud189) Login(account *model.Account) error {
|
|||||||
return errors.New("ocr error:" + jsoniter.Get(vRes.Body(), "msg").ToString())
|
return errors.New("ocr error:" + jsoniter.Get(vRes.Body(), "msg").ToString())
|
||||||
}
|
}
|
||||||
vCodeRS = jsoniter.Get(vRes.Body(), "result").ToString()
|
vCodeRS = jsoniter.Get(vRes.Body(), "result").ToString()
|
||||||
|
log.Debugln("code: ", vCodeRS)
|
||||||
}
|
}
|
||||||
userRsa := RsaEncode([]byte(account.Username), jRsakey)
|
userRsa := RsaEncode([]byte(account.Username), jRsakey, true)
|
||||||
passwordRsa := RsaEncode([]byte(account.Password), jRsakey)
|
passwordRsa := RsaEncode([]byte(account.Password), jRsakey, true)
|
||||||
url = "https://open.e.189.cn/api/logbox/oauth2/loginSubmit.do"
|
url = "https://open.e.189.cn/api/logbox/oauth2/loginSubmit.do"
|
||||||
var loginResp LoginResp
|
var loginResp LoginResp
|
||||||
res, err := client.R().
|
res, err := client.R().
|
||||||
@ -222,39 +216,6 @@ func (driver Cloud189) Login(account *model.Account) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Cloud189Error struct {
|
|
||||||
ErrorCode string `json:"errorCode"`
|
|
||||||
ErrorMsg string `json:"errorMsg"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Cloud189File struct {
|
|
||||||
Id int64 `json:"id"`
|
|
||||||
LastOpTime string `json:"lastOpTime"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Icon struct {
|
|
||||||
SmallUrl string `json:"smallUrl"`
|
|
||||||
//LargeUrl string `json:"largeUrl"`
|
|
||||||
} `json:"icon"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Cloud189Folder struct {
|
|
||||||
Id int64 `json:"id"`
|
|
||||||
LastOpTime string `json:"lastOpTime"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Cloud189Files struct {
|
|
||||||
ResCode int `json:"res_code"`
|
|
||||||
ResMessage string `json:"res_message"`
|
|
||||||
FileListAO struct {
|
|
||||||
Count int `json:"count"`
|
|
||||||
FileList []Cloud189File `json:"fileList"`
|
|
||||||
FolderList []Cloud189Folder `json:"folderList"`
|
|
||||||
} `json:"fileListAO"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (driver Cloud189) isFamily(account *model.Account) bool {
|
func (driver Cloud189) isFamily(account *model.Account) bool {
|
||||||
return account.InternalType == "Family"
|
return account.InternalType == "Family"
|
||||||
}
|
}
|
||||||
@ -344,7 +305,7 @@ func (driver Cloud189) Request(url string, method int, query, form map[string]st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debug(res.String())
|
//log.Debug(res.String())
|
||||||
if e.ErrorCode != "" {
|
if e.ErrorCode != "" {
|
||||||
if e.ErrorCode == "InvalidSessionKey" {
|
if e.ErrorCode == "InvalidSessionKey" {
|
||||||
err = driver.Login(account)
|
err = driver.Login(account)
|
||||||
@ -361,36 +322,68 @@ func (driver Cloud189) Request(url string, method int, query, form map[string]st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Cloud189) GetSessionKey(account *model.Account) (string, error) {
|
func (driver Cloud189) GetSessionKey(account *model.Account) (string, error) {
|
||||||
|
//info, ok := infoMap[account.Name]
|
||||||
|
//if !ok {
|
||||||
|
// info = Info{}
|
||||||
|
// infoMap[account.Name] = info
|
||||||
|
//} else {
|
||||||
|
// log.Debugf("hit")
|
||||||
|
//}
|
||||||
|
//if info.SessionKey != "" {
|
||||||
|
// return info.SessionKey, nil
|
||||||
|
//}
|
||||||
resp, err := driver.Request("https://cloud.189.cn/v2/getUserBriefInfo.action", base.Get, nil, nil, nil, account)
|
resp, err := driver.Request("https://cloud.189.cn/v2/getUserBriefInfo.action", base.Get, nil, nil, nil, account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return jsoniter.Get(resp, "sessionKey").ToString(), nil
|
sessionKey := jsoniter.Get(resp, "sessionKey").ToString()
|
||||||
|
//info.SessionKey = sessionKey
|
||||||
|
return sessionKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Cloud189) GetResKey(account *model.Account) (string, string, error) {
|
func (driver Cloud189) GetResKey(account *model.Account) (string, string, error) {
|
||||||
|
rsa, ok := infoMap[account.Name]
|
||||||
|
if !ok {
|
||||||
|
rsa = Rsa{}
|
||||||
|
infoMap[account.Name] = rsa
|
||||||
|
}
|
||||||
|
now := time.Now().UnixMilli()
|
||||||
|
if rsa.Expire > now {
|
||||||
|
return rsa.PubKey, rsa.PkId, nil
|
||||||
|
}
|
||||||
resp, err := driver.Request("https://cloud.189.cn/api/security/generateRsaKey.action", base.Get, nil, nil, nil, account)
|
resp, err := driver.Request("https://cloud.189.cn/api/security/generateRsaKey.action", base.Get, nil, nil, nil, account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
return jsoniter.Get(resp, "pubKey").ToString(), jsoniter.Get(resp, "pkId").ToString(), nil
|
pubKey, pkId := jsoniter.Get(resp, "pubKey").ToString(), jsoniter.Get(resp, "pkId").ToString()
|
||||||
|
rsa.PubKey, rsa.PkId = pubKey, pkId
|
||||||
|
rsa.Expire = jsoniter.Get(resp, "expire").ToInt64()
|
||||||
|
return pubKey, pkId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Cloud189) UploadRequest(url string, form map[string]string, account *model.Account) ([]byte, error) {
|
func (driver Cloud189) UploadRequest1(uri string, form map[string]string, account *model.Account, resp interface{}) ([]byte, error) {
|
||||||
sessionKey, err := driver.GetSessionKey(account)
|
//sessionKey, err := driver.GetSessionKey(account)
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
//}
|
||||||
|
sessionKey := account.DriveId
|
||||||
pubKey, pkId, err := driver.GetResKey(account)
|
pubKey, pkId, err := driver.GetResKey(account)
|
||||||
|
log.Debugln(sessionKey, pubKey, pkId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
xRId := uuid.New().String()
|
xRId := Random("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx")
|
||||||
pkey := strings.ReplaceAll(xRId, "-", "")[:mathRand.Intn(16)+16]
|
pkey := Random("xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx")[0 : 16+int(16*mathRand.Float32())]
|
||||||
params := aesEncrypt(qs(form), pkey[:16])
|
params := hex.EncodeToString(aesEncrypt([]byte(qs(form)), []byte(pkey[0:16])))
|
||||||
date := strconv.FormatInt(time.Now().Unix(), 10)
|
date := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
signature := hmacSha1(fmt.Sprintf("SessionKey=%s&Operate=GET&RequestURI=%s&Date=%s¶ms=%s", sessionKey, url, date, params), pkey)
|
a := make(url.Values)
|
||||||
encryptionText := RsaEncode([]byte(pkey), pubKey)
|
a.Set("SessionKey", sessionKey)
|
||||||
|
a.Set("Operate", http.MethodGet)
|
||||||
|
a.Set("RequestURI", uri)
|
||||||
|
a.Set("Date", date)
|
||||||
|
a.Set("params", params)
|
||||||
|
signature := hex.EncodeToString(SHA1(EncodeParam(a), pkey))
|
||||||
|
encryptionText := RsaEncode([]byte(pkey), pubKey, false)
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"signature": signature,
|
"signature": signature,
|
||||||
"sessionKey": sessionKey,
|
"sessionKey": sessionKey,
|
||||||
@ -398,23 +391,72 @@ func (driver Cloud189) UploadRequest(url string, form map[string]string, account
|
|||||||
"pkId": pkId,
|
"pkId": pkId,
|
||||||
"x-request-id": xRId,
|
"x-request-id": xRId,
|
||||||
"x-request-date": date,
|
"x-request-date": date,
|
||||||
"origin": "https://cloud.189.cn",
|
|
||||||
"referer": "https://cloud.189.cn/",
|
|
||||||
}
|
}
|
||||||
log.Debugf("%+v\n%s", headers, params)
|
req := base.RestyClient.R().SetHeaders(headers).SetQueryParam("params", params)
|
||||||
res, err := base.RestyClient.R().SetHeaders(headers).SetQueryParam("params", params).Get("https://upload.cloud.189.cn" + url)
|
if resp != nil {
|
||||||
|
req.SetResult(resp)
|
||||||
|
}
|
||||||
|
res, err := req.Get("https://upload.cloud.189.cn" + uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debug(res.String())
|
//log.Debug(res.String())
|
||||||
data := res.Body()
|
data := res.Body()
|
||||||
if jsoniter.Get(data, "code").ToString() != "SUCCESS" {
|
if jsoniter.Get(data, "code").ToString() != "SUCCESS" {
|
||||||
return nil, errors.New(jsoniter.Get(data, "msg").ToString())
|
return nil, errors.New(uri + "---" + jsoniter.Get(data, "msg").ToString())
|
||||||
}
|
}
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload Error: decrypt encryptionText failed
|
func (driver Cloud189) UploadRequest(uri string, form map[string]string, account *model.Account, resp interface{}) ([]byte, error) {
|
||||||
|
c := strconv.FormatInt(time.Now().UnixMilli(), 10)
|
||||||
|
r := Random("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx")
|
||||||
|
l := Random("xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx")
|
||||||
|
l = l[0 : 16+int(16*mathRand.Float32())]
|
||||||
|
|
||||||
|
e := qs(form)
|
||||||
|
data := aesEncrypt([]byte(e), []byte(l[0:16]))
|
||||||
|
h := hex.EncodeToString(data)
|
||||||
|
|
||||||
|
sessionKey := account.DriveId
|
||||||
|
a := make(url.Values)
|
||||||
|
a.Set("SessionKey", sessionKey)
|
||||||
|
a.Set("Operate", http.MethodGet)
|
||||||
|
a.Set("RequestURI", uri)
|
||||||
|
a.Set("Date", c)
|
||||||
|
a.Set("params", h)
|
||||||
|
g := SHA1(EncodeParam(a), l)
|
||||||
|
|
||||||
|
pubKey, pkId, err := driver.GetResKey(account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b := RsaEncode([]byte(l), pubKey, false)
|
||||||
|
|
||||||
|
req := base.RestyClient.R()
|
||||||
|
req.Header.Set("accept", "application/json;charset=UTF-8")
|
||||||
|
req.Header.Set("SessionKey", sessionKey)
|
||||||
|
req.Header.Set("Signature", hex.EncodeToString(g))
|
||||||
|
req.Header.Set("X-Request-Date", c)
|
||||||
|
req.Header.Set("X-Request-ID", r)
|
||||||
|
req.Header.Set("EncryptionText", b)
|
||||||
|
req.Header.Set("PkId", pkId)
|
||||||
|
if resp != nil {
|
||||||
|
req.SetResult(resp)
|
||||||
|
}
|
||||||
|
res, err := req.Get("https://upload.cloud.189.cn" + uri + "?params=" + h)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//log.Debug(res.String())
|
||||||
|
data = res.Body()
|
||||||
|
if jsoniter.Get(data, "code").ToString() != "SUCCESS" {
|
||||||
|
return nil, errors.New(uri + "---" + jsoniter.Get(data, "msg").ToString())
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUpload Error: signature check false
|
||||||
func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account) error {
|
func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account) error {
|
||||||
const DEFAULT uint64 = 10485760
|
const DEFAULT uint64 = 10485760
|
||||||
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
|
var count = int64(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
|
||||||
@ -432,11 +474,14 @@ func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account)
|
|||||||
"fileSize": strconv.FormatInt(int64(file.Size), 10),
|
"fileSize": strconv.FormatInt(int64(file.Size), 10),
|
||||||
"sliceSize": strconv.FormatInt(int64(DEFAULT), 10),
|
"sliceSize": strconv.FormatInt(int64(DEFAULT), 10),
|
||||||
"lazyCheck": "1",
|
"lazyCheck": "1",
|
||||||
}, account)
|
}, account, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uploadFileId := jsoniter.Get(res, "data.uploadFileId").ToString()
|
uploadFileId := jsoniter.Get(res, "data", "uploadFileId").ToString()
|
||||||
|
//_, err = driver.UploadRequest("/person/getUploadedPartsInfo", map[string]string{
|
||||||
|
// "uploadFileId": uploadFileId,
|
||||||
|
//}, account, nil)
|
||||||
var i int64
|
var i int64
|
||||||
var byteSize uint64
|
var byteSize uint64
|
||||||
md5s := make([]string, 0)
|
md5s := make([]string, 0)
|
||||||
@ -455,171 +500,73 @@ func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account)
|
|||||||
}
|
}
|
||||||
finish += uint64(n)
|
finish += uint64(n)
|
||||||
md5Bytes := getMd5(byteData)
|
md5Bytes := getMd5(byteData)
|
||||||
md5Str := hex.EncodeToString(md5Bytes)
|
md5Hex := hex.EncodeToString(md5Bytes)
|
||||||
md5Base64 := base64.StdEncoding.EncodeToString(md5Bytes)
|
md5Base64 := base64.StdEncoding.EncodeToString(md5Bytes)
|
||||||
md5s = append(md5s, md5Str)
|
md5s = append(md5s, strings.ToUpper(md5Hex))
|
||||||
md5Sum.Write(byteData)
|
md5Sum.Write(byteData)
|
||||||
|
log.Debugf("md5Bytes: %+v,md5Str:%s,md5Base64:%s", md5Bytes, md5Hex, md5Base64)
|
||||||
|
var resp UploadUrlsResp
|
||||||
res, err = driver.UploadRequest("/person/getMultiUploadUrls", map[string]string{
|
res, err = driver.UploadRequest("/person/getMultiUploadUrls", map[string]string{
|
||||||
"partInfo": fmt.Sprintf("%s-%s", strconv.FormatInt(i, 10), md5Base64),
|
"partInfo": fmt.Sprintf("%s-%s", strconv.FormatInt(i, 10), md5Base64),
|
||||||
"uploadFileId": uploadFileId,
|
"uploadFileId": uploadFileId,
|
||||||
}, account)
|
}, account, &resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uploadData := jsoniter.Get(res, "uploadUrls.partNumber_"+strconv.FormatInt(i, 10))
|
uploadData := resp.UploadUrls["partNumber_"+strconv.FormatInt(i, 10)]
|
||||||
headers := strings.Split(uploadData.Get("requestHeader").ToString(), "&")
|
log.Debugf("uploadData: %+v", uploadData)
|
||||||
req, err := http.NewRequest("PUT", uploadData.Get("requestURL").ToString(), bytes.NewBuffer(byteData))
|
requestURL := uploadData.RequestURL
|
||||||
|
uploadHeaders := strings.Split(decodeURIComponent(uploadData.RequestHeader), "&")
|
||||||
|
req, _ := http.NewRequest(http.MethodPut, requestURL, bytes.NewReader(byteData))
|
||||||
|
for _, v := range uploadHeaders {
|
||||||
|
i := strings.Index(v, "=")
|
||||||
|
req.Header.Set(v[0:i], v[i+1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := base.HttpClient.Do(req)
|
||||||
|
log.Debugf("%+v %+v", r, r.Request.Header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, header := range headers {
|
|
||||||
kv := strings.Split(header, "=")
|
|
||||||
req.Header.Set(kv[0], strings.Join(kv[1:], "="))
|
|
||||||
}
|
}
|
||||||
res, err := base.HttpClient.Do(req)
|
fileMd5 := hex.EncodeToString(md5Sum.Sum(nil))
|
||||||
if err != nil {
|
sliceMd5 := fileMd5
|
||||||
return err
|
if file.GetSize() > DEFAULT {
|
||||||
|
sliceMd5 = utils.GetMD5Encode(strings.Join(md5s, "\n"))
|
||||||
}
|
}
|
||||||
log.Debugf("%+v", res)
|
|
||||||
}
|
|
||||||
id := md5Sum.Sum(nil)
|
|
||||||
res, err = driver.UploadRequest("/person/commitMultiUploadFile", map[string]string{
|
res, err = driver.UploadRequest("/person/commitMultiUploadFile", map[string]string{
|
||||||
"uploadFileId": uploadFileId,
|
"uploadFileId": uploadFileId,
|
||||||
"fileMd5": hex.EncodeToString(id),
|
"fileMd5": fileMd5,
|
||||||
"sliceMd5": utils.GetMD5Encode(strings.Join(md5s, "\n")),
|
"sliceMd5": sliceMd5,
|
||||||
"lazyCheck": "1",
|
"lazyCheck": "1",
|
||||||
}, account)
|
}, account, nil)
|
||||||
|
account.DriveId, _ = driver.GetSessionKey(account)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func random() string {
|
func (driver Cloud189) OldUpload(file *model.FileStream, account *model.Account) error {
|
||||||
return fmt.Sprintf("0.%17v", mathRand.New(mathRand.NewSource(time.Now().UnixNano())).Int63n(100000000000000000))
|
//return base.ErrNotImplement
|
||||||
}
|
client, err := driver.getClient(account)
|
||||||
|
|
||||||
func RsaEncode(origData []byte, j_rsakey string) string {
|
|
||||||
publicKey := []byte("-----BEGIN PUBLIC KEY-----\n" + j_rsakey + "\n-----END PUBLIC KEY-----")
|
|
||||||
block, _ := pem.Decode(publicKey)
|
|
||||||
pubInterface, _ := x509.ParsePKIXPublicKey(block.Bytes)
|
|
||||||
pub := pubInterface.(*rsa.PublicKey)
|
|
||||||
b, err := rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("err: %s", err.Error())
|
return err
|
||||||
}
|
}
|
||||||
return b64tohex(base64.StdEncoding.EncodeToString(b))
|
parentFile, err := driver.File(file.ParentPath, account)
|
||||||
}
|
if err != nil {
|
||||||
|
return err
|
||||||
var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
}
|
||||||
|
// api refer to PanIndex
|
||||||
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"
|
res, err := client.R().SetMultipartFormData(map[string]string{
|
||||||
|
"parentId": parentFile.Id,
|
||||||
func int2char(a int) string {
|
"sessionKey": account.DriveId,
|
||||||
return strings.Split(BI_RM, "")[a]
|
"opertype": "1",
|
||||||
}
|
"fname": file.GetFileName(),
|
||||||
|
}).SetMultipartField("Filedata", file.GetFileName(), file.GetMIMEType(), file).Post("https://hb02.upload.cloud.189.cn/v1/DCIWebUploadAction")
|
||||||
func b64tohex(a string) string {
|
if err != nil {
|
||||||
d := ""
|
return err
|
||||||
e := 0
|
}
|
||||||
c := 0
|
if jsoniter.Get(res.Body(), "MD5").ToString() != "" {
|
||||||
for i := 0; i < len(a); i++ {
|
return nil
|
||||||
m := strings.Split(a, "")[i]
|
}
|
||||||
if m != "=" {
|
log.Debugf(res.String())
|
||||||
v := strings.Index(b64map, m)
|
return errors.New(res.String())
|
||||||
if 0 == e {
|
|
||||||
e = 1
|
|
||||||
d += int2char(v >> 2)
|
|
||||||
c = 3 & v
|
|
||||||
} else if 1 == e {
|
|
||||||
e = 2
|
|
||||||
d += int2char(c<<2 | v>>4)
|
|
||||||
c = 15 & v
|
|
||||||
} else if 2 == e {
|
|
||||||
e = 3
|
|
||||||
d += int2char(c)
|
|
||||||
d += int2char(v >> 2)
|
|
||||||
c = 3 & v
|
|
||||||
} else {
|
|
||||||
e = 0
|
|
||||||
d += int2char(c<<2 | v>>4)
|
|
||||||
d += int2char(15 & v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if e == 1 {
|
|
||||||
d += int2char(c << 2)
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func qs(form map[string]string) string {
|
|
||||||
strList := make([]string, 0)
|
|
||||||
for k, v := range form {
|
|
||||||
strList = append(strList, fmt.Sprintf("%s=%s", k, url.QueryEscape(v)))
|
|
||||||
}
|
|
||||||
return strings.Join(strList, "&")
|
|
||||||
}
|
|
||||||
|
|
||||||
func aesEncrypt(data, key string) string {
|
|
||||||
encrypted := AesEncryptECB([]byte(data), []byte(key))
|
|
||||||
//return string(encrypted)
|
|
||||||
return hex.EncodeToString(encrypted)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hmacSha1(data string, secret string) string {
|
|
||||||
h := hmac.New(sha1.New, []byte(secret))
|
|
||||||
h.Write([]byte(data))
|
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func AesEncryptECB(origData []byte, key []byte) (encrypted []byte) {
|
|
||||||
cipher, _ := aes.NewCipher(generateKey(key))
|
|
||||||
length := (len(origData) + aes.BlockSize) / aes.BlockSize
|
|
||||||
plain := make([]byte, length*aes.BlockSize)
|
|
||||||
copy(plain, origData)
|
|
||||||
pad := byte(len(plain) - len(origData))
|
|
||||||
for i := len(origData); i < len(plain); i++ {
|
|
||||||
plain[i] = pad
|
|
||||||
}
|
|
||||||
encrypted = make([]byte, len(plain))
|
|
||||||
// 分组分块加密
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs <= len(origData); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
|
||||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
|
||||||
}
|
|
||||||
|
|
||||||
return encrypted
|
|
||||||
}
|
|
||||||
func AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) {
|
|
||||||
cipher, _ := aes.NewCipher(generateKey(key))
|
|
||||||
decrypted = make([]byte, len(encrypted))
|
|
||||||
//
|
|
||||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
|
||||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
|
||||||
}
|
|
||||||
|
|
||||||
trim := 0
|
|
||||||
if len(decrypted) > 0 {
|
|
||||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
return decrypted[:trim]
|
|
||||||
}
|
|
||||||
func generateKey(key []byte) (genKey []byte) {
|
|
||||||
genKey = make([]byte, 16)
|
|
||||||
copy(genKey, key)
|
|
||||||
for i := 16; i < len(key); {
|
|
||||||
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
|
|
||||||
genKey[j] ^= key[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return genKey
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMd5(data []byte) []byte {
|
|
||||||
h := md5.New()
|
|
||||||
h.Write(data)
|
|
||||||
return h.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
base.RegisterDriver(&Cloud189{})
|
|
||||||
client189Map = make(map[string]*resty.Client, 0)
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
package _89
|
package _89
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Xhofe/alist/conf"
|
"github.com/Xhofe/alist/conf"
|
||||||
"github.com/Xhofe/alist/drivers/base"
|
"github.com/Xhofe/alist/drivers/base"
|
||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
@ -350,29 +348,8 @@ func (driver Cloud189) Upload(file *model.FileStream, account *model.Account) er
|
|||||||
if file == nil {
|
if file == nil {
|
||||||
return base.ErrEmptyFile
|
return base.ErrEmptyFile
|
||||||
}
|
}
|
||||||
client, err := driver.getClient(account)
|
//return driver.NewUpload(file, account)
|
||||||
if err != nil {
|
return driver.OldUpload(file, account)
|
||||||
return err
|
|
||||||
}
|
|
||||||
parentFile, err := driver.File(file.ParentPath, account)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// api refer to PanIndex
|
|
||||||
res, err := client.R().SetMultipartFormData(map[string]string{
|
|
||||||
"parentId": parentFile.Id,
|
|
||||||
"sessionKey": account.DriveId,
|
|
||||||
"opertype": "1",
|
|
||||||
"fname": file.GetFileName(),
|
|
||||||
}).SetMultipartField("Filedata", file.GetFileName(), file.GetMIMEType(), file).Post("https://hb02.upload.cloud.189.cn/v1/DCIWebUploadAction")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if jsoniter.Get(res.Body(), "MD5").ToString() != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
log.Debugf(res.String())
|
|
||||||
return errors.New(res.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ base.Driver = (*Cloud189)(nil)
|
var _ base.Driver = (*Cloud189)(nil)
|
||||||
|
55
drivers/189/types.go
Normal file
55
drivers/189/types.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package _89
|
||||||
|
|
||||||
|
type Cloud189Error struct {
|
||||||
|
ErrorCode string `json:"errorCode"`
|
||||||
|
ErrorMsg string `json:"errorMsg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cloud189File struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
LastOpTime string `json:"lastOpTime"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Icon struct {
|
||||||
|
SmallUrl string `json:"smallUrl"`
|
||||||
|
//LargeUrl string `json:"largeUrl"`
|
||||||
|
} `json:"icon"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cloud189Folder struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
LastOpTime string `json:"lastOpTime"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cloud189Files struct {
|
||||||
|
ResCode int `json:"res_code"`
|
||||||
|
ResMessage string `json:"res_message"`
|
||||||
|
FileListAO struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
FileList []Cloud189File `json:"fileList"`
|
||||||
|
FolderList []Cloud189Folder `json:"folderList"`
|
||||||
|
} `json:"fileListAO"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UploadUrlsResp struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
UploadUrls map[string]Part `json:"uploadUrls"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Part struct {
|
||||||
|
RequestURL string `json:"requestURL"`
|
||||||
|
RequestHeader string `json:"requestHeader"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//type Info struct {
|
||||||
|
// SessionKey string
|
||||||
|
// Rsa Rsa
|
||||||
|
//}
|
||||||
|
|
||||||
|
type Rsa struct {
|
||||||
|
Expire int64 `json:"expire"`
|
||||||
|
PkId string `json:"pkId"`
|
||||||
|
PubKey string `json:"pubKey"`
|
||||||
|
}
|
188
drivers/189/util.go
Normal file
188
drivers/189/util.go
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
package _89
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/pem"
|
||||||
|
"fmt"
|
||||||
|
"github.com/Xhofe/alist/drivers/base"
|
||||||
|
"github.com/go-resty/resty/v2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
mathRand "math/rand"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func random() string {
|
||||||
|
return fmt.Sprintf("0.%17v", mathRand.New(mathRand.NewSource(time.Now().UnixNano())).Int63n(100000000000000000))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RsaEncode(origData []byte, j_rsakey string, hex bool) string {
|
||||||
|
publicKey := []byte("-----BEGIN PUBLIC KEY-----\n" + j_rsakey + "\n-----END PUBLIC KEY-----")
|
||||||
|
block, _ := pem.Decode(publicKey)
|
||||||
|
pubInterface, _ := x509.ParsePKIXPublicKey(block.Bytes)
|
||||||
|
pub := pubInterface.(*rsa.PublicKey)
|
||||||
|
b, err := rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("err: %s", err.Error())
|
||||||
|
}
|
||||||
|
res := base64.StdEncoding.EncodeToString(b)
|
||||||
|
if hex {
|
||||||
|
return b64tohex(res)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||||
|
|
||||||
|
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
func int2char(a int) string {
|
||||||
|
return strings.Split(BI_RM, "")[a]
|
||||||
|
}
|
||||||
|
|
||||||
|
func b64tohex(a string) string {
|
||||||
|
d := ""
|
||||||
|
e := 0
|
||||||
|
c := 0
|
||||||
|
for i := 0; i < len(a); i++ {
|
||||||
|
m := strings.Split(a, "")[i]
|
||||||
|
if m != "=" {
|
||||||
|
v := strings.Index(b64map, m)
|
||||||
|
if 0 == e {
|
||||||
|
e = 1
|
||||||
|
d += int2char(v >> 2)
|
||||||
|
c = 3 & v
|
||||||
|
} else if 1 == e {
|
||||||
|
e = 2
|
||||||
|
d += int2char(c<<2 | v>>4)
|
||||||
|
c = 15 & v
|
||||||
|
} else if 2 == e {
|
||||||
|
e = 3
|
||||||
|
d += int2char(c)
|
||||||
|
d += int2char(v >> 2)
|
||||||
|
c = 3 & v
|
||||||
|
} else {
|
||||||
|
e = 0
|
||||||
|
d += int2char(c<<2 | v>>4)
|
||||||
|
d += int2char(15 & v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if e == 1 {
|
||||||
|
d += int2char(c << 2)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func qs(form map[string]string) string {
|
||||||
|
f := make(url.Values)
|
||||||
|
for k, v := range form {
|
||||||
|
f.Set(k, v)
|
||||||
|
}
|
||||||
|
return EncodeParam(f)
|
||||||
|
//strList := make([]string, 0)
|
||||||
|
//for k, v := range form {
|
||||||
|
// strList = append(strList, fmt.Sprintf("%s=%s", k, url.QueryEscape(v)))
|
||||||
|
//}
|
||||||
|
//return strings.Join(strList, "&")
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncodeParam(v url.Values) string {
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var buf strings.Builder
|
||||||
|
keys := make([]string, 0, len(v))
|
||||||
|
for k := range v {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
vs := v[k]
|
||||||
|
for _, v := range vs {
|
||||||
|
if buf.Len() > 0 {
|
||||||
|
buf.WriteByte('&')
|
||||||
|
}
|
||||||
|
buf.WriteString(k)
|
||||||
|
buf.WriteByte('=')
|
||||||
|
buf.WriteString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func aesEncrypt(data, key []byte) []byte {
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
if block == nil {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
data = PKCS7Padding(data, block.BlockSize())
|
||||||
|
decrypted := make([]byte, len(data))
|
||||||
|
size := block.BlockSize()
|
||||||
|
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
|
||||||
|
block.Encrypt(decrypted[bs:be], data[bs:be])
|
||||||
|
}
|
||||||
|
return decrypted
|
||||||
|
}
|
||||||
|
|
||||||
|
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(ciphertext)%blockSize
|
||||||
|
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(ciphertext, padtext...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hmacSha1(data string, secret string) string {
|
||||||
|
h := hmac.New(sha1.New, []byte(secret))
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMd5(data []byte) []byte {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(data)
|
||||||
|
return h.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
base.RegisterDriver(&Cloud189{})
|
||||||
|
client189Map = make(map[string]*resty.Client, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeURIComponent(str string) string {
|
||||||
|
r, _ := url.PathUnescape(str)
|
||||||
|
//r = strings.ReplaceAll(r, " ", "+")
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func Random(v string) string {
|
||||||
|
reg := regexp.MustCompilePOSIX("[xy]")
|
||||||
|
data := reg.ReplaceAllFunc([]byte(v), func(msg []byte) []byte {
|
||||||
|
var i int64
|
||||||
|
t := int64(16 * mathRand.Float32())
|
||||||
|
if msg[0] == 120 {
|
||||||
|
i = t
|
||||||
|
} else {
|
||||||
|
i = 3&t | 8
|
||||||
|
}
|
||||||
|
return []byte(strconv.FormatInt(i, 16))
|
||||||
|
})
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SHA1(v, l string) []byte {
|
||||||
|
key := []byte(l)
|
||||||
|
mac := hmac.New(sha1.New, key)
|
||||||
|
mac.Write([]byte(v))
|
||||||
|
return mac.Sum(nil)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user