mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-10-10 21:13:10 +08:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe416ba15c | |||
| de66708b24 | |||
| 2ca3e0b8bc | |||
| ae04a0a760 | |||
| c28168c970 | |||
| 46b2ed2507 | |||
| 22843ffc70 | |||
| e1b6368343 | |||
| 62dae50d70 | |||
| 43a8ed472b | |||
| d87878c232 | |||
| ab7dee49b0 | |||
| dca115506d | |||
| be17fba0c6 | |||
| cd58aa5efe | |||
| 946833d2cc | |||
| eb42d09849 | |||
| 9d00492750 | |||
| b6711d6ab9 | |||
| 7bc46de8aa | |||
| a4f4fb2d73 | |||
| a181b56ea7 | |||
| d0b743d955 | |||
| a985b748e9 | |||
| 44cb8aaafe | |||
| 51f5d1b3c4 | |||
| 36e0d6f787 | |||
| 3d0065bdcf | |||
| 7bf8071095 | |||
| 30d39f8e10 | |||
| 20d3ef7de6 | |||
| 86e5dae4d1 | |||
| d89b1d4871 | |||
| 080e6fb22a | |||
| e1cd71616d | |||
| c92e11dad5 | |||
| b52e8747fa | |||
| 14305748f0 | |||
| 44f8112e53 | |||
| 6a90b1d40a | |||
| b42ec3e810 | |||
| 28875ce304 |
@@ -25,6 +25,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo snap install zig --classic --beta
|
||||
docker pull crazymax/xgo:latest
|
||||
go install github.com/crazy-max/xgo@latest
|
||||
sudo apt install upx
|
||||
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build_docker:
|
||||
name: Docker
|
||||
name: Build docker
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -30,10 +30,36 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
build_docker_with_aria2:
|
||||
needs: build_docker
|
||||
name: Build docker with aria2
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: alist-org/with_aria2
|
||||
ref: main
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Commit
|
||||
run: |
|
||||
git config --local user.email "i@nn.ci"
|
||||
git config --local user.name "Noah Hsu"
|
||||
git commit --allow-empty -m "Trigger build for ${{ github.sha }}"
|
||||
|
||||
- name: Push commit
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.MY_TOKEN }}
|
||||
branch: main
|
||||
repository: alist-org/with_aria2
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
if: github.event.label.name == 'question'
|
||||
steps:
|
||||
- name: Create comment
|
||||
uses: actions-cool/issues-helper@v3.3.3
|
||||
uses: actions-cool/issues-helper@v3.4.0
|
||||
with:
|
||||
actions: 'create-comment'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -38,6 +38,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo snap install zig --classic --beta
|
||||
docker pull crazymax/xgo:latest
|
||||
go install github.com/crazy-max/xgo@latest
|
||||
sudo apt install upx
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release_docker:
|
||||
name: Docker
|
||||
name: Release Docker
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -33,10 +33,36 @@ jobs:
|
||||
|
||||
- name: Build and push
|
||||
id: docker_build
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/arm/v6,linux/s390x
|
||||
|
||||
release_docker_with_aria2:
|
||||
needs: release_docker
|
||||
name: Release docker with aria2
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: alist-org/with_aria2
|
||||
ref: main
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Add tag
|
||||
run: |
|
||||
git config --local user.email "i@nn.ci"
|
||||
git config --local user.name "Noah Hsu"
|
||||
git tag -a ${{ github.ref_name }} -m "release ${{ github.ref_name }}"
|
||||
|
||||
- name: Push tags
|
||||
uses: ad-m/github-push-action@master
|
||||
with:
|
||||
github_token: ${{ secrets.MY_TOKEN }}
|
||||
branch: main
|
||||
repository: alist-org/with_aria2
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
appName="alist"
|
||||
builtAt="$(date +'%F %T %z')"
|
||||
goVersion=$(go version | sed 's/go version //')
|
||||
gitAuthor=$(git show -s --format='format:%aN <%ae>' HEAD)
|
||||
gitAuthor="Xhofe <i@nn.ci>"
|
||||
gitCommit=$(git log --pretty=format:"%h" -1)
|
||||
|
||||
if [ "$1" = "dev" ]; then
|
||||
@@ -41,6 +41,15 @@ FetchWebRelease() {
|
||||
rm -rf dist.tar.gz
|
||||
}
|
||||
|
||||
BuildWinArm64() {
|
||||
echo building for windows-arm64
|
||||
export GOOS=windows
|
||||
export GOARCH=arm64
|
||||
export CC=$(pwd)/wrapper/zcc-arm64
|
||||
export CXX=$(pwd)/wrapper/zcxx-arm64
|
||||
go build -o "$1" -ldflags="$ldflags" -tags=jsoniter .
|
||||
}
|
||||
|
||||
BuildDev() {
|
||||
rm -rf .git/
|
||||
xgo -targets=linux/amd64,windows/amd64,darwin/amd64 -out "$appName" -ldflags="$ldflags" -tags=jsoniter .
|
||||
@@ -48,7 +57,7 @@ BuildDev() {
|
||||
mv alist-* dist
|
||||
cd dist
|
||||
upx -9 ./alist-linux*
|
||||
upx -9 ./alist-windows*
|
||||
upx -9 ./alist-windows-amd64.exe
|
||||
find . -type f -print0 | xargs -0 md5sum >md5.txt
|
||||
cat md5.txt
|
||||
}
|
||||
@@ -80,10 +89,11 @@ BuildRelease() {
|
||||
export CGO_ENABLED=1
|
||||
go build -o ./build/$appName-$os_arch -ldflags="$muslflags" -tags=jsoniter .
|
||||
done
|
||||
BuildWinArm64 ./build/alist-windows-arm64.exe
|
||||
xgo -out "$appName" -ldflags="$ldflags" -tags=jsoniter .
|
||||
# why? Because some target platforms seem to have issues with upx compression
|
||||
upx -9 ./alist-linux-amd64
|
||||
upx -9 ./alist-windows*
|
||||
upx -9 ./alist-windows-amd64.exe
|
||||
mv alist-* build
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ the address is defined in config file`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Init()
|
||||
bootstrap.InitAria2()
|
||||
bootstrap.InitQbittorrent()
|
||||
bootstrap.LoadStorages()
|
||||
if !flags.Debug && !flags.Dev {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
@@ -96,14 +96,14 @@ func (d *Pan123) Link(ctx context.Context, file model.Obj, args model.LinkArgs)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
u_ := fmt.Sprintf("https://%s%s", u.Host, u.Path)
|
||||
u_ := u.String()
|
||||
res, err := base.NoRedirectClient.R().SetQueryParamsFromValues(u.Query()).Head(u_)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug(res.String())
|
||||
link := model.Link{
|
||||
URL: downloadUrl,
|
||||
URL: u_,
|
||||
}
|
||||
log.Debugln("res code: ", res.StatusCode())
|
||||
if res.StatusCode() == 302 {
|
||||
|
||||
+27
-7
@@ -83,8 +83,7 @@ func (d *Yun139) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin
|
||||
}
|
||||
pathname = "/orchestration/familyCloud/cloudCatalog/v1.0/createCloudDoc"
|
||||
}
|
||||
_, err := d.post(pathname,
|
||||
data, nil)
|
||||
_, err := d.post(pathname, data, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -222,6 +221,22 @@ func (d *Yun139) Remove(ctx context.Context, obj model.Obj) error {
|
||||
return err
|
||||
}
|
||||
|
||||
const (
|
||||
_ = iota //ignore first value by assigning to blank identifier
|
||||
KB = 1 << (10 * iota)
|
||||
MB
|
||||
GB
|
||||
TB
|
||||
)
|
||||
|
||||
func getPartSize(size int64) int64 {
|
||||
// 网盘对于分片数量存在上限
|
||||
if size/GB > 30 {
|
||||
return 512 * MB
|
||||
}
|
||||
return 100 * MB
|
||||
}
|
||||
|
||||
func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
||||
data := base.Json{
|
||||
"manualRename": 2,
|
||||
@@ -267,17 +282,17 @@ func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
|
||||
// Progress
|
||||
p := driver.NewProgress(stream.GetSize(), up)
|
||||
|
||||
var Default int64 = 104857600
|
||||
part := (stream.GetSize() + Default - 1) / Default
|
||||
var partSize = getPartSize(stream.GetSize())
|
||||
part := (stream.GetSize() + partSize - 1) / partSize
|
||||
for i := int64(0); i < part; i++ {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
start := i * Default
|
||||
start := i * partSize
|
||||
byteSize := stream.GetSize() - start
|
||||
if byteSize > Default {
|
||||
byteSize = Default
|
||||
if byteSize > partSize {
|
||||
byteSize = partSize
|
||||
}
|
||||
|
||||
limitReader := io.LimitReader(stream, byteSize)
|
||||
@@ -301,6 +316,11 @@ func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
|
||||
return err
|
||||
}
|
||||
log.Debugf("%+v", res)
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("unexpected status code: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
res.Body.Close()
|
||||
}
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ func (d *AListV3) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
SetResult(&resp).
|
||||
SetHeader("Authorization", d.AccessToken).
|
||||
SetBody(MoveCopyReq{
|
||||
SrcDir: srcObj.GetPath(),
|
||||
SrcDir: path.Dir(srcObj.GetPath()),
|
||||
DstDir: dstDir.GetPath(),
|
||||
Names: []string{srcObj.GetName()},
|
||||
}).Post(url)
|
||||
@@ -135,7 +135,7 @@ func (d *AListV3) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
SetResult(&resp).
|
||||
SetHeader("Authorization", d.AccessToken).
|
||||
SetBody(MoveCopyReq{
|
||||
SrcDir: srcObj.GetPath(),
|
||||
SrcDir: path.Dir(srcObj.GetPath()),
|
||||
DstDir: dstDir.GetPath(),
|
||||
Names: []string{srcObj.GetName()},
|
||||
}).Post(url)
|
||||
@@ -149,7 +149,7 @@ func (d *AListV3) Remove(ctx context.Context, obj model.Obj) error {
|
||||
SetResult(&resp).
|
||||
SetHeader("Authorization", d.AccessToken).
|
||||
SetBody(RemoveReq{
|
||||
Dir: obj.GetPath(),
|
||||
Dir: path.Dir(obj.GetPath()),
|
||||
Names: []string{obj.GetName()},
|
||||
}).Post(url)
|
||||
return checkResp(resp, err)
|
||||
|
||||
@@ -31,6 +31,7 @@ type AliDrive struct {
|
||||
AccessToken string
|
||||
cron *cron.Cron
|
||||
DriveId string
|
||||
UserID string
|
||||
}
|
||||
|
||||
func (d *AliDrive) Config() driver.Config {
|
||||
@@ -54,6 +55,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,7 +63,22 @@ func (d *AliDrive) Init(ctx context.Context) error {
|
||||
log.Errorf("%+v", err)
|
||||
}
|
||||
})
|
||||
return err
|
||||
if global.Has(d.UserID) {
|
||||
return nil
|
||||
}
|
||||
// init deviceID
|
||||
deviceID := utils.GetSHA256Encode(d.UserID)
|
||||
// init privateKey
|
||||
privateKey, _ := NewPrivateKeyFromHex(deviceID)
|
||||
state := State{
|
||||
nonce: -1,
|
||||
privateKey: privateKey,
|
||||
deviceID: deviceID,
|
||||
}
|
||||
// store state
|
||||
global.Store(d.UserID, &state)
|
||||
// init signature
|
||||
return d.reSign()
|
||||
}
|
||||
|
||||
func (d *AliDrive) Drop(ctx context.Context) error {
|
||||
@@ -169,17 +186,27 @@ func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileS
|
||||
"type": "file",
|
||||
}
|
||||
|
||||
var localFile *os.File
|
||||
if fileStream, ok := file.ReadCloser.(*model.FileStream); ok {
|
||||
localFile, _ = fileStream.ReadCloser.(*os.File)
|
||||
}
|
||||
if d.RapidUpload {
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
io.CopyN(buf, file, 1024)
|
||||
reqBody["pre_hash"] = utils.GetSHA1Encode(buf.String())
|
||||
// 把头部拼接回去
|
||||
file.ReadCloser = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.MultiReader(buf, file),
|
||||
Closer: file,
|
||||
if localFile != nil {
|
||||
if _, err := localFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 把头部拼接回去
|
||||
file.ReadCloser = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.MultiReader(buf, file),
|
||||
Closer: file,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reqBody["content_hash_name"] = "none"
|
||||
@@ -196,18 +223,28 @@ func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileS
|
||||
}
|
||||
|
||||
if d.RapidUpload && e.Code == "PreHashMatched" {
|
||||
tempFile, err := os.CreateTemp(conf.Conf.TempDir, "file-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tempFile.Close()
|
||||
_ = os.Remove(tempFile.Name())
|
||||
}()
|
||||
delete(reqBody, "pre_hash")
|
||||
h := sha1.New()
|
||||
if _, err = io.Copy(io.MultiWriter(tempFile, h), file); err != nil {
|
||||
return err
|
||||
if localFile != nil {
|
||||
if _, err = io.Copy(h, localFile); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = localFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
tempFile, err := os.CreateTemp(conf.Conf.TempDir, "file-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tempFile.Close()
|
||||
_ = os.Remove(tempFile.Name())
|
||||
}()
|
||||
if _, err = io.Copy(io.MultiWriter(tempFile, h), file); err != nil {
|
||||
return err
|
||||
}
|
||||
localFile = tempFile
|
||||
}
|
||||
reqBody["content_hash"] = hex.EncodeToString(h.Sum(nil))
|
||||
reqBody["content_hash_name"] = "sha1"
|
||||
@@ -228,7 +265,7 @@ func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileS
|
||||
if file.GetSize() > 0 {
|
||||
o = r.Mod(r, i)
|
||||
}
|
||||
n, _ := io.NewSectionReader(tempFile, o.Int64(), 8).Read(buf[:8])
|
||||
n, _ := io.NewSectionReader(localFile, o.Int64(), 8).Read(buf[:8])
|
||||
reqBody["proof_code"] = base64.StdEncoding.EncodeToString(buf[:n])
|
||||
|
||||
_, err, e := d.request("https://api.aliyundrive.com/adrive/v2/file/createWithFolders", http.MethodPost, func(req *resty.Request) {
|
||||
@@ -241,17 +278,21 @@ func (d *AliDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileS
|
||||
return nil
|
||||
}
|
||||
// 秒传失败
|
||||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
||||
if _, err = localFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
file.ReadCloser = tempFile
|
||||
file.ReadCloser = localFile
|
||||
}
|
||||
|
||||
for i, partInfo := range resp.PartInfoList {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
}
|
||||
req, err := http.NewRequest("PUT", partInfo.UploadUrl, io.LimitReader(file, DEFAULT))
|
||||
url := partInfo.UploadUrl
|
||||
if d.InternalUpload {
|
||||
url = partInfo.InternalUploadUrl
|
||||
}
|
||||
req, err := http.NewRequest("PUT", url, io.LimitReader(file, DEFAULT))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package aliyundrive
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/alist-org/alist/v3/pkg/generic_sync"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
deviceID string
|
||||
signature string
|
||||
nonce int
|
||||
privateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
var global = generic_sync.MapOf[string, *State]{}
|
||||
@@ -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...)
|
||||
}
|
||||
@@ -7,10 +7,12 @@ import (
|
||||
|
||||
type Addition struct {
|
||||
driver.RootID
|
||||
RefreshToken string `json:"refresh_token" required:"true"`
|
||||
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"`
|
||||
InternalUpload bool `json:"internal_upload"`
|
||||
}
|
||||
|
||||
var config = driver.Config{
|
||||
|
||||
@@ -48,7 +48,8 @@ type UploadResp struct {
|
||||
FileId string `json:"file_id"`
|
||||
UploadId string `json:"upload_id"`
|
||||
PartInfoList []struct {
|
||||
UploadUrl string `json:"upload_url"`
|
||||
UploadUrl string `json:"upload_url"`
|
||||
InternalUploadUrl string `json:"internal_upload_url"`
|
||||
} `json:"part_info_list"`
|
||||
|
||||
RapidUpload bool `json:"rapid_upload"`
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package aliyundrive
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -8,9 +10,69 @@ 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"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (d *AliDrive) createSession() error {
|
||||
state, ok := global.Load(d.UserID)
|
||||
if !ok {
|
||||
return fmt.Errorf("can't load user state, user_id: %s", d.UserID)
|
||||
}
|
||||
_, 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": state.nonce,
|
||||
"pubKey": PublicKeyToHex(&state.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() {
|
||||
state, ok := global.Load(d.UserID)
|
||||
if !ok {
|
||||
log.Errorf("can't load user state, user_id: %s", d.UserID)
|
||||
return
|
||||
}
|
||||
secpAppID := "5dde4e1bdf9e4966b387ba58f4b3fdc3"
|
||||
singdata := fmt.Sprintf("%s:%s:%s:%d", secpAppID, state.deviceID, d.UserID, state.nonce)
|
||||
hash := sha256.Sum256([]byte(singdata))
|
||||
data, _ := ecc.SignBytes(state.privateKey, hash[:], ecc.RecID|ecc.LowerS)
|
||||
state.signature = hex.EncodeToString(data)
|
||||
}
|
||||
|
||||
func (d *AliDrive) reSign() error {
|
||||
state, ok := global.Load(d.UserID)
|
||||
if !ok {
|
||||
return fmt.Errorf("can't load user state, user_id: %s", d.UserID)
|
||||
}
|
||||
state.nonce++
|
||||
if state.nonce >= 1073741823 {
|
||||
state.nonce = 0
|
||||
}
|
||||
d.sign()
|
||||
if state.nonce == 0 {
|
||||
return d.createSession()
|
||||
}
|
||||
err := d.renewSession()
|
||||
if err != nil && err.Error() == "device session signature error" {
|
||||
state.nonce = 0
|
||||
d.sign()
|
||||
return d.createSession()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// do others that not defined in Driver interface
|
||||
|
||||
func (d *AliDrive) refreshToken() error {
|
||||
@@ -39,9 +101,24 @@ 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")
|
||||
state, ok := global.Load(d.UserID)
|
||||
if !ok {
|
||||
if url == "https://api.aliyundrive.com/v2/user/get" {
|
||||
state = &State{}
|
||||
} else {
|
||||
return nil, fmt.Errorf("can't load user state, user_id: %s", d.UserID), RespErr{}
|
||||
}
|
||||
}
|
||||
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": state.signature,
|
||||
"x-request-id": uuid.NewString(),
|
||||
"X-Canary": "client=Android,app=adrive,version=v4.1.0",
|
||||
"X-Device-Id": state.deviceID,
|
||||
})
|
||||
if callback != nil {
|
||||
callback(req)
|
||||
} else {
|
||||
@@ -57,14 +134,21 @@ func (d *AliDrive) request(url, method string, callback base.ReqCallback, resp i
|
||||
return nil, err, e
|
||||
}
|
||||
if e.Code != "" {
|
||||
if e.Code == "AccessTokenInvalid" {
|
||||
switch e.Code {
|
||||
case "AccessTokenInvalid":
|
||||
err = d.refreshToken()
|
||||
if err != nil {
|
||||
return nil, err, e
|
||||
}
|
||||
return d.request(url, method, callback, resp)
|
||||
case "DeviceSessionSignatureInvalid":
|
||||
err = d.reSign()
|
||||
if err != nil {
|
||||
return nil, err, e
|
||||
}
|
||||
default:
|
||||
return nil, errors.New(e.Message), e
|
||||
}
|
||||
return nil, errors.New(e.Message), e
|
||||
return d.request(url, method, callback, resp)
|
||||
} else if res.IsError() {
|
||||
return nil, errors.New("bad status code " + res.Status()), e
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ func (d *AliyundriveShare) Drop(ctx context.Context) error {
|
||||
if d.cron != nil {
|
||||
d.cron.Stop()
|
||||
}
|
||||
d.DriveId = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ func (d *BaiduNetdisk) create(path string, size int64, isdir int, uploadid, bloc
|
||||
params := map[string]string{
|
||||
"method": "create",
|
||||
}
|
||||
data := fmt.Sprintf("path=%s&size=%d&isdir=%d", encodeURIComponent(path), size, isdir)
|
||||
data := fmt.Sprintf("path=%s&size=%d&isdir=%d&rtype=3", encodeURIComponent(path), size, isdir)
|
||||
if uploadid != "" {
|
||||
data += fmt.Sprintf("&uploadid=%s&block_list=%s", uploadid, block_list)
|
||||
}
|
||||
|
||||
@@ -23,8 +23,9 @@ func init() {
|
||||
}
|
||||
|
||||
func NewRestyClient() *resty.Client {
|
||||
return resty.New().
|
||||
client := resty.New().
|
||||
SetHeader("user-agent", UserAgent).
|
||||
SetRetryCount(3).
|
||||
SetTimeout(DefaultTimeout)
|
||||
return client
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func (d *GoogleDrive) Link(ctx context.Context, file model.Obj, args model.LinkA
|
||||
return nil, err
|
||||
}
|
||||
link := model.Link{
|
||||
URL: url + "&alt=media",
|
||||
URL: url + "&alt=media&acknowledgeAbuse=true",
|
||||
Header: http.Header{
|
||||
"Authorization": []string{"Bearer " + d.AccessToken},
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user