mirror of https://github.com/cloudreve/Cloudreve
fix(directlink): direct link should not be accessible if the parent file is in trash bin (#2415)
parent
ec53769e33
commit
65095855c1
|
@ -45,7 +45,7 @@ type (
|
||||||
func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inventory.ShareClient,
|
func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inventory.ShareClient,
|
||||||
l logging.Logger, ls lock.LockSystem, settingClient setting.Provider,
|
l logging.Logger, ls lock.LockSystem, settingClient setting.Provider,
|
||||||
storagePolicyClient inventory.StoragePolicyClient, hasher hashid.Encoder, userClient inventory.UserClient,
|
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{
|
return &DBFS{
|
||||||
user: u,
|
user: u,
|
||||||
navigators: make(map[string]Navigator),
|
navigators: make(map[string]Navigator),
|
||||||
|
@ -59,6 +59,7 @@ func NewDatabaseFS(u *ent.User, fileClient inventory.FileClient, shareClient inv
|
||||||
userClient: userClient,
|
userClient: userClient,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
stateKv: stateKv,
|
stateKv: stateKv,
|
||||||
|
directLinkClient: directLinkClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@ type DBFS struct {
|
||||||
userClient inventory.UserClient
|
userClient inventory.UserClient
|
||||||
storagePolicyClient inventory.StoragePolicyClient
|
storagePolicyClient inventory.StoragePolicyClient
|
||||||
shareClient inventory.ShareClient
|
shareClient inventory.ShareClient
|
||||||
|
directLinkClient inventory.DirectLinkClient
|
||||||
l logging.Logger
|
l logging.Logger
|
||||||
ls lock.LockSystem
|
ls lock.LockSystem
|
||||||
settingClient setting.Provider
|
settingClient setting.Provider
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
"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"
|
||||||
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
"github.com/cloudreve/Cloudreve/v4/inventory/types"
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/fs"
|
"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()
|
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) {
|
func (f *DBFS) deleteEntity(ctx context.Context, target *File, entityId int) (inventory.StorageDiff, error) {
|
||||||
if target.PrimaryEntityID() == entityId {
|
if target.PrimaryEntityID() == entityId {
|
||||||
return nil, fs.ErrNotSupportedAction.WithError(fmt.Errorf("cannot delete current version"))
|
return nil, fs.ErrNotSupportedAction.WithError(fmt.Errorf("cannot delete current version"))
|
||||||
|
|
|
@ -197,6 +197,25 @@ func (b *baseNavigator) walkNext(ctx context.Context, root *File, next string, i
|
||||||
return newFile(root, child), nil
|
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) {
|
func (b *baseNavigator) walkUp(ctx context.Context, child *File) (*File, error) {
|
||||||
parent, err := b.fileClient.GetParentFile(ctx, child.Model, false)
|
parent, err := b.fileClient.GetParentFile(ctx, child.Model, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -300,25 +300,6 @@ func (n *shareNavigator) ExecuteHook(ctx context.Context, hookType fs.HookType,
|
||||||
return nil
|
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 {
|
func (n *shareNavigator) Walk(ctx context.Context, levelFiles []*File, limit, depth int, f WalkFunc) error {
|
||||||
return n.baseNavigator.walk(ctx, levelFiles, limit, depth, f)
|
return n.baseNavigator.walk(ctx, levelFiles, limit, depth, f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,8 @@ type (
|
||||||
// - `delete` is false: set version as current version;
|
// - `delete` is false: set version as current version;
|
||||||
// - `delete` is true: delete version.
|
// - `delete` is true: delete version.
|
||||||
VersionControl(ctx context.Context, path *URI, versionId int, delete bool) error
|
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 {
|
UploadManager interface {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cloudreve/Cloudreve/v4/ent"
|
"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/inventory/types"
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/cluster/routes"
|
"github.com/cloudreve/Cloudreve/v4/pkg/cluster/routes"
|
||||||
"github.com/cloudreve/Cloudreve/v4/pkg/filemanager/driver"
|
"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)
|
opt.Apply(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := dl.Edges.FileOrErr()
|
file, err := m.fs.GetFileFromDirectLink(ctx, dl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
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
|
// Find primary entity
|
||||||
target, found := lo.Find(entities, func(entity *ent.Entity) bool {
|
target, found := lo.Find(file.Entities(), func(entity fs.Entity) bool {
|
||||||
return entity.ID == file.PrimaryEntity
|
return entity.ID() == file.PrimaryEntityID()
|
||||||
})
|
})
|
||||||
if !found {
|
if !found {
|
||||||
return "", nil, fs.ErrDirectLinkInvalid.WithError(fmt.Errorf("primary entity not found"))
|
return "", nil, fs.ErrDirectLinkInvalid.WithError(fmt.Errorf("primary entity not found"))
|
||||||
}
|
}
|
||||||
primaryEntity := fs.NewEntity(target)
|
primaryEntity := target
|
||||||
|
|
||||||
// Generate url
|
// Generate url
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -137,7 +137,7 @@ func NewFileManager(dep dependency.Dep, u *ent.User) FileManager {
|
||||||
user: u,
|
user: u,
|
||||||
settings: dep.SettingProvider(),
|
settings: dep.SettingProvider(),
|
||||||
fs: dbfs.NewDatabaseFS(u, dep.FileClient(), dep.ShareClient(), dep.Logger(), dep.LockSystem(),
|
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(),
|
kv: dep.KV(),
|
||||||
config: config,
|
config: config,
|
||||||
auth: dep.GeneralAuth(),
|
auth: dep.GeneralAuth(),
|
||||||
|
|
Loading…
Reference in New Issue