From f46f0a6d826ec7ad39d25baecd7a795938e1dbe7 Mon Sep 17 00:00:00 2001 From: jyxjjj <773933146@qq.com> Date: Wed, 26 Nov 2025 09:45:41 +0800 Subject: [PATCH 01/15] fix(drivers/crypt): refuse to load crypt driver when upstream driver is down --- drivers/crypt/driver.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 1398ff1cb..ed129bc17 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -68,6 +68,13 @@ func (d *Crypt) Init(ctx context.Context) error { if err != nil { return fmt.Errorf("can't find remote storage: %w", err) } + + // ensure the remote (upper-level) storage is initialized and healthy + // If the upper-level storage failed to initialize, refuse to load this crypt driver. + if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK { + return fmt.Errorf("remote storage not ready (status=%s)", storage.GetStorage().Status) + } + d.remoteStorage = storage p, _ := strings.CutPrefix(d.Password, obfuscatedPrefix) From a154df59fd856c3713a0e875c09c29b10a15416c Mon Sep 17 00:00:00 2001 From: KirCute Date: Wed, 26 Nov 2025 16:40:54 +0800 Subject: [PATCH 02/15] fix(crypt): support virtual paths --- drivers/crypt/driver.go | 110 +++++++++++++++++++++++----------------- drivers/crypt/util.go | 37 +++++++++++--- 2 files changed, 92 insertions(+), 55 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index ed129bc17..3782715c0 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -20,6 +20,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server/common" + "github.com/pkg/errors" rcCrypt "github.com/rclone/rclone/backend/crypt" "github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/obscure" @@ -29,8 +30,7 @@ import ( type Crypt struct { model.Storage Addition - cipher *rcCrypt.Cipher - remoteStorage driver.Driver + cipher *rcCrypt.Cipher } const obfuscatedPrefix = "___Obfuscated___" @@ -60,23 +60,10 @@ func (d *Crypt) Init(ctx context.Context) error { } d.FileNameEncoding = utils.GetNoneEmpty(d.FileNameEncoding, "base64") d.EncryptedSuffix = utils.GetNoneEmpty(d.EncryptedSuffix, ".bin") + d.RemotePath = utils.FixAndCleanPath(d.RemotePath) op.MustSaveDriverStorage(d) - // need remote storage exist - storage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) - if err != nil { - return fmt.Errorf("can't find remote storage: %w", err) - } - - // ensure the remote (upper-level) storage is initialized and healthy - // If the upper-level storage failed to initialize, refuse to load this crypt driver. - if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK { - return fmt.Errorf("remote storage not ready (status=%s)", storage.GetStorage().Status) - } - - d.remoteStorage = storage - p, _ := strings.CutPrefix(d.Password, obfuscatedPrefix) p2, _ := strings.CutPrefix(d.Salt, obfuscatedPrefix) config := configmap.Simple{ @@ -115,11 +102,13 @@ func (d *Crypt) Drop(ctx context.Context) error { } func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - path := dir.GetPath() - // return d.list(ctx, d.RemotePath, path) - // remoteFull - - objs, err := fs.List(ctx, d.getPathForRemote(path, true), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) + remoteStorage, actualPath, err := d.getStorageAndActualPathForRemote(dir.GetPath(), true) + if errors.Is(err, errs.StorageNotFound) { // listing virtual path + return fs.List(ctx, stdpath.Join(d.RemotePath, dir.GetPath()), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) + } else if err != nil { + return nil, err + } + objs, err := fs.List(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, actualPath), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { @@ -201,17 +190,22 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { Path: "/", }, nil } - remoteFullPath := "" + remoteStorage, rootActualPath, restActualPath, err := d.getStorageAndPlainPath(path) + if errors.Is(err, errs.StorageNotFound) { // getting virtual path + return fs.Get(ctx, stdpath.Join(d.RemotePath, path), &fs.GetArgs{NoLog: true}) + } else if err != nil { + return nil, err + } var remoteObj model.Obj - var err, err2 error + var err2 error firstTryIsFolder, secondTry := guessPath(path) - remoteFullPath = d.getPathForRemote(path, firstTryIsFolder) - remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) + encryptedActualPath := d.getActualPathForRemote(restActualPath, firstTryIsFolder) + remoteObj, err = fs.Get(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, rootActualPath, encryptedActualPath), &fs.GetArgs{NoLog: true}) if err != nil { if errs.IsObjectNotFound(err) && secondTry { // try the opposite - remoteFullPath = d.getPathForRemote(path, !firstTryIsFolder) - remoteObj, err2 = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) + encryptedActualPath = d.getActualPathForRemote(restActualPath, !firstTryIsFolder) + remoteObj, err2 = fs.Get(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, rootActualPath, encryptedActualPath), &fs.GetArgs{NoLog: true}) if err2 != nil { return nil, err2 } @@ -254,11 +248,11 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { const fileHeaderSize = 32 func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - dstDirActualPath, err := d.getActualPathForRemote(file.GetPath(), false) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(file.GetPath(), false) if err != nil { return nil, fmt.Errorf("failed to convert path to remote path: %w", err) } - remoteLink, remoteFile, err := op.Link(ctx, d.remoteStorage, dstDirActualPath, args) + remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, args) if err != nil { return nil, err } @@ -330,62 +324,83 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) ( } func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - dstDirActualPath, err := d.getActualPathForRemote(parentDir.GetPath(), true) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(parentDir.GetPath(), true) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } dir := d.cipher.EncryptDirName(dirName) - return op.MakeDir(ctx, d.remoteStorage, stdpath.Join(dstDirActualPath, dir)) + return op.MakeDir(ctx, remoteStorage, stdpath.Join(dstDirActualPath, dir)) } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + srcRemoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + dstRemoteStorage, dstRemoteActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - return op.Move(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + if srcRemoteActualPath == "/" { + return fmt.Errorf("cannot move remote storage root") + } + if srcRemoteStorage.GetStorage().MountPath == dstRemoteStorage.GetStorage().MountPath { + return op.Move(ctx, srcRemoteStorage, srcRemoteActualPath, dstRemoteActualPath) + } + srcOriginPath := stdpath.Join(srcRemoteStorage.GetStorage().MountPath, srcRemoteActualPath) + dstOriginPath := stdpath.Join(dstRemoteStorage.GetStorage().MountPath, dstRemoteActualPath) + _, err = fs.Move(ctx, srcOriginPath, dstOriginPath) + return err } func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - remoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + remoteStorage, remoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } + if remoteActualPath == "/" { + return fmt.Errorf("cannot rename remote storage root") + } var newEncryptedName string if srcObj.IsDir() { newEncryptedName = d.cipher.EncryptDirName(newName) } else { newEncryptedName = d.cipher.EncryptFileName(newName) } - return op.Rename(ctx, d.remoteStorage, remoteActualPath, newEncryptedName) + return op.Rename(ctx, remoteStorage, remoteActualPath, newEncryptedName) } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + srcRemoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + dstRemoteStorage, dstRemoteActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - return op.Copy(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + if srcRemoteStorage.GetStorage().MountPath == dstRemoteStorage.GetStorage().MountPath { + return op.Copy(ctx, srcRemoteStorage, srcRemoteActualPath, dstRemoteActualPath) + } + srcOriginPath := stdpath.Join(srcRemoteStorage.GetStorage().MountPath, srcRemoteActualPath) + dstOriginPath := stdpath.Join(dstRemoteStorage.GetStorage().MountPath, dstRemoteActualPath) + _, err = fs.Copy(ctx, srcOriginPath, dstOriginPath) + return err } func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error { - remoteActualPath, err := d.getActualPathForRemote(obj.GetPath(), obj.IsDir()) + remoteStorage, remoteActualPath, err := d.getStorageAndActualPathForRemote(obj.GetPath(), obj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - return op.Remove(ctx, d.remoteStorage, remoteActualPath) + if remoteActualPath == "/" { + return fmt.Errorf("cannot remove remote storage mount path") + } + return op.Remove(ctx, remoteStorage, remoteActualPath) } func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error { - dstDirActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), true) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), true) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } @@ -411,7 +426,7 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt ForceStreamUpload: true, Exist: streamer.GetExist(), } - err = op.Put(ctx, d.remoteStorage, dstDirActualPath, streamOut, up, false) + err = op.Put(ctx, remoteStorage, dstDirActualPath, streamOut, up, false) if err != nil { return err } @@ -419,13 +434,14 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt } func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { - remoteDetails, err := op.GetStorageDetails(ctx, d.remoteStorage) + remoteStorage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) if err != nil { + if errors.Is(err, errs.StorageNotFound) { + err = errs.NotImplement + } return nil, err } - return &model.StorageDetails{ - DiskUsage: remoteDetails.DiskUsage, - }, nil + return op.GetStorageDetails(ctx, remoteStorage) } //func (d *Safe) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { diff --git a/drivers/crypt/util.go b/drivers/crypt/util.go index 417059d38..196ed8eac 100644 --- a/drivers/crypt/util.go +++ b/drivers/crypt/util.go @@ -5,24 +5,29 @@ import ( "path/filepath" "strings" + "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/op" + "github.com/OpenListTeam/OpenList/v4/pkg/utils" ) // will give the best guessing based on the path func guessPath(path string) (isFolder, secondTry bool) { if strings.HasSuffix(path, "/") { - //confirmed a folder + // confirmed a folder return true, false } lastSlash := strings.LastIndex(path, "/") if strings.Index(path[lastSlash:], ".") < 0 { - //no dot, try folder then try file + // no dot, try folder then try file return true, true } return false, true } -func (d *Crypt) getPathForRemote(path string, isFolder bool) (remoteFullPath string) { +func (d *Crypt) getActualPathForRemote(path string, isFolder bool) string { + if path == "" || path == "/" { + return "" + } if isFolder && !strings.HasSuffix(path, "/") { path = path + "/" } @@ -33,12 +38,28 @@ func (d *Crypt) getPathForRemote(path string, isFolder bool) (remoteFullPath str if len(strings.TrimSpace(fileName)) > 0 { remoteFileName = d.cipher.EncryptFileName(fileName) } - return stdpath.Join(d.RemotePath, remoteDir, remoteFileName) - + return stdpath.Join(remoteDir, remoteFileName) } // actual path is used for internal only. any link for user should come from remoteFullPath -func (d *Crypt) getActualPathForRemote(path string, isFolder bool) (string, error) { - _, remoteActualPath, err := op.GetStorageAndActualPath(d.getPathForRemote(path, isFolder)) - return remoteActualPath, err +func (d *Crypt) getStorageAndActualPathForRemote(path string, isFolder bool) (driver.Driver, string, error) { + storage, rootActualPath, restActualPath, err := d.getStorageAndPlainPath(path) + if err != nil { + return nil, "", err + } + encryptedSubPath := d.getActualPathForRemote(restActualPath, isFolder) + return storage, stdpath.Join(rootActualPath, encryptedSubPath), nil +} + +func (d *Crypt) getStorageAndPlainPath(path string) (storage driver.Driver, rootActualPath string, restActualPath string, err error) { + storage, actualPath, err := op.GetStorageAndActualPath(stdpath.Join(d.RemotePath, path)) + if err != nil { + return nil, "", "", err + } + subRoot := "" + if sr, ok := strings.CutPrefix(d.RemotePath, utils.GetActualMountPath(storage.GetStorage().MountPath)); ok { + subRoot = sr + } + subPath := strings.TrimPrefix(actualPath, subRoot) + return storage, subRoot, subPath, nil } From ed68c19eb07f46043f80591b21be260097b50af1 Mon Sep 17 00:00:00 2001 From: KirCute Date: Wed, 26 Nov 2025 17:41:02 +0800 Subject: [PATCH 03/15] fix(fs/other): add check status --- drivers/alias/driver.go | 15 +++++---------- drivers/crypt/driver.go | 8 +++++++- drivers/crypt/meta.go | 5 +++-- internal/op/fs.go | 23 +++++++++++++---------- 4 files changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/alias/driver.go b/drivers/alias/driver.go index 208708aa9..536365268 100644 --- a/drivers/alias/driver.go +++ b/drivers/alias/driver.go @@ -234,16 +234,8 @@ func (d *Alias) Other(ctx context.Context, args model.OtherArgs) (interface{}, e if err != nil { continue } - other, ok := storage.(driver.Other) - if !ok { - continue - } - obj, err := op.GetUnwrap(ctx, storage, actualPath) - if err != nil { - continue - } - return other.Other(ctx, model.OtherArgs{ - Obj: obj, + return op.Other(ctx, storage, model.FsOtherArgs{ + Path: actualPath, Method: args.Method, Data: args.Data, }) @@ -535,6 +527,9 @@ func (d *Alias) ResolveLinkCacheMode(path string) driver.LinkCacheMode { if err != nil { continue } + if storage.Config().CheckStatus && storage.GetStorage().GetStorage().Status != op.WORK { + continue + } mode := storage.Config().LinkCacheMode if mode == -1 { return storage.(driver.LinkCacheModeResolver).ResolveLinkCacheMode(actualPath) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 3782715c0..ede0b38e4 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -441,7 +441,13 @@ func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { } return nil, err } - return op.GetStorageDetails(ctx, remoteStorage) + remoteDetails, err := op.GetStorageDetails(ctx, remoteStorage) + if err != nil { + return nil, err + } + return &model.StorageDetails{ + DiskUsage: remoteDetails.DiskUsage, + }, nil } //func (d *Safe) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { diff --git a/drivers/crypt/meta.go b/drivers/crypt/meta.go index b2d009ba3..c3ecdd8a5 100644 --- a/drivers/crypt/meta.go +++ b/drivers/crypt/meta.go @@ -7,8 +7,8 @@ import ( type Addition struct { // Usually one of two - //driver.RootPath - //driver.RootID + // driver.RootPath + // driver.RootID // define other FileNameEnc string `json:"filename_encryption" type:"select" required:"true" options:"off,standard,obfuscate" default:"off"` @@ -32,6 +32,7 @@ var config = driver.Config{ NoCache: true, DefaultRoot: "/", NoLinkURL: true, + CheckStatus: true, } func init() { diff --git a/internal/op/fs.go b/internal/op/fs.go index 087857f5d..9e2f91bdb 100644 --- a/internal/op/fs.go +++ b/internal/op/fs.go @@ -227,20 +227,23 @@ func Link(ctx context.Context, storage driver.Driver, path string, args model.Li } // Other api -func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (interface{}, error) { +func Other(ctx context.Context, storage driver.Driver, args model.FsOtherArgs) (any, error) { + if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { + return nil, errors.WithMessagef(errs.StorageNotInit, "storage status: %s", storage.GetStorage().Status) + } + o, ok := storage.(driver.Other) + if !ok { + return nil, errs.NotImplement + } obj, err := GetUnwrap(ctx, storage, args.Path) if err != nil { return nil, errors.WithMessagef(err, "failed to get obj") } - if o, ok := storage.(driver.Other); ok { - return o.Other(ctx, model.OtherArgs{ - Obj: obj, - Method: args.Method, - Data: args.Data, - }) - } else { - return nil, errs.NotImplement - } + return o.Other(ctx, model.OtherArgs{ + Obj: obj, + Method: args.Method, + Data: args.Data, + }) } var mkdirG singleflight.Group[any] From 1e6a627a1cbe11bbbd206145db61fca331ce70fa Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 18:46:49 +0800 Subject: [PATCH 04/15] Revert "fix(crypt): support virtual paths" This reverts commit a154df59fd856c3713a0e875c09c29b10a15416c. --- drivers/crypt/driver.go | 110 ++++++++++++++++------------------------ drivers/crypt/util.go | 37 +++----------- 2 files changed, 52 insertions(+), 95 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index ede0b38e4..ed129bc17 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -20,7 +20,6 @@ import ( "github.com/OpenListTeam/OpenList/v4/pkg/http_range" "github.com/OpenListTeam/OpenList/v4/pkg/utils" "github.com/OpenListTeam/OpenList/v4/server/common" - "github.com/pkg/errors" rcCrypt "github.com/rclone/rclone/backend/crypt" "github.com/rclone/rclone/fs/config/configmap" "github.com/rclone/rclone/fs/config/obscure" @@ -30,7 +29,8 @@ import ( type Crypt struct { model.Storage Addition - cipher *rcCrypt.Cipher + cipher *rcCrypt.Cipher + remoteStorage driver.Driver } const obfuscatedPrefix = "___Obfuscated___" @@ -60,10 +60,23 @@ func (d *Crypt) Init(ctx context.Context) error { } d.FileNameEncoding = utils.GetNoneEmpty(d.FileNameEncoding, "base64") d.EncryptedSuffix = utils.GetNoneEmpty(d.EncryptedSuffix, ".bin") - d.RemotePath = utils.FixAndCleanPath(d.RemotePath) op.MustSaveDriverStorage(d) + // need remote storage exist + storage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) + if err != nil { + return fmt.Errorf("can't find remote storage: %w", err) + } + + // ensure the remote (upper-level) storage is initialized and healthy + // If the upper-level storage failed to initialize, refuse to load this crypt driver. + if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK { + return fmt.Errorf("remote storage not ready (status=%s)", storage.GetStorage().Status) + } + + d.remoteStorage = storage + p, _ := strings.CutPrefix(d.Password, obfuscatedPrefix) p2, _ := strings.CutPrefix(d.Salt, obfuscatedPrefix) config := configmap.Simple{ @@ -102,13 +115,11 @@ func (d *Crypt) Drop(ctx context.Context) error { } func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - remoteStorage, actualPath, err := d.getStorageAndActualPathForRemote(dir.GetPath(), true) - if errors.Is(err, errs.StorageNotFound) { // listing virtual path - return fs.List(ctx, stdpath.Join(d.RemotePath, dir.GetPath()), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) - } else if err != nil { - return nil, err - } - objs, err := fs.List(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, actualPath), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) + path := dir.GetPath() + // return d.list(ctx, d.RemotePath, path) + // remoteFull + + objs, err := fs.List(ctx, d.getPathForRemote(path, true), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { @@ -190,22 +201,17 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { Path: "/", }, nil } - remoteStorage, rootActualPath, restActualPath, err := d.getStorageAndPlainPath(path) - if errors.Is(err, errs.StorageNotFound) { // getting virtual path - return fs.Get(ctx, stdpath.Join(d.RemotePath, path), &fs.GetArgs{NoLog: true}) - } else if err != nil { - return nil, err - } + remoteFullPath := "" var remoteObj model.Obj - var err2 error + var err, err2 error firstTryIsFolder, secondTry := guessPath(path) - encryptedActualPath := d.getActualPathForRemote(restActualPath, firstTryIsFolder) - remoteObj, err = fs.Get(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, rootActualPath, encryptedActualPath), &fs.GetArgs{NoLog: true}) + remoteFullPath = d.getPathForRemote(path, firstTryIsFolder) + remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) if err != nil { if errs.IsObjectNotFound(err) && secondTry { // try the opposite - encryptedActualPath = d.getActualPathForRemote(restActualPath, !firstTryIsFolder) - remoteObj, err2 = fs.Get(ctx, stdpath.Join(remoteStorage.GetStorage().MountPath, rootActualPath, encryptedActualPath), &fs.GetArgs{NoLog: true}) + remoteFullPath = d.getPathForRemote(path, !firstTryIsFolder) + remoteObj, err2 = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) if err2 != nil { return nil, err2 } @@ -248,11 +254,11 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { const fileHeaderSize = 32 func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(file.GetPath(), false) + dstDirActualPath, err := d.getActualPathForRemote(file.GetPath(), false) if err != nil { return nil, fmt.Errorf("failed to convert path to remote path: %w", err) } - remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, args) + remoteLink, remoteFile, err := op.Link(ctx, d.remoteStorage, dstDirActualPath, args) if err != nil { return nil, err } @@ -324,83 +330,62 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) ( } func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(parentDir.GetPath(), true) + dstDirActualPath, err := d.getActualPathForRemote(parentDir.GetPath(), true) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } dir := d.cipher.EncryptDirName(dirName) - return op.MakeDir(ctx, remoteStorage, stdpath.Join(dstDirActualPath, dir)) + return op.MakeDir(ctx, d.remoteStorage, stdpath.Join(dstDirActualPath, dir)) } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - dstRemoteStorage, dstRemoteActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - if srcRemoteActualPath == "/" { - return fmt.Errorf("cannot move remote storage root") - } - if srcRemoteStorage.GetStorage().MountPath == dstRemoteStorage.GetStorage().MountPath { - return op.Move(ctx, srcRemoteStorage, srcRemoteActualPath, dstRemoteActualPath) - } - srcOriginPath := stdpath.Join(srcRemoteStorage.GetStorage().MountPath, srcRemoteActualPath) - dstOriginPath := stdpath.Join(dstRemoteStorage.GetStorage().MountPath, dstRemoteActualPath) - _, err = fs.Move(ctx, srcOriginPath, dstOriginPath) - return err + return op.Move(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - remoteStorage, remoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + remoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - if remoteActualPath == "/" { - return fmt.Errorf("cannot rename remote storage root") - } var newEncryptedName string if srcObj.IsDir() { newEncryptedName = d.cipher.EncryptDirName(newName) } else { newEncryptedName = d.cipher.EncryptFileName(newName) } - return op.Rename(ctx, remoteStorage, remoteActualPath, newEncryptedName) + return op.Rename(ctx, d.remoteStorage, remoteActualPath, newEncryptedName) } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - dstRemoteStorage, dstRemoteActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - if srcRemoteStorage.GetStorage().MountPath == dstRemoteStorage.GetStorage().MountPath { - return op.Copy(ctx, srcRemoteStorage, srcRemoteActualPath, dstRemoteActualPath) - } - srcOriginPath := stdpath.Join(srcRemoteStorage.GetStorage().MountPath, srcRemoteActualPath) - dstOriginPath := stdpath.Join(dstRemoteStorage.GetStorage().MountPath, dstRemoteActualPath) - _, err = fs.Copy(ctx, srcOriginPath, dstOriginPath) - return err + return op.Copy(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error { - remoteStorage, remoteActualPath, err := d.getStorageAndActualPathForRemote(obj.GetPath(), obj.IsDir()) + remoteActualPath, err := d.getActualPathForRemote(obj.GetPath(), obj.IsDir()) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } - if remoteActualPath == "/" { - return fmt.Errorf("cannot remove remote storage mount path") - } - return op.Remove(ctx, remoteStorage, remoteActualPath) + return op.Remove(ctx, d.remoteStorage, remoteActualPath) } func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPathForRemote(dstDir.GetPath(), true) + dstDirActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), true) if err != nil { return fmt.Errorf("failed to convert path to remote path: %w", err) } @@ -426,7 +411,7 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt ForceStreamUpload: true, Exist: streamer.GetExist(), } - err = op.Put(ctx, remoteStorage, dstDirActualPath, streamOut, up, false) + err = op.Put(ctx, d.remoteStorage, dstDirActualPath, streamOut, up, false) if err != nil { return err } @@ -434,14 +419,7 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt } func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { - remoteStorage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) - if err != nil { - if errors.Is(err, errs.StorageNotFound) { - err = errs.NotImplement - } - return nil, err - } - remoteDetails, err := op.GetStorageDetails(ctx, remoteStorage) + remoteDetails, err := op.GetStorageDetails(ctx, d.remoteStorage) if err != nil { return nil, err } diff --git a/drivers/crypt/util.go b/drivers/crypt/util.go index 196ed8eac..417059d38 100644 --- a/drivers/crypt/util.go +++ b/drivers/crypt/util.go @@ -5,29 +5,24 @@ import ( "path/filepath" "strings" - "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/op" - "github.com/OpenListTeam/OpenList/v4/pkg/utils" ) // will give the best guessing based on the path func guessPath(path string) (isFolder, secondTry bool) { if strings.HasSuffix(path, "/") { - // confirmed a folder + //confirmed a folder return true, false } lastSlash := strings.LastIndex(path, "/") if strings.Index(path[lastSlash:], ".") < 0 { - // no dot, try folder then try file + //no dot, try folder then try file return true, true } return false, true } -func (d *Crypt) getActualPathForRemote(path string, isFolder bool) string { - if path == "" || path == "/" { - return "" - } +func (d *Crypt) getPathForRemote(path string, isFolder bool) (remoteFullPath string) { if isFolder && !strings.HasSuffix(path, "/") { path = path + "/" } @@ -38,28 +33,12 @@ func (d *Crypt) getActualPathForRemote(path string, isFolder bool) string { if len(strings.TrimSpace(fileName)) > 0 { remoteFileName = d.cipher.EncryptFileName(fileName) } - return stdpath.Join(remoteDir, remoteFileName) -} + return stdpath.Join(d.RemotePath, remoteDir, remoteFileName) -// actual path is used for internal only. any link for user should come from remoteFullPath -func (d *Crypt) getStorageAndActualPathForRemote(path string, isFolder bool) (driver.Driver, string, error) { - storage, rootActualPath, restActualPath, err := d.getStorageAndPlainPath(path) - if err != nil { - return nil, "", err - } - encryptedSubPath := d.getActualPathForRemote(restActualPath, isFolder) - return storage, stdpath.Join(rootActualPath, encryptedSubPath), nil } -func (d *Crypt) getStorageAndPlainPath(path string) (storage driver.Driver, rootActualPath string, restActualPath string, err error) { - storage, actualPath, err := op.GetStorageAndActualPath(stdpath.Join(d.RemotePath, path)) - if err != nil { - return nil, "", "", err - } - subRoot := "" - if sr, ok := strings.CutPrefix(d.RemotePath, utils.GetActualMountPath(storage.GetStorage().MountPath)); ok { - subRoot = sr - } - subPath := strings.TrimPrefix(actualPath, subRoot) - return storage, subRoot, subPath, nil +// actual path is used for internal only. any link for user should come from remoteFullPath +func (d *Crypt) getActualPathForRemote(path string, isFolder bool) (string, error) { + _, remoteActualPath, err := op.GetStorageAndActualPath(d.getPathForRemote(path, isFolder)) + return remoteActualPath, err } From 5fd9f03282160e7f505be7804bf53388cc17a1ad Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 18:55:53 +0800 Subject: [PATCH 05/15] fix(crypt): streamline remote storage handling in Crypt driver --- drivers/crypt/driver.go | 89 ++++++++++++++++++----------------------- drivers/crypt/meta.go | 1 - drivers/crypt/util.go | 8 ++-- 3 files changed, 44 insertions(+), 54 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index ed129bc17..0443e71fc 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -29,8 +29,7 @@ import ( type Crypt struct { model.Storage Addition - cipher *rcCrypt.Cipher - remoteStorage driver.Driver + cipher *rcCrypt.Cipher } const obfuscatedPrefix = "___Obfuscated___" @@ -60,22 +59,7 @@ func (d *Crypt) Init(ctx context.Context) error { } d.FileNameEncoding = utils.GetNoneEmpty(d.FileNameEncoding, "base64") d.EncryptedSuffix = utils.GetNoneEmpty(d.EncryptedSuffix, ".bin") - - op.MustSaveDriverStorage(d) - - // need remote storage exist - storage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) - if err != nil { - return fmt.Errorf("can't find remote storage: %w", err) - } - - // ensure the remote (upper-level) storage is initialized and healthy - // If the upper-level storage failed to initialize, refuse to load this crypt driver. - if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK { - return fmt.Errorf("remote storage not ready (status=%s)", storage.GetStorage().Status) - } - - d.remoteStorage = storage + d.RemotePath = utils.FixAndCleanPath(d.RemotePath) p, _ := strings.CutPrefix(d.Password, obfuscatedPrefix) p2, _ := strings.CutPrefix(d.Salt, obfuscatedPrefix) @@ -115,11 +99,14 @@ func (d *Crypt) Drop(ctx context.Context) error { } func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - path := dir.GetPath() - // return d.list(ctx, d.RemotePath, path) - // remoteFull - - objs, err := fs.List(ctx, d.getPathForRemote(path, true), &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(dir.GetPath(), true) + if err != nil { + return nil, err + } + objs, err := op.List(ctx, remoteStorage, dstDirActualPath, model.ListArgs{ + ReqPath: args.ReqPath, + Refresh: args.Refresh, + }) // the obj must implement the model.SetPath interface // return objs, err if err != nil { @@ -254,11 +241,11 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { const fileHeaderSize = 32 func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - dstDirActualPath, err := d.getActualPathForRemote(file.GetPath(), false) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(file.GetPath(), false) if err != nil { - return nil, fmt.Errorf("failed to convert path to remote path: %w", err) + return nil, err } - remoteLink, remoteFile, err := op.Link(ctx, d.remoteStorage, dstDirActualPath, args) + remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, args) if err != nil { return nil, err } @@ -330,30 +317,30 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) ( } func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - dstDirActualPath, err := d.getActualPathForRemote(parentDir.GetPath(), true) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(parentDir.GetPath(), true) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } dir := d.cipher.EncryptDirName(dirName) - return op.MakeDir(ctx, d.remoteStorage, stdpath.Join(dstDirActualPath, dir)) + return op.MakeDir(ctx, remoteStorage, stdpath.Join(dstDirActualPath, dir)) } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + remoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } - dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + _, dstRemoteActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), dstDir.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } - return op.Move(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + return op.Move(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - remoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + remoteStorage, remoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } var newEncryptedName string if srcObj.IsDir() { @@ -361,33 +348,33 @@ func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) er } else { newEncryptedName = d.cipher.EncryptFileName(newName) } - return op.Rename(ctx, d.remoteStorage, remoteActualPath, newEncryptedName) + return op.Rename(ctx, remoteStorage, remoteActualPath, newEncryptedName) } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - srcRemoteActualPath, err := d.getActualPathForRemote(srcObj.GetPath(), srcObj.IsDir()) + remoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } - dstRemoteActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), dstDir.IsDir()) + _, dstRemoteActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), dstDir.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } - return op.Copy(ctx, d.remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + return op.Copy(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error { - remoteActualPath, err := d.getActualPathForRemote(obj.GetPath(), obj.IsDir()) + remoteStorage, remoteActualPath, err := d.getStorageAndActualPath(obj.GetPath(), obj.IsDir()) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } - return op.Remove(ctx, d.remoteStorage, remoteActualPath) + return op.Remove(ctx, remoteStorage, remoteActualPath) } func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error { - dstDirActualPath, err := d.getActualPathForRemote(dstDir.GetPath(), true) + remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), true) if err != nil { - return fmt.Errorf("failed to convert path to remote path: %w", err) + return err } // Encrypt the data into wrappedIn @@ -411,7 +398,7 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt ForceStreamUpload: true, Exist: streamer.GetExist(), } - err = op.Put(ctx, d.remoteStorage, dstDirActualPath, streamOut, up, false) + err = op.Put(ctx, remoteStorage, dstDirActualPath, streamOut, up, false) if err != nil { return err } @@ -419,7 +406,11 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt } func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { - remoteDetails, err := op.GetStorageDetails(ctx, d.remoteStorage) + remoteStorage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) + if err != nil { + return nil, errs.NotImplement + } + remoteDetails, err := op.GetStorageDetails(ctx, remoteStorage) if err != nil { return nil, err } diff --git a/drivers/crypt/meta.go b/drivers/crypt/meta.go index c3ecdd8a5..778d6d83c 100644 --- a/drivers/crypt/meta.go +++ b/drivers/crypt/meta.go @@ -32,7 +32,6 @@ var config = driver.Config{ NoCache: true, DefaultRoot: "/", NoLinkURL: true, - CheckStatus: true, } func init() { diff --git a/drivers/crypt/util.go b/drivers/crypt/util.go index 417059d38..7c76c66fb 100644 --- a/drivers/crypt/util.go +++ b/drivers/crypt/util.go @@ -5,6 +5,7 @@ import ( "path/filepath" "strings" + "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/op" ) @@ -15,7 +16,7 @@ func guessPath(path string) (isFolder, secondTry bool) { return true, false } lastSlash := strings.LastIndex(path, "/") - if strings.Index(path[lastSlash:], ".") < 0 { + if !strings.Contains(path[lastSlash:], ".") { //no dot, try folder then try file return true, true } @@ -38,7 +39,6 @@ func (d *Crypt) getPathForRemote(path string, isFolder bool) (remoteFullPath str } // actual path is used for internal only. any link for user should come from remoteFullPath -func (d *Crypt) getActualPathForRemote(path string, isFolder bool) (string, error) { - _, remoteActualPath, err := op.GetStorageAndActualPath(d.getPathForRemote(path, isFolder)) - return remoteActualPath, err +func (d *Crypt) getStorageAndActualPath(path string, isFolder bool) (storage driver.Driver, actualPath string, err error) { + return op.GetStorageAndActualPath(d.getPathForRemote(path, isFolder)) } From 9cef4aa7314458a57f45d2aaed0f58668ee9c328 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 20:38:36 +0800 Subject: [PATCH 06/15] fix(crypt): refactor path handling in Crypt driver for improved clarity and functionality --- drivers/crypt/driver.go | 50 +++++++++++++++++++---------------------- drivers/crypt/util.go | 25 +++++++++------------ 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 0443e71fc..2104b2eff 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -115,8 +115,9 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ var result []model.Obj for _, obj := range objs { + name := model.UnwrapObj(obj).GetName() if obj.IsDir() { - name, err := d.cipher.DecryptDirName(obj.GetName()) + name, err = d.cipher.DecryptDirName(name) if err != nil { // filter illegal files continue @@ -140,7 +141,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ // filter illegal files continue } - name, err := d.cipher.DecryptFileName(obj.GetName()) + name, err = d.cipher.DecryptFileName(name) if err != nil { // filter illegal files continue @@ -188,42 +189,41 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { Path: "/", }, nil } - remoteFullPath := "" - var remoteObj model.Obj - var err, err2 error + + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) + if err != nil { + return nil, err + } firstTryIsFolder, secondTry := guessPath(path) - remoteFullPath = d.getPathForRemote(path, firstTryIsFolder) - remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) + remoteObj, err := op.Get(ctx, remoteStorage, stdpath.Join(remoteActualPath, d.convertPath(path, firstTryIsFolder))) if err != nil { - if errs.IsObjectNotFound(err) && secondTry { + if secondTry && errs.IsObjectNotFound(err) { // try the opposite - remoteFullPath = d.getPathForRemote(path, !firstTryIsFolder) - remoteObj, err2 = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) - if err2 != nil { - return nil, err2 + remoteObj, err = op.Get(ctx, remoteStorage, stdpath.Join(remoteActualPath, d.convertPath(path, !firstTryIsFolder))) + if err != nil { + return nil, err } } else { return nil, err } } + var size int64 = 0 - name := "" + name := model.UnwrapObj(remoteObj).GetName() if !remoteObj.IsDir() { size, err = d.cipher.DecryptedSize(remoteObj.GetSize()) if err != nil { log.Warnf("DecryptedSize failed for %s ,will use original size, err:%s", path, err) size = remoteObj.GetSize() } - name, err = d.cipher.DecryptFileName(remoteObj.GetName()) + name, err = d.cipher.DecryptFileName(name) if err != nil { log.Warnf("DecryptFileName failed for %s ,will use original name, err:%s", path, err) - name = remoteObj.GetName() } } else { - name, err = d.cipher.DecryptDirName(remoteObj.GetName()) + name, err = d.cipher.DecryptDirName(name) if err != nil { log.Warnf("DecryptDirName failed for %s ,will use original name, err:%s", path, err) - name = remoteObj.GetName() } } obj := &model.Object{ @@ -326,14 +326,12 @@ func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) - if err != nil { - return err - } - _, dstRemoteActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), dstDir.IsDir()) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } + srcRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(srcObj.GetPath(), srcObj.IsDir())) + dstRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(dstDir.GetPath(), dstDir.IsDir())) return op.Move(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } @@ -352,14 +350,12 @@ func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) er } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, srcRemoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) - if err != nil { - return err - } - _, dstRemoteActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), dstDir.IsDir()) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } + srcRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(srcObj.GetPath(), srcObj.IsDir())) + dstRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(dstDir.GetPath(), dstDir.IsDir())) return op.Copy(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) } diff --git a/drivers/crypt/util.go b/drivers/crypt/util.go index 7c76c66fb..4a8b9e7c2 100644 --- a/drivers/crypt/util.go +++ b/drivers/crypt/util.go @@ -23,22 +23,19 @@ func guessPath(path string) (isFolder, secondTry bool) { return false, true } -func (d *Crypt) getPathForRemote(path string, isFolder bool) (remoteFullPath string) { - if isFolder && !strings.HasSuffix(path, "/") { - path = path + "/" +func (d *Crypt) convertPath(path string, isFolder bool) (remotePath string) { + if isFolder { + return d.cipher.EncryptDirName(path) } dir, fileName := filepath.Split(path) - - remoteDir := d.cipher.EncryptDirName(dir) - remoteFileName := "" - if len(strings.TrimSpace(fileName)) > 0 { - remoteFileName = d.cipher.EncryptFileName(fileName) - } - return stdpath.Join(d.RemotePath, remoteDir, remoteFileName) - + return stdpath.Join(d.cipher.EncryptDirName(dir), d.cipher.EncryptFileName(fileName)) } -// actual path is used for internal only. any link for user should come from remoteFullPath -func (d *Crypt) getStorageAndActualPath(path string, isFolder bool) (storage driver.Driver, actualPath string, err error) { - return op.GetStorageAndActualPath(d.getPathForRemote(path, isFolder)) +// get the remote storage and actual path for the given path +func (d *Crypt) getStorageAndActualPath(path string, isFolder bool) (remoteStorage driver.Driver, remoteActualPath string, err error) { + remoteStorage, remoteActualPath, err = op.GetStorageAndActualPath(d.RemotePath) + if err == nil { + remoteActualPath = stdpath.Join(remoteActualPath, d.convertPath(path, isFolder)) + } + return } From 8f1065f63acaf2d5ce692f68ca1d161df985552f Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 21:07:34 +0800 Subject: [PATCH 07/15] fix(crypt): simplify List method --- drivers/crypt/driver.go | 89 +++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 2104b2eff..5673ca2c3 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -103,10 +103,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ if err != nil { return nil, err } - objs, err := op.List(ctx, remoteStorage, dstDirActualPath, model.ListArgs{ - ReqPath: args.ReqPath, - Refresh: args.Refresh, - }) + objs, err := op.List(ctx, remoteStorage, dstDirActualPath, model.ListArgs{Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { @@ -125,57 +122,53 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ if !d.ShowHidden && strings.HasPrefix(name, ".") { continue } - objRes := model.Object{ + result = append(result, &model.Object{ Name: name, Size: 0, Modified: obj.ModTime(), IsFolder: obj.IsDir(), Ctime: obj.CreateTime(), // discarding hash as it's encrypted - } - result = append(result, &objRes) - } else { - thumb, ok := model.GetThumb(obj) - size, err := d.cipher.DecryptedSize(obj.GetSize()) - if err != nil { - // filter illegal files - continue - } - name, err = d.cipher.DecryptFileName(name) - if err != nil { - // filter illegal files - continue - } - if !d.ShowHidden && strings.HasPrefix(name, ".") { - continue - } - objRes := model.Object{ - Name: name, - Size: size, - Modified: obj.ModTime(), - IsFolder: obj.IsDir(), - Ctime: obj.CreateTime(), - // discarding hash as it's encrypted - } - if d.Thumbnail && thumb == "" { - thumbPath := stdpath.Join(args.ReqPath, ".thumbnails", name+".webp") - thumb = fmt.Sprintf("%s/d%s?sign=%s", - common.GetApiUrl(ctx), - utils.EncodePath(thumbPath, true), - sign.Sign(thumbPath)) - } - if !ok && !d.Thumbnail { - result = append(result, &objRes) - } else { - objWithThumb := model.ObjThumb{ - Object: objRes, - Thumbnail: model.Thumbnail{ - Thumbnail: thumb, - }, - } - result = append(result, &objWithThumb) - } + }) + continue + } + + size, err := d.cipher.DecryptedSize(obj.GetSize()) + if err != nil { + // filter illegal files + continue + } + name, err = d.cipher.DecryptFileName(name) + if err != nil { + // filter illegal files + continue + } + if !d.ShowHidden && strings.HasPrefix(name, ".") { + continue + } + objRes := &model.Object{ + Name: name, + Size: size, + Modified: obj.ModTime(), + IsFolder: obj.IsDir(), + Ctime: obj.CreateTime(), + // discarding hash as it's encrypted + } + if !d.Thumbnail || !strings.HasPrefix(args.ReqPath, "/") { + result = append(result, objRes) + continue } + thumbPath := stdpath.Join(args.ReqPath, ".thumbnails", name+".webp") + thumb := fmt.Sprintf("%s/d%s?sign=%s", + common.GetApiUrl(ctx), + utils.EncodePath(thumbPath, true), + sign.Sign(thumbPath)) + result = append(result, &model.ObjThumb{ + Object: *objRes, + Thumbnail: model.Thumbnail{ + Thumbnail: thumb, + }, + }) } return result, nil From aca84f5235ada48da5754601a765045a5f4b8e6e Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 21:09:59 +0800 Subject: [PATCH 08/15] fix(alias): correct storage status check in ResolveLinkCacheMode --- drivers/alias/driver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/alias/driver.go b/drivers/alias/driver.go index 536365268..32047b01b 100644 --- a/drivers/alias/driver.go +++ b/drivers/alias/driver.go @@ -527,7 +527,7 @@ func (d *Alias) ResolveLinkCacheMode(path string) driver.LinkCacheMode { if err != nil { continue } - if storage.Config().CheckStatus && storage.GetStorage().GetStorage().Status != op.WORK { + if storage.Config().CheckStatus && storage.GetStorage().Status != op.WORK { continue } mode := storage.Config().LinkCacheMode From c06b41b849016c8020f9b75048613b9fd23d0e67 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 21:22:38 +0800 Subject: [PATCH 09/15] fix(crypt): remove unused LinkArgs parameter in Link method --- drivers/crypt/driver.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 5673ca2c3..21ed58cbc 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -233,12 +233,12 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { // https://github.com/rclone/rclone/blob/v1.67.0/backend/crypt/cipher.go#L37 const fileHeaderSize = 32 -func (d *Crypt) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { +func (d *Crypt) Link(ctx context.Context, file model.Obj, _ model.LinkArgs) (*model.Link, error) { remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(file.GetPath(), false) if err != nil { return nil, err } - remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, args) + remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, model.LinkArgs{}) if err != nil { return nil, err } From 1158f8c6e9bf8858a9fafc6f623019b537872df2 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Wed, 26 Nov 2025 22:08:31 +0800 Subject: [PATCH 10/15] fix(op): prevent moving, renaming, or deleting the root folder --- internal/op/fs.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/internal/op/fs.go b/internal/op/fs.go index 9e2f91bdb..e88287b88 100644 --- a/internal/op/fs.go +++ b/internal/op/fs.go @@ -312,6 +312,9 @@ func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string return errors.WithMessagef(errs.StorageNotInit, "storage status: %s", storage.GetStorage().Status) } srcPath = utils.FixAndCleanPath(srcPath) + if utils.PathEqual(srcPath, "/") { + return errors.New("move root folder is not allowed") + } srcDirPath := stdpath.Dir(srcPath) dstDirPath = utils.FixAndCleanPath(dstDirPath) if dstDirPath == srcDirPath { @@ -374,6 +377,9 @@ func Rename(ctx context.Context, storage driver.Driver, srcPath, dstName string, return errors.WithMessagef(errs.StorageNotInit, "storage status: %s", storage.GetStorage().Status) } srcPath = utils.FixAndCleanPath(srcPath) + if utils.PathEqual(srcPath, "/") { + return errors.New("rename root folder is not allowed") + } srcRawObj, err := Get(ctx, storage, srcPath) if err != nil { return errors.WithMessage(err, "failed to get src object") @@ -474,10 +480,10 @@ func Remove(ctx context.Context, storage driver.Driver, path string) error { if storage.Config().CheckStatus && storage.GetStorage().Status != WORK { return errors.WithMessagef(errs.StorageNotInit, "storage status: %s", storage.GetStorage().Status) } + path = utils.FixAndCleanPath(path) if utils.PathEqual(path, "/") { - return errors.New("delete root folder is not allowed, please goto the manage page to delete the storage instead") + return errors.New("delete root folder is not allowed") } - path = utils.FixAndCleanPath(path) rawObj, err := Get(ctx, storage, path) if err != nil { // if object not found, it's ok From 51659cd3b735b8157a6ab5aaf1e35cecc19728d0 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Thu, 27 Nov 2025 18:46:20 +0800 Subject: [PATCH 11/15] refactor(crypt): streamline path handling --- drivers/crypt/driver.go | 78 ++++++++++++++++++----------------------- drivers/crypt/meta.go | 5 --- drivers/crypt/util.go | 14 +------- 3 files changed, 36 insertions(+), 61 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 21ed58cbc..b9ba2346a 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -12,7 +12,6 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/errs" - "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" @@ -99,22 +98,23 @@ func (d *Crypt) Drop(ctx context.Context) error { } func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(dir.GetPath(), true) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return nil, err } - objs, err := op.List(ctx, remoteStorage, dstDirActualPath, model.ListArgs{Refresh: args.Refresh}) + encryptedPath := dir.GetPath() + objs, err := op.List(ctx, remoteStorage, encryptedPath, model.ListArgs{Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { return nil, err } - var result []model.Obj + result := make([]model.Obj, 0, len(objs)) for _, obj := range objs { - name := model.UnwrapObj(obj).GetName() + rawName := model.UnwrapObj(obj).GetName() if obj.IsDir() { - name, err = d.cipher.DecryptDirName(name) + name, err := d.cipher.DecryptDirName(rawName) if err != nil { // filter illegal files continue @@ -123,6 +123,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ continue } result = append(result, &model.Object{ + Path: stdpath.Join(encryptedPath, rawName), Name: name, Size: 0, Modified: obj.ModTime(), @@ -138,7 +139,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ // filter illegal files continue } - name, err = d.cipher.DecryptFileName(name) + name, err := d.cipher.DecryptFileName(rawName) if err != nil { // filter illegal files continue @@ -147,6 +148,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ continue } objRes := &model.Object{ + Path: stdpath.Join(encryptedPath, rawName), Name: name, Size: size, Modified: obj.ModTime(), @@ -175,24 +177,26 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ } func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) + if err != nil { + return nil, err + } if utils.PathEqual(path, "/") { return &model.Object{ Name: "Root", IsFolder: true, - Path: "/", + Path: remoteActualPath, }, nil } - remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) - if err != nil { - return nil, err - } firstTryIsFolder, secondTry := guessPath(path) - remoteObj, err := op.Get(ctx, remoteStorage, stdpath.Join(remoteActualPath, d.convertPath(path, firstTryIsFolder))) + encryptedPath := stdpath.Join(remoteActualPath, d.encryptPath(path, firstTryIsFolder)) + remoteObj, err := op.Get(ctx, remoteStorage, encryptedPath) if err != nil { if secondTry && errs.IsObjectNotFound(err) { // try the opposite - remoteObj, err = op.Get(ctx, remoteStorage, stdpath.Join(remoteActualPath, d.convertPath(path, !firstTryIsFolder))) + encryptedPath = stdpath.Join(remoteActualPath, d.encryptPath(path, !firstTryIsFolder)) + remoteObj, err = op.Get(ctx, remoteStorage, encryptedPath) if err != nil { return nil, err } @@ -220,7 +224,7 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { } } obj := &model.Object{ - Path: path, + Path: encryptedPath, Name: name, Size: size, Modified: remoteObj.ModTime(), @@ -234,11 +238,11 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { const fileHeaderSize = 32 func (d *Crypt) Link(ctx context.Context, file model.Obj, _ model.LinkArgs) (*model.Link, error) { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(file.GetPath(), false) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return nil, err } - remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, dstDirActualPath, model.LinkArgs{}) + remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, file.GetPath(), model.LinkArgs{}) if err != nil { return nil, err } @@ -310,26 +314,24 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, _ model.LinkArgs) (*mo } func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(parentDir.GetPath(), true) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } - dir := d.cipher.EncryptDirName(dirName) - return op.MakeDir(ctx, remoteStorage, stdpath.Join(dstDirActualPath, dir)) + encryptedName := d.cipher.EncryptDirName(dirName) + return op.MakeDir(ctx, remoteStorage, stdpath.Join(parentDir.GetPath(), encryptedName)) } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } - srcRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(srcObj.GetPath(), srcObj.IsDir())) - dstRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(dstDir.GetPath(), dstDir.IsDir())) - return op.Move(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + return op.Move(ctx, remoteStorage, srcObj.GetPath(), dstDir.GetPath()) } func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - remoteStorage, remoteActualPath, err := d.getStorageAndActualPath(srcObj.GetPath(), srcObj.IsDir()) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } @@ -339,29 +341,27 @@ func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) er } else { newEncryptedName = d.cipher.EncryptFileName(newName) } - return op.Rename(ctx, remoteStorage, remoteActualPath, newEncryptedName) + return op.Rename(ctx, remoteStorage, srcObj.GetPath(), newEncryptedName) } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } - srcRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(srcObj.GetPath(), srcObj.IsDir())) - dstRemoteActualPath := stdpath.Join(remoteActualPath, d.convertPath(dstDir.GetPath(), dstDir.IsDir())) - return op.Copy(ctx, remoteStorage, srcRemoteActualPath, dstRemoteActualPath) + return op.Copy(ctx, remoteStorage, srcObj.GetPath(), dstDir.GetPath()) } func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error { - remoteStorage, remoteActualPath, err := d.getStorageAndActualPath(obj.GetPath(), obj.IsDir()) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } - return op.Remove(ctx, remoteStorage, remoteActualPath) + return op.Remove(ctx, remoteStorage, obj.GetPath()) } func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error { - remoteStorage, dstDirActualPath, err := d.getStorageAndActualPath(dstDir.GetPath(), true) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return err } @@ -387,15 +387,11 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt ForceStreamUpload: true, Exist: streamer.GetExist(), } - err = op.Put(ctx, remoteStorage, dstDirActualPath, streamOut, up, false) - if err != nil { - return err - } - return nil + return op.Put(ctx, remoteStorage, dstDir.GetPath(), streamOut, up, false) } func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { - remoteStorage, err := fs.GetStorage(d.RemotePath, &fs.GetStoragesArgs{}) + remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) if err != nil { return nil, errs.NotImplement } @@ -408,8 +404,4 @@ func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { }, nil } -//func (d *Safe) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { -// return nil, errs.NotSupport -//} - var _ driver.Driver = (*Crypt)(nil) diff --git a/drivers/crypt/meta.go b/drivers/crypt/meta.go index 778d6d83c..5bb6245a5 100644 --- a/drivers/crypt/meta.go +++ b/drivers/crypt/meta.go @@ -6,11 +6,6 @@ import ( ) type Addition struct { - // Usually one of two - // driver.RootPath - // driver.RootID - // define other - FileNameEnc string `json:"filename_encryption" type:"select" required:"true" options:"off,standard,obfuscate" default:"off"` DirNameEnc string `json:"directory_name_encryption" type:"select" required:"true" options:"false,true" default:"false"` RemotePath string `json:"remote_path" required:"true" help:"This is where the encrypted data stores"` diff --git a/drivers/crypt/util.go b/drivers/crypt/util.go index 4a8b9e7c2..e0f2bef74 100644 --- a/drivers/crypt/util.go +++ b/drivers/crypt/util.go @@ -4,9 +4,6 @@ import ( stdpath "path" "path/filepath" "strings" - - "github.com/OpenListTeam/OpenList/v4/internal/driver" - "github.com/OpenListTeam/OpenList/v4/internal/op" ) // will give the best guessing based on the path @@ -23,19 +20,10 @@ func guessPath(path string) (isFolder, secondTry bool) { return false, true } -func (d *Crypt) convertPath(path string, isFolder bool) (remotePath string) { +func (d *Crypt) encryptPath(path string, isFolder bool) string { if isFolder { return d.cipher.EncryptDirName(path) } dir, fileName := filepath.Split(path) return stdpath.Join(d.cipher.EncryptDirName(dir), d.cipher.EncryptFileName(fileName)) } - -// get the remote storage and actual path for the given path -func (d *Crypt) getStorageAndActualPath(path string, isFolder bool) (remoteStorage driver.Driver, remoteActualPath string, err error) { - remoteStorage, remoteActualPath, err = op.GetStorageAndActualPath(d.RemotePath) - if err == nil { - remoteActualPath = stdpath.Join(remoteActualPath, d.convertPath(path, isFolder)) - } - return -} From 5ff0a794441a693912e79e41efb50e2146248210 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Thu, 27 Nov 2025 18:52:42 +0800 Subject: [PATCH 12/15] fix(crypt): optimize size retrieval in Get method --- drivers/crypt/driver.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index b9ba2346a..9402fbe69 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -205,13 +205,12 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { } } - var size int64 = 0 + size := remoteObj.GetSize() name := model.UnwrapObj(remoteObj).GetName() if !remoteObj.IsDir() { - size, err = d.cipher.DecryptedSize(remoteObj.GetSize()) + size, err = d.cipher.DecryptedSize(size) if err != nil { log.Warnf("DecryptedSize failed for %s ,will use original size, err:%s", path, err) - size = remoteObj.GetSize() } name, err = d.cipher.DecryptFileName(name) if err != nil { @@ -231,7 +230,6 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { IsFolder: remoteObj.IsDir(), } return obj, nil - // return nil, errs.ObjectNotFound } // https://github.com/rclone/rclone/blob/v1.67.0/backend/crypt/cipher.go#L37 From aa38ccf1ebb207888e017143b642c3448ead3d6c Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Thu, 27 Nov 2025 20:54:10 +0800 Subject: [PATCH 13/15] fix(crypt): support virtual paths --- drivers/crypt/driver.go | 61 ++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 9402fbe69..5677e4848 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -12,6 +12,7 @@ import ( "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/errs" + "github.com/OpenListTeam/OpenList/v4/internal/fs" "github.com/OpenListTeam/OpenList/v4/internal/model" "github.com/OpenListTeam/OpenList/v4/internal/op" "github.com/OpenListTeam/OpenList/v4/internal/sign" @@ -98,12 +99,12 @@ func (d *Crypt) Drop(ctx context.Context) error { } func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteFullPath := dir.GetPath() + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(remoteFullPath) if err != nil { return nil, err } - encryptedPath := dir.GetPath() - objs, err := op.List(ctx, remoteStorage, encryptedPath, model.ListArgs{Refresh: args.Refresh}) + objs, err := op.List(ctx, remoteStorage, remoteActualPath, model.ListArgs{Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { @@ -123,7 +124,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ continue } result = append(result, &model.Object{ - Path: stdpath.Join(encryptedPath, rawName), + Path: stdpath.Join(remoteFullPath, rawName), Name: name, Size: 0, Modified: obj.ModTime(), @@ -148,7 +149,7 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ continue } objRes := &model.Object{ - Path: stdpath.Join(encryptedPath, rawName), + Path: stdpath.Join(remoteFullPath, rawName), Name: name, Size: size, Modified: obj.ModTime(), @@ -177,26 +178,22 @@ func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([ } func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { - remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(d.RemotePath) - if err != nil { - return nil, err - } if utils.PathEqual(path, "/") { return &model.Object{ Name: "Root", IsFolder: true, - Path: remoteActualPath, + Path: d.RemotePath, }, nil } firstTryIsFolder, secondTry := guessPath(path) - encryptedPath := stdpath.Join(remoteActualPath, d.encryptPath(path, firstTryIsFolder)) - remoteObj, err := op.Get(ctx, remoteStorage, encryptedPath) + remoteFullPath := stdpath.Join(d.RemotePath, d.encryptPath(path, firstTryIsFolder)) + remoteObj, err := fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) if err != nil { if secondTry && errs.IsObjectNotFound(err) { // try the opposite - encryptedPath = stdpath.Join(remoteActualPath, d.encryptPath(path, !firstTryIsFolder)) - remoteObj, err = op.Get(ctx, remoteStorage, encryptedPath) + remoteFullPath = stdpath.Join(d.RemotePath, d.encryptPath(path, !firstTryIsFolder)) + remoteObj, err = fs.Get(ctx, remoteFullPath, &fs.GetArgs{NoLog: true}) if err != nil { return nil, err } @@ -223,7 +220,7 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { } } obj := &model.Object{ - Path: encryptedPath, + Path: remoteFullPath, Name: name, Size: size, Modified: remoteObj.ModTime(), @@ -236,11 +233,11 @@ func (d *Crypt) Get(ctx context.Context, path string) (model.Obj, error) { const fileHeaderSize = 32 func (d *Crypt) Link(ctx context.Context, file model.Obj, _ model.LinkArgs) (*model.Link, error) { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(file.GetPath()) if err != nil { return nil, err } - remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, file.GetPath(), model.LinkArgs{}) + remoteLink, remoteFile, err := op.Link(ctx, remoteStorage, remoteActualPath, model.LinkArgs{}) if err != nil { return nil, err } @@ -312,24 +309,21 @@ func (d *Crypt) Link(ctx context.Context, file model.Obj, _ model.LinkArgs) (*mo } func (d *Crypt) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(parentDir.GetPath()) if err != nil { return err } encryptedName := d.cipher.EncryptDirName(dirName) - return op.MakeDir(ctx, remoteStorage, stdpath.Join(parentDir.GetPath(), encryptedName)) + return op.MakeDir(ctx, remoteStorage, stdpath.Join(remoteActualPath, encryptedName)) } func (d *Crypt) Move(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) - if err != nil { - return err - } - return op.Move(ctx, remoteStorage, srcObj.GetPath(), dstDir.GetPath()) + _, err := fs.Move(ctx, srcObj.GetPath(), dstDir.GetPath()) + return err } func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(srcObj.GetPath()) if err != nil { return err } @@ -339,27 +333,24 @@ func (d *Crypt) Rename(ctx context.Context, srcObj model.Obj, newName string) er } else { newEncryptedName = d.cipher.EncryptFileName(newName) } - return op.Rename(ctx, remoteStorage, srcObj.GetPath(), newEncryptedName) + return op.Rename(ctx, remoteStorage, remoteActualPath, newEncryptedName) } func (d *Crypt) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) - if err != nil { - return err - } - return op.Copy(ctx, remoteStorage, srcObj.GetPath(), dstDir.GetPath()) + _, err := fs.Copy(ctx, srcObj.GetPath(), dstDir.GetPath()) + return err } func (d *Crypt) Remove(ctx context.Context, obj model.Obj) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(obj.GetPath()) if err != nil { return err } - return op.Remove(ctx, remoteStorage, obj.GetPath()) + return op.Remove(ctx, remoteStorage, remoteActualPath) } func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileStreamer, up driver.UpdateProgress) error { - remoteStorage, _, err := op.GetStorageAndActualPath(d.RemotePath) + remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(dstDir.GetPath()) if err != nil { return err } @@ -385,7 +376,7 @@ func (d *Crypt) Put(ctx context.Context, dstDir model.Obj, streamer model.FileSt ForceStreamUpload: true, Exist: streamer.GetExist(), } - return op.Put(ctx, remoteStorage, dstDir.GetPath(), streamOut, up, false) + return op.Put(ctx, remoteStorage, remoteActualPath, streamOut, up) } func (d *Crypt) GetDetails(ctx context.Context) (*model.StorageDetails, error) { From 769c918ab45c99b50636133127803197479af6e2 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Thu, 27 Nov 2025 21:00:22 +0800 Subject: [PATCH 14/15] fix(crypt): replace op.List with fs.List in List method --- drivers/crypt/driver.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/crypt/driver.go b/drivers/crypt/driver.go index 5677e4848..7b14894c9 100644 --- a/drivers/crypt/driver.go +++ b/drivers/crypt/driver.go @@ -100,11 +100,7 @@ func (d *Crypt) Drop(ctx context.Context) error { func (d *Crypt) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { remoteFullPath := dir.GetPath() - remoteStorage, remoteActualPath, err := op.GetStorageAndActualPath(remoteFullPath) - if err != nil { - return nil, err - } - objs, err := op.List(ctx, remoteStorage, remoteActualPath, model.ListArgs{Refresh: args.Refresh}) + objs, err := fs.List(ctx, remoteFullPath, &fs.ListArgs{NoLog: true, Refresh: args.Refresh}) // the obj must implement the model.SetPath interface // return objs, err if err != nil { From bad8daeb06e5a5ece90d5f5a4a7c3be68bec7f12 Mon Sep 17 00:00:00 2001 From: j2rong4cn Date: Thu, 27 Nov 2025 21:15:24 +0800 Subject: [PATCH 15/15] fix(crypt): ensure CheckStatus is enabled in driver configuration --- drivers/crypt/meta.go | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypt/meta.go b/drivers/crypt/meta.go index 5bb6245a5..6a4659910 100644 --- a/drivers/crypt/meta.go +++ b/drivers/crypt/meta.go @@ -27,6 +27,7 @@ var config = driver.Config{ NoCache: true, DefaultRoot: "/", NoLinkURL: true, + CheckStatus: true, } func init() {