fix(directlink): direct link should not be accessible if the parent file is in trash bin (#2415)

pull/2224/merge
Aaron Liu 2025-05-29 09:42:22 +08:00
parent ec53769e33
commit 65095855c1
7 changed files with 62 additions and 41 deletions

View File

@ -45,7 +45,7 @@ type (
func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inventory.ShareClient,
l logging.Logger, ls lock.LockSystem, settingClient setting.Provider,
storagePolicyClient inventory.StoragePolicyClient, hasher hashid.Encoder, userClient inventory.UserClient,
cache, stateKv cache.Driver) fs.FileSystem {
cache, stateKv cache.Driver, directLinkClient inventory.DirectLinkClient) fs.FileSystem {
return &DBFS{
user: u,
navigators: make(map[string]Navigator),
@ -59,6 +59,7 @@ func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inv
userClient: userClient,
cache: cache,
stateKv: stateKv,
directLinkClient: directLinkClient,
}
}
@ -69,6 +70,7 @@ type DBFS struct {
userClient inventory.UserClient
storagePolicyClient inventory.StoragePolicyClient
shareClient inventory.ShareClient
directLinkClient inventory.DirectLinkClient
l logging.Logger
ls lock.LockSystem
settingClient setting.Provider

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/ent/user"
"github.com/cloudreve/Cloudreve/v4/inventory"
"github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
@ -608,6 +609,38 @@ func (f *DBFS) MoveOrCopy(ctx context.Context, path []*fs.URI, dst *fs.URI, isCo
return ae.Aggregate()
}
func (f *DBFS) GetFileFromDirectLink(ctx context.Context, dl *ent.DirectLink) (fs.File, error) {
fileModel, err := dl.Edges.FileOrErr()
if err != nil {
return nil, err
}
owner, err := fileModel.Edges.OwnerOrErr()
if err != nil {
return nil, err
}
// File owner must be active
if owner.Status != user.StatusActive {
return nil, fs.ErrDirectLinkInvalid.WithError(fmt.Errorf("file owner is not active"))
}
file := newFile(nil, fileModel)
// Traverse to the root file
baseNavigator := newBaseNavigator(f.fileClient, defaultFilter, f.user, f.hasher, f.settingClient.DBFS(ctx))
root, err := baseNavigator.findRoot(ctx, file)
if err != nil {
return nil, fmt.Errorf("failed to find root file: %w", err)
}
if root.Name() != inventory.RootFolderName {
return nil, serializer.NewError(serializer.CodeNotFound, "direct link not found", err)
}
return file, nil
}
func (f *DBFS) deleteEntity(ctx context.Context, target *File, entityId int) (inventory.StorageDiff, error) {
if target.PrimaryEntityID() == entityId {
return nil, fs.ErrNotSupportedAction.WithError(fmt.Errorf("cannot delete current version"))

View File

@ -197,6 +197,25 @@ func (b *baseNavigator) walkNext(ctx context.Context, root *File, next string, i
return newFile(root, child), nil
}
// findRoot finds the root folder of the given child.
func (b *baseNavigator) findRoot(ctx context.Context, child *File) (*File, error) {
root := child
for {
newRoot, err := b.walkUp(ctx, root)
if err != nil {
if !ent.IsNotFound(err) {
return nil, err
}
break
}
root = newRoot
}
return root, nil
}
func (b *baseNavigator) walkUp(ctx context.Context, child *File) (*File, error) {
parent, err := b.fileClient.GetParentFile(ctx, child.Model, false)
if err != nil {

View File

@ -300,25 +300,6 @@ func (n *shareNavigator) ExecuteHook(ctx context.Context, hookType fs.HookType,
return nil
}
// findRoot finds the root folder of the given child.
func (n *shareNavigator) findRoot(ctx context.Context, child *File) (*File, error) {
root := child
for {
newRoot, err := n.baseNavigator.walkUp(ctx, root)
if err != nil {
if !ent.IsNotFound(err) {
return nil, err
}
break
}
root = newRoot
}
return root, nil
}
func (n *shareNavigator) Walk(ctx context.Context, levelFiles []*File, limit, depth int, f WalkFunc) error {
return n.baseNavigator.walk(ctx, levelFiles, limit, depth, f)
}

View File

@ -93,6 +93,8 @@ type (
// - `delete` is false: set version as current version;
// - `delete` is true: delete version.
VersionControl(ctx context.Context, path *URI, versionId int, delete bool) error
// GetFileFromDirectLink gets a file from a direct link.
GetFileFromDirectLink(ctx context.Context, dl *ent.DirectLink) (File, error)
}
UploadManager interface {

View File

@ -8,7 +8,6 @@ import (
"time"
"github.com/cloudreve/Cloudreve/v4/ent"
"github.com/cloudreve/Cloudreve/v4/ent/user"
"github.com/cloudreve/Cloudreve/v4/inventory/types"
"github.com/cloudreve/Cloudreve/v4/pkg/cluster/routes"
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver"
@ -147,34 +146,19 @@ func (m *manager) GetUrlForRedirectedDirectLink(ctx context.Context, dl *ent.Dir
opt.Apply(o)
}
file, err := dl.Edges.FileOrErr()
file, err := m.fs.GetFileFromDirectLink(ctx, dl)
if err != nil {
return "", nil, err
}
owner, err := file.Edges.OwnerOrErr()
if err != nil {
return "", nil, err
}
entities, err := file.Edges.EntitiesOrErr()
if err != nil {
return "", nil, err
}
// File owner must be active
if owner.Status != user.StatusActive {
return "", nil, fs.ErrDirectLinkInvalid.WithError(fmt.Errorf("file owner is not active"))
}
// Find primary entity
target, found := lo.Find(entities, func(entity *ent.Entity) bool {
return entity.ID == file.PrimaryEntity
target, found := lo.Find(file.Entities(), func(entity fs.Entity) bool {
return entity.ID() == file.PrimaryEntityID()
})
if !found {
return "", nil, fs.ErrDirectLinkInvalid.WithError(fmt.Errorf("primary entity not found"))
}
primaryEntity := fs.NewEntity(target)
primaryEntity := target
// Generate url
var (

View File

@ -137,7 +137,7 @@ func NewFileManager(dep dependency.Dep, u *ent.User) FileManager {
user: u,
settings: dep.SettingProvider(),
fs: dbfs.NewDatabaseFS(u, dep.FileClient(), dep.ShareClient(), dep.Logger(), dep.LockSystem(),
dep.SettingProvider(), dep.StoragePolicyClient(), dep.HashIDEncoder(), dep.UserClient(), dep.KV(), dep.NavigatorStateKV()),
dep.SettingProvider(), dep.StoragePolicyClient(), dep.HashIDEncoder(), dep.UserClient(), dep.KV(), dep.NavigatorStateKV(), dep.DirectLinkClient()),
kv: dep.KV(),
config: config,
auth: dep.GeneralAuth(),