WebClient: fix rename

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-04-15 14:16:26 +02:00
parent 3cb53b2c33
commit 466f2e88b3
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
6 changed files with 96 additions and 10 deletions

2
go.mod
View file

@ -104,7 +104,7 @@ require (
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/fatih/color v1.15.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect

3
go.sum
View file

@ -839,8 +839,9 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=

View file

@ -587,7 +587,7 @@ func (c *BaseConnection) copyFile(virtualSourcePath, virtualTargetPath string, s
if ok, _ := c.User.IsFileAllowed(virtualTargetPath); !ok {
return fmt.Errorf("file %q is not allowed: %w", virtualTargetPath, c.GetPermissionDeniedError())
}
if c.isSameResource(virtualSourcePath, virtualTargetPath) {
if c.IsSameResource(virtualSourcePath, virtualTargetPath) {
fs, fsTargetPath, err := c.GetFsAndResolvedPath(virtualTargetPath)
if err != nil {
return err
@ -1156,7 +1156,7 @@ func (c *BaseConnection) checkFolderRename(fsSrc, fsDst vfs.Fs, fsSourcePath, fs
func (c *BaseConnection) isRenamePermitted(fsSrc, fsDst vfs.Fs, fsSourcePath, fsTargetPath, virtualSourcePath,
virtualTargetPath string, fi os.FileInfo,
) bool {
if !c.isSameResource(virtualSourcePath, virtualTargetPath) {
if !c.IsSameResource(virtualSourcePath, virtualTargetPath) {
c.Log(logger.LevelInfo, "rename %#q->%q is not allowed: the paths must be on the same resource",
virtualSourcePath, virtualTargetPath)
return false
@ -1407,7 +1407,8 @@ func (c *BaseConnection) HasSpace(checkFiles, getUsage bool, requestPath string)
return result, transferQuota
}
func (c *BaseConnection) isSameResource(virtualSourcePath, virtualTargetPath string) bool {
// IsSameResource returns true if source and target paths are on the same resource
func (c *BaseConnection) IsSameResource(virtualSourcePath, virtualTargetPath string) bool {
sourceFolder, errSrc := c.User.GetVirtualFolderForPath(virtualSourcePath)
dstFolder, errDst := c.User.GetVirtualFolderForPath(virtualTargetPath)
if errSrc != nil && errDst != nil {

View file

@ -3854,8 +3854,13 @@ func TestEventRule(t *testing.T) {
err = os.Remove(uploadLogFilePath)
assert.NoError(t, err)
lastReceivedEmail.reset()
assert.Eventually(t, func() bool {
return lastReceivedEmail.get().From != ""
}, 3000*time.Millisecond, 100*time.Millisecond)
}
lastReceivedEmail.reset()
_, err = httpdtest.RemoveEventRule(rule1, http.StatusOK)
assert.NoError(t, err)
_, err = httpdtest.RemoveEventRule(rule2, http.StatusOK)

View file

@ -134,11 +134,23 @@ func renameUserFsEntry(w http.ResponseWriter, r *http.Request) {
oldName := connection.User.GetCleanedPath(r.URL.Query().Get("path"))
newName := connection.User.GetCleanedPath(r.URL.Query().Get("target"))
err = connection.Rename(oldName, newName)
if err != nil {
sendAPIResponse(w, r, err, fmt.Sprintf("Unable to rename %q -> %q", oldName, newName),
getMappedStatusCode(err))
return
if !connection.IsSameResource(oldName, newName) {
if err := connection.Copy(oldName, newName); err != nil {
sendAPIResponse(w, r, err, fmt.Sprintf("Cannot perform copy step to rename %q -> %q", oldName, newName),
getMappedStatusCode(err))
return
}
if err := connection.RemoveAll(oldName); err != nil {
sendAPIResponse(w, r, err, fmt.Sprintf("Cannot perform remove step to rename %q -> %q", oldName, newName),
getMappedStatusCode(err))
return
}
} else {
if err := connection.Rename(oldName, newName); err != nil {
sendAPIResponse(w, r, err, fmt.Sprintf("Unable to rename %q -> %q", oldName, newName),
getMappedStatusCode(err))
return
}
}
sendAPIResponse(w, r, nil, fmt.Sprintf("%q renamed to %q", oldName, newName), http.StatusOK)
}

View file

@ -15235,6 +15235,73 @@ func TestWebGetFiles(t *testing.T) {
assert.NoError(t, err)
}
func TestRenameDifferentResource(t *testing.T) {
folderName := "foldercryptfs"
u := getTestUser()
u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
BaseVirtualFolder: vfs.BaseVirtualFolder{
Name: folderName,
MappedPath: filepath.Join(os.TempDir(), "folderName"),
FsConfig: vfs.Filesystem{
Provider: sdk.CryptedFilesystemProvider,
CryptConfig: vfs.CryptFsConfig{
Passphrase: kms.NewPlainSecret("super secret"),
},
},
},
VirtualPath: "/folderPath",
})
user, _, err := httpdtest.AddUser(u, http.StatusCreated)
assert.NoError(t, err)
testFileName := "file.txt"
webAPIToken, err := getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
assert.NoError(t, err)
req, err := http.NewRequest(http.MethodPost, userFileActionsPath+"/move?path="+testFileName+"&target="+url.QueryEscape(path.Join("/", "folderPath", testFileName)), nil)
assert.NoError(t, err)
setBearerForReq(req, webAPIToken)
rr := executeRequest(req)
checkResponseCode(t, http.StatusNotFound, rr)
assert.Contains(t, rr.Body.String(), "Cannot perform copy step")
err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), []byte("just a test"), os.ModePerm)
assert.NoError(t, err)
req, err = http.NewRequest(http.MethodPost, userFileActionsPath+"/move?path="+testFileName+"&target="+url.QueryEscape(path.Join("/", "folderPath", testFileName)), nil)
assert.NoError(t, err)
setBearerForReq(req, webAPIToken)
rr = executeRequest(req)
checkResponseCode(t, http.StatusOK, rr)
// recreate the file and remove the delete permission
err = os.WriteFile(filepath.Join(user.GetHomeDir(), testFileName), []byte("just another test"), os.ModePerm)
assert.NoError(t, err)
u.Permissions = map[string][]string{
"/": {dataprovider.PermUpload, dataprovider.PermListItems, dataprovider.PermCreateDirs,
dataprovider.PermDownload, dataprovider.PermOverwrite},
}
_, resp, err := httpdtest.UpdateUser(u, http.StatusOK, "")
assert.NoError(t, err, string(resp))
webAPIToken, err = getJWTAPIUserTokenFromTestServer(defaultUsername, defaultPassword)
assert.NoError(t, err)
req, err = http.NewRequest(http.MethodPost, userFileActionsPath+"/move?path="+testFileName+"&target="+url.QueryEscape(path.Join("/", "folderPath", testFileName)), nil)
assert.NoError(t, err)
setBearerForReq(req, webAPIToken)
rr = executeRequest(req)
checkResponseCode(t, http.StatusForbidden, rr)
assert.Contains(t, rr.Body.String(), "Cannot perform remove step")
_, err = httpdtest.RemoveUser(user, http.StatusOK)
assert.NoError(t, err)
err = os.RemoveAll(user.GetHomeDir())
assert.NoError(t, err)
_, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
assert.NoError(t, err)
}
func TestWebDirsAPI(t *testing.T) {
user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
assert.NoError(t, err)