webdavd_test.go 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675
  1. package webdavd_test
  2. import (
  3. "bytes"
  4. "crypto/rand"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net"
  9. "net/http"
  10. "os"
  11. "os/exec"
  12. "path"
  13. "path/filepath"
  14. "runtime"
  15. "strings"
  16. "sync"
  17. "testing"
  18. "time"
  19. "github.com/minio/sio"
  20. "github.com/rs/zerolog"
  21. "github.com/stretchr/testify/assert"
  22. "github.com/studio-b12/gowebdav"
  23. "github.com/drakkan/sftpgo/common"
  24. "github.com/drakkan/sftpgo/config"
  25. "github.com/drakkan/sftpgo/dataprovider"
  26. "github.com/drakkan/sftpgo/httpclient"
  27. "github.com/drakkan/sftpgo/httpdtest"
  28. "github.com/drakkan/sftpgo/kms"
  29. "github.com/drakkan/sftpgo/logger"
  30. "github.com/drakkan/sftpgo/sftpd"
  31. "github.com/drakkan/sftpgo/vfs"
  32. "github.com/drakkan/sftpgo/webdavd"
  33. )
  34. const (
  35. logSender = "webavdTesting"
  36. webDavServerAddr = "127.0.0.1:9090"
  37. webDavServerPort = 9090
  38. sftpServerAddr = "127.0.0.1:9022"
  39. defaultUsername = "test_user_dav"
  40. defaultPassword = "test_password"
  41. configDir = ".."
  42. osWindows = "windows"
  43. webDavCert = `-----BEGIN CERTIFICATE-----
  44. MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
  45. RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
  46. dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
  47. OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
  48. VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
  49. IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
  50. NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
  51. 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
  52. GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
  53. SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
  54. /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
  55. dV4vKmHUzwK/eIx+8Ay3neE=
  56. -----END CERTIFICATE-----`
  57. webDavKey = `-----BEGIN EC PARAMETERS-----
  58. BgUrgQQAIg==
  59. -----END EC PARAMETERS-----
  60. -----BEGIN EC PRIVATE KEY-----
  61. MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
  62. UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
  63. WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
  64. CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
  65. -----END EC PRIVATE KEY-----`
  66. testFileName = "test_file_dav.dat"
  67. testDLFileName = "test_download_dav.dat"
  68. )
  69. var (
  70. allPerms = []string{dataprovider.PermAny}
  71. homeBasePath string
  72. hookCmdPath string
  73. extAuthPath string
  74. preLoginPath string
  75. postConnectPath string
  76. logFilePath string
  77. certPath string
  78. keyPath string
  79. )
  80. func TestMain(m *testing.M) {
  81. logFilePath = filepath.Join(configDir, "sftpgo_webdavd_test.log")
  82. logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
  83. err := config.LoadConfig(configDir, "")
  84. if err != nil {
  85. logger.ErrorToConsole("error loading configuration: %v", err)
  86. os.Exit(1)
  87. }
  88. providerConf := config.GetProviderConf()
  89. logger.InfoToConsole("Starting WebDAVD tests, provider: %v", providerConf.Driver)
  90. commonConf := config.GetCommonConfig()
  91. commonConf.UploadMode = 2
  92. homeBasePath = os.TempDir()
  93. if runtime.GOOS != osWindows {
  94. commonConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  95. commonConf.Actions.Hook = hookCmdPath
  96. hookCmdPath, err = exec.LookPath("true")
  97. if err != nil {
  98. logger.Warn(logSender, "", "unable to get hook command: %v", err)
  99. logger.WarnToConsole("unable to get hook command: %v", err)
  100. }
  101. }
  102. certPath = filepath.Join(os.TempDir(), "test_dav.crt")
  103. keyPath = filepath.Join(os.TempDir(), "test_dav.key")
  104. err = os.WriteFile(certPath, []byte(webDavCert), os.ModePerm)
  105. if err != nil {
  106. logger.ErrorToConsole("error writing WebDAV certificate: %v", err)
  107. os.Exit(1)
  108. }
  109. err = os.WriteFile(keyPath, []byte(webDavKey), os.ModePerm)
  110. if err != nil {
  111. logger.ErrorToConsole("error writing WebDAV private key: %v", err)
  112. os.Exit(1)
  113. }
  114. err = common.Initialize(commonConf)
  115. if err != nil {
  116. logger.WarnToConsole("error initializing common: %v", err)
  117. os.Exit(1)
  118. }
  119. err = dataprovider.Initialize(providerConf, configDir, true)
  120. if err != nil {
  121. logger.ErrorToConsole("error initializing data provider: %v", err)
  122. os.Exit(1)
  123. }
  124. httpConfig := config.GetHTTPConfig()
  125. httpConfig.Initialize(configDir) //nolint:errcheck
  126. kmsConfig := config.GetKMSConfig()
  127. err = kmsConfig.Initialize()
  128. if err != nil {
  129. logger.ErrorToConsole("error initializing kms: %v", err)
  130. os.Exit(1)
  131. }
  132. httpdConf := config.GetHTTPDConfig()
  133. httpdConf.Bindings[0].Port = 8078
  134. httpdtest.SetBaseURL("http://127.0.0.1:8078")
  135. // required to test sftpfs
  136. sftpdConf := config.GetSFTPDConfig()
  137. sftpdConf.Bindings = []sftpd.Binding{
  138. {
  139. Port: 9022,
  140. },
  141. }
  142. hostKeyPath := filepath.Join(os.TempDir(), "id_ecdsa")
  143. sftpdConf.HostKeys = []string{hostKeyPath}
  144. webDavConf := config.GetWebDAVDConfig()
  145. webDavConf.Bindings = []webdavd.Binding{
  146. {
  147. Port: webDavServerPort,
  148. },
  149. }
  150. webDavConf.Cors = webdavd.Cors{
  151. Enabled: true,
  152. AllowedOrigins: []string{"*"},
  153. AllowedMethods: []string{
  154. http.MethodHead,
  155. http.MethodGet,
  156. http.MethodPost,
  157. http.MethodPut,
  158. http.MethodPatch,
  159. http.MethodDelete,
  160. },
  161. AllowedHeaders: []string{"*"},
  162. AllowCredentials: true,
  163. }
  164. status := webdavd.GetStatus()
  165. if status.IsActive {
  166. logger.ErrorToConsole("webdav server is already active")
  167. os.Exit(1)
  168. }
  169. extAuthPath = filepath.Join(homeBasePath, "extauth.sh")
  170. preLoginPath = filepath.Join(homeBasePath, "prelogin.sh")
  171. postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
  172. go func() {
  173. logger.Debug(logSender, "", "initializing WebDAV server with config %+v", webDavConf)
  174. if err := webDavConf.Initialize(configDir); err != nil {
  175. logger.ErrorToConsole("could not start WebDAV server: %v", err)
  176. os.Exit(1)
  177. }
  178. }()
  179. go func() {
  180. if err := httpdConf.Initialize(configDir); err != nil {
  181. logger.ErrorToConsole("could not start HTTP server: %v", err)
  182. os.Exit(1)
  183. }
  184. }()
  185. go func() {
  186. logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
  187. if err := sftpdConf.Initialize(configDir); err != nil {
  188. logger.ErrorToConsole("could not start SFTP server: %v", err)
  189. os.Exit(1)
  190. }
  191. }()
  192. waitTCPListening(webDavConf.Bindings[0].GetAddress())
  193. waitTCPListening(httpdConf.Bindings[0].GetAddress())
  194. waitTCPListening(sftpdConf.Bindings[0].GetAddress())
  195. webdavd.ReloadCertificateMgr() //nolint:errcheck
  196. exitCode := m.Run()
  197. os.Remove(logFilePath)
  198. os.Remove(extAuthPath)
  199. os.Remove(preLoginPath)
  200. os.Remove(postConnectPath)
  201. os.Remove(certPath)
  202. os.Remove(keyPath)
  203. os.Remove(hostKeyPath)
  204. os.Remove(hostKeyPath + ".pub")
  205. os.Exit(exitCode)
  206. }
  207. func TestInitialization(t *testing.T) {
  208. cfg := webdavd.Configuration{
  209. Bindings: []webdavd.Binding{
  210. {
  211. Port: 1234,
  212. EnableHTTPS: true,
  213. },
  214. {
  215. Port: 0,
  216. },
  217. },
  218. CertificateFile: "missing path",
  219. CertificateKeyFile: "bad path",
  220. }
  221. err := cfg.Initialize(configDir)
  222. assert.Error(t, err)
  223. cfg.Cache = config.GetWebDAVDConfig().Cache
  224. cfg.Bindings[0].Port = webDavServerPort
  225. cfg.CertificateFile = certPath
  226. cfg.CertificateKeyFile = keyPath
  227. err = cfg.Initialize(configDir)
  228. assert.Error(t, err)
  229. err = webdavd.ReloadCertificateMgr()
  230. assert.NoError(t, err)
  231. cfg.Bindings = []webdavd.Binding{
  232. {
  233. Port: 0,
  234. },
  235. }
  236. err = cfg.Initialize(configDir)
  237. assert.EqualError(t, err, common.ErrNoBinding.Error())
  238. cfg.CertificateFile = certPath
  239. cfg.CertificateKeyFile = keyPath
  240. cfg.CACertificates = []string{""}
  241. cfg.Bindings = []webdavd.Binding{
  242. {
  243. Port: 9022,
  244. ClientAuthType: 1,
  245. EnableHTTPS: true,
  246. },
  247. }
  248. err = cfg.Initialize(configDir)
  249. assert.Error(t, err)
  250. cfg.CACertificates = nil
  251. cfg.CARevocationLists = []string{""}
  252. err = cfg.Initialize(configDir)
  253. assert.Error(t, err)
  254. cfg.CARevocationLists = nil
  255. err = cfg.Initialize(configDir)
  256. assert.Error(t, err)
  257. }
  258. func TestBasicHandling(t *testing.T) {
  259. u := getTestUser()
  260. u.QuotaSize = 6553600
  261. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  262. assert.NoError(t, err)
  263. u = getTestSFTPUser()
  264. u.QuotaSize = 6553600
  265. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  266. assert.NoError(t, err)
  267. for _, user := range []dataprovider.User{localUser, sftpUser} {
  268. client := getWebDavClient(user)
  269. assert.NoError(t, checkBasicFunc(client))
  270. testFilePath := filepath.Join(homeBasePath, testFileName)
  271. testFileSize := int64(65535)
  272. expectedQuotaSize := testFileSize
  273. expectedQuotaFiles := 1
  274. err = createTestFile(testFilePath, testFileSize)
  275. assert.NoError(t, err)
  276. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  277. assert.NoError(t, err)
  278. // overwrite an existing file
  279. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  280. assert.NoError(t, err)
  281. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  282. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  283. assert.NoError(t, err)
  284. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  285. assert.NoError(t, err)
  286. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  287. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  288. err = client.Rename(testFileName, testFileName+"1", false)
  289. assert.NoError(t, err)
  290. _, err = client.Stat(testFileName)
  291. assert.Error(t, err)
  292. // the webdav client hide the error we check the quota
  293. err = client.Remove(testFileName)
  294. assert.NoError(t, err)
  295. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  296. assert.NoError(t, err)
  297. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  298. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  299. err = client.Remove(testFileName + "1")
  300. assert.NoError(t, err)
  301. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  302. assert.NoError(t, err)
  303. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  304. assert.Equal(t, expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  305. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  306. assert.Error(t, err)
  307. testDir := "testdir"
  308. err = client.Mkdir(testDir, os.ModePerm)
  309. assert.NoError(t, err)
  310. err = client.MkdirAll(path.Join(testDir, "sub", "sub"), os.ModePerm)
  311. assert.NoError(t, err)
  312. err = client.MkdirAll(path.Join(testDir, "sub1", "sub1"), os.ModePerm)
  313. assert.NoError(t, err)
  314. err = client.MkdirAll(path.Join(testDir, "sub2", "sub2"), os.ModePerm)
  315. assert.NoError(t, err)
  316. err = uploadFile(testFilePath, path.Join(testDir, testFileName+".txt"), testFileSize, client)
  317. assert.NoError(t, err)
  318. err = uploadFile(testFilePath, path.Join(testDir, testFileName), testFileSize, client)
  319. assert.NoError(t, err)
  320. files, err := client.ReadDir(testDir)
  321. assert.NoError(t, err)
  322. assert.Len(t, files, 5)
  323. err = client.Copy(testDir, testDir+"_copy", false)
  324. assert.NoError(t, err)
  325. err = client.RemoveAll(testDir)
  326. assert.NoError(t, err)
  327. err = os.Remove(testFilePath)
  328. assert.NoError(t, err)
  329. err = os.Remove(localDownloadPath)
  330. assert.NoError(t, err)
  331. if user.Username == defaultUsername {
  332. err = os.RemoveAll(user.GetHomeDir())
  333. assert.NoError(t, err)
  334. }
  335. }
  336. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  337. assert.NoError(t, err)
  338. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  339. assert.NoError(t, err)
  340. err = os.RemoveAll(localUser.GetHomeDir())
  341. assert.NoError(t, err)
  342. assert.Len(t, common.Connections.GetStats(), 0)
  343. status := webdavd.GetStatus()
  344. assert.True(t, status.IsActive)
  345. }
  346. func TestBasicHandlingCryptFs(t *testing.T) {
  347. u := getTestUserWithCryptFs()
  348. u.QuotaSize = 6553600
  349. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  350. assert.NoError(t, err)
  351. client := getWebDavClient(user)
  352. assert.NoError(t, checkBasicFunc(client))
  353. testFilePath := filepath.Join(homeBasePath, testFileName)
  354. testFileSize := int64(65535)
  355. encryptedFileSize, err := getEncryptedFileSize(testFileSize)
  356. assert.NoError(t, err)
  357. expectedQuotaSize := user.UsedQuotaSize + encryptedFileSize
  358. expectedQuotaFiles := user.UsedQuotaFiles + 1
  359. err = createTestFile(testFilePath, testFileSize)
  360. assert.NoError(t, err)
  361. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  362. assert.NoError(t, err)
  363. // overwrite an existing file
  364. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  365. assert.NoError(t, err)
  366. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  367. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  368. assert.NoError(t, err)
  369. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  370. assert.NoError(t, err)
  371. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  372. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  373. files, err := client.ReadDir("/")
  374. assert.NoError(t, err)
  375. if assert.Len(t, files, 1) {
  376. assert.Equal(t, testFileSize, files[0].Size())
  377. }
  378. err = client.Remove(testFileName)
  379. assert.NoError(t, err)
  380. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  381. assert.NoError(t, err)
  382. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  383. assert.Equal(t, expectedQuotaSize-encryptedFileSize, user.UsedQuotaSize)
  384. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  385. assert.Error(t, err)
  386. testDir := "testdir"
  387. err = client.Mkdir(testDir, os.ModePerm)
  388. assert.NoError(t, err)
  389. err = client.MkdirAll(path.Join(testDir, "sub", "sub"), os.ModePerm)
  390. assert.NoError(t, err)
  391. err = client.MkdirAll(path.Join(testDir, "sub1", "sub1"), os.ModePerm)
  392. assert.NoError(t, err)
  393. err = client.MkdirAll(path.Join(testDir, "sub2", "sub2"), os.ModePerm)
  394. assert.NoError(t, err)
  395. err = uploadFile(testFilePath, path.Join(testDir, testFileName+".txt"), testFileSize, client)
  396. assert.NoError(t, err)
  397. err = uploadFile(testFilePath, path.Join(testDir, testFileName), testFileSize, client)
  398. assert.NoError(t, err)
  399. files, err = client.ReadDir(testDir)
  400. assert.NoError(t, err)
  401. assert.Len(t, files, 5)
  402. for _, f := range files {
  403. if strings.HasPrefix(f.Name(), testFileName) {
  404. assert.Equal(t, testFileSize, f.Size())
  405. } else {
  406. assert.True(t, f.IsDir())
  407. }
  408. }
  409. err = os.Remove(testFilePath)
  410. assert.NoError(t, err)
  411. err = os.Remove(localDownloadPath)
  412. assert.NoError(t, err)
  413. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  414. assert.NoError(t, err)
  415. err = os.RemoveAll(user.GetHomeDir())
  416. assert.NoError(t, err)
  417. assert.Len(t, common.Connections.GetStats(), 0)
  418. }
  419. func TestPropPatch(t *testing.T) {
  420. u := getTestUser()
  421. u.Username = u.Username + "1"
  422. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  423. assert.NoError(t, err)
  424. sftpUser := getTestSFTPUser()
  425. sftpUser.FsConfig.SFTPConfig.Username = localUser.Username
  426. for _, u := range []dataprovider.User{getTestUser(), getTestUserWithCryptFs(), sftpUser} {
  427. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  428. assert.NoError(t, err)
  429. client := getWebDavClient(user)
  430. assert.NoError(t, checkBasicFunc(client), sftpUser.Username)
  431. testFilePath := filepath.Join(homeBasePath, testFileName)
  432. testFileSize := int64(65535)
  433. err = createTestFile(testFilePath, testFileSize)
  434. assert.NoError(t, err)
  435. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  436. assert.NoError(t, err)
  437. httpClient := httpclient.GetHTTPClient()
  438. propatchBody := `<?xml version="1.0" encoding="utf-8" ?><D:propertyupdate xmlns:D="DAV:" xmlns:Z="urn:schemas-microsoft-com:"><D:set><D:prop><Z:Win32CreationTime>Wed, 04 Nov 2020 13:25:51 GMT</Z:Win32CreationTime><Z:Win32LastAccessTime>Sat, 05 Dec 2020 21:16:12 GMT</Z:Win32LastAccessTime><Z:Win32LastModifiedTime>Wed, 04 Nov 2020 13:25:51 GMT</Z:Win32LastModifiedTime><Z:Win32FileAttributes>00000000</Z:Win32FileAttributes></D:prop></D:set></D:propertyupdate>`
  439. req, err := http.NewRequest("PROPPATCH", fmt.Sprintf("http://%v/%v", webDavServerAddr, testFileName), bytes.NewReader([]byte(propatchBody)))
  440. assert.NoError(t, err)
  441. req.SetBasicAuth(u.Username, u.Password)
  442. resp, err := httpClient.Do(req)
  443. assert.NoError(t, err)
  444. assert.Equal(t, 207, resp.StatusCode)
  445. err = resp.Body.Close()
  446. assert.NoError(t, err)
  447. info, err := client.Stat(testFileName)
  448. if assert.NoError(t, err) {
  449. assert.Equal(t, testFileSize, info.Size())
  450. }
  451. err = os.Remove(testFilePath)
  452. assert.NoError(t, err)
  453. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  454. assert.NoError(t, err)
  455. err = os.RemoveAll(user.GetHomeDir())
  456. assert.NoError(t, err)
  457. assert.Len(t, common.Connections.GetStats(), 0)
  458. }
  459. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  460. assert.NoError(t, err)
  461. err = os.RemoveAll(localUser.GetHomeDir())
  462. assert.NoError(t, err)
  463. }
  464. func TestLoginInvalidPwd(t *testing.T) {
  465. u := getTestUser()
  466. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  467. assert.NoError(t, err)
  468. client := getWebDavClient(user)
  469. assert.NoError(t, checkBasicFunc(client))
  470. user.Password = "wrong"
  471. client = getWebDavClient(user)
  472. assert.Error(t, checkBasicFunc(client))
  473. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  474. assert.NoError(t, err)
  475. }
  476. func TestLoginNonExistentUser(t *testing.T) {
  477. user := getTestUser()
  478. client := getWebDavClient(user)
  479. assert.Error(t, checkBasicFunc(client))
  480. }
  481. func TestDefender(t *testing.T) {
  482. oldConfig := config.GetCommonConfig()
  483. cfg := config.GetCommonConfig()
  484. cfg.DefenderConfig.Enabled = true
  485. cfg.DefenderConfig.Threshold = 3
  486. err := common.Initialize(cfg)
  487. assert.NoError(t, err)
  488. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  489. assert.NoError(t, err)
  490. client := getWebDavClient(user)
  491. assert.NoError(t, checkBasicFunc(client))
  492. for i := 0; i < 3; i++ {
  493. user.Password = "wrong_pwd"
  494. client = getWebDavClient(user)
  495. assert.Error(t, checkBasicFunc(client))
  496. }
  497. user.Password = defaultPassword
  498. client = getWebDavClient(user)
  499. err = checkBasicFunc(client)
  500. if assert.Error(t, err) {
  501. assert.Contains(t, err.Error(), "403")
  502. }
  503. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  504. assert.NoError(t, err)
  505. err = os.RemoveAll(user.GetHomeDir())
  506. assert.NoError(t, err)
  507. err = common.Initialize(oldConfig)
  508. assert.NoError(t, err)
  509. }
  510. func TestLoginExternalAuth(t *testing.T) {
  511. if runtime.GOOS == osWindows {
  512. t.Skip("this test is not available on Windows")
  513. }
  514. u := getTestUser()
  515. err := dataprovider.Close()
  516. assert.NoError(t, err)
  517. err = config.LoadConfig(configDir, "")
  518. assert.NoError(t, err)
  519. providerConf := config.GetProviderConf()
  520. err = os.WriteFile(extAuthPath, getExtAuthScriptContent(u, false, ""), os.ModePerm)
  521. assert.NoError(t, err)
  522. providerConf.ExternalAuthHook = extAuthPath
  523. providerConf.ExternalAuthScope = 0
  524. err = dataprovider.Initialize(providerConf, configDir, true)
  525. assert.NoError(t, err)
  526. client := getWebDavClient(u)
  527. assert.NoError(t, checkBasicFunc(client))
  528. u.Username = defaultUsername + "1"
  529. client = getWebDavClient(u)
  530. assert.Error(t, checkBasicFunc(client))
  531. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  532. assert.NoError(t, err)
  533. assert.Equal(t, defaultUsername, user.Username)
  534. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  535. assert.NoError(t, err)
  536. err = os.RemoveAll(user.GetHomeDir())
  537. assert.NoError(t, err)
  538. err = dataprovider.Close()
  539. assert.NoError(t, err)
  540. err = config.LoadConfig(configDir, "")
  541. assert.NoError(t, err)
  542. providerConf = config.GetProviderConf()
  543. err = dataprovider.Initialize(providerConf, configDir, true)
  544. assert.NoError(t, err)
  545. err = os.Remove(extAuthPath)
  546. assert.NoError(t, err)
  547. }
  548. func TestPreLoginHook(t *testing.T) {
  549. if runtime.GOOS == osWindows {
  550. t.Skip("this test is not available on Windows")
  551. }
  552. u := getTestUser()
  553. err := dataprovider.Close()
  554. assert.NoError(t, err)
  555. err = config.LoadConfig(configDir, "")
  556. assert.NoError(t, err)
  557. providerConf := config.GetProviderConf()
  558. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  559. assert.NoError(t, err)
  560. providerConf.PreLoginHook = preLoginPath
  561. err = dataprovider.Initialize(providerConf, configDir, true)
  562. assert.NoError(t, err)
  563. _, _, err = httpdtest.GetUserByUsername(defaultUsername, http.StatusNotFound)
  564. assert.NoError(t, err)
  565. client := getWebDavClient(u)
  566. assert.NoError(t, checkBasicFunc(client))
  567. user, _, err := httpdtest.GetUserByUsername(defaultUsername, http.StatusOK)
  568. assert.NoError(t, err)
  569. // test login with an existing user
  570. client = getWebDavClient(user)
  571. assert.NoError(t, checkBasicFunc(client))
  572. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), os.ModePerm)
  573. assert.NoError(t, err)
  574. // update the user to remove it from the cache
  575. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  576. assert.NoError(t, err)
  577. client = getWebDavClient(user)
  578. assert.Error(t, checkBasicFunc(client))
  579. // update the user to remove it from the cache
  580. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  581. assert.NoError(t, err)
  582. user.Status = 0
  583. err = os.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  584. assert.NoError(t, err)
  585. client = getWebDavClient(user)
  586. assert.Error(t, checkBasicFunc(client))
  587. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  588. assert.NoError(t, err)
  589. err = os.RemoveAll(user.GetHomeDir())
  590. assert.NoError(t, err)
  591. err = dataprovider.Close()
  592. assert.NoError(t, err)
  593. err = config.LoadConfig(configDir, "")
  594. assert.NoError(t, err)
  595. providerConf = config.GetProviderConf()
  596. err = dataprovider.Initialize(providerConf, configDir, true)
  597. assert.NoError(t, err)
  598. err = os.Remove(preLoginPath)
  599. assert.NoError(t, err)
  600. }
  601. func TestPostConnectHook(t *testing.T) {
  602. if runtime.GOOS == osWindows {
  603. t.Skip("this test is not available on Windows")
  604. }
  605. common.Config.PostConnectHook = postConnectPath
  606. u := getTestUser()
  607. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  608. assert.NoError(t, err)
  609. err = os.WriteFile(postConnectPath, getPostConnectScriptContent(0), os.ModePerm)
  610. assert.NoError(t, err)
  611. client := getWebDavClient(user)
  612. assert.NoError(t, checkBasicFunc(client))
  613. err = os.WriteFile(postConnectPath, getPostConnectScriptContent(1), os.ModePerm)
  614. assert.NoError(t, err)
  615. assert.Error(t, checkBasicFunc(client))
  616. common.Config.PostConnectHook = "http://127.0.0.1:8078/healthz"
  617. assert.NoError(t, checkBasicFunc(client))
  618. common.Config.PostConnectHook = "http://127.0.0.1:8078/notfound"
  619. assert.Error(t, checkBasicFunc(client))
  620. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  621. assert.NoError(t, err)
  622. err = os.RemoveAll(user.GetHomeDir())
  623. assert.NoError(t, err)
  624. common.Config.PostConnectHook = ""
  625. }
  626. func TestMaxConnections(t *testing.T) {
  627. oldValue := common.Config.MaxTotalConnections
  628. common.Config.MaxTotalConnections = 1
  629. user, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
  630. assert.NoError(t, err)
  631. client := getWebDavClient(user)
  632. assert.NoError(t, checkBasicFunc(client))
  633. // now add a fake connection
  634. fs := vfs.NewOsFs("id", os.TempDir(), nil)
  635. connection := &webdavd.Connection{
  636. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  637. }
  638. common.Connections.Add(connection)
  639. assert.Error(t, checkBasicFunc(client))
  640. common.Connections.Remove(connection.GetID())
  641. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  642. assert.NoError(t, err)
  643. err = os.RemoveAll(user.GetHomeDir())
  644. assert.NoError(t, err)
  645. assert.Len(t, common.Connections.GetStats(), 0)
  646. common.Config.MaxTotalConnections = oldValue
  647. }
  648. func TestMaxSessions(t *testing.T) {
  649. u := getTestUser()
  650. u.MaxSessions = 1
  651. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  652. assert.NoError(t, err)
  653. client := getWebDavClient(user)
  654. assert.NoError(t, checkBasicFunc(client))
  655. // now add a fake connection
  656. fs := vfs.NewOsFs("id", os.TempDir(), nil)
  657. connection := &webdavd.Connection{
  658. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  659. }
  660. common.Connections.Add(connection)
  661. assert.Error(t, checkBasicFunc(client))
  662. common.Connections.Remove(connection.GetID())
  663. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  664. assert.NoError(t, err)
  665. err = os.RemoveAll(user.GetHomeDir())
  666. assert.NoError(t, err)
  667. assert.Len(t, common.Connections.GetStats(), 0)
  668. }
  669. func TestLoginWithIPilters(t *testing.T) {
  670. u := getTestUser()
  671. u.Filters.DeniedIP = []string{"192.167.0.0/24", "172.18.0.0/16"}
  672. u.Filters.AllowedIP = []string{"172.19.0.0/16"}
  673. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  674. assert.NoError(t, err)
  675. client := getWebDavClient(user)
  676. assert.Error(t, checkBasicFunc(client))
  677. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  678. assert.NoError(t, err)
  679. err = os.RemoveAll(user.GetHomeDir())
  680. assert.NoError(t, err)
  681. }
  682. func TestDownloadErrors(t *testing.T) {
  683. u := getTestUser()
  684. u.QuotaFiles = 1
  685. subDir1 := "sub1"
  686. subDir2 := "sub2"
  687. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  688. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  689. dataprovider.PermDelete, dataprovider.PermDownload}
  690. // use an unknown mime to trigger content type detection
  691. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  692. {
  693. Path: "/sub2",
  694. AllowedExtensions: []string{},
  695. DeniedExtensions: []string{".zipp"},
  696. },
  697. }
  698. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  699. {
  700. Path: "/sub2",
  701. AllowedPatterns: []string{},
  702. DeniedPatterns: []string{"*.jpg"},
  703. },
  704. }
  705. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  706. assert.NoError(t, err)
  707. client := getWebDavClient(user)
  708. testFilePath1 := filepath.Join(user.HomeDir, subDir1, "file.zipp")
  709. testFilePath2 := filepath.Join(user.HomeDir, subDir2, "file.zipp")
  710. testFilePath3 := filepath.Join(user.HomeDir, subDir2, "file.jpg")
  711. err = os.MkdirAll(filepath.Dir(testFilePath1), os.ModePerm)
  712. assert.NoError(t, err)
  713. err = os.MkdirAll(filepath.Dir(testFilePath2), os.ModePerm)
  714. assert.NoError(t, err)
  715. err = os.WriteFile(testFilePath1, []byte("file1"), os.ModePerm)
  716. assert.NoError(t, err)
  717. err = os.WriteFile(testFilePath2, []byte("file2"), os.ModePerm)
  718. assert.NoError(t, err)
  719. err = os.WriteFile(testFilePath3, []byte("file3"), os.ModePerm)
  720. assert.NoError(t, err)
  721. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  722. err = downloadFile(path.Join("/", subDir1, "file.zipp"), localDownloadPath, 5, client)
  723. assert.Error(t, err)
  724. err = downloadFile(path.Join("/", subDir2, "file.zipp"), localDownloadPath, 5, client)
  725. assert.Error(t, err)
  726. err = downloadFile(path.Join("/", subDir2, "file.jpg"), localDownloadPath, 5, client)
  727. assert.Error(t, err)
  728. err = downloadFile(path.Join("missing.zip"), localDownloadPath, 5, client)
  729. assert.Error(t, err)
  730. err = os.Remove(localDownloadPath)
  731. assert.NoError(t, err)
  732. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  733. assert.NoError(t, err)
  734. err = os.RemoveAll(user.GetHomeDir())
  735. assert.NoError(t, err)
  736. }
  737. func TestUploadErrors(t *testing.T) {
  738. u := getTestUser()
  739. u.QuotaSize = 65535
  740. subDir1 := "sub1"
  741. subDir2 := "sub2"
  742. // we need download permission to get size since PROPFIND will open the file
  743. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems, dataprovider.PermDownload}
  744. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  745. dataprovider.PermDelete, dataprovider.PermDownload}
  746. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  747. {
  748. Path: "/sub2",
  749. AllowedExtensions: []string{},
  750. DeniedExtensions: []string{".zip"},
  751. },
  752. }
  753. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  754. assert.NoError(t, err)
  755. client := getWebDavClient(user)
  756. testFilePath := filepath.Join(homeBasePath, testFileName)
  757. testFileSize := user.QuotaSize
  758. err = createTestFile(testFilePath, testFileSize)
  759. assert.NoError(t, err)
  760. err = client.Mkdir(subDir1, os.ModePerm)
  761. assert.NoError(t, err)
  762. err = client.Mkdir(subDir2, os.ModePerm)
  763. assert.NoError(t, err)
  764. err = uploadFile(testFilePath, path.Join(subDir1, testFileName), testFileSize, client)
  765. assert.Error(t, err)
  766. err = uploadFile(testFilePath, path.Join(subDir2, testFileName+".zip"), testFileSize, client)
  767. assert.Error(t, err)
  768. err = uploadFile(testFilePath, path.Join(subDir2, testFileName), testFileSize, client)
  769. assert.NoError(t, err)
  770. err = client.Rename(path.Join(subDir2, testFileName), path.Join(subDir1, testFileName), false)
  771. assert.Error(t, err)
  772. err = uploadFile(testFilePath, path.Join(subDir2, testFileName), testFileSize, client)
  773. assert.Error(t, err)
  774. err = uploadFile(testFilePath, subDir1, testFileSize, client)
  775. assert.Error(t, err)
  776. // overquota
  777. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  778. assert.Error(t, err)
  779. err = client.Remove(path.Join(subDir2, testFileName))
  780. assert.NoError(t, err)
  781. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  782. assert.NoError(t, err)
  783. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  784. assert.Error(t, err)
  785. err = os.Remove(testFilePath)
  786. assert.NoError(t, err)
  787. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  788. assert.NoError(t, err)
  789. err = os.RemoveAll(user.GetHomeDir())
  790. assert.NoError(t, err)
  791. }
  792. func TestDeniedLoginMethod(t *testing.T) {
  793. u := getTestUser()
  794. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  795. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  796. assert.NoError(t, err)
  797. client := getWebDavClient(user)
  798. assert.Error(t, checkBasicFunc(client))
  799. user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodKeyAndKeyboardInt}
  800. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  801. assert.NoError(t, err)
  802. client = getWebDavClient(user)
  803. assert.NoError(t, checkBasicFunc(client))
  804. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  805. assert.NoError(t, err)
  806. err = os.RemoveAll(user.GetHomeDir())
  807. assert.NoError(t, err)
  808. }
  809. func TestDeniedProtocols(t *testing.T) {
  810. u := getTestUser()
  811. u.Filters.DeniedProtocols = []string{common.ProtocolWebDAV}
  812. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  813. assert.NoError(t, err)
  814. client := getWebDavClient(user)
  815. assert.Error(t, checkBasicFunc(client))
  816. user.Filters.DeniedProtocols = []string{common.ProtocolSSH, common.ProtocolFTP}
  817. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  818. assert.NoError(t, err)
  819. client = getWebDavClient(user)
  820. assert.NoError(t, checkBasicFunc(client))
  821. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  822. assert.NoError(t, err)
  823. err = os.RemoveAll(user.GetHomeDir())
  824. assert.NoError(t, err)
  825. }
  826. func TestQuotaLimits(t *testing.T) {
  827. u := getTestUser()
  828. u.QuotaFiles = 1
  829. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  830. assert.NoError(t, err)
  831. u = getTestSFTPUser()
  832. u.QuotaFiles = 1
  833. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  834. assert.NoError(t, err)
  835. for _, user := range []dataprovider.User{localUser, sftpUser} {
  836. testFileSize := int64(65535)
  837. testFilePath := filepath.Join(homeBasePath, testFileName)
  838. err = createTestFile(testFilePath, testFileSize)
  839. assert.NoError(t, err)
  840. testFileSize1 := int64(131072)
  841. testFileName1 := "test_file1.dat"
  842. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  843. err = createTestFile(testFilePath1, testFileSize1)
  844. assert.NoError(t, err)
  845. testFileSize2 := int64(32768)
  846. testFileName2 := "test_file2.dat"
  847. testFilePath2 := filepath.Join(homeBasePath, testFileName2)
  848. err = createTestFile(testFilePath2, testFileSize2)
  849. assert.NoError(t, err)
  850. client := getWebDavClient(user)
  851. // test quota files
  852. err = uploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  853. assert.NoError(t, err)
  854. err = uploadFile(testFilePath, testFileName+".quota1", testFileSize, client)
  855. assert.Error(t, err)
  856. err = client.Rename(testFileName+".quota", testFileName, false)
  857. assert.NoError(t, err)
  858. files, err := client.ReadDir("/")
  859. assert.NoError(t, err)
  860. assert.Len(t, files, 1)
  861. // test quota size
  862. user.QuotaSize = testFileSize - 1
  863. user.QuotaFiles = 0
  864. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  865. assert.NoError(t, err)
  866. err = uploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  867. assert.Error(t, err)
  868. err = client.Rename(testFileName, testFileName+".quota", false)
  869. assert.NoError(t, err)
  870. // now test quota limits while uploading the current file, we have 1 bytes remaining
  871. user.QuotaSize = testFileSize + 1
  872. user.QuotaFiles = 0
  873. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  874. assert.NoError(t, err)
  875. err = uploadFile(testFilePath1, testFileName1, testFileSize1, client)
  876. assert.Error(t, err)
  877. _, err = client.Stat(testFileName1)
  878. assert.Error(t, err)
  879. err = client.Rename(testFileName+".quota", testFileName, false)
  880. assert.NoError(t, err)
  881. // overwriting an existing file will work if the resulting size is lesser or equal than the current one
  882. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  883. assert.NoError(t, err)
  884. err = uploadFile(testFilePath2, testFileName, testFileSize2, client)
  885. assert.NoError(t, err)
  886. err = uploadFile(testFilePath1, testFileName, testFileSize1, client)
  887. assert.Error(t, err)
  888. err = uploadFile(testFilePath2, testFileName, testFileSize2, client)
  889. assert.NoError(t, err)
  890. err = os.Remove(testFilePath)
  891. assert.NoError(t, err)
  892. err = os.Remove(testFilePath1)
  893. assert.NoError(t, err)
  894. err = os.Remove(testFilePath2)
  895. assert.NoError(t, err)
  896. if user.Username == defaultUsername {
  897. err = os.RemoveAll(user.GetHomeDir())
  898. assert.NoError(t, err)
  899. user.QuotaFiles = 0
  900. user.QuotaSize = 0
  901. _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  902. assert.NoError(t, err)
  903. }
  904. }
  905. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  906. assert.NoError(t, err)
  907. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  908. assert.NoError(t, err)
  909. err = os.RemoveAll(localUser.GetHomeDir())
  910. assert.NoError(t, err)
  911. }
  912. func TestUploadMaxSize(t *testing.T) {
  913. testFileSize := int64(65535)
  914. u := getTestUser()
  915. u.Filters.MaxUploadFileSize = testFileSize + 1
  916. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  917. assert.NoError(t, err)
  918. u = getTestSFTPUser()
  919. u.Filters.MaxUploadFileSize = testFileSize + 1
  920. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  921. assert.NoError(t, err)
  922. for _, user := range []dataprovider.User{localUser, sftpUser} {
  923. testFilePath := filepath.Join(homeBasePath, testFileName)
  924. err = createTestFile(testFilePath, testFileSize)
  925. assert.NoError(t, err)
  926. testFileSize1 := int64(131072)
  927. testFileName1 := "test_file_dav1.dat"
  928. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  929. err = createTestFile(testFilePath1, testFileSize1)
  930. assert.NoError(t, err)
  931. client := getWebDavClient(user)
  932. err = uploadFile(testFilePath1, testFileName1, testFileSize1, client)
  933. assert.Error(t, err)
  934. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  935. assert.NoError(t, err)
  936. // now test overwrite an existing file with a size bigger than the allowed one
  937. err = createTestFile(filepath.Join(user.GetHomeDir(), testFileName1), testFileSize1)
  938. assert.NoError(t, err)
  939. err = uploadFile(testFilePath1, testFileName1, testFileSize1, client)
  940. assert.Error(t, err)
  941. err = os.Remove(testFilePath)
  942. assert.NoError(t, err)
  943. err = os.Remove(testFilePath1)
  944. assert.NoError(t, err)
  945. if user.Username == defaultUsername {
  946. err = os.RemoveAll(user.GetHomeDir())
  947. assert.NoError(t, err)
  948. user.Filters.MaxUploadFileSize = 65536000
  949. _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  950. assert.NoError(t, err)
  951. }
  952. }
  953. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  954. assert.NoError(t, err)
  955. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  956. assert.NoError(t, err)
  957. err = os.RemoveAll(localUser.GetHomeDir())
  958. assert.NoError(t, err)
  959. }
  960. func TestClientClose(t *testing.T) {
  961. u := getTestUser()
  962. u.UploadBandwidth = 64
  963. u.DownloadBandwidth = 64
  964. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  965. assert.NoError(t, err)
  966. u = getTestSFTPUser()
  967. u.UploadBandwidth = 64
  968. u.DownloadBandwidth = 64
  969. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  970. assert.NoError(t, err)
  971. for _, user := range []dataprovider.User{localUser, sftpUser} {
  972. testFileSize := int64(1048576)
  973. testFilePath := filepath.Join(homeBasePath, testFileName)
  974. err = createTestFile(testFilePath, testFileSize)
  975. assert.NoError(t, err)
  976. client := getWebDavClient(user)
  977. assert.NoError(t, checkBasicFunc(client))
  978. var wg sync.WaitGroup
  979. wg.Add(1)
  980. go func() {
  981. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  982. assert.Error(t, err)
  983. wg.Done()
  984. }()
  985. assert.Eventually(t, func() bool {
  986. for _, stat := range common.Connections.GetStats() {
  987. if len(stat.Transfers) > 0 {
  988. return true
  989. }
  990. }
  991. return false
  992. }, 1*time.Second, 50*time.Millisecond)
  993. for _, stat := range common.Connections.GetStats() {
  994. common.Connections.Close(stat.ConnectionID)
  995. }
  996. wg.Wait()
  997. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  998. 1*time.Second, 100*time.Millisecond)
  999. err = os.Remove(testFilePath)
  1000. assert.NoError(t, err)
  1001. testFilePath = filepath.Join(user.HomeDir, testFileName)
  1002. err = createTestFile(testFilePath, testFileSize)
  1003. assert.NoError(t, err)
  1004. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  1005. wg.Add(1)
  1006. go func() {
  1007. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  1008. assert.Error(t, err)
  1009. wg.Done()
  1010. }()
  1011. assert.Eventually(t, func() bool {
  1012. for _, stat := range common.Connections.GetStats() {
  1013. if len(stat.Transfers) > 0 {
  1014. return true
  1015. }
  1016. }
  1017. return false
  1018. }, 1*time.Second, 50*time.Millisecond)
  1019. for _, stat := range common.Connections.GetStats() {
  1020. common.Connections.Close(stat.ConnectionID)
  1021. }
  1022. wg.Wait()
  1023. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  1024. 1*time.Second, 100*time.Millisecond)
  1025. err = os.Remove(localDownloadPath)
  1026. assert.NoError(t, err)
  1027. }
  1028. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1029. assert.NoError(t, err)
  1030. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1031. assert.NoError(t, err)
  1032. err = os.RemoveAll(localUser.GetHomeDir())
  1033. assert.NoError(t, err)
  1034. }
  1035. func TestLoginWithDatabaseCredentials(t *testing.T) {
  1036. u := getTestUser()
  1037. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  1038. u.FsConfig.GCSConfig.Bucket = "test"
  1039. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret(`{ "type": "service_account" }`)
  1040. providerConf := config.GetProviderConf()
  1041. providerConf.PreferDatabaseCredentials = true
  1042. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  1043. if !filepath.IsAbs(credentialsFile) {
  1044. credentialsFile = filepath.Join(configDir, credentialsFile)
  1045. }
  1046. assert.NoError(t, dataprovider.Close())
  1047. err := dataprovider.Initialize(providerConf, configDir, true)
  1048. assert.NoError(t, err)
  1049. if _, err = os.Stat(credentialsFile); err == nil {
  1050. // remove the credentials file
  1051. assert.NoError(t, os.Remove(credentialsFile))
  1052. }
  1053. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1054. assert.NoError(t, err)
  1055. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus())
  1056. assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload())
  1057. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  1058. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey())
  1059. assert.NoFileExists(t, credentialsFile)
  1060. client := getWebDavClient(user)
  1061. err = client.Connect()
  1062. assert.NoError(t, err)
  1063. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1064. assert.NoError(t, err)
  1065. err = os.RemoveAll(user.GetHomeDir())
  1066. assert.NoError(t, err)
  1067. assert.NoError(t, dataprovider.Close())
  1068. assert.NoError(t, config.LoadConfig(configDir, ""))
  1069. providerConf = config.GetProviderConf()
  1070. assert.NoError(t, dataprovider.Initialize(providerConf, configDir, true))
  1071. }
  1072. func TestLoginInvalidFs(t *testing.T) {
  1073. u := getTestUser()
  1074. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  1075. u.FsConfig.GCSConfig.Bucket = "test"
  1076. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials")
  1077. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1078. assert.NoError(t, err)
  1079. providerConf := config.GetProviderConf()
  1080. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  1081. if !filepath.IsAbs(credentialsFile) {
  1082. credentialsFile = filepath.Join(configDir, credentialsFile)
  1083. }
  1084. // now remove the credentials file so the filesystem creation will fail
  1085. err = os.Remove(credentialsFile)
  1086. assert.NoError(t, err)
  1087. client := getWebDavClient(user)
  1088. assert.Error(t, checkBasicFunc(client))
  1089. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1090. assert.NoError(t, err)
  1091. err = os.RemoveAll(user.GetHomeDir())
  1092. assert.NoError(t, err)
  1093. }
  1094. func TestBytesRangeRequests(t *testing.T) {
  1095. u := getTestUser()
  1096. u.Username = u.Username + "1"
  1097. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1098. assert.NoError(t, err)
  1099. sftpUser := getTestSFTPUser()
  1100. sftpUser.FsConfig.SFTPConfig.Username = localUser.Username
  1101. for _, u := range []dataprovider.User{getTestUser(), getTestUserWithCryptFs(), sftpUser} {
  1102. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1103. assert.NoError(t, err)
  1104. testFileName := "test_file.txt"
  1105. testFilePath := filepath.Join(homeBasePath, testFileName)
  1106. fileContent := []byte("test file contents")
  1107. err = os.WriteFile(testFilePath, fileContent, os.ModePerm)
  1108. assert.NoError(t, err)
  1109. client := getWebDavClient(user)
  1110. err = uploadFile(testFilePath, testFileName, int64(len(fileContent)), client)
  1111. assert.NoError(t, err)
  1112. remotePath := fmt.Sprintf("http://%v/%v", webDavServerAddr, testFileName)
  1113. req, err := http.NewRequest(http.MethodGet, remotePath, nil)
  1114. if assert.NoError(t, err) {
  1115. httpClient := httpclient.GetHTTPClient()
  1116. req.SetBasicAuth(user.Username, defaultPassword)
  1117. req.Header.Set("Range", "bytes=5-")
  1118. resp, err := httpClient.Do(req)
  1119. if assert.NoError(t, err) {
  1120. defer resp.Body.Close()
  1121. assert.Equal(t, http.StatusPartialContent, resp.StatusCode)
  1122. bodyBytes, err := io.ReadAll(resp.Body)
  1123. assert.NoError(t, err)
  1124. assert.Equal(t, "file contents", string(bodyBytes))
  1125. }
  1126. req.Header.Set("Range", "bytes=5-8")
  1127. resp, err = httpClient.Do(req)
  1128. if assert.NoError(t, err) {
  1129. defer resp.Body.Close()
  1130. assert.Equal(t, http.StatusPartialContent, resp.StatusCode)
  1131. bodyBytes, err := io.ReadAll(resp.Body)
  1132. assert.NoError(t, err)
  1133. assert.Equal(t, "file", string(bodyBytes))
  1134. }
  1135. }
  1136. assert.NoError(t, err)
  1137. err = os.Remove(testFilePath)
  1138. assert.NoError(t, err)
  1139. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1140. assert.NoError(t, err)
  1141. err = os.RemoveAll(user.GetHomeDir())
  1142. assert.NoError(t, err)
  1143. }
  1144. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1145. assert.NoError(t, err)
  1146. err = os.RemoveAll(localUser.GetHomeDir())
  1147. assert.NoError(t, err)
  1148. }
  1149. func TestHEAD(t *testing.T) {
  1150. u := getTestUser()
  1151. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1152. assert.NoError(t, err)
  1153. rootPath := fmt.Sprintf("http://%v", webDavServerAddr)
  1154. httpClient := httpclient.GetHTTPClient()
  1155. req, err := http.NewRequest(http.MethodHead, rootPath, nil)
  1156. if assert.NoError(t, err) {
  1157. req.SetBasicAuth(u.Username, u.Password)
  1158. resp, err := httpClient.Do(req)
  1159. if assert.NoError(t, err) {
  1160. assert.Equal(t, http.StatusMultiStatus, resp.StatusCode)
  1161. assert.Equal(t, "text/xml; charset=utf-8", resp.Header.Get("Content-Type"))
  1162. resp.Body.Close()
  1163. }
  1164. }
  1165. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1166. assert.NoError(t, err)
  1167. err = os.RemoveAll(user.GetHomeDir())
  1168. assert.NoError(t, err)
  1169. }
  1170. func TestGETAsPROPFIND(t *testing.T) {
  1171. u := getTestUser()
  1172. subDir1 := "/sub1"
  1173. u.Permissions[subDir1] = []string{dataprovider.PermUpload, dataprovider.PermCreateDirs}
  1174. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1175. assert.NoError(t, err)
  1176. rootPath := fmt.Sprintf("http://%v/", webDavServerAddr)
  1177. httpClient := httpclient.GetHTTPClient()
  1178. req, err := http.NewRequest(http.MethodGet, rootPath, nil)
  1179. if assert.NoError(t, err) {
  1180. req.SetBasicAuth(u.Username, u.Password)
  1181. resp, err := httpClient.Do(req)
  1182. if assert.NoError(t, err) {
  1183. assert.Equal(t, http.StatusMultiStatus, resp.StatusCode)
  1184. resp.Body.Close()
  1185. }
  1186. }
  1187. client := getWebDavClient(user)
  1188. err = client.MkdirAll(path.Join(subDir1, "sub", "sub1"), os.ModePerm)
  1189. assert.NoError(t, err)
  1190. subPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, subDir1)
  1191. req, err = http.NewRequest(http.MethodGet, subPath, nil)
  1192. if assert.NoError(t, err) {
  1193. req.SetBasicAuth(u.Username, u.Password)
  1194. resp, err := httpClient.Do(req)
  1195. if assert.NoError(t, err) {
  1196. // before the performance patch we have a 500 here, now we have 207 but an empty list
  1197. //assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
  1198. assert.Equal(t, http.StatusMultiStatus, resp.StatusCode)
  1199. resp.Body.Close()
  1200. }
  1201. }
  1202. // we cannot stat the sub at all
  1203. subPath1 := fmt.Sprintf("http://%v/%v", webDavServerAddr, path.Join(subDir1, "sub"))
  1204. req, err = http.NewRequest(http.MethodGet, subPath1, nil)
  1205. if assert.NoError(t, err) {
  1206. req.SetBasicAuth(u.Username, u.Password)
  1207. resp, err := httpClient.Do(req)
  1208. if assert.NoError(t, err) {
  1209. // here the stat will fail, so the request will not be changed in propfind
  1210. assert.Equal(t, http.StatusForbidden, resp.StatusCode)
  1211. resp.Body.Close()
  1212. }
  1213. }
  1214. // we have no permission, we get an empty list
  1215. files, err := client.ReadDir(subDir1)
  1216. assert.NoError(t, err)
  1217. assert.Len(t, files, 0)
  1218. // if we grant the permissions the files are listed
  1219. user.Permissions[subDir1] = []string{dataprovider.PermDownload, dataprovider.PermListItems}
  1220. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1221. assert.NoError(t, err)
  1222. files, err = client.ReadDir(subDir1)
  1223. assert.NoError(t, err)
  1224. assert.Len(t, files, 1)
  1225. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1226. assert.NoError(t, err)
  1227. err = os.RemoveAll(user.GetHomeDir())
  1228. assert.NoError(t, err)
  1229. }
  1230. func TestStat(t *testing.T) {
  1231. u := getTestUser()
  1232. u.Permissions["/subdir"] = []string{dataprovider.PermUpload, dataprovider.PermListItems, dataprovider.PermDownload}
  1233. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1234. assert.NoError(t, err)
  1235. client := getWebDavClient(user)
  1236. subDir := "subdir"
  1237. testFilePath := filepath.Join(homeBasePath, testFileName)
  1238. testFileSize := int64(65535)
  1239. err = createTestFile(testFilePath, testFileSize)
  1240. assert.NoError(t, err)
  1241. err = client.Mkdir(subDir, os.ModePerm)
  1242. assert.NoError(t, err)
  1243. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  1244. assert.NoError(t, err)
  1245. err = uploadFile(testFilePath, path.Join("/", subDir, testFileName), testFileSize, client)
  1246. assert.NoError(t, err)
  1247. user.Permissions["/subdir"] = []string{dataprovider.PermUpload, dataprovider.PermDownload}
  1248. user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1249. assert.NoError(t, err)
  1250. _, err = client.Stat(testFileName)
  1251. assert.NoError(t, err)
  1252. _, err = client.Stat(path.Join("/", subDir, testFileName))
  1253. assert.Error(t, err)
  1254. err = os.Remove(testFilePath)
  1255. assert.NoError(t, err)
  1256. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1257. assert.NoError(t, err)
  1258. err = os.RemoveAll(user.GetHomeDir())
  1259. assert.NoError(t, err)
  1260. }
  1261. func TestUploadOverwriteVfolder(t *testing.T) {
  1262. u := getTestUser()
  1263. vdir := "/vdir"
  1264. mappedPath := filepath.Join(os.TempDir(), "mappedDir")
  1265. folderName := filepath.Base(mappedPath)
  1266. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  1267. BaseVirtualFolder: vfs.BaseVirtualFolder{
  1268. Name: folderName,
  1269. MappedPath: mappedPath,
  1270. },
  1271. VirtualPath: vdir,
  1272. QuotaSize: -1,
  1273. QuotaFiles: -1,
  1274. })
  1275. err := os.MkdirAll(mappedPath, os.ModePerm)
  1276. assert.NoError(t, err)
  1277. user, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1278. assert.NoError(t, err)
  1279. client := getWebDavClient(user)
  1280. files, err := client.ReadDir(".")
  1281. assert.NoError(t, err)
  1282. vdirFound := false
  1283. for _, info := range files {
  1284. if info.Name() == path.Base(vdir) {
  1285. vdirFound = true
  1286. break
  1287. }
  1288. }
  1289. assert.True(t, vdirFound)
  1290. info, err := client.Stat(vdir)
  1291. if assert.NoError(t, err) {
  1292. assert.Equal(t, path.Base(vdir), info.Name())
  1293. }
  1294. testFilePath := filepath.Join(homeBasePath, testFileName)
  1295. testFileSize := int64(65535)
  1296. err = createTestFile(testFilePath, testFileSize)
  1297. assert.NoError(t, err)
  1298. err = uploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client)
  1299. assert.NoError(t, err)
  1300. folder, _, err := httpdtest.GetFolderByName(folderName, http.StatusOK)
  1301. assert.NoError(t, err)
  1302. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  1303. assert.Equal(t, 1, folder.UsedQuotaFiles)
  1304. err = uploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client)
  1305. assert.NoError(t, err)
  1306. folder, _, err = httpdtest.GetFolderByName(folderName, http.StatusOK)
  1307. assert.NoError(t, err)
  1308. assert.Equal(t, testFileSize, folder.UsedQuotaSize)
  1309. assert.Equal(t, 1, folder.UsedQuotaFiles)
  1310. err = os.Remove(testFilePath)
  1311. assert.NoError(t, err)
  1312. _, err = httpdtest.RemoveUser(user, http.StatusOK)
  1313. assert.NoError(t, err)
  1314. _, err = httpdtest.RemoveFolder(vfs.BaseVirtualFolder{Name: folderName}, http.StatusOK)
  1315. assert.NoError(t, err)
  1316. err = os.RemoveAll(user.GetHomeDir())
  1317. assert.NoError(t, err)
  1318. err = os.RemoveAll(mappedPath)
  1319. assert.NoError(t, err)
  1320. }
  1321. func TestMiscCommands(t *testing.T) {
  1322. u := getTestUser()
  1323. u.QuotaFiles = 100
  1324. localUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1325. assert.NoError(t, err)
  1326. u = getTestSFTPUser()
  1327. u.QuotaFiles = 100
  1328. sftpUser, _, err := httpdtest.AddUser(u, http.StatusCreated)
  1329. assert.NoError(t, err)
  1330. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1331. dir := "testDir"
  1332. client := getWebDavClient(user)
  1333. err = client.MkdirAll(path.Join(dir, "sub1", "sub2"), os.ModePerm)
  1334. assert.NoError(t, err)
  1335. testFilePath := filepath.Join(homeBasePath, testFileName)
  1336. testFileSize := int64(65535)
  1337. err = createTestFile(testFilePath, testFileSize)
  1338. assert.NoError(t, err)
  1339. err = uploadFile(testFilePath, path.Join(dir, testFileName), testFileSize, client)
  1340. assert.NoError(t, err)
  1341. err = uploadFile(testFilePath, path.Join(dir, "sub1", testFileName), testFileSize, client)
  1342. assert.NoError(t, err)
  1343. err = uploadFile(testFilePath, path.Join(dir, "sub1", "sub2", testFileName), testFileSize, client)
  1344. assert.NoError(t, err)
  1345. err = client.Copy(dir, dir+"_copy", false)
  1346. assert.NoError(t, err)
  1347. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  1348. assert.NoError(t, err)
  1349. assert.Equal(t, 6, user.UsedQuotaFiles)
  1350. assert.Equal(t, 6*testFileSize, user.UsedQuotaSize)
  1351. err = client.Copy(dir, dir+"_copy1", false)
  1352. assert.NoError(t, err)
  1353. err = client.Copy(dir+"_copy", dir+"_copy1", false)
  1354. assert.Error(t, err)
  1355. err = client.Copy(dir+"_copy", dir+"_copy1", true)
  1356. assert.NoError(t, err)
  1357. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  1358. assert.NoError(t, err)
  1359. assert.Equal(t, 9, user.UsedQuotaFiles)
  1360. assert.Equal(t, 9*testFileSize, user.UsedQuotaSize)
  1361. err = client.Rename(dir+"_copy1", dir+"_copy2", false)
  1362. assert.NoError(t, err)
  1363. err = client.Remove(path.Join(dir+"_copy", testFileName))
  1364. assert.NoError(t, err)
  1365. err = client.Rename(dir+"_copy2", dir+"_copy", true)
  1366. assert.NoError(t, err)
  1367. err = client.Copy(dir+"_copy", dir+"_copy1", false)
  1368. assert.NoError(t, err)
  1369. err = client.RemoveAll(dir + "_copy1")
  1370. assert.NoError(t, err)
  1371. user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
  1372. assert.NoError(t, err)
  1373. assert.Equal(t, 6, user.UsedQuotaFiles)
  1374. assert.Equal(t, 6*testFileSize, user.UsedQuotaSize)
  1375. err = os.Remove(testFilePath)
  1376. assert.NoError(t, err)
  1377. if user.Username == defaultUsername {
  1378. err = os.RemoveAll(user.GetHomeDir())
  1379. assert.NoError(t, err)
  1380. user.QuotaFiles = 0
  1381. _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "")
  1382. assert.NoError(t, err)
  1383. }
  1384. }
  1385. _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
  1386. assert.NoError(t, err)
  1387. _, err = httpdtest.RemoveUser(localUser, http.StatusOK)
  1388. assert.NoError(t, err)
  1389. err = os.RemoveAll(localUser.GetHomeDir())
  1390. assert.NoError(t, err)
  1391. }
  1392. func checkBasicFunc(client *gowebdav.Client) error {
  1393. err := client.Connect()
  1394. if err != nil {
  1395. return err
  1396. }
  1397. _, err = client.ReadDir("/")
  1398. return err
  1399. }
  1400. func uploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *gowebdav.Client) error {
  1401. srcFile, err := os.Open(localSourcePath)
  1402. if err != nil {
  1403. return err
  1404. }
  1405. defer srcFile.Close()
  1406. err = client.WriteStream(remoteDestPath, srcFile, os.ModePerm)
  1407. if err != nil {
  1408. return err
  1409. }
  1410. if expectedSize > 0 {
  1411. info, err := client.Stat(remoteDestPath)
  1412. if err != nil {
  1413. return err
  1414. }
  1415. if info.Size() != expectedSize {
  1416. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", info.Size(), expectedSize)
  1417. }
  1418. }
  1419. return nil
  1420. }
  1421. func downloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *gowebdav.Client) error {
  1422. downloadDest, err := os.Create(localDestPath)
  1423. if err != nil {
  1424. return err
  1425. }
  1426. defer downloadDest.Close()
  1427. reader, err := client.ReadStream(remoteSourcePath)
  1428. if err != nil {
  1429. return err
  1430. }
  1431. defer reader.Close()
  1432. written, err := io.Copy(downloadDest, reader)
  1433. if err != nil {
  1434. return err
  1435. }
  1436. if written != expectedSize {
  1437. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", written, expectedSize)
  1438. }
  1439. return nil
  1440. }
  1441. func getWebDavClient(user dataprovider.User) *gowebdav.Client {
  1442. rootPath := fmt.Sprintf("http://%v/", webDavServerAddr)
  1443. pwd := defaultPassword
  1444. if user.Password != "" {
  1445. pwd = user.Password
  1446. }
  1447. client := gowebdav.NewClient(rootPath, user.Username, pwd)
  1448. client.SetTimeout(5 * time.Second)
  1449. return client
  1450. }
  1451. func waitTCPListening(address string) {
  1452. for {
  1453. conn, err := net.Dial("tcp", address)
  1454. if err != nil {
  1455. logger.WarnToConsole("tcp server %v not listening: %v", address, err)
  1456. time.Sleep(100 * time.Millisecond)
  1457. continue
  1458. }
  1459. logger.InfoToConsole("tcp server %v now listening", address)
  1460. conn.Close()
  1461. break
  1462. }
  1463. }
  1464. func getTestUser() dataprovider.User {
  1465. user := dataprovider.User{
  1466. Username: defaultUsername,
  1467. Password: defaultPassword,
  1468. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  1469. Status: 1,
  1470. ExpirationDate: 0,
  1471. }
  1472. user.Permissions = make(map[string][]string)
  1473. user.Permissions["/"] = allPerms
  1474. return user
  1475. }
  1476. func getTestSFTPUser() dataprovider.User {
  1477. u := getTestUser()
  1478. u.Username = u.Username + "_sftp"
  1479. u.FsConfig.Provider = dataprovider.SFTPFilesystemProvider
  1480. u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
  1481. u.FsConfig.SFTPConfig.Username = defaultUsername
  1482. u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
  1483. return u
  1484. }
  1485. func getTestUserWithCryptFs() dataprovider.User {
  1486. user := getTestUser()
  1487. user.FsConfig.Provider = dataprovider.CryptedFilesystemProvider
  1488. user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("testPassphrase")
  1489. return user
  1490. }
  1491. func getEncryptedFileSize(size int64) (int64, error) {
  1492. encSize, err := sio.EncryptedSize(uint64(size))
  1493. return int64(encSize) + 33, err
  1494. }
  1495. func getExtAuthScriptContent(user dataprovider.User, nonJSONResponse bool, username string) []byte {
  1496. extAuthContent := []byte("#!/bin/sh\n\n")
  1497. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
  1498. if len(username) > 0 {
  1499. user.Username = username
  1500. }
  1501. u, _ := json.Marshal(user)
  1502. if nonJSONResponse {
  1503. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1504. } else {
  1505. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1506. }
  1507. extAuthContent = append(extAuthContent, []byte("else\n")...)
  1508. if nonJSONResponse {
  1509. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1510. } else {
  1511. extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
  1512. }
  1513. extAuthContent = append(extAuthContent, []byte("fi\n")...)
  1514. return extAuthContent
  1515. }
  1516. func getPreLoginScriptContent(user dataprovider.User, nonJSONResponse bool) []byte {
  1517. content := []byte("#!/bin/sh\n\n")
  1518. if nonJSONResponse {
  1519. content = append(content, []byte("echo 'text response'\n")...)
  1520. return content
  1521. }
  1522. if len(user.Username) > 0 {
  1523. u, _ := json.Marshal(user)
  1524. content = append(content, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1525. }
  1526. return content
  1527. }
  1528. func getPostConnectScriptContent(exitCode int) []byte {
  1529. content := []byte("#!/bin/sh\n\n")
  1530. content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
  1531. return content
  1532. }
  1533. func createTestFile(path string, size int64) error {
  1534. baseDir := filepath.Dir(path)
  1535. if _, err := os.Stat(baseDir); os.IsNotExist(err) {
  1536. err = os.MkdirAll(baseDir, os.ModePerm)
  1537. if err != nil {
  1538. return err
  1539. }
  1540. }
  1541. content := make([]byte, size)
  1542. _, err := rand.Read(content)
  1543. if err != nil {
  1544. return err
  1545. }
  1546. return os.WriteFile(path, content, os.ModePerm)
  1547. }