connection_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package common
  15. import (
  16. "os"
  17. "path"
  18. "path/filepath"
  19. "runtime"
  20. "testing"
  21. "time"
  22. "github.com/pkg/sftp"
  23. "github.com/rs/xid"
  24. "github.com/sftpgo/sdk"
  25. "github.com/stretchr/testify/assert"
  26. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  27. "github.com/drakkan/sftpgo/v2/internal/kms"
  28. "github.com/drakkan/sftpgo/v2/internal/util"
  29. "github.com/drakkan/sftpgo/v2/internal/vfs"
  30. )
  31. // MockOsFs mockable OsFs
  32. type MockOsFs struct {
  33. vfs.Fs
  34. hasVirtualFolders bool
  35. name string
  36. }
  37. // Name returns the name for the Fs implementation
  38. func (fs *MockOsFs) Name() string {
  39. if fs.name != "" {
  40. return fs.name
  41. }
  42. return "mockOsFs"
  43. }
  44. // HasVirtualFolders returns true if folders are emulated
  45. func (fs *MockOsFs) HasVirtualFolders() bool {
  46. return fs.hasVirtualFolders
  47. }
  48. func (fs *MockOsFs) IsUploadResumeSupported() bool {
  49. return !fs.hasVirtualFolders
  50. }
  51. func (fs *MockOsFs) Chtimes(name string, atime, mtime time.Time, isUploading bool) error {
  52. return vfs.ErrVfsUnsupported
  53. }
  54. func newMockOsFs(hasVirtualFolders bool, connectionID, rootDir, name string) vfs.Fs {
  55. return &MockOsFs{
  56. Fs: vfs.NewOsFs(connectionID, rootDir, ""),
  57. name: name,
  58. hasVirtualFolders: hasVirtualFolders,
  59. }
  60. }
  61. func TestRemoveErrors(t *testing.T) {
  62. mappedPath := filepath.Join(os.TempDir(), "map")
  63. homePath := filepath.Join(os.TempDir(), "home")
  64. user := dataprovider.User{
  65. BaseUser: sdk.BaseUser{
  66. Username: "remove_errors_user",
  67. HomeDir: homePath,
  68. },
  69. VirtualFolders: []vfs.VirtualFolder{
  70. {
  71. BaseVirtualFolder: vfs.BaseVirtualFolder{
  72. Name: filepath.Base(mappedPath),
  73. MappedPath: mappedPath,
  74. },
  75. VirtualPath: "/virtualpath",
  76. },
  77. },
  78. }
  79. user.Permissions = make(map[string][]string)
  80. user.Permissions["/"] = []string{dataprovider.PermAny}
  81. fs := vfs.NewOsFs("", os.TempDir(), "")
  82. conn := NewBaseConnection("", ProtocolFTP, "", "", user)
  83. err := conn.IsRemoveDirAllowed(fs, mappedPath, "/virtualpath1")
  84. if assert.Error(t, err) {
  85. assert.Contains(t, err.Error(), "permission denied")
  86. }
  87. err = conn.RemoveFile(fs, filepath.Join(homePath, "missing_file"), "/missing_file",
  88. vfs.NewFileInfo("info", false, 100, time.Now(), false))
  89. assert.Error(t, err)
  90. }
  91. func TestSetStatMode(t *testing.T) {
  92. oldSetStatMode := Config.SetstatMode
  93. Config.SetstatMode = 1
  94. fakePath := "fake path"
  95. user := dataprovider.User{
  96. BaseUser: sdk.BaseUser{
  97. HomeDir: os.TempDir(),
  98. },
  99. }
  100. user.Permissions = make(map[string][]string)
  101. user.Permissions["/"] = []string{dataprovider.PermAny}
  102. fs := newMockOsFs(true, "", user.GetHomeDir(), "")
  103. conn := NewBaseConnection("", ProtocolWebDAV, "", "", user)
  104. err := conn.handleChmod(fs, fakePath, fakePath, nil)
  105. assert.NoError(t, err)
  106. err = conn.handleChown(fs, fakePath, fakePath, nil)
  107. assert.NoError(t, err)
  108. err = conn.handleChtimes(fs, fakePath, fakePath, nil)
  109. assert.NoError(t, err)
  110. Config.SetstatMode = 2
  111. err = conn.handleChmod(fs, fakePath, fakePath, nil)
  112. assert.NoError(t, err)
  113. err = conn.handleChtimes(fs, fakePath, fakePath, &StatAttributes{
  114. Atime: time.Now(),
  115. Mtime: time.Now(),
  116. })
  117. assert.NoError(t, err)
  118. Config.SetstatMode = oldSetStatMode
  119. }
  120. func TestRecursiveRenameWalkError(t *testing.T) {
  121. fs := vfs.NewOsFs("", filepath.Clean(os.TempDir()), "")
  122. conn := NewBaseConnection("", ProtocolWebDAV, "", "", dataprovider.User{
  123. BaseUser: sdk.BaseUser{
  124. Permissions: map[string][]string{
  125. "/": {dataprovider.PermListItems, dataprovider.PermUpload,
  126. dataprovider.PermDownload, dataprovider.PermRenameDirs},
  127. },
  128. },
  129. })
  130. err := conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"),
  131. filepath.Join(os.TempDir(), "/target"), "/source", "/target",
  132. vfs.NewFileInfo("source", true, 0, time.Now(), false))
  133. assert.ErrorIs(t, err, os.ErrNotExist)
  134. conn.User.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  135. dataprovider.PermDownload, dataprovider.PermRenameFiles}
  136. // no dir rename permission, the quick check path returns permission error without walking
  137. err = conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"),
  138. filepath.Join(os.TempDir(), "/target"), "/source", "/target",
  139. vfs.NewFileInfo("source", true, 0, time.Now(), false))
  140. if assert.Error(t, err) {
  141. assert.EqualError(t, err, conn.GetPermissionDeniedError().Error())
  142. }
  143. }
  144. func TestCrossRenameFsErrors(t *testing.T) {
  145. fs := vfs.NewOsFs("", os.TempDir(), "")
  146. conn := NewBaseConnection("", ProtocolWebDAV, "", "", dataprovider.User{})
  147. res := conn.hasSpaceForCrossRename(fs, vfs.QuotaCheckResult{}, 1, "missingsource")
  148. assert.False(t, res)
  149. if runtime.GOOS != osWindows {
  150. dirPath := filepath.Join(os.TempDir(), "d")
  151. err := os.Mkdir(dirPath, os.ModePerm)
  152. assert.NoError(t, err)
  153. err = os.Chmod(dirPath, 0001)
  154. assert.NoError(t, err)
  155. res = conn.hasSpaceForCrossRename(fs, vfs.QuotaCheckResult{}, 1, dirPath)
  156. assert.False(t, res)
  157. err = os.Chmod(dirPath, os.ModePerm)
  158. assert.NoError(t, err)
  159. err = os.Remove(dirPath)
  160. assert.NoError(t, err)
  161. }
  162. }
  163. func TestRenameVirtualFolders(t *testing.T) {
  164. vdir := "/avdir"
  165. u := dataprovider.User{}
  166. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  167. BaseVirtualFolder: vfs.BaseVirtualFolder{
  168. Name: "name",
  169. MappedPath: "mappedPath",
  170. },
  171. VirtualPath: vdir,
  172. })
  173. fs := vfs.NewOsFs("", os.TempDir(), "")
  174. conn := NewBaseConnection("", ProtocolFTP, "", "", u)
  175. res := conn.isRenamePermitted(fs, fs, "source", "target", vdir, "vdirtarget", nil)
  176. assert.False(t, res)
  177. }
  178. func TestRenamePerms(t *testing.T) {
  179. src := "source"
  180. target := "target"
  181. sub := "/sub"
  182. subTarget := sub + "/target"
  183. u := dataprovider.User{}
  184. u.Permissions = map[string][]string{}
  185. u.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload, dataprovider.PermCreateSymlinks,
  186. dataprovider.PermDeleteFiles}
  187. conn := NewBaseConnection("", ProtocolSFTP, "", "", u)
  188. assert.False(t, conn.hasRenamePerms(src, target, nil))
  189. u.Permissions["/"] = []string{dataprovider.PermRename}
  190. assert.True(t, conn.hasRenamePerms(src, target, nil))
  191. u.Permissions["/"] = []string{dataprovider.PermCreateDirs, dataprovider.PermUpload, dataprovider.PermDeleteFiles,
  192. dataprovider.PermDeleteDirs}
  193. assert.False(t, conn.hasRenamePerms(src, target, nil))
  194. info := vfs.NewFileInfo(src, true, 0, time.Now(), false)
  195. u.Permissions["/"] = []string{dataprovider.PermRenameFiles}
  196. assert.False(t, conn.hasRenamePerms(src, target, info))
  197. u.Permissions["/"] = []string{dataprovider.PermRenameDirs}
  198. assert.True(t, conn.hasRenamePerms(src, target, info))
  199. u.Permissions["/"] = []string{dataprovider.PermRename}
  200. assert.True(t, conn.hasRenamePerms(src, target, info))
  201. u.Permissions["/"] = []string{dataprovider.PermDownload, dataprovider.PermUpload, dataprovider.PermDeleteDirs}
  202. assert.False(t, conn.hasRenamePerms(src, target, info))
  203. // test with different permissions between source and target
  204. u.Permissions["/"] = []string{dataprovider.PermRename}
  205. u.Permissions[sub] = []string{dataprovider.PermRenameFiles}
  206. assert.False(t, conn.hasRenamePerms(src, subTarget, info))
  207. u.Permissions[sub] = []string{dataprovider.PermRenameDirs}
  208. assert.True(t, conn.hasRenamePerms(src, subTarget, info))
  209. // test files
  210. info = vfs.NewFileInfo(src, false, 0, time.Now(), false)
  211. u.Permissions["/"] = []string{dataprovider.PermRenameDirs}
  212. assert.False(t, conn.hasRenamePerms(src, target, info))
  213. u.Permissions["/"] = []string{dataprovider.PermRenameFiles}
  214. assert.True(t, conn.hasRenamePerms(src, target, info))
  215. u.Permissions["/"] = []string{dataprovider.PermRename}
  216. assert.True(t, conn.hasRenamePerms(src, target, info))
  217. // test with different permissions between source and target
  218. u.Permissions["/"] = []string{dataprovider.PermRename}
  219. u.Permissions[sub] = []string{dataprovider.PermRenameDirs}
  220. assert.False(t, conn.hasRenamePerms(src, subTarget, info))
  221. u.Permissions[sub] = []string{dataprovider.PermRenameFiles}
  222. assert.True(t, conn.hasRenamePerms(src, subTarget, info))
  223. }
  224. func TestUpdateQuotaAfterRename(t *testing.T) {
  225. user := dataprovider.User{
  226. BaseUser: sdk.BaseUser{
  227. Username: userTestUsername,
  228. HomeDir: filepath.Join(os.TempDir(), "home"),
  229. },
  230. }
  231. mappedPath := filepath.Join(os.TempDir(), "vdir")
  232. user.Permissions = make(map[string][]string)
  233. user.Permissions["/"] = []string{dataprovider.PermAny}
  234. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  235. BaseVirtualFolder: vfs.BaseVirtualFolder{
  236. MappedPath: mappedPath,
  237. },
  238. VirtualPath: "/vdir",
  239. QuotaFiles: -1,
  240. QuotaSize: -1,
  241. })
  242. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  243. BaseVirtualFolder: vfs.BaseVirtualFolder{
  244. MappedPath: mappedPath,
  245. },
  246. VirtualPath: "/vdir1",
  247. QuotaFiles: -1,
  248. QuotaSize: -1,
  249. })
  250. err := os.MkdirAll(user.GetHomeDir(), os.ModePerm)
  251. assert.NoError(t, err)
  252. err = os.MkdirAll(mappedPath, os.ModePerm)
  253. assert.NoError(t, err)
  254. fs, err := user.GetFilesystem("id")
  255. assert.NoError(t, err)
  256. c := NewBaseConnection("", ProtocolSFTP, "", "", user)
  257. request := sftp.NewRequest("Rename", "/testfile")
  258. if runtime.GOOS != osWindows {
  259. request.Filepath = "/dir"
  260. request.Target = path.Join("/vdir", "dir")
  261. testDirPath := filepath.Join(mappedPath, "dir")
  262. err := os.MkdirAll(testDirPath, os.ModePerm)
  263. assert.NoError(t, err)
  264. err = os.Chmod(testDirPath, 0001)
  265. assert.NoError(t, err)
  266. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, testDirPath, 0)
  267. assert.Error(t, err)
  268. err = os.Chmod(testDirPath, os.ModePerm)
  269. assert.NoError(t, err)
  270. }
  271. testFile1 := "/testfile1"
  272. request.Target = testFile1
  273. request.Filepath = path.Join("/vdir", "file")
  274. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 0)
  275. assert.Error(t, err)
  276. err = os.WriteFile(filepath.Join(mappedPath, "file"), []byte("test content"), os.ModePerm)
  277. assert.NoError(t, err)
  278. request.Filepath = testFile1
  279. request.Target = path.Join("/vdir", "file")
  280. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  281. assert.NoError(t, err)
  282. err = os.WriteFile(filepath.Join(user.GetHomeDir(), "testfile1"), []byte("test content"), os.ModePerm)
  283. assert.NoError(t, err)
  284. request.Target = testFile1
  285. request.Filepath = path.Join("/vdir", "file")
  286. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  287. assert.NoError(t, err)
  288. request.Target = path.Join("/vdir1", "file")
  289. request.Filepath = path.Join("/vdir", "file")
  290. err = c.updateQuotaAfterRename(fs, request.Filepath, request.Target, filepath.Join(mappedPath, "file"), 12)
  291. assert.NoError(t, err)
  292. err = os.RemoveAll(mappedPath)
  293. assert.NoError(t, err)
  294. err = os.RemoveAll(user.GetHomeDir())
  295. assert.NoError(t, err)
  296. }
  297. func TestErrorsMapping(t *testing.T) {
  298. fs := vfs.NewOsFs("", os.TempDir(), "")
  299. conn := NewBaseConnection("", ProtocolSFTP, "", "", dataprovider.User{BaseUser: sdk.BaseUser{HomeDir: os.TempDir()}})
  300. osErrorsProtocols := []string{ProtocolWebDAV, ProtocolFTP, ProtocolHTTP, ProtocolHTTPShare,
  301. ProtocolDataRetention, ProtocolOIDC, protocolEventAction}
  302. for _, protocol := range supportedProtocols {
  303. conn.SetProtocol(protocol)
  304. err := conn.GetFsError(fs, os.ErrNotExist)
  305. if protocol == ProtocolSFTP {
  306. assert.ErrorIs(t, err, sftp.ErrSSHFxNoSuchFile)
  307. } else if util.Contains(osErrorsProtocols, protocol) {
  308. assert.EqualError(t, err, os.ErrNotExist.Error())
  309. } else {
  310. assert.EqualError(t, err, ErrNotExist.Error())
  311. }
  312. err = conn.GetFsError(fs, os.ErrPermission)
  313. if protocol == ProtocolSFTP {
  314. assert.EqualError(t, err, sftp.ErrSSHFxPermissionDenied.Error())
  315. } else {
  316. assert.EqualError(t, err, ErrPermissionDenied.Error())
  317. }
  318. err = conn.GetFsError(fs, os.ErrClosed)
  319. if protocol == ProtocolSFTP {
  320. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  321. } else {
  322. assert.EqualError(t, err, ErrGenericFailure.Error())
  323. }
  324. err = conn.GetFsError(fs, ErrPermissionDenied)
  325. if protocol == ProtocolSFTP {
  326. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  327. } else {
  328. assert.EqualError(t, err, ErrPermissionDenied.Error())
  329. }
  330. err = conn.GetFsError(fs, vfs.ErrVfsUnsupported)
  331. if protocol == ProtocolSFTP {
  332. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  333. } else {
  334. assert.EqualError(t, err, ErrOpUnsupported.Error())
  335. }
  336. err = conn.GetFsError(fs, vfs.ErrStorageSizeUnavailable)
  337. if protocol == ProtocolSFTP {
  338. assert.ErrorIs(t, err, sftp.ErrSSHFxOpUnsupported)
  339. assert.Contains(t, err.Error(), vfs.ErrStorageSizeUnavailable.Error())
  340. } else {
  341. assert.EqualError(t, err, vfs.ErrStorageSizeUnavailable.Error())
  342. }
  343. err = conn.GetQuotaExceededError()
  344. assert.True(t, conn.IsQuotaExceededError(err))
  345. err = conn.GetReadQuotaExceededError()
  346. if protocol == ProtocolSFTP {
  347. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  348. assert.Contains(t, err.Error(), ErrReadQuotaExceeded.Error())
  349. } else {
  350. assert.ErrorIs(t, err, ErrReadQuotaExceeded)
  351. }
  352. err = conn.GetNotExistError()
  353. assert.True(t, conn.IsNotExistError(err))
  354. err = conn.GetFsError(fs, nil)
  355. assert.NoError(t, err)
  356. err = conn.GetOpUnsupportedError()
  357. if protocol == ProtocolSFTP {
  358. assert.EqualError(t, err, sftp.ErrSSHFxOpUnsupported.Error())
  359. } else {
  360. assert.EqualError(t, err, ErrOpUnsupported.Error())
  361. }
  362. err = conn.GetFsError(fs, ErrShuttingDown)
  363. if protocol == ProtocolSFTP {
  364. assert.ErrorIs(t, err, sftp.ErrSSHFxFailure)
  365. assert.Contains(t, err.Error(), ErrShuttingDown.Error())
  366. } else {
  367. assert.EqualError(t, err, ErrShuttingDown.Error())
  368. }
  369. }
  370. }
  371. func TestMaxWriteSize(t *testing.T) {
  372. permissions := make(map[string][]string)
  373. permissions["/"] = []string{dataprovider.PermAny}
  374. user := dataprovider.User{
  375. BaseUser: sdk.BaseUser{
  376. Username: userTestUsername,
  377. Permissions: permissions,
  378. HomeDir: filepath.Clean(os.TempDir()),
  379. },
  380. }
  381. fs, err := user.GetFilesystem("123")
  382. assert.NoError(t, err)
  383. conn := NewBaseConnection("", ProtocolFTP, "", "", user)
  384. quotaResult := vfs.QuotaCheckResult{
  385. HasSpace: true,
  386. }
  387. size, err := conn.GetMaxWriteSize(quotaResult, false, 0, fs.IsUploadResumeSupported())
  388. assert.NoError(t, err)
  389. assert.Equal(t, int64(0), size)
  390. conn.User.Filters.MaxUploadFileSize = 100
  391. size, err = conn.GetMaxWriteSize(quotaResult, false, 0, fs.IsUploadResumeSupported())
  392. assert.NoError(t, err)
  393. assert.Equal(t, int64(100), size)
  394. quotaResult.QuotaSize = 1000
  395. size, err = conn.GetMaxWriteSize(quotaResult, false, 50, fs.IsUploadResumeSupported())
  396. assert.NoError(t, err)
  397. assert.Equal(t, int64(100), size)
  398. quotaResult.QuotaSize = 1000
  399. quotaResult.UsedSize = 990
  400. size, err = conn.GetMaxWriteSize(quotaResult, false, 50, fs.IsUploadResumeSupported())
  401. assert.NoError(t, err)
  402. assert.Equal(t, int64(60), size)
  403. quotaResult.QuotaSize = 0
  404. quotaResult.UsedSize = 0
  405. size, err = conn.GetMaxWriteSize(quotaResult, true, 100, fs.IsUploadResumeSupported())
  406. assert.True(t, conn.IsQuotaExceededError(err))
  407. assert.Equal(t, int64(0), size)
  408. size, err = conn.GetMaxWriteSize(quotaResult, true, 10, fs.IsUploadResumeSupported())
  409. assert.NoError(t, err)
  410. assert.Equal(t, int64(90), size)
  411. fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), "")
  412. size, err = conn.GetMaxWriteSize(quotaResult, true, 100, fs.IsUploadResumeSupported())
  413. assert.EqualError(t, err, ErrOpUnsupported.Error())
  414. assert.Equal(t, int64(0), size)
  415. }
  416. func TestCheckParentDirsErrors(t *testing.T) {
  417. permissions := make(map[string][]string)
  418. permissions["/"] = []string{dataprovider.PermAny}
  419. user := dataprovider.User{
  420. BaseUser: sdk.BaseUser{
  421. Username: userTestUsername,
  422. Permissions: permissions,
  423. HomeDir: filepath.Clean(os.TempDir()),
  424. },
  425. FsConfig: vfs.Filesystem{
  426. Provider: sdk.CryptedFilesystemProvider,
  427. },
  428. }
  429. c := NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  430. err := c.CheckParentDirs("/a/dir")
  431. assert.Error(t, err)
  432. user.FsConfig.Provider = sdk.LocalFilesystemProvider
  433. user.VirtualFolders = nil
  434. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  435. BaseVirtualFolder: vfs.BaseVirtualFolder{
  436. FsConfig: vfs.Filesystem{
  437. Provider: sdk.CryptedFilesystemProvider,
  438. },
  439. },
  440. VirtualPath: "/vdir",
  441. })
  442. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  443. BaseVirtualFolder: vfs.BaseVirtualFolder{
  444. MappedPath: filepath.Clean(os.TempDir()),
  445. },
  446. VirtualPath: "/vdir/sub",
  447. })
  448. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  449. err = c.CheckParentDirs("/vdir/sub/dir")
  450. assert.Error(t, err)
  451. user = dataprovider.User{
  452. BaseUser: sdk.BaseUser{
  453. Username: userTestUsername,
  454. Permissions: permissions,
  455. HomeDir: filepath.Clean(os.TempDir()),
  456. },
  457. FsConfig: vfs.Filesystem{
  458. Provider: sdk.S3FilesystemProvider,
  459. S3Config: vfs.S3FsConfig{
  460. BaseS3FsConfig: sdk.BaseS3FsConfig{
  461. Bucket: "buck",
  462. Region: "us-east-1",
  463. AccessKey: "key",
  464. },
  465. AccessSecret: kms.NewPlainSecret("s3secret"),
  466. },
  467. },
  468. }
  469. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  470. err = c.CheckParentDirs("/a/dir")
  471. assert.NoError(t, err)
  472. user.VirtualFolders = append(user.VirtualFolders, vfs.VirtualFolder{
  473. BaseVirtualFolder: vfs.BaseVirtualFolder{
  474. MappedPath: filepath.Clean(os.TempDir()),
  475. },
  476. VirtualPath: "/local/dir",
  477. })
  478. c = NewBaseConnection(xid.New().String(), ProtocolSFTP, "", "", user)
  479. err = c.CheckParentDirs("/local/dir/sub-dir")
  480. assert.NoError(t, err)
  481. err = os.RemoveAll(filepath.Join(os.TempDir(), "sub-dir"))
  482. assert.NoError(t, err)
  483. }