Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
6fd05d7d72 | |||
f26ac57569 | |||
2434ac54d0 | |||
f25b557327 | |||
81a0706d01 | |||
5f6b576cbf | |||
549877f71e | |||
c6a5ba9b91 | |||
1a69d80489 | |||
b797f4302c | |||
bf9aa5c3d3 | |||
7390e19a7a | |||
b31a12a0cc | |||
26ce001782 | |||
a2c7ff3262 | |||
8fc7c716c0 | |||
c70fc3fc4b | |||
df513b7dc0 | |||
2a9598f4c6 | |||
224c20779c | |||
5d722298cb |
@ -50,7 +50,7 @@ English | [中文](./README_cn.md)
|
|||||||
- [x] Cloudflare workers proxy
|
- [x] Cloudflare workers proxy
|
||||||
- [x] File/Folder package download
|
- [x] File/Folder package download
|
||||||
- [x] Support video list playback and subtitles(ass,srt,vtt)
|
- [x] Support video list playback and subtitles(ass,srt,vtt)
|
||||||
- [x] Web upload(Can allow visitors to upload) and delete
|
- [x] Web upload(Can allow visitors to upload), delete, mkdir, rename, move and copy
|
||||||
|
|
||||||
## Discussion
|
## Discussion
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
- [x] Cloudflare workers 中转
|
- [x] Cloudflare workers 中转
|
||||||
- [x] 文件/文件夹打包下载
|
- [x] 文件/文件夹打包下载
|
||||||
- [x] 支持视频列表播放和字幕(ass,srt,vtt)
|
- [x] 支持视频列表播放和字幕(ass,srt,vtt)
|
||||||
- [x] 网页上传(可以允许访客上传),删除
|
- [x] 网页上传(可以允许访客上传),删除,新建文件夹,重命名,移动,复制
|
||||||
|
|
||||||
## 讨论
|
## 讨论
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ func InitAccounts() {
|
|||||||
if !ok {
|
if !ok {
|
||||||
log.Errorf("no [%s] driver", account.Type)
|
log.Errorf("no [%s] driver", account.Type)
|
||||||
} else {
|
} else {
|
||||||
|
log.Infof("start init account: [%s], type: [%s]", account.Name, account.Type)
|
||||||
err := driver.Save(&accounts[i], nil)
|
err := driver.Save(&accounts[i], nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("init account [%s] error:[%s]", account.Name, err.Error())
|
log.Errorf("init account [%s] error:[%s]", account.Name, err.Error())
|
||||||
@ -27,4 +28,4 @@ func InitAccounts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitConf init config
|
// InitConf init config
|
||||||
@ -41,4 +42,8 @@ func InitConf() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("update config struct error: %s", err.Error())
|
log.Fatalf("update config struct error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
err = os.MkdirAll("data/temp", 0700)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("create temp dir error: %s", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,14 @@ func InitSettings() {
|
|||||||
Access: model.PUBLIC,
|
Access: model.PUBLIC,
|
||||||
Group: model.FRONT,
|
Group: model.FRONT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Key: "ocr api",
|
||||||
|
Value: "https://api.xhofe.top/ocr/file/json",
|
||||||
|
Description: "Used to identify verification codes",
|
||||||
|
Type: "string",
|
||||||
|
Access: model.PRIVATE,
|
||||||
|
Group: model.BACK,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, _ := range settings {
|
for i, _ := range settings {
|
||||||
v := settings[i]
|
v := settings[i]
|
||||||
|
@ -36,7 +36,7 @@ func DefaultConfig() *Config {
|
|||||||
return &Config{
|
return &Config{
|
||||||
Address: "0.0.0.0",
|
Address: "0.0.0.0",
|
||||||
Port: 5244,
|
Port: 5244,
|
||||||
Assets: "zhimg",
|
Assets: "jsdelivr",
|
||||||
Database: Database{
|
Database: Database{
|
||||||
Type: "sqlite3",
|
Type: "sqlite3",
|
||||||
Port: 0,
|
Port: 0,
|
||||||
|
@ -36,10 +36,10 @@ var (
|
|||||||
OfficeTypes = []string{"doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"}
|
OfficeTypes = []string{"doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf"}
|
||||||
VideoTypes = []string{"mp4", "mkv", "avi", "mov", "rmvb", "webm", "flv"}
|
VideoTypes = []string{"mp4", "mkv", "avi", "mov", "rmvb", "webm", "flv"}
|
||||||
AudioTypes = []string{"mp3", "flac", "ogg", "m4a", "wav"}
|
AudioTypes = []string{"mp3", "flac", "ogg", "m4a", "wav"}
|
||||||
ImageTypes = []string{"jpg", "tiff", "jpeg", "png", "gif", "bmp", "svg", "ico", "swf"}
|
ImageTypes = []string{"jpg", "tiff", "jpeg", "png", "gif", "bmp", "svg", "ico", "swf", "webp"}
|
||||||
)
|
)
|
||||||
|
|
||||||
var settingsMap = make(map[string]string, 0)
|
var settingsMap = make(map[string]string)
|
||||||
|
|
||||||
func Set(key string, value string) {
|
func Set(key string, value string) {
|
||||||
settingsMap[key] = value
|
settingsMap[key] = value
|
||||||
@ -78,6 +78,7 @@ var (
|
|||||||
"check parent folder", "check down link", "WebDAV username", "WebDAV password",
|
"check parent folder", "check down link", "WebDAV username", "WebDAV password",
|
||||||
"Visitor WebDAV username", "Visitor WebDAV password",
|
"Visitor WebDAV username", "Visitor WebDAV password",
|
||||||
"default page size", "load type",
|
"default page size", "load type",
|
||||||
|
"ocr api",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package _23
|
package _23
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Xhofe/alist/conf"
|
"github.com/Xhofe/alist/conf"
|
||||||
"github.com/Xhofe/alist/drivers/base"
|
"github.com/Xhofe/alist/drivers/base"
|
||||||
@ -12,7 +14,10 @@ import (
|
|||||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
@ -294,10 +299,37 @@ func (driver Pan123) Upload(file *model.FileStream, account *model.Account) erro
|
|||||||
return base.ErrNotFolder
|
return base.ErrNotFolder
|
||||||
}
|
}
|
||||||
parentFileId, _ := strconv.Atoi(parentFile.Id)
|
parentFileId, _ := strconv.Atoi(parentFile.Id)
|
||||||
|
tempFile, err := ioutil.TempFile("data/temp", "file-*")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = tempFile.Close()
|
||||||
|
_ = os.Remove(tempFile.Name())
|
||||||
|
}()
|
||||||
|
_, err = io.Copy(tempFile, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := md5.New()
|
||||||
|
_, err = io.Copy(h, tempFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
etag := hex.EncodeToString(h.Sum(nil))
|
||||||
|
log.Debugln("md5:", etag)
|
||||||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
data := base.Json{
|
data := base.Json{
|
||||||
"driveId": 0,
|
"driveId": 0,
|
||||||
"duplicate": true,
|
"duplicate": true,
|
||||||
"etag": "836aae6cac845e17fce51919594737d0", //maybe file's md5
|
"etag": etag,
|
||||||
"fileName": file.GetFileName(),
|
"fileName": file.GetFileName(),
|
||||||
"parentFileId": parentFileId,
|
"parentFileId": parentFileId,
|
||||||
"size": file.GetSize(),
|
"size": file.GetSize(),
|
||||||
@ -310,6 +342,9 @@ func (driver Pan123) Upload(file *model.FileStream, account *model.Account) erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if resp.Data.Key == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
cfg := &aws.Config{
|
cfg := &aws.Config{
|
||||||
Credentials: credentials.NewStaticCredentials(resp.Data.AccessKeyId, resp.Data.SecretAccessKey, resp.Data.SessionToken),
|
Credentials: credentials.NewStaticCredentials(resp.Data.AccessKeyId, resp.Data.SecretAccessKey, resp.Data.SessionToken),
|
||||||
Region: aws.String("123pan"),
|
Region: aws.String("123pan"),
|
||||||
@ -324,7 +359,7 @@ func (driver Pan123) Upload(file *model.FileStream, account *model.Account) erro
|
|||||||
input := &s3manager.UploadInput{
|
input := &s3manager.UploadInput{
|
||||||
Bucket: &resp.Data.Bucket,
|
Bucket: &resp.Data.Bucket,
|
||||||
Key: &resp.Data.Key,
|
Key: &resp.Data.Key,
|
||||||
Body: file,
|
Body: tempFile,
|
||||||
}
|
}
|
||||||
_, err = uploader.Upload(input)
|
_, err = uploader.Upload(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -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,14 +12,12 @@ 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"
|
||||||
"math"
|
"math"
|
||||||
mathRand "math/rand"
|
mathRand "math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -35,6 +26,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var client189Map map[string]*resty.Client
|
var client189Map map[string]*resty.Client
|
||||||
|
var infoMap = make(map[string]Rsa)
|
||||||
|
|
||||||
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]
|
||||||
@ -153,9 +145,33 @@ func (driver Cloud189) Login(account *model.Account) error {
|
|||||||
vCodeRS := ""
|
vCodeRS := ""
|
||||||
if vCodeID != "" {
|
if vCodeID != "" {
|
||||||
// need ValidateCode
|
// need ValidateCode
|
||||||
|
log.Debugf("try to identify verification codes")
|
||||||
|
timeStamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
|
||||||
|
u := "https://open.e.189.cn/api/logbox/oauth2/picCaptcha.do?token=" + vCodeID + timeStamp
|
||||||
|
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",
|
||||||
|
"Referer": "https://open.e.189.cn/api/logbox/oauth2/unifyAccountLogin.do",
|
||||||
|
"Sec-Fetch-Dest": "image",
|
||||||
|
"Sec-Fetch-Mode": "no-cors",
|
||||||
|
"Sec-Fetch-Site": "same-origin",
|
||||||
|
}).Get(u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vRes, err := client.R().SetMultipartField(
|
||||||
|
"image", "validateCode.png", "image/png", bytes.NewReader(imgRes.Body())).
|
||||||
|
Post(conf.GetStr("ocr api"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if jsoniter.Get(vRes.Body(), "status").ToInt() != 200 {
|
||||||
|
return errors.New("ocr error:" + jsoniter.Get(vRes.Body(), "msg").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().
|
||||||
@ -199,39 +215,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"
|
||||||
}
|
}
|
||||||
@ -249,8 +232,8 @@ func (driver Cloud189) GetFiles(fileId string, account *model.Account) ([]Cloud1
|
|||||||
"mediaType": "0",
|
"mediaType": "0",
|
||||||
"folderId": fileId,
|
"folderId": fileId,
|
||||||
"iconOption": "5",
|
"iconOption": "5",
|
||||||
"orderBy": account.OrderBy,
|
"orderBy": "lastOpTime", //account.OrderBy
|
||||||
"descending": account.OrderDirection,
|
"descending": "true", //account.OrderDirection
|
||||||
}, nil, nil, account)
|
}, nil, nil, account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -321,7 +304,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)
|
||||||
@ -338,61 +321,198 @@ 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)
|
||||||
|
// log.Debugln(sessionKey, pubKey, pkId)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// xRId := Random("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx")
|
||||||
|
// pkey := Random("xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx")[0 : 16+int(16*mathRand.Float32())]
|
||||||
|
// params := hex.EncodeToString(AesEncrypt([]byte(qs(form)), []byte(pkey[0:16])))
|
||||||
|
// date := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
// a := make(url.Values)
|
||||||
|
// 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{
|
||||||
|
// "signature": signature,
|
||||||
|
// "sessionKey": sessionKey,
|
||||||
|
// "encryptionText": encryptionText,
|
||||||
|
// "pkId": pkId,
|
||||||
|
// "x-request-id": xRId,
|
||||||
|
// "x-request-date": date,
|
||||||
|
// }
|
||||||
|
// req := base.RestyClient.R().SetHeaders(headers).SetQueryParam("params", params)
|
||||||
|
// if resp != nil {
|
||||||
|
// req.SetResult(resp)
|
||||||
|
// }
|
||||||
|
// res, err := req.Get("https://upload.cloud.189.cn" + uri)
|
||||||
|
// 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
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//func (driver Cloud189) UploadRequest2(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)
|
||||||
|
// client, err := driver.getClient(account)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// req := client.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
|
||||||
|
//}
|
||||||
|
|
||||||
|
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
|
||||||
|
signature := hmacSha1(fmt.Sprintf("SessionKey=%s&Operate=GET&RequestURI=%s&Date=%s¶ms=%s", sessionKey, uri, c, h), l)
|
||||||
|
|
||||||
pubKey, pkId, err := driver.GetResKey(account)
|
pubKey, pkId, err := driver.GetResKey(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
xRId := uuid.New().String()
|
b := RsaEncode([]byte(l), pubKey, false)
|
||||||
pkey := strings.ReplaceAll(xRId, "-", "")[:mathRand.Intn(16)+16]
|
client, err := driver.getClient(account)
|
||||||
params := aesEncrypt(qs(form), pkey[:16])
|
|
||||||
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)
|
|
||||||
encryptionText := RsaEncode([]byte(pkey), pubKey)
|
|
||||||
headers := map[string]string{
|
|
||||||
"signature": signature,
|
|
||||||
"sessionKey": sessionKey,
|
|
||||||
"encryptionText": encryptionText,
|
|
||||||
"pkId": pkId,
|
|
||||||
"x-request-id": xRId,
|
|
||||||
"x-request-date": date,
|
|
||||||
"origin": "https://cloud.189.cn",
|
|
||||||
"referer": "https://cloud.189.cn/",
|
|
||||||
}
|
|
||||||
log.Debugf("%+v\n%s", headers, params)
|
|
||||||
res, err := base.RestyClient.R().SetHeaders(headers).SetQueryParam("params", params).Get("https://upload.cloud.189.cn" + url)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debug(res.String())
|
req := client.R()
|
||||||
data := res.Body()
|
req.Header.Set("accept", "application/json;charset=UTF-8")
|
||||||
|
req.Header.Set("SessionKey", sessionKey)
|
||||||
|
req.Header.Set("Signature", signature)
|
||||||
|
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" {
|
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
|
// 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 {
|
||||||
|
sessionKey, err := driver.GetSessionKey(account)
|
||||||
|
if err != nil {
|
||||||
|
account.Status = err.Error()
|
||||||
|
} else {
|
||||||
|
account.Status = "work"
|
||||||
|
account.DriveId = sessionKey
|
||||||
|
}
|
||||||
|
_ = model.SaveAccount(account)
|
||||||
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)))
|
||||||
var finish uint64 = 0
|
var finish uint64 = 0
|
||||||
@ -409,11 +529,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)
|
||||||
@ -423,180 +546,82 @@ func (driver Cloud189) NewUpload(file *model.FileStream, account *model.Account)
|
|||||||
if DEFAULT < byteSize {
|
if DEFAULT < byteSize {
|
||||||
byteSize = DEFAULT
|
byteSize = DEFAULT
|
||||||
}
|
}
|
||||||
log.Debugf("%d,%d", byteSize, finish)
|
//log.Debugf("%d,%d", byteSize, finish)
|
||||||
byteData := make([]byte, byteSize)
|
byteData := make([]byte, byteSize)
|
||||||
n, err := io.ReadFull(file, byteData)
|
n, err := io.ReadFull(file, byteData)
|
||||||
log.Debug(err, n)
|
//log.Debug(err, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Debugf("%+v", res)
|
|
||||||
}
|
}
|
||||||
id := md5Sum.Sum(nil)
|
fileMd5 := hex.EncodeToString(md5Sum.Sum(nil))
|
||||||
|
sliceMd5 := fileMd5
|
||||||
|
if file.GetSize() > DEFAULT {
|
||||||
|
sliceMd5 = utils.GetMD5Encode(strings.Join(md5s, "\n"))
|
||||||
|
}
|
||||||
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+/"
|
|
||||||
|
|
||||||
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 {
|
// api refer to PanIndex
|
||||||
d += int2char(c << 2)
|
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
|
||||||
}
|
}
|
||||||
return d
|
if jsoniter.Get(res.Body(), "MD5").ToString() != "" {
|
||||||
}
|
return nil
|
||||||
|
|
||||||
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, "&")
|
log.Debugf(res.String())
|
||||||
}
|
return errors.New(res.String())
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
@ -17,7 +15,8 @@ type Cloud189 struct{}
|
|||||||
|
|
||||||
func (driver Cloud189) Config() base.DriverConfig {
|
func (driver Cloud189) Config() base.DriverConfig {
|
||||||
return base.DriverConfig{
|
return base.DriverConfig{
|
||||||
Name: "189Cloud",
|
Name: "189Cloud",
|
||||||
|
LocalSort: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,20 +54,20 @@ func (driver Cloud189) Items() []base.Item {
|
|||||||
// Label: "family id",
|
// Label: "family id",
|
||||||
// Type: base.TypeString,
|
// Type: base.TypeString,
|
||||||
//},
|
//},
|
||||||
{
|
//{
|
||||||
Name: "order_by",
|
// Name: "order_by",
|
||||||
Label: "order_by",
|
// Label: "order_by",
|
||||||
Type: base.TypeSelect,
|
// Type: base.TypeSelect,
|
||||||
Values: "name,size,lastOpTime,createdDate",
|
// Values: "name,size,lastOpTime,createdDate",
|
||||||
Required: true,
|
// Required: true,
|
||||||
},
|
//},
|
||||||
{
|
//{
|
||||||
Name: "order_direction",
|
// Name: "order_direction",
|
||||||
Label: "desc",
|
// Label: "desc",
|
||||||
Type: base.TypeSelect,
|
// Type: base.TypeSelect,
|
||||||
Values: "true,false",
|
// Values: "true,false",
|
||||||
Required: true,
|
// Required: true,
|
||||||
},
|
//},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
//}
|
@ -84,7 +84,7 @@ func GetDriversMap() map[string]Driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetDrivers() map[string][]Item {
|
func GetDrivers() map[string][]Item {
|
||||||
res := make(map[string][]Item, 0)
|
res := make(map[string][]Item)
|
||||||
for k, v := range driversMap {
|
for k, v := range driversMap {
|
||||||
if v.Config().OnlyProxy {
|
if v.Config().OnlyProxy {
|
||||||
res[k] = v.Items()
|
res[k] = v.Items()
|
||||||
|
@ -12,6 +12,7 @@ var (
|
|||||||
ErrNotSupport = errors.New("not support")
|
ErrNotSupport = errors.New("not support")
|
||||||
ErrNotFolder = errors.New("not a folder")
|
ErrNotFolder = errors.New("not a folder")
|
||||||
ErrEmptyFile = errors.New("empty file")
|
ErrEmptyFile = errors.New("empty file")
|
||||||
|
ErrRelativePath = errors.New("access using relative path is not allowed")
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -21,9 +21,11 @@ func (driver FTP) Login(account *model.Account) (*ftp.ServerConn, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
connMap[account.Name] = conn
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.RegisterDriver(&FTP{})
|
base.RegisterDriver(&FTP{})
|
||||||
|
connMap = make(map[string]*ftp.ServerConn)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package mediatrack
|
package mediatrack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -18,6 +17,8 @@ import (
|
|||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -265,21 +266,39 @@ func (driver MediaTrack) Upload(file *model.FileStream, account *model.Account)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
tempFile, err := ioutil.TempFile("data/temp", "file-*")
|
||||||
read := io.TeeReader(file, &buf)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = tempFile.Close()
|
||||||
|
_ = os.Remove(tempFile.Name())
|
||||||
|
}()
|
||||||
|
_, err = io.Copy(tempFile, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
uploader := s3manager.NewUploader(s)
|
uploader := s3manager.NewUploader(s)
|
||||||
input := &s3manager.UploadInput{
|
input := &s3manager.UploadInput{
|
||||||
Bucket: &resp.Data.Bucket,
|
Bucket: &resp.Data.Bucket,
|
||||||
Key: &resp.Data.Object,
|
Key: &resp.Data.Object,
|
||||||
Body: read,
|
Body: tempFile,
|
||||||
}
|
}
|
||||||
_, err = uploader.Upload(input)
|
_, err = uploader.Upload(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("https://jayce.api.mediatrack.cn/v3/assets/%s/children", parentFile.Id)
|
url := fmt.Sprintf("https://jayce.api.mediatrack.cn/v3/assets/%s/children", parentFile.Id)
|
||||||
|
_, err = tempFile.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
_, err = io.Copy(h, &buf)
|
_, err = io.Copy(h, tempFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,9 @@ func (driver Native) Save(account *model.Account, old *model.Account) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) File(path string, account *model.Account) (*model.File, error) {
|
func (driver Native) File(path string, account *model.Account) (*model.File, error) {
|
||||||
|
if utils.IsContain(strings.Split(path, "/"), "..") {
|
||||||
|
return nil, base.ErrRelativePath
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, path)
|
fullPath := filepath.Join(account.RootFolder, path)
|
||||||
if !utils.Exists(fullPath) {
|
if !utils.Exists(fullPath) {
|
||||||
return nil, base.ErrPathNotFound
|
return nil, base.ErrPathNotFound
|
||||||
@ -82,6 +85,9 @@ func (driver Native) File(path string, account *model.Account) (*model.File, err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) Files(path string, account *model.Account) ([]model.File, error) {
|
func (driver Native) Files(path string, account *model.Account) ([]model.File, error) {
|
||||||
|
if utils.IsContain(strings.Split(path, "/"), "..") {
|
||||||
|
return nil, base.ErrRelativePath
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, path)
|
fullPath := filepath.Join(account.RootFolder, path)
|
||||||
if !utils.Exists(fullPath) {
|
if !utils.Exists(fullPath) {
|
||||||
return nil, base.ErrPathNotFound
|
return nil, base.ErrPathNotFound
|
||||||
@ -114,6 +120,10 @@ func (driver Native) Files(path string, account *model.Account) ([]model.File, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) Link(args base.Args, account *model.Account) (*base.Link, error) {
|
func (driver Native) Link(args base.Args, account *model.Account) (*base.Link, error) {
|
||||||
|
_, err := driver.File(args.Path, account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, args.Path)
|
fullPath := filepath.Join(account.RootFolder, args.Path)
|
||||||
s, err := os.Stat(fullPath)
|
s, err := os.Stat(fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,12 +165,18 @@ func (driver Native) Preview(path string, account *model.Account) (interface{},
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) MakeDir(path string, account *model.Account) error {
|
func (driver Native) MakeDir(path string, account *model.Account) error {
|
||||||
|
if utils.IsContain(strings.Split(path, "/"), "..") {
|
||||||
|
return base.ErrRelativePath
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, path)
|
fullPath := filepath.Join(account.RootFolder, path)
|
||||||
err := os.MkdirAll(fullPath, 0700)
|
err := os.MkdirAll(fullPath, 0700)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) Move(src string, dst string, account *model.Account) error {
|
func (driver Native) Move(src string, dst string, account *model.Account) error {
|
||||||
|
if utils.IsContain(strings.Split(src+"/"+dst, "/"), "..") {
|
||||||
|
return base.ErrRelativePath
|
||||||
|
}
|
||||||
fullSrc := filepath.Join(account.RootFolder, src)
|
fullSrc := filepath.Join(account.RootFolder, src)
|
||||||
fullDst := filepath.Join(account.RootFolder, dst)
|
fullDst := filepath.Join(account.RootFolder, dst)
|
||||||
return os.Rename(fullSrc, fullDst)
|
return os.Rename(fullSrc, fullDst)
|
||||||
@ -171,6 +187,9 @@ func (driver Native) Rename(src string, dst string, account *model.Account) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) Copy(src string, dst string, account *model.Account) error {
|
func (driver Native) Copy(src string, dst string, account *model.Account) error {
|
||||||
|
if utils.IsContain(strings.Split(src+"/"+dst, "/"), "..") {
|
||||||
|
return base.ErrRelativePath
|
||||||
|
}
|
||||||
fullSrc := filepath.Join(account.RootFolder, src)
|
fullSrc := filepath.Join(account.RootFolder, src)
|
||||||
fullDst := filepath.Join(account.RootFolder, dst)
|
fullDst := filepath.Join(account.RootFolder, dst)
|
||||||
srcFile, err := driver.File(src, account)
|
srcFile, err := driver.File(src, account)
|
||||||
@ -190,6 +209,9 @@ func (driver Native) Copy(src string, dst string, account *model.Account) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Native) Delete(path string, account *model.Account) error {
|
func (driver Native) Delete(path string, account *model.Account) error {
|
||||||
|
if utils.IsContain(strings.Split(path, "/"), "..") {
|
||||||
|
return base.ErrRelativePath
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, path)
|
fullPath := filepath.Join(account.RootFolder, path)
|
||||||
file, err := driver.File(path, account)
|
file, err := driver.File(path, account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -205,6 +227,9 @@ func (driver Native) Upload(file *model.FileStream, account *model.Account) erro
|
|||||||
if file == nil {
|
if file == nil {
|
||||||
return base.ErrEmptyFile
|
return base.ErrEmptyFile
|
||||||
}
|
}
|
||||||
|
if utils.IsContain(strings.Split(file.ParentPath, "/"), "..") {
|
||||||
|
return base.ErrRelativePath
|
||||||
|
}
|
||||||
fullPath := filepath.Join(account.RootFolder, file.ParentPath, file.Name)
|
fullPath := filepath.Join(account.RootFolder, file.ParentPath, file.Name)
|
||||||
_, err := driver.File(filepath.Join(file.ParentPath, file.Name), account)
|
_, err := driver.File(filepath.Join(file.ParentPath, file.Name), account)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -224,6 +249,16 @@ func (driver Native) Upload(file *model.FileStream, account *model.Account) erro
|
|||||||
defer func() {
|
defer func() {
|
||||||
_ = out.Close()
|
_ = out.Close()
|
||||||
}()
|
}()
|
||||||
|
//var buf bytes.Buffer
|
||||||
|
//reader := io.TeeReader(file, &buf)
|
||||||
|
//h := md5.New()
|
||||||
|
//_, err = io.Copy(h, reader)
|
||||||
|
//if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//hash := hex.EncodeToString(h.Sum(nil))
|
||||||
|
//log.Debugln("md5:", hash)
|
||||||
|
//_, err = io.Copy(out, &buf)
|
||||||
_, err = io.Copy(out, file)
|
_, err = io.Copy(out, file)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,28 @@ import (
|
|||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"runtime/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func Path(driver base.Driver, account *model.Account, path string) (*model.File, []model.File, error) {
|
||||||
|
return driver.Path(path, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Files(driver base.Driver, account *model.Account, path string) ([]model.File, error) {
|
||||||
|
_, files, err := Path(driver, account, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if files == nil {
|
||||||
|
return nil, base.ErrNotFolder
|
||||||
|
}
|
||||||
|
return files, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func File(driver base.Driver, account *model.Account, path string) (*model.File, error) {
|
||||||
|
return driver.File(path, account)
|
||||||
|
}
|
||||||
|
|
||||||
func MakeDir(driver base.Driver, account *model.Account, path string, clearCache bool) error {
|
func MakeDir(driver base.Driver, account *model.Account, path string, clearCache bool) error {
|
||||||
log.Debugf("mkdir: %s", path)
|
log.Debugf("mkdir: %s", path)
|
||||||
err := driver.MakeDir(path, account)
|
err := driver.MakeDir(path, account)
|
||||||
@ -78,5 +98,6 @@ func Upload(driver base.Driver, account *model.Account, file *model.FileStream,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("upload error: %s", err.Error())
|
log.Errorf("upload error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
debug.FreeOSMemory()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,6 @@ func (driver S3) GetKey(path string, account *model.Account, dir bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
sessionsMap = make(map[string]*session.Session, 0)
|
sessionsMap = make(map[string]*session.Session)
|
||||||
base.RegisterDriver(&S3{})
|
base.RegisterDriver(&S3{})
|
||||||
}
|
}
|
||||||
|
@ -252,7 +252,34 @@ func (driver Teambition) Delete(path string, account *model.Account) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (driver Teambition) Upload(file *model.FileStream, account *model.Account) error {
|
func (driver Teambition) Upload(file *model.FileStream, account *model.Account) error {
|
||||||
return base.ErrNotImplement
|
if file == nil {
|
||||||
|
return base.ErrEmptyFile
|
||||||
|
}
|
||||||
|
parentFile, err := driver.File(file.ParentPath, account)
|
||||||
|
if !parentFile.IsDir() {
|
||||||
|
return base.ErrNotFolder
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
res, err := driver.Request("/projects", base.Get, nil, nil, nil, nil, nil, account)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
token := GetBetweenStr(string(res), "strikerAuth":"", "","phoneForLogin")
|
||||||
|
var newFile *FileUpload
|
||||||
|
if file.Size <= 20971520 {
|
||||||
|
// post upload
|
||||||
|
newFile, err = driver.upload(file, token, account)
|
||||||
|
} else {
|
||||||
|
// chunk upload
|
||||||
|
//err = base.ErrNotImplement
|
||||||
|
newFile, err = driver.chunkUpload(file, token, account)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return driver.finishUpload(newFile, parentFile.Id, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ base.Driver = (*Teambition)(nil)
|
var _ base.Driver = (*Teambition)(nil)
|
||||||
|
@ -2,11 +2,14 @@ package teambition
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"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/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -66,25 +69,6 @@ func (driver Teambition) Request(pathname string, method int, headers, query, fo
|
|||||||
return res.Body(), nil
|
return res.Body(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Collection struct {
|
|
||||||
ID string `json:"_id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Updated time.Time `json:"updated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Work struct {
|
|
||||||
ID string `json:"_id"`
|
|
||||||
FileName string `json:"fileName"`
|
|
||||||
FileSize int64 `json:"fileSize"`
|
|
||||||
FileKey string `json:"fileKey"`
|
|
||||||
FileCategory string `json:"fileCategory"`
|
|
||||||
DownloadURL string `json:"downloadUrl"`
|
|
||||||
ThumbnailURL string `json:"thumbnailUrl"`
|
|
||||||
Thumbnail string `json:"thumbnail"`
|
|
||||||
Updated time.Time `json:"updated"`
|
|
||||||
PreviewURL string `json:"previewUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (driver Teambition) GetFiles(parentId string, account *model.Account) ([]model.File, error) {
|
func (driver Teambition) GetFiles(parentId string, account *model.Account) ([]model.File, error) {
|
||||||
files := make([]model.File, 0)
|
files := make([]model.File, 0)
|
||||||
page := 1
|
page := 1
|
||||||
@ -151,6 +135,101 @@ func (driver Teambition) GetFiles(parentId string, account *model.Account) ([]mo
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (driver Teambition) upload(file *model.FileStream, token string, account *model.Account) (*FileUpload, error) {
|
||||||
|
prefix := "tcs"
|
||||||
|
if account.InternalType == "International" {
|
||||||
|
prefix = "us-tcs"
|
||||||
|
}
|
||||||
|
var newFile FileUpload
|
||||||
|
_, err := base.RestyClient.R().SetResult(&newFile).SetHeader("Authorization", token).
|
||||||
|
SetMultipartFormData(map[string]string{
|
||||||
|
"name": file.GetFileName(),
|
||||||
|
"type": file.GetMIMEType(),
|
||||||
|
"size": strconv.FormatUint(file.GetSize(), 10),
|
||||||
|
//"lastModifiedDate": "",
|
||||||
|
}).SetMultipartField("file", file.GetFileName(), file.GetMIMEType(), file).
|
||||||
|
Post(fmt.Sprintf("https://%s.teambition.net/upload", prefix))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &newFile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (driver Teambition) chunkUpload(file *model.FileStream, token string, account *model.Account) (*FileUpload, error) {
|
||||||
|
prefix := "tcs"
|
||||||
|
if account.InternalType == "International" {
|
||||||
|
prefix = "us-tcs"
|
||||||
|
}
|
||||||
|
var newChunk ChunkUpload
|
||||||
|
_, err := base.RestyClient.R().SetResult(&newChunk).SetHeader("Authorization", token).
|
||||||
|
SetBody(base.Json{
|
||||||
|
"fileName": file.GetFileName(),
|
||||||
|
"fileSize": file.GetSize(),
|
||||||
|
"lastUpdated": time.Now(),
|
||||||
|
}).Post(fmt.Sprintf("https://%s.teambition.net/upload/chunk", prefix))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := 0; i < newChunk.Chunks; i++ {
|
||||||
|
chunkSize := newChunk.ChunkSize
|
||||||
|
if i == newChunk.Chunks-1 {
|
||||||
|
chunkSize = int(file.GetSize()) - i*chunkSize
|
||||||
|
}
|
||||||
|
log.Debugf("%d : %d", i, chunkSize)
|
||||||
|
chunkData := make([]byte, chunkSize)
|
||||||
|
_, err = io.ReadFull(file, chunkData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u := fmt.Sprintf("https://%s.teambition.net/upload/chunk/%s?chunk=%d&chunks=%d",
|
||||||
|
prefix, newChunk.FileKey, i+1, newChunk.Chunks)
|
||||||
|
log.Debugf("url: %s", u)
|
||||||
|
res, err := base.RestyClient.R().SetHeaders(map[string]string{
|
||||||
|
"Authorization": token,
|
||||||
|
"Content-Type": "application/octet-stream",
|
||||||
|
"Referer": "https://www.teambition.com/",
|
||||||
|
}).SetBody(chunkData).Post(u)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debug(res.Status(), res.String())
|
||||||
|
//req, err := http.NewRequest("POST",
|
||||||
|
// u,
|
||||||
|
// bytes.NewBuffer(chunkData))
|
||||||
|
//if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
//}
|
||||||
|
//req.Header.Set("Authorization", token)
|
||||||
|
//req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
|
//req.Header.Set("Referer", "https://www.teambition.com/")
|
||||||
|
//resp, err := base.HttpClient.Do(req)
|
||||||
|
//res, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
//log.Debugf("chunk upload status: %s, res: %s", resp.Status, string(res))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res, err := base.RestyClient.R().SetHeader("Authorization", token).Post(
|
||||||
|
fmt.Sprintf("https://%s.teambition.net/upload/chunk/%s",
|
||||||
|
prefix, newChunk.FileKey))
|
||||||
|
log.Debug(res.Status(), res.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &newChunk.FileUpload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (driver Teambition) finishUpload(file *FileUpload, parentId string, account *model.Account) error {
|
||||||
|
file.InvolveMembers = []interface{}{}
|
||||||
|
file.Visible = "members"
|
||||||
|
file.ParentId = parentId
|
||||||
|
_, err := driver.Request("/api/works", base.Post, nil, nil, nil, base.Json{
|
||||||
|
"works": []FileUpload{*file},
|
||||||
|
"_parentId": parentId,
|
||||||
|
}, nil, account)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.RegisterDriver(&Teambition{})
|
base.RegisterDriver(&Teambition{})
|
||||||
}
|
}
|
||||||
|
63
drivers/teambition/types.go
Normal file
63
drivers/teambition/types.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package teambition
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Collection struct {
|
||||||
|
ID string `json:"_id"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Work struct {
|
||||||
|
ID string `json:"_id"`
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
FileSize int64 `json:"fileSize"`
|
||||||
|
FileKey string `json:"fileKey"`
|
||||||
|
FileCategory string `json:"fileCategory"`
|
||||||
|
DownloadURL string `json:"downloadUrl"`
|
||||||
|
ThumbnailURL string `json:"thumbnailUrl"`
|
||||||
|
Thumbnail string `json:"thumbnail"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
|
PreviewURL string `json:"previewUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileUpload struct {
|
||||||
|
FileKey string `json:"fileKey"`
|
||||||
|
FileName string `json:"fileName"`
|
||||||
|
FileType string `json:"fileType"`
|
||||||
|
FileSize int `json:"fileSize"`
|
||||||
|
FileCategory string `json:"fileCategory"`
|
||||||
|
ImageWidth int `json:"imageWidth"`
|
||||||
|
ImageHeight int `json:"imageHeight"`
|
||||||
|
InvolveMembers []interface{} `json:"involveMembers"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
Visible string `json:"visible"`
|
||||||
|
ParentId string `json:"_parentId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChunkUpload struct {
|
||||||
|
FileUpload
|
||||||
|
Storage string `json:"storage"`
|
||||||
|
MimeType string `json:"mimeType"`
|
||||||
|
Chunks int `json:"chunks"`
|
||||||
|
ChunkSize int `json:"chunkSize"`
|
||||||
|
Created time.Time `json:"created"`
|
||||||
|
FileMD5 string `json:"fileMD5"`
|
||||||
|
LastUpdated time.Time `json:"lastUpdated"`
|
||||||
|
UploadedChunks []interface{} `json:"uploadedChunks"`
|
||||||
|
Token struct {
|
||||||
|
AppID string `json:"AppID"`
|
||||||
|
OrganizationID string `json:"OrganizationID"`
|
||||||
|
UserID string `json:"UserID"`
|
||||||
|
Exp time.Time `json:"Exp"`
|
||||||
|
Storage string `json:"Storage"`
|
||||||
|
Resource string `json:"Resource"`
|
||||||
|
Speed int `json:"Speed"`
|
||||||
|
} `json:"token"`
|
||||||
|
DownloadUrl string `json:"downloadUrl"`
|
||||||
|
ThumbnailUrl string `json:"thumbnailUrl"`
|
||||||
|
PreviewUrl string `json:"previewUrl"`
|
||||||
|
ImmPreviewUrl string `json:"immPreviewUrl"`
|
||||||
|
PreviewExt string `json:"previewExt"`
|
||||||
|
LastUploadTime interface{} `json:"lastUploadTime"`
|
||||||
|
}
|
18
drivers/teambition/util.go
Normal file
18
drivers/teambition/util.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package teambition
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func GetBetweenStr(str, start, end string) string {
|
||||||
|
n := strings.Index(str, start)
|
||||||
|
if n == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
n = n + len(start)
|
||||||
|
str = string([]byte(str)[n:])
|
||||||
|
m := strings.Index(str, end)
|
||||||
|
if m == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
str = string([]byte(str)[:m])
|
||||||
|
return str
|
||||||
|
}
|
61
server/controllers/file/copy.go
Normal file
61
server/controllers/file/copy.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Xhofe/alist/drivers/base"
|
||||||
|
"github.com/Xhofe/alist/drivers/operate"
|
||||||
|
"github.com/Xhofe/alist/model"
|
||||||
|
"github.com/Xhofe/alist/server/common"
|
||||||
|
"github.com/Xhofe/alist/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Copy(c *gin.Context) {
|
||||||
|
var req MoveCopyReq
|
||||||
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
|
common.ErrorResp(c, err, 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(req.Names) == 0 {
|
||||||
|
common.ErrorStrResp(c, "Empty file names", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if model.AccountsCount() > 1 && (req.SrcDir == "/" || req.DstDir == "/") {
|
||||||
|
common.ErrorStrResp(c, "Can't operate root folder", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srcAccount, srcPath, srcDriver, err := common.ParsePath(utils.Join(req.SrcDir, req.Names[0]))
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dstAccount, dstPath, _, err := common.ParsePath(utils.Join(req.DstDir, req.Names[0]))
|
||||||
|
if err != nil {
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if srcAccount.Name != dstAccount.Name {
|
||||||
|
common.ErrorStrResp(c, "Can't copy files between two accounts", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if srcPath == "/" || dstPath == "/" {
|
||||||
|
common.ErrorStrResp(c, "Can't copy root folder", 400)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
srcDir, dstDir := utils.Dir(srcPath), utils.Dir(dstPath)
|
||||||
|
for i, name := range req.Names {
|
||||||
|
clearCache := false
|
||||||
|
if i == len(req.Names)-1 {
|
||||||
|
clearCache = true
|
||||||
|
}
|
||||||
|
err := operate.Copy(srcDriver, srcAccount, utils.Join(srcDir, name), utils.Join(dstDir, name), clearCache)
|
||||||
|
if err != nil {
|
||||||
|
if i == 0 {
|
||||||
|
_ = base.DeleteCache(srcDir, srcAccount)
|
||||||
|
_ = base.DeleteCache(dstDir, dstAccount)
|
||||||
|
}
|
||||||
|
common.ErrorResp(c, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
common.SuccessResp(c)
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Xhofe/alist/drivers/operate"
|
||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/server/common"
|
"github.com/Xhofe/alist/server/common"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -30,7 +31,7 @@ func Folder(c *gin.Context) {
|
|||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file, rawFiles, err := driver.Path(path, account)
|
file, rawFiles, err := operate.Path(driver, account, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
|
@ -9,14 +9,14 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MoveReq struct {
|
type MoveCopyReq struct {
|
||||||
SrcDir string `json:"src_dir"`
|
SrcDir string `json:"src_dir"`
|
||||||
DstDir string `json:"dst_dir"`
|
DstDir string `json:"dst_dir"`
|
||||||
Names []string `json:"names"`
|
Names []string `json:"names"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Move(c *gin.Context) {
|
func Move(c *gin.Context) {
|
||||||
var req MoveReq
|
var req MoveCopyReq
|
||||||
if err := c.ShouldBind(&req); err != nil {
|
if err := c.ShouldBind(&req); err != nil {
|
||||||
common.ErrorResp(c, err, 400)
|
common.ErrorResp(c, err, 400)
|
||||||
return
|
return
|
||||||
|
@ -24,7 +24,7 @@ func Rename(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if path_ == "/" {
|
if path_ == "/" {
|
||||||
common.ErrorStrResp(c, "Can't account name here", 400)
|
common.ErrorStrResp(c, "Can't edit account name here", 400)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = operate.Move(driver, account, path_, utils.Join(utils.Dir(path_), req.Name), true)
|
err = operate.Move(driver, account, path_, utils.Join(utils.Dir(path_), req.Name), true)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"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/drivers/operate"
|
||||||
"github.com/Xhofe/alist/model"
|
"github.com/Xhofe/alist/model"
|
||||||
"github.com/Xhofe/alist/server/common"
|
"github.com/Xhofe/alist/server/common"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
@ -109,7 +110,7 @@ func Path(c *gin.Context) {
|
|||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file, files, err := driver.Path(path, account)
|
file, files, err := operate.Path(driver, account, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"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/drivers/operate"
|
||||||
"github.com/Xhofe/alist/server/common"
|
"github.com/Xhofe/alist/server/common"
|
||||||
"github.com/Xhofe/alist/utils"
|
"github.com/Xhofe/alist/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -50,7 +51,7 @@ func Proxy(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 检查文件
|
// 检查文件
|
||||||
file, err := driver.File(path, account)
|
file, err := operate.File(driver, account, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.ErrorResp(c, err, 500)
|
common.ErrorResp(c, err, 500)
|
||||||
return
|
return
|
||||||
@ -100,10 +101,10 @@ func Proxy(c *gin.Context) {
|
|||||||
c.File(link.Url)
|
c.File(link.Url)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if utils.GetFileType(filepath.Ext(rawPath)) == conf.TEXT {
|
//if utils.GetFileType(filepath.Ext(rawPath)) == conf.TEXT {
|
||||||
Text(c, link)
|
// Text(c, link)
|
||||||
return
|
// return
|
||||||
}
|
//}
|
||||||
driver.Proxy(c, account)
|
driver.Proxy(c, account)
|
||||||
r := c.Request
|
r := c.Request
|
||||||
w := c.Writer
|
w := c.Writer
|
||||||
|
@ -19,7 +19,7 @@ func Auth(c *gin.Context) {
|
|||||||
//}
|
//}
|
||||||
//if token != utils.GetMD5Encode(password.Value) {
|
//if token != utils.GetMD5Encode(password.Value) {
|
||||||
if token != conf.Token {
|
if token != conf.Token {
|
||||||
common.ErrorStrResp(c, "Wrong password", 401)
|
common.ErrorStrResp(c, "Invalid token", 401)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Next()
|
c.Next()
|
||||||
|
@ -54,6 +54,7 @@ func InitApiRouter(r *gin.Engine) {
|
|||||||
admin.POST("/mkdir", file.Mkdir)
|
admin.POST("/mkdir", file.Mkdir)
|
||||||
admin.POST("/rename", file.Rename)
|
admin.POST("/rename", file.Rename)
|
||||||
admin.POST("/move", file.Move)
|
admin.POST("/move", file.Move)
|
||||||
|
admin.POST("/copy", file.Copy)
|
||||||
admin.POST("/folder", file.Folder)
|
admin.POST("/folder", file.Folder)
|
||||||
}
|
}
|
||||||
WebDav(r)
|
WebDav(r)
|
||||||
|
@ -40,7 +40,7 @@ func (fs *FileSystem) File(rawPath string) (*model.File, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return driver.File(path_, account)
|
return operate.File(driver, account, path_)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FileSystem) Files(ctx context.Context, rawPath string) ([]model.File, error) {
|
func (fs *FileSystem) Files(ctx context.Context, rawPath string) ([]model.File, error) {
|
||||||
@ -56,7 +56,7 @@ func (fs *FileSystem) Files(ctx context.Context, rawPath string) ([]model.File,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
files, err := driver.Files(path_, account)
|
files, err := operate.Files(driver, account, path_)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func (h *Handler) stripPrefix(p string) (string, int, error) {
|
|||||||
func isPathExist(ctx context.Context, fs *FileSystem, path string) (bool, FileInfo) {
|
func isPathExist(ctx context.Context, fs *FileSystem, path string) (bool, FileInfo) {
|
||||||
file, err := fs.File(path)
|
file, err := fs.File(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(path, err)
|
log.Debugln(path, err)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return true, file
|
return true, file
|
||||||
|
Reference in New Issue
Block a user