mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-25 09:00:27 +00:00
daac90c4e1
hooks doing something like this: err = provider.updateUser(u) ... return provider.userExists(username) could be racy if another update happen before provider.userExists(username) also pass a pointer to updateUser so if the user is modified inside "validateUser" we can just return the modified user without do a new query
1255 lines
42 KiB
Go
1255 lines
42 KiB
Go
package common
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/minio/sio"
|
|
"github.com/pkg/sftp"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/drakkan/sftpgo/dataprovider"
|
|
"github.com/drakkan/sftpgo/kms"
|
|
"github.com/drakkan/sftpgo/vfs"
|
|
)
|
|
|
|
// MockOsFs mockable OsFs
|
|
type MockOsFs struct {
|
|
vfs.Fs
|
|
hasVirtualFolders bool
|
|
}
|
|
|
|
// Name returns the name for the Fs implementation
|
|
func (fs MockOsFs) Name() string {
|
|
return "mockOsFs"
|
|
}
|
|
|
|
// HasVirtualFolders returns true if folders are emulated
|
|
func (fs MockOsFs) HasVirtualFolders() bool {
|
|
return fs.hasVirtualFolders
|
|
}
|
|
|
|
func (fs MockOsFs) IsUploadResumeSupported() bool {
|
|
return !fs.hasVirtualFolders
|
|
}
|
|
|
|
func newMockOsFs(hasVirtualFolders bool, connectionID, rootDir string) vfs.Fs {
|
|
return &MockOsFs{
|
|
Fs: vfs.NewOsFs(connectionID, rootDir, nil),
|
|
hasVirtualFolders: hasVirtualFolders,
|
|
}
|
|
}
|
|
|
|
func TestListDir(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermUpload}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir",
|
|
})
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
_, err = c.ListDir(user.GetHomeDir(), "/")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
c.User.Permissions["/"] = []string{dataprovider.PermAny}
|
|
files, err := c.ListDir(user.GetHomeDir(), "/")
|
|
if assert.NoError(t, err) {
|
|
vdirFound := false
|
|
for _, f := range files {
|
|
if f.Name() == "vdir" {
|
|
vdirFound = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, vdirFound)
|
|
}
|
|
_, err = c.ListDir(mappedPath, "/vdir")
|
|
assert.Error(t, err)
|
|
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestCreateDir(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/sub"] = []string{dataprovider.PermListItems}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir",
|
|
})
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.CreateDir("", "/sub/dir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateDir("", "/vdir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateDir(filepath.Join(mappedPath, "adir"), "/vdir/adir")
|
|
assert.Error(t, err)
|
|
err = c.CreateDir(filepath.Join(user.GetHomeDir(), "dir"), "/dir")
|
|
assert.NoError(t, err)
|
|
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRemoveFile(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/sub"] = []string{dataprovider.PermListItems}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
user.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
|
|
{
|
|
Path: "/p",
|
|
AllowedExtensions: []string{},
|
|
DeniedExtensions: []string{".zip"},
|
|
},
|
|
}
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.RemoveFile("", "/sub/file", nil)
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.RemoveFile("", "/p/file.zip", nil)
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
testFile := filepath.Join(mappedPath, "afile")
|
|
err = ioutil.WriteFile(testFile, []byte("test data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
info, err := os.Stat(testFile)
|
|
assert.NoError(t, err)
|
|
err = c.RemoveFile(filepath.Join(user.GetHomeDir(), "missing"), "/missing", info)
|
|
assert.Error(t, err)
|
|
err = c.RemoveFile(testFile, "/vdir/afile", info)
|
|
assert.NoError(t, err)
|
|
|
|
err = os.RemoveAll(mappedPath)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRemoveDir(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/sub"] = []string{dataprovider.PermListItems}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/adir/vdir",
|
|
})
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.RemoveDir(user.GetHomeDir(), "/")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.RemoveDir(mappedPath, "/adir/vdir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.RemoveDir(mappedPath, "/adir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetOpUnsupportedError().Error())
|
|
}
|
|
err = c.RemoveDir(mappedPath, "/adir/dir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.RemoveDir(filepath.Join(user.GetHomeDir(), "/sub/dir"), "/sub/dir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
testDir := filepath.Join(user.GetHomeDir(), "testDir")
|
|
err = c.RemoveDir(testDir, "testDir")
|
|
assert.Error(t, err)
|
|
err = ioutil.WriteFile(testDir, []byte("data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.RemoveDir(testDir, "testDir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetGenericError(err).Error())
|
|
}
|
|
err = os.Remove(testDir)
|
|
assert.NoError(t, err)
|
|
testDirSub := filepath.Join(testDir, "sub")
|
|
err = os.MkdirAll(testDirSub, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.RemoveDir(testDir, "/testDir")
|
|
assert.Error(t, err)
|
|
err = os.RemoveAll(testDirSub)
|
|
assert.NoError(t, err)
|
|
err = c.RemoveDir(testDir, "/testDir")
|
|
assert.NoError(t, err)
|
|
|
|
err = c.RemoveDir(testDir, "/testDir")
|
|
assert.Error(t, err)
|
|
|
|
fs = newMockOsFs(true, "", user.GetHomeDir())
|
|
c.Fs = fs
|
|
err = c.RemoveDir(testDir, "/testDir")
|
|
assert.NoError(t, err)
|
|
|
|
err = os.RemoveAll(mappedPath)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRename(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
QuotaSize: 10485760,
|
|
}
|
|
mappedPath1 := filepath.Join(os.TempDir(), "vdir1")
|
|
mappedPath2 := filepath.Join(os.TempDir(), "vdir2")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/sub"] = []string{dataprovider.PermListItems}
|
|
user.Permissions["/sub1"] = []string{dataprovider.PermRename}
|
|
user.Permissions["/dir"] = []string{dataprovider.PermListItems}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath1,
|
|
},
|
|
VirtualPath: "/vdir1/sub",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath2,
|
|
},
|
|
VirtualPath: "/vdir2",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
err := os.MkdirAll(filepath.Join(user.GetHomeDir(), "sub"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "dir", "sub"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath1, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath2, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.Rename(mappedPath1, "", "", "")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.Rename("", mappedPath2, "", "")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.Rename("missing", "", "", "")
|
|
assert.Error(t, err)
|
|
testFile := filepath.Join(user.GetHomeDir(), "file")
|
|
err = ioutil.WriteFile(testFile, []byte("data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
testSubFile := filepath.Join(user.GetHomeDir(), "sub", "file")
|
|
err = ioutil.WriteFile(testSubFile, []byte("data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.Rename(testSubFile, filepath.Join(user.GetHomeDir(), "file"), "/sub/file", "/file")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.Rename(testFile, filepath.Join(user.GetHomeDir(), "sub"), "/file", "/sub")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetOpUnsupportedError().Error())
|
|
}
|
|
err = c.Rename(testSubFile, testFile, "/file", "/sub1/file")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "sub"), filepath.Join(user.GetHomeDir(), "adir"), "/vdir1", "/adir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetOpUnsupportedError().Error())
|
|
}
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "dir"), filepath.Join(user.GetHomeDir(), "adir"), "/dir", "/adir")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "testdir"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "testdir"), filepath.Join(user.GetHomeDir(), "tdir", "sub"), "/testdir", "/tdir/sub")
|
|
assert.Error(t, err)
|
|
err = os.Remove(testSubFile)
|
|
assert.NoError(t, err)
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "sub"), filepath.Join(user.GetHomeDir(), "adir"), "/sub", "/adir")
|
|
assert.NoError(t, err)
|
|
err = os.MkdirAll(filepath.Join(user.GetHomeDir(), "adir"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(user.GetHomeDir(), "adir", "file"), []byte("data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "adir", "file"), filepath.Join(user.GetHomeDir(), "file"), "/adir/file", "/file")
|
|
assert.NoError(t, err)
|
|
// rename between virtual folder this should fail since the virtual folder is not found inside the data provider
|
|
// and so the remaining space cannot be computed
|
|
err = c.Rename(filepath.Join(user.GetHomeDir(), "adir"), filepath.Join(user.GetHomeDir(), "another"), "/vdir1/sub/a", "/vdir2/b")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetGenericError(err).Error())
|
|
}
|
|
|
|
err = os.RemoveAll(mappedPath1)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(mappedPath2)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestCreateSymlink(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath1 := filepath.Join(os.TempDir(), "vdir1")
|
|
mappedPath2 := filepath.Join(os.TempDir(), "vdir2")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/sub"] = []string{dataprovider.PermListItems}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath1,
|
|
},
|
|
VirtualPath: "/vdir1",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath2,
|
|
},
|
|
VirtualPath: "/vdir2",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath1, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(mappedPath2, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.CreateSymlink(user.GetHomeDir(), mappedPath1, "/", "/vdir1")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateSymlink(filepath.Join(user.GetHomeDir(), "a"), mappedPath1, "/a", "/vdir1")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateSymlink(filepath.Join(user.GetHomeDir(), "b"), mappedPath1, "/b", "/sub/b")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateSymlink(filepath.Join(user.GetHomeDir(), "b"), mappedPath1, "/vdir1/b", "/vdir2/b")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetOpUnsupportedError().Error())
|
|
}
|
|
err = c.CreateSymlink(mappedPath1, filepath.Join(mappedPath1, "b"), "/vdir1/a", "/vdir1/b")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.CreateSymlink(filepath.Join(mappedPath1, "b"), mappedPath1, "/vdir1/a", "/vdir1/b")
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
|
|
err = os.Mkdir(filepath.Join(user.GetHomeDir(), "b"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.CreateSymlink(filepath.Join(user.GetHomeDir(), "b"), filepath.Join(user.GetHomeDir(), "c"), "/b", "/c")
|
|
assert.NoError(t, err)
|
|
err = c.CreateSymlink(filepath.Join(user.GetHomeDir(), "b"), filepath.Join(user.GetHomeDir(), "c"), "/b", "/c")
|
|
assert.Error(t, err)
|
|
|
|
err = os.RemoveAll(mappedPath1)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(mappedPath2)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestDoStat(t *testing.T) {
|
|
testFile := filepath.Join(os.TempDir(), "afile.txt")
|
|
fs := vfs.NewOsFs("123", os.TempDir(), nil)
|
|
u := dataprovider.User{
|
|
Username: "user",
|
|
HomeDir: os.TempDir(),
|
|
}
|
|
u.Permissions = make(map[string][]string)
|
|
u.Permissions["/"] = []string{dataprovider.PermAny}
|
|
err := ioutil.WriteFile(testFile, []byte("data"), os.ModePerm)
|
|
require.NoError(t, err)
|
|
err = os.Symlink(testFile, testFile+".sym")
|
|
require.NoError(t, err)
|
|
conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, u, fs)
|
|
infoStat, err := conn.DoStat(testFile+".sym", 0)
|
|
if assert.NoError(t, err) {
|
|
assert.Equal(t, int64(4), infoStat.Size())
|
|
}
|
|
infoLstat, err := conn.DoStat(testFile+".sym", 1)
|
|
if assert.NoError(t, err) {
|
|
assert.NotEqual(t, int64(4), infoLstat.Size())
|
|
}
|
|
assert.False(t, os.SameFile(infoStat, infoLstat))
|
|
|
|
fs, err = vfs.NewCryptFs(fs.ConnectionID(), os.TempDir(), vfs.CryptFsConfig{
|
|
Passphrase: kms.NewPlainSecret("payload"),
|
|
})
|
|
assert.NoError(t, err)
|
|
conn = NewBaseConnection(fs.ConnectionID(), ProtocolFTP, u, fs)
|
|
dataSize := int64(32768)
|
|
data := make([]byte, dataSize)
|
|
err = ioutil.WriteFile(testFile, data, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
infoStat, err = conn.DoStat(testFile, 0)
|
|
assert.NoError(t, err)
|
|
assert.Less(t, infoStat.Size(), dataSize)
|
|
encSize, err := sio.EncryptedSize(uint64(infoStat.Size()))
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(encSize)+33, dataSize)
|
|
|
|
err = os.Remove(testFile)
|
|
assert.NoError(t, err)
|
|
err = os.Remove(testFile + ".sym")
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conn.GetTransfers(), 0)
|
|
}
|
|
|
|
func TestSetStat(t *testing.T) {
|
|
oldSetStatMode := Config.SetstatMode
|
|
Config.SetstatMode = 1
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.Permissions["/dir1"] = []string{dataprovider.PermChmod}
|
|
user.Permissions["/dir2"] = []string{dataprovider.PermChown}
|
|
user.Permissions["/dir3"] = []string{dataprovider.PermChtimes}
|
|
dir1 := filepath.Join(user.GetHomeDir(), "dir1")
|
|
dir2 := filepath.Join(user.GetHomeDir(), "dir2")
|
|
dir3 := filepath.Join(user.GetHomeDir(), "dir3")
|
|
err := os.Mkdir(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(dir1, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(dir2, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Mkdir(dir3, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
|
|
fs, err := user.GetFilesystem("")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
err = c.SetStat(user.GetHomeDir(), "/", &StatAttributes{})
|
|
assert.NoError(t, err)
|
|
|
|
err = c.SetStat(dir2, "/dir1/file", &StatAttributes{
|
|
Mode: os.ModePerm,
|
|
Flags: StatAttrPerms,
|
|
})
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(dir1, "/dir2/file", &StatAttributes{
|
|
UID: os.Getuid(),
|
|
GID: os.Getgid(),
|
|
Flags: StatAttrUIDGID,
|
|
})
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(dir1, "/dir3/file", &StatAttributes{
|
|
Atime: time.Now(),
|
|
Mtime: time.Now(),
|
|
Flags: StatAttrTimes,
|
|
})
|
|
assert.NoError(t, err)
|
|
|
|
Config.SetstatMode = 2
|
|
assert.False(t, c.ignoreSetStat())
|
|
c1 := NewBaseConnection("", ProtocolSFTP, user, newMockOsFs(false, fs.ConnectionID(), user.GetHomeDir()))
|
|
assert.True(t, c1.ignoreSetStat())
|
|
|
|
Config.SetstatMode = oldSetStatMode
|
|
// chmod
|
|
err = c.SetStat(dir1, "/dir1/file", &StatAttributes{
|
|
Mode: os.ModePerm,
|
|
Flags: StatAttrPerms,
|
|
})
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(dir2, "/dir2/file", &StatAttributes{
|
|
Mode: os.ModePerm,
|
|
Flags: StatAttrPerms,
|
|
})
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.SetStat(filepath.Join(user.GetHomeDir(), "missing"), "/missing", &StatAttributes{
|
|
Mode: os.ModePerm,
|
|
Flags: StatAttrPerms,
|
|
})
|
|
assert.Error(t, err)
|
|
// chown
|
|
if runtime.GOOS != osWindows {
|
|
err = c.SetStat(dir1, "/dir2/file", &StatAttributes{
|
|
UID: os.Getuid(),
|
|
GID: os.Getgid(),
|
|
Flags: StatAttrUIDGID,
|
|
})
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
err = c.SetStat(dir1, "/dir3/file", &StatAttributes{
|
|
UID: os.Getuid(),
|
|
GID: os.Getgid(),
|
|
Flags: StatAttrUIDGID,
|
|
})
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
|
|
err = c.SetStat(filepath.Join(user.GetHomeDir(), "missing"), "/missing", &StatAttributes{
|
|
UID: os.Getuid(),
|
|
GID: os.Getgid(),
|
|
Flags: StatAttrUIDGID,
|
|
})
|
|
assert.Error(t, err)
|
|
// chtimes
|
|
err = c.SetStat(dir1, "/dir3/file", &StatAttributes{
|
|
Atime: time.Now(),
|
|
Mtime: time.Now(),
|
|
Flags: StatAttrTimes,
|
|
})
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(dir1, "/dir1/file", &StatAttributes{
|
|
Atime: time.Now(),
|
|
Mtime: time.Now(),
|
|
Flags: StatAttrTimes,
|
|
})
|
|
if assert.Error(t, err) {
|
|
assert.EqualError(t, err, c.GetPermissionDeniedError().Error())
|
|
}
|
|
err = c.SetStat(filepath.Join(user.GetHomeDir(), "missing"), "/missing", &StatAttributes{
|
|
Atime: time.Now(),
|
|
Mtime: time.Now(),
|
|
Flags: StatAttrTimes,
|
|
})
|
|
assert.Error(t, err)
|
|
// truncate
|
|
err = c.SetStat(filepath.Join(user.GetHomeDir(), "/missing/missing"), "/missing/missing", &StatAttributes{
|
|
Size: 1,
|
|
Flags: StatAttrSize,
|
|
})
|
|
assert.Error(t, err)
|
|
err = c.SetStat(filepath.Join(dir3, "afile.txt"), "/dir3/afile.txt", &StatAttributes{
|
|
Size: 1,
|
|
Flags: StatAttrSize,
|
|
})
|
|
assert.Error(t, err)
|
|
|
|
filePath := filepath.Join(user.GetHomeDir(), "afile.txt")
|
|
err = ioutil.WriteFile(filePath, []byte("hello"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(filePath, "/afile.txt", &StatAttributes{
|
|
Flags: StatAttrSize,
|
|
Size: 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
fi, err := os.Stat(filePath)
|
|
if assert.NoError(t, err) {
|
|
assert.Equal(t, int64(1), fi.Size())
|
|
}
|
|
|
|
vDir := filepath.Join(os.TempDir(), "vdir")
|
|
err = os.MkdirAll(vDir, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
c.User.VirtualFolders = nil
|
|
c.User.VirtualFolders = append(c.User.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: vDir,
|
|
},
|
|
VirtualPath: "/vpath",
|
|
QuotaSize: -1,
|
|
QuotaFiles: -1,
|
|
})
|
|
|
|
filePath = filepath.Join(vDir, "afile.txt")
|
|
err = ioutil.WriteFile(filePath, []byte("hello"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = c.SetStat(filePath, "/vpath/afile.txt", &StatAttributes{
|
|
Flags: StatAttrSize,
|
|
Size: 1,
|
|
})
|
|
assert.NoError(t, err)
|
|
fi, err = os.Stat(filePath)
|
|
if assert.NoError(t, err) {
|
|
assert.Equal(t, int64(1), fi.Size())
|
|
}
|
|
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(vDir)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestSpaceForCrossRename(t *testing.T) {
|
|
permissions := make(map[string][]string)
|
|
permissions["/"] = []string{dataprovider.PermAny}
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
Permissions: permissions,
|
|
HomeDir: filepath.Clean(os.TempDir()),
|
|
}
|
|
fs, err := user.GetFilesystem("123")
|
|
assert.NoError(t, err)
|
|
conn := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
quotaResult := vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
}
|
|
assert.False(t, conn.hasSpaceForCrossRename(quotaResult, -1, filepath.Join(os.TempDir(), "a missing file")))
|
|
if runtime.GOOS != osWindows {
|
|
testDir := filepath.Join(os.TempDir(), "dir")
|
|
err = os.MkdirAll(testDir, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(testDir, "afile.txt"), []byte("content"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Chmod(testDir, 0001)
|
|
assert.NoError(t, err)
|
|
assert.False(t, conn.hasSpaceForCrossRename(quotaResult, -1, testDir))
|
|
err = os.Chmod(testDir, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(testDir)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
testFile := filepath.Join(os.TempDir(), "afile.txt")
|
|
err = ioutil.WriteFile(testFile, []byte("test data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: false,
|
|
QuotaSize: 0,
|
|
}
|
|
assert.True(t, conn.hasSpaceForCrossRename(quotaResult, 123, testFile))
|
|
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: false,
|
|
QuotaSize: 124,
|
|
UsedSize: 125,
|
|
}
|
|
assert.False(t, conn.hasSpaceForCrossRename(quotaResult, 8, testFile))
|
|
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: false,
|
|
QuotaSize: 124,
|
|
UsedSize: 124,
|
|
}
|
|
assert.True(t, conn.hasSpaceForCrossRename(quotaResult, 123, testFile))
|
|
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
QuotaSize: 10,
|
|
UsedSize: 1,
|
|
}
|
|
assert.True(t, conn.hasSpaceForCrossRename(quotaResult, -1, testFile))
|
|
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
QuotaSize: 7,
|
|
UsedSize: 0,
|
|
}
|
|
assert.False(t, conn.hasSpaceForCrossRename(quotaResult, -1, testFile))
|
|
|
|
err = os.Remove(testFile)
|
|
assert.NoError(t, err)
|
|
|
|
testDir := filepath.Join(os.TempDir(), "testDir")
|
|
err = os.MkdirAll(testDir, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(testDir, "1"), []byte("1"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(testDir, "2"), []byte("2"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
QuotaFiles: 2,
|
|
UsedFiles: 1,
|
|
}
|
|
assert.False(t, conn.hasSpaceForCrossRename(quotaResult, -1, testDir))
|
|
|
|
quotaResult = vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
QuotaFiles: 2,
|
|
UsedFiles: 0,
|
|
}
|
|
assert.True(t, conn.hasSpaceForCrossRename(quotaResult, -1, testDir))
|
|
|
|
err = os.RemoveAll(testDir)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestRenamePermission(t *testing.T) {
|
|
permissions := make(map[string][]string)
|
|
permissions["/"] = []string{dataprovider.PermAny}
|
|
permissions["/dir1"] = []string{dataprovider.PermRename}
|
|
permissions["/dir2"] = []string{dataprovider.PermUpload}
|
|
permissions["/dir3"] = []string{dataprovider.PermDelete}
|
|
permissions["/dir4"] = []string{dataprovider.PermListItems}
|
|
permissions["/dir5"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload}
|
|
permissions["/dir6"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload,
|
|
dataprovider.PermListItems, dataprovider.PermCreateSymlinks}
|
|
permissions["/dir7"] = []string{dataprovider.PermAny}
|
|
permissions["/dir8"] = []string{dataprovider.PermAny}
|
|
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
Permissions: permissions,
|
|
HomeDir: os.TempDir(),
|
|
}
|
|
fs, err := user.GetFilesystem("123")
|
|
assert.NoError(t, err)
|
|
conn := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
request := sftp.NewRequest("Rename", "/testfile")
|
|
request.Target = "/dir1/testfile"
|
|
// rename is granted on Source and Target
|
|
assert.True(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request.Target = "/dir4/testfile"
|
|
// rename is not granted on Target
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request = sftp.NewRequest("Rename", "/dir1/testfile")
|
|
request.Target = "/dir2/testfile" //nolint:goconst
|
|
// rename is granted on Source but not on Target
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request = sftp.NewRequest("Rename", "/dir4/testfile")
|
|
request.Target = "/dir1/testfile"
|
|
// rename is granted on Target but not on Source
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request = sftp.NewRequest("Rename", "/dir4/testfile")
|
|
request.Target = "/testfile"
|
|
// rename is granted on Target but not on Source
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request = sftp.NewRequest("Rename", "/dir3/testfile")
|
|
request.Target = "/dir2/testfile"
|
|
// delete is granted on Source and Upload on Target, the target is a file this is enough
|
|
assert.True(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
request = sftp.NewRequest("Rename", "/dir2/testfile")
|
|
request.Target = "/dir3/testfile"
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
tmpDir := filepath.Join(os.TempDir(), "dir")
|
|
tmpDirLink := filepath.Join(os.TempDir(), "link")
|
|
err = os.Mkdir(tmpDir, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Symlink(tmpDir, tmpDirLink)
|
|
assert.NoError(t, err)
|
|
request.Filepath = "/dir"
|
|
request.Target = "/dir2/dir"
|
|
// the source is a dir and the target has no createDirs perm
|
|
info, err := os.Lstat(tmpDir)
|
|
if assert.NoError(t, err) {
|
|
assert.False(t, conn.isRenamePermitted(tmpDir, request.Filepath, request.Target, info))
|
|
conn.User.Permissions["/dir2"] = []string{dataprovider.PermUpload, dataprovider.PermCreateDirs}
|
|
// the source is a dir and the target has createDirs perm
|
|
assert.True(t, conn.isRenamePermitted(tmpDir, request.Filepath, request.Target, info))
|
|
|
|
request = sftp.NewRequest("Rename", "/testfile")
|
|
request.Target = "/dir5/testfile"
|
|
// the source is a dir and the target has createDirs and upload perm
|
|
assert.True(t, conn.isRenamePermitted(tmpDir, request.Filepath, request.Target, info))
|
|
}
|
|
info, err = os.Lstat(tmpDirLink)
|
|
if assert.NoError(t, err) {
|
|
assert.True(t, info.Mode()&os.ModeSymlink != 0)
|
|
// the source is a symlink and the target has createDirs and upload perm
|
|
assert.False(t, conn.isRenamePermitted(tmpDir, request.Filepath, request.Target, info))
|
|
}
|
|
err = os.RemoveAll(tmpDir)
|
|
assert.NoError(t, err)
|
|
err = os.Remove(tmpDirLink)
|
|
assert.NoError(t, err)
|
|
conn.User.VirtualFolders = append(conn.User.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: os.TempDir(),
|
|
},
|
|
VirtualPath: "/dir1",
|
|
})
|
|
request = sftp.NewRequest("Rename", "/dir1")
|
|
request.Target = "/dir2/testfile"
|
|
// renaming a virtual folder is not allowed
|
|
assert.False(t, conn.isRenamePermitted("", request.Filepath, request.Target, nil))
|
|
err = conn.checkRecursiveRenameDirPermissions("invalid", "invalid")
|
|
assert.Error(t, err)
|
|
dir3 := filepath.Join(conn.User.HomeDir, "dir3")
|
|
dir6 := filepath.Join(conn.User.HomeDir, "dir6")
|
|
err = os.MkdirAll(filepath.Join(dir3, "subdir"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(dir3, "subdir", "testfile"), []byte("test"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = conn.checkRecursiveRenameDirPermissions(dir3, dir6)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(dir3)
|
|
assert.NoError(t, err)
|
|
|
|
dir7 := filepath.Join(conn.User.HomeDir, "dir7")
|
|
dir8 := filepath.Join(conn.User.HomeDir, "dir8")
|
|
err = os.MkdirAll(filepath.Join(dir8, "subdir"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(dir8, "subdir", "testfile"), []byte("test"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = conn.checkRecursiveRenameDirPermissions(dir8, dir7)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(dir8)
|
|
assert.NoError(t, err)
|
|
|
|
assert.False(t, conn.isRenamePermitted(user.GetHomeDir(), "", "", nil))
|
|
|
|
conn.User.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
|
|
{
|
|
Path: "/p",
|
|
AllowedExtensions: []string{},
|
|
DeniedExtensions: []string{".zip"},
|
|
},
|
|
}
|
|
testFile := filepath.Join(user.HomeDir, "testfile")
|
|
err = ioutil.WriteFile(testFile, []byte("data"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
info, err = os.Stat(testFile)
|
|
assert.NoError(t, err)
|
|
assert.False(t, conn.isRenamePermitted(dir7, "/file", "/p/file.zip", info))
|
|
err = os.Remove(testFile)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestHasSpaceForRename(t *testing.T) {
|
|
err := closeDataprovider()
|
|
assert.NoError(t, err)
|
|
_, err = initializeDataprovider(0)
|
|
assert.NoError(t, err)
|
|
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir1",
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir2",
|
|
QuotaSize: -1,
|
|
QuotaFiles: -1,
|
|
})
|
|
fs, err := user.GetFilesystem("id")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
// with quota tracking disabled hasSpaceForRename will always return true
|
|
assert.True(t, c.hasSpaceForRename("", "", 0, ""))
|
|
quotaResult := c.HasSpace(true, "")
|
|
assert.True(t, quotaResult.HasSpace)
|
|
|
|
err = closeDataprovider()
|
|
assert.NoError(t, err)
|
|
_, err = initializeDataprovider(-1)
|
|
assert.NoError(t, err)
|
|
|
|
// rename inside the same mapped path
|
|
assert.True(t, c.hasSpaceForRename("/vdir1/file", "/vdir2/file", 0, filepath.Join(mappedPath, "file")))
|
|
// rename between user root dir and a virtual folder included in user quota
|
|
assert.True(t, c.hasSpaceForRename("/file", "/vdir2/file", 0, filepath.Join(mappedPath, "file")))
|
|
|
|
assert.True(t, c.isCrossFoldersRequest("/file", "/vdir2/file"))
|
|
}
|
|
|
|
func TestUpdateQuotaAfterRename(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir1",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
err := os.MkdirAll(user.GetHomeDir(), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.MkdirAll(mappedPath, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("id")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
request := sftp.NewRequest("Rename", "/testfile")
|
|
if runtime.GOOS != osWindows {
|
|
request.Filepath = "/dir"
|
|
request.Target = path.Join("/vdir", "dir")
|
|
testDirPath := filepath.Join(mappedPath, "dir")
|
|
err := os.MkdirAll(testDirPath, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
err = os.Chmod(testDirPath, 0001)
|
|
assert.NoError(t, err)
|
|
err = c.updateQuotaAfterRename(request.Filepath, request.Target, testDirPath, 0)
|
|
assert.Error(t, err)
|
|
err = os.Chmod(testDirPath, os.ModePerm)
|
|
assert.NoError(t, err)
|
|
}
|
|
testFile1 := "/testfile1"
|
|
request.Target = testFile1
|
|
request.Filepath = path.Join("/vdir", "file")
|
|
err = c.updateQuotaAfterRename(request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 0)
|
|
assert.Error(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(mappedPath, "file"), []byte("test content"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
request.Filepath = testFile1
|
|
request.Target = path.Join("/vdir", "file")
|
|
err = c.updateQuotaAfterRename(request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
|
|
assert.NoError(t, err)
|
|
err = ioutil.WriteFile(filepath.Join(user.GetHomeDir(), "testfile1"), []byte("test content"), os.ModePerm)
|
|
assert.NoError(t, err)
|
|
request.Target = testFile1
|
|
request.Filepath = path.Join("/vdir", "file")
|
|
err = c.updateQuotaAfterRename(request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
|
|
assert.NoError(t, err)
|
|
request.Target = path.Join("/vdir1", "file")
|
|
request.Filepath = path.Join("/vdir", "file")
|
|
err = c.updateQuotaAfterRename(request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
|
|
assert.NoError(t, err)
|
|
|
|
err = os.RemoveAll(mappedPath)
|
|
assert.NoError(t, err)
|
|
err = os.RemoveAll(user.GetHomeDir())
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestHasSpace(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
Password: userTestPwd,
|
|
}
|
|
mappedPath := filepath.Join(os.TempDir(), "vdir")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath,
|
|
},
|
|
VirtualPath: "/vdir",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
fs, err := user.GetFilesystem("id")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
quotaResult := c.HasSpace(true, "/")
|
|
assert.True(t, quotaResult.HasSpace)
|
|
|
|
user.VirtualFolders[0].QuotaFiles = 0
|
|
user.VirtualFolders[0].QuotaSize = 0
|
|
err = dataprovider.AddUser(&user)
|
|
assert.NoError(t, err)
|
|
user, err = dataprovider.UserExists(user.Username)
|
|
assert.NoError(t, err)
|
|
c.User = user
|
|
quotaResult = c.HasSpace(true, "/vdir/file")
|
|
assert.True(t, quotaResult.HasSpace)
|
|
|
|
user.VirtualFolders[0].QuotaFiles = 10
|
|
user.VirtualFolders[0].QuotaSize = 1048576
|
|
err = dataprovider.UpdateUser(&user)
|
|
assert.NoError(t, err)
|
|
c.User = user
|
|
quotaResult = c.HasSpace(true, "/vdir/file1")
|
|
assert.True(t, quotaResult.HasSpace)
|
|
|
|
quotaResult = c.HasSpace(true, "/file")
|
|
assert.True(t, quotaResult.HasSpace)
|
|
|
|
folder, err := dataprovider.GetFolderByPath(mappedPath)
|
|
assert.NoError(t, err)
|
|
err = dataprovider.UpdateVirtualFolderQuota(folder, 10, 1048576, true)
|
|
assert.NoError(t, err)
|
|
quotaResult = c.HasSpace(true, "/vdir/file1")
|
|
assert.False(t, quotaResult.HasSpace)
|
|
|
|
err = dataprovider.DeleteUser(&user)
|
|
assert.NoError(t, err)
|
|
|
|
err = dataprovider.DeleteFolder(&folder)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestUpdateQuotaMoveVFolders(t *testing.T) {
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
HomeDir: filepath.Join(os.TempDir(), "home"),
|
|
Password: userTestPwd,
|
|
QuotaFiles: 100,
|
|
}
|
|
mappedPath1 := filepath.Join(os.TempDir(), "vdir1")
|
|
mappedPath2 := filepath.Join(os.TempDir(), "vdir2")
|
|
user.Permissions = make(map[string][]string)
|
|
user.Permissions["/"] = []string{dataprovider.PermAny}
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath1,
|
|
},
|
|
VirtualPath: "/vdir1",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
|
|
BaseVirtualFolder: vfs.BaseVirtualFolder{
|
|
MappedPath: mappedPath2,
|
|
},
|
|
VirtualPath: "/vdir2",
|
|
QuotaFiles: -1,
|
|
QuotaSize: -1,
|
|
})
|
|
err := dataprovider.AddUser(&user)
|
|
assert.NoError(t, err)
|
|
user, err = dataprovider.UserExists(user.Username)
|
|
assert.NoError(t, err)
|
|
folder1, err := dataprovider.GetFolderByPath(mappedPath1)
|
|
assert.NoError(t, err)
|
|
folder2, err := dataprovider.GetFolderByPath(mappedPath2)
|
|
assert.NoError(t, err)
|
|
err = dataprovider.UpdateVirtualFolderQuota(folder1, 1, 100, true)
|
|
assert.NoError(t, err)
|
|
err = dataprovider.UpdateVirtualFolderQuota(folder2, 2, 150, true)
|
|
assert.NoError(t, err)
|
|
fs, err := user.GetFilesystem("id")
|
|
assert.NoError(t, err)
|
|
c := NewBaseConnection("", ProtocolSFTP, user, fs)
|
|
c.updateQuotaMoveBetweenVFolders(user.VirtualFolders[0], user.VirtualFolders[1], -1, 100, 1)
|
|
folder1, err = dataprovider.GetFolderByPath(mappedPath1)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 0, folder1.UsedQuotaFiles)
|
|
assert.Equal(t, int64(0), folder1.UsedQuotaSize)
|
|
folder2, err = dataprovider.GetFolderByPath(mappedPath2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 3, folder2.UsedQuotaFiles)
|
|
assert.Equal(t, int64(250), folder2.UsedQuotaSize)
|
|
|
|
c.updateQuotaMoveBetweenVFolders(user.VirtualFolders[1], user.VirtualFolders[0], 10, 100, 1)
|
|
folder1, err = dataprovider.GetFolderByPath(mappedPath1)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 0, folder1.UsedQuotaFiles)
|
|
assert.Equal(t, int64(90), folder1.UsedQuotaSize)
|
|
folder2, err = dataprovider.GetFolderByPath(mappedPath2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, folder2.UsedQuotaFiles)
|
|
assert.Equal(t, int64(150), folder2.UsedQuotaSize)
|
|
|
|
err = dataprovider.UpdateUserQuota(user, 1, 100, true)
|
|
assert.NoError(t, err)
|
|
c.updateQuotaMoveFromVFolder(user.VirtualFolders[1], -1, 50, 1)
|
|
folder2, err = dataprovider.GetFolderByPath(mappedPath2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, folder2.UsedQuotaFiles)
|
|
assert.Equal(t, int64(100), folder2.UsedQuotaSize)
|
|
user, err = dataprovider.GetUserByID(user.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, user.UsedQuotaFiles)
|
|
assert.Equal(t, int64(100), user.UsedQuotaSize)
|
|
|
|
c.updateQuotaMoveToVFolder(user.VirtualFolders[1], -1, 100, 1)
|
|
folder2, err = dataprovider.GetFolderByPath(mappedPath2)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 2, folder2.UsedQuotaFiles)
|
|
assert.Equal(t, int64(200), folder2.UsedQuotaSize)
|
|
user, err = dataprovider.GetUserByID(user.ID)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, user.UsedQuotaFiles)
|
|
assert.Equal(t, int64(100), user.UsedQuotaSize)
|
|
|
|
err = dataprovider.DeleteUser(&user)
|
|
assert.NoError(t, err)
|
|
err = dataprovider.DeleteFolder(&folder1)
|
|
assert.NoError(t, err)
|
|
err = dataprovider.DeleteFolder(&folder2)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestErrorsMapping(t *testing.T) {
|
|
fs := vfs.NewOsFs("", os.TempDir(), nil)
|
|
conn := NewBaseConnection("", ProtocolSFTP, dataprovider.User{}, fs)
|
|
for _, protocol := range supportedProtocols {
|
|
conn.SetProtocol(protocol)
|
|
err := conn.GetFsError(os.ErrNotExist)
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxNoSuchFile.Error())
|
|
} else if protocol == ProtocolWebDAV || protocol == ProtocolFTP {
|
|
assert.EqualError(t, err, os.ErrNotExist.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrNotExist.Error())
|
|
}
|
|
err = conn.GetFsError(os.ErrPermission)
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxPermissionDenied.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrPermissionDenied.Error())
|
|
}
|
|
err = conn.GetFsError(os.ErrClosed)
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrGenericFailure.Error())
|
|
}
|
|
err = conn.GetFsError(ErrPermissionDenied)
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxFailure.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrPermissionDenied.Error())
|
|
}
|
|
err = conn.GetFsError(vfs.ErrVfsUnsupported)
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrOpUnsupported.Error())
|
|
}
|
|
err = conn.GetFsError(nil)
|
|
assert.NoError(t, err)
|
|
err = conn.GetOpUnsupportedError()
|
|
if protocol == ProtocolSFTP {
|
|
assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
|
|
} else {
|
|
assert.EqualError(t, err, ErrOpUnsupported.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestMaxWriteSize(t *testing.T) {
|
|
permissions := make(map[string][]string)
|
|
permissions["/"] = []string{dataprovider.PermAny}
|
|
user := dataprovider.User{
|
|
Username: userTestUsername,
|
|
Permissions: permissions,
|
|
HomeDir: filepath.Clean(os.TempDir()),
|
|
}
|
|
fs, err := user.GetFilesystem("123")
|
|
assert.NoError(t, err)
|
|
conn := NewBaseConnection("", ProtocolFTP, user, fs)
|
|
quotaResult := vfs.QuotaCheckResult{
|
|
HasSpace: true,
|
|
}
|
|
size, err := conn.GetMaxWriteSize(quotaResult, false, 0)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(0), size)
|
|
|
|
conn.User.Filters.MaxUploadFileSize = 100
|
|
size, err = conn.GetMaxWriteSize(quotaResult, false, 0)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(100), size)
|
|
|
|
quotaResult.QuotaSize = 1000
|
|
size, err = conn.GetMaxWriteSize(quotaResult, false, 50)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(100), size)
|
|
|
|
quotaResult.QuotaSize = 1000
|
|
quotaResult.UsedSize = 990
|
|
size, err = conn.GetMaxWriteSize(quotaResult, false, 50)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(60), size)
|
|
|
|
quotaResult.QuotaSize = 0
|
|
quotaResult.UsedSize = 0
|
|
size, err = conn.GetMaxWriteSize(quotaResult, true, 100)
|
|
assert.EqualError(t, err, ErrQuotaExceeded.Error())
|
|
assert.Equal(t, int64(0), size)
|
|
|
|
size, err = conn.GetMaxWriteSize(quotaResult, true, 10)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, int64(90), size)
|
|
|
|
conn.Fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir())
|
|
size, err = conn.GetMaxWriteSize(quotaResult, true, 100)
|
|
assert.EqualError(t, err, ErrOpUnsupported.Error())
|
|
assert.Equal(t, int64(0), size)
|
|
}
|