webdavd_test.go 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. package webdavd_test
  2. import (
  3. "crypto/rand"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "os"
  11. "os/exec"
  12. "path"
  13. "path/filepath"
  14. "runtime"
  15. "sync"
  16. "testing"
  17. "time"
  18. "github.com/rs/zerolog"
  19. "github.com/stretchr/testify/assert"
  20. "github.com/studio-b12/gowebdav"
  21. "github.com/drakkan/sftpgo/common"
  22. "github.com/drakkan/sftpgo/config"
  23. "github.com/drakkan/sftpgo/dataprovider"
  24. "github.com/drakkan/sftpgo/httpclient"
  25. "github.com/drakkan/sftpgo/httpd"
  26. "github.com/drakkan/sftpgo/logger"
  27. "github.com/drakkan/sftpgo/vfs"
  28. "github.com/drakkan/sftpgo/webdavd"
  29. )
  30. const (
  31. logSender = "webavdTesting"
  32. webDavServerAddr = "127.0.0.1:9090"
  33. webDavServerPort = 9090
  34. defaultUsername = "test_user_dav"
  35. defaultPassword = "test_password"
  36. configDir = ".."
  37. osWindows = "windows"
  38. webDavCert = `-----BEGIN CERTIFICATE-----
  39. MIICHTCCAaKgAwIBAgIUHnqw7QnB1Bj9oUsNpdb+ZkFPOxMwCgYIKoZIzj0EAwIw
  40. RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
  41. dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDAyMDQwOTUzMDRaFw0zMDAyMDEw
  42. OTUzMDRaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
  43. VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQA
  44. IgNiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVqWvrJ51t5OxV0v25NsOgR82CA
  45. NXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIVCzgWkxiz7XE4lgUwX44FCXZM
  46. 3+JeUbKjUzBRMB0GA1UdDgQWBBRhLw+/o3+Z02MI/d4tmaMui9W16jAfBgNVHSME
  47. GDAWgBRhLw+/o3+Z02MI/d4tmaMui9W16jAPBgNVHRMBAf8EBTADAQH/MAoGCCqG
  48. SM49BAMCA2kAMGYCMQDqLt2lm8mE+tGgtjDmtFgdOcI72HSbRQ74D5rYTzgST1rY
  49. /8wTi5xl8TiFUyLMUsICMQC5ViVxdXbhuG7gX6yEqSkMKZICHpO8hqFwOD/uaFVI
  50. dV4vKmHUzwK/eIx+8Ay3neE=
  51. -----END CERTIFICATE-----`
  52. webDavKey = `-----BEGIN EC PARAMETERS-----
  53. BgUrgQQAIg==
  54. -----END EC PARAMETERS-----
  55. -----BEGIN EC PRIVATE KEY-----
  56. MIGkAgEBBDCfMNsN6miEE3rVyUPwElfiJSWaR5huPCzUenZOfJT04GAcQdWvEju3
  57. UM2lmBLIXpGgBwYFK4EEACKhZANiAARCjRMqJ85rzMC998X5z761nJ+xL3bkmGVq
  58. WvrJ51t5OxV0v25NsOgR82CANXUgvhVYs7vNFN+jxtb2aj6Xg+/2G/BNxkaFspIV
  59. CzgWkxiz7XE4lgUwX44FCXZM3+JeUbI=
  60. -----END EC PRIVATE KEY-----`
  61. testFileName = "test_file_dav.dat"
  62. testDLFileName = "test_download_dav.dat"
  63. )
  64. var (
  65. allPerms = []string{dataprovider.PermAny}
  66. homeBasePath string
  67. hookCmdPath string
  68. extAuthPath string
  69. preLoginPath string
  70. postConnectPath string
  71. logFilePath string
  72. certPath string
  73. keyPath string
  74. )
  75. func TestMain(m *testing.M) {
  76. logFilePath = filepath.Join(configDir, "sftpgo_webdavd_test.log")
  77. logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
  78. err := config.LoadConfig(configDir, "")
  79. if err != nil {
  80. logger.ErrorToConsole("error loading configuration: %v", err)
  81. os.Exit(1)
  82. }
  83. providerConf := config.GetProviderConf()
  84. logger.InfoToConsole("Starting WebDAVD tests, provider: %v", providerConf.Driver)
  85. commonConf := config.GetCommonConfig()
  86. commonConf.UploadMode = 2
  87. homeBasePath = os.TempDir()
  88. if runtime.GOOS != osWindows {
  89. commonConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  90. commonConf.Actions.Hook = hookCmdPath
  91. hookCmdPath, err = exec.LookPath("true")
  92. if err != nil {
  93. logger.Warn(logSender, "", "unable to get hook command: %v", err)
  94. logger.WarnToConsole("unable to get hook command: %v", err)
  95. }
  96. }
  97. certPath = filepath.Join(os.TempDir(), "test_dav.crt")
  98. keyPath = filepath.Join(os.TempDir(), "test_dav.key")
  99. err = ioutil.WriteFile(certPath, []byte(webDavCert), os.ModePerm)
  100. if err != nil {
  101. logger.ErrorToConsole("error writing WebDAV certificate: %v", err)
  102. os.Exit(1)
  103. }
  104. err = ioutil.WriteFile(keyPath, []byte(webDavKey), os.ModePerm)
  105. if err != nil {
  106. logger.ErrorToConsole("error writing WebDAV private key: %v", err)
  107. os.Exit(1)
  108. }
  109. common.Initialize(commonConf)
  110. err = dataprovider.Initialize(providerConf, configDir)
  111. if err != nil {
  112. logger.ErrorToConsole("error initializing data provider: %v", err)
  113. os.Exit(1)
  114. }
  115. httpConfig := config.GetHTTPConfig()
  116. httpConfig.Initialize(configDir)
  117. httpdConf := config.GetHTTPDConfig()
  118. httpdConf.BindPort = 8078
  119. httpd.SetBaseURLAndCredentials("http://127.0.0.1:8078", "", "")
  120. webDavConf := config.GetWebDAVDConfig()
  121. webDavConf.BindPort = webDavServerPort
  122. webDavConf.Cors = webdavd.Cors{
  123. Enabled: true,
  124. AllowedOrigins: []string{"*"},
  125. AllowedMethods: []string{
  126. http.MethodHead,
  127. http.MethodGet,
  128. http.MethodPost,
  129. http.MethodPut,
  130. http.MethodPatch,
  131. http.MethodDelete,
  132. },
  133. AllowedHeaders: []string{"*"},
  134. AllowCredentials: true,
  135. }
  136. extAuthPath = filepath.Join(homeBasePath, "extauth.sh")
  137. preLoginPath = filepath.Join(homeBasePath, "prelogin.sh")
  138. postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
  139. go func() {
  140. logger.Debug(logSender, "", "initializing WebDAV server with config %+v", webDavConf)
  141. if err := webDavConf.Initialize(configDir); err != nil {
  142. logger.ErrorToConsole("could not start WebDAV server: %v", err)
  143. os.Exit(1)
  144. }
  145. }()
  146. go func() {
  147. if err := httpdConf.Initialize(configDir, false); err != nil {
  148. logger.ErrorToConsole("could not start HTTP server: %v", err)
  149. os.Exit(1)
  150. }
  151. }()
  152. waitTCPListening(fmt.Sprintf("%s:%d", webDavConf.BindAddress, webDavConf.BindPort))
  153. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  154. webdavd.ReloadTLSCertificate() //nolint:errcheck
  155. exitCode := m.Run()
  156. os.Remove(logFilePath)
  157. os.Remove(extAuthPath)
  158. os.Remove(preLoginPath)
  159. os.Remove(postConnectPath)
  160. os.Remove(certPath)
  161. os.Remove(keyPath)
  162. os.Exit(exitCode)
  163. }
  164. func TestInitialization(t *testing.T) {
  165. config := webdavd.Configuration{
  166. BindPort: 1234,
  167. CertificateFile: "missing path",
  168. CertificateKeyFile: "bad path",
  169. }
  170. err := config.Initialize(configDir)
  171. assert.Error(t, err)
  172. config.BindPort = webDavServerPort
  173. config.CertificateFile = certPath
  174. config.CertificateKeyFile = keyPath
  175. err = config.Initialize(configDir)
  176. assert.Error(t, err)
  177. err = webdavd.ReloadTLSCertificate()
  178. assert.NoError(t, err)
  179. }
  180. func TestBasicHandling(t *testing.T) {
  181. u := getTestUser()
  182. u.QuotaSize = 6553600
  183. user, _, err := httpd.AddUser(u, http.StatusOK)
  184. assert.NoError(t, err)
  185. client := getWebDavClient(user)
  186. assert.NoError(t, checkBasicFunc(client))
  187. testFilePath := filepath.Join(homeBasePath, testFileName)
  188. testFileSize := int64(65535)
  189. expectedQuotaSize := user.UsedQuotaSize + testFileSize
  190. expectedQuotaFiles := user.UsedQuotaFiles + 1
  191. err = createTestFile(testFilePath, testFileSize)
  192. assert.NoError(t, err)
  193. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  194. assert.NoError(t, err)
  195. // overwrite an existing file
  196. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  197. assert.NoError(t, err)
  198. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  199. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  200. assert.NoError(t, err)
  201. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  202. assert.NoError(t, err)
  203. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  204. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  205. err = client.Rename(testFileName, testFileName+"1", false)
  206. assert.NoError(t, err)
  207. _, err = client.Stat(testFileName)
  208. assert.Error(t, err)
  209. // the webdav client hide the error we check the quota
  210. err = client.Remove(testFileName)
  211. assert.NoError(t, err)
  212. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  213. assert.NoError(t, err)
  214. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  215. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  216. err = client.Remove(testFileName + "1")
  217. assert.NoError(t, err)
  218. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  219. assert.NoError(t, err)
  220. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  221. assert.Equal(t, expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  222. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  223. assert.Error(t, err)
  224. testDir := "testdir"
  225. err = client.Mkdir(testDir, os.ModePerm)
  226. assert.NoError(t, err)
  227. err = client.MkdirAll(path.Join(testDir, "sub", "sub"), os.ModePerm)
  228. assert.NoError(t, err)
  229. err = client.MkdirAll(path.Join(testDir, "sub1", "sub1"), os.ModePerm)
  230. assert.NoError(t, err)
  231. err = client.MkdirAll(path.Join(testDir, "sub2", "sub2"), os.ModePerm)
  232. assert.NoError(t, err)
  233. err = uploadFile(testFilePath, path.Join(testDir, testFileName+".txt"), testFileSize, client)
  234. assert.NoError(t, err)
  235. files, err := client.ReadDir(testDir)
  236. assert.NoError(t, err)
  237. assert.Len(t, files, 4)
  238. err = client.Copy(testDir, testDir+"_copy", false)
  239. assert.NoError(t, err)
  240. err = client.RemoveAll(testDir)
  241. assert.NoError(t, err)
  242. err = os.Remove(testFilePath)
  243. assert.NoError(t, err)
  244. err = os.Remove(localDownloadPath)
  245. assert.NoError(t, err)
  246. _, err = httpd.RemoveUser(user, http.StatusOK)
  247. assert.NoError(t, err)
  248. err = os.RemoveAll(user.GetHomeDir())
  249. assert.NoError(t, err)
  250. assert.Len(t, common.Connections.GetStats(), 0)
  251. }
  252. func TestLoginInvalidPwd(t *testing.T) {
  253. u := getTestUser()
  254. user, _, err := httpd.AddUser(u, http.StatusOK)
  255. assert.NoError(t, err)
  256. client := getWebDavClient(user)
  257. assert.NoError(t, checkBasicFunc(client))
  258. user.Password = "wrong"
  259. client = getWebDavClient(user)
  260. assert.Error(t, checkBasicFunc(client))
  261. _, err = httpd.RemoveUser(user, http.StatusOK)
  262. assert.NoError(t, err)
  263. }
  264. func TestLoginInvalidURL(t *testing.T) {
  265. u := getTestUser()
  266. user, _, err := httpd.AddUser(u, http.StatusOK)
  267. assert.NoError(t, err)
  268. u1 := getTestUser()
  269. u1.Username = user.Username + "1"
  270. user1, _, err := httpd.AddUser(u1, http.StatusOK)
  271. assert.NoError(t, err)
  272. rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username+"1")
  273. client := gowebdav.NewClient(rootPath, user.Username, defaultPassword)
  274. client.SetTimeout(5 * time.Second)
  275. assert.Error(t, checkBasicFunc(client))
  276. _, err = httpd.RemoveUser(user, http.StatusOK)
  277. assert.NoError(t, err)
  278. _, err = httpd.RemoveUser(user1, http.StatusOK)
  279. assert.NoError(t, err)
  280. }
  281. func TestLoginExternalAuth(t *testing.T) {
  282. if runtime.GOOS == osWindows {
  283. t.Skip("this test is not available on Windows")
  284. }
  285. u := getTestUser()
  286. err := dataprovider.Close()
  287. assert.NoError(t, err)
  288. err = config.LoadConfig(configDir, "")
  289. assert.NoError(t, err)
  290. providerConf := config.GetProviderConf()
  291. err = ioutil.WriteFile(extAuthPath, getExtAuthScriptContent(u, false, ""), os.ModePerm)
  292. assert.NoError(t, err)
  293. providerConf.ExternalAuthHook = extAuthPath
  294. providerConf.ExternalAuthScope = 0
  295. err = dataprovider.Initialize(providerConf, configDir)
  296. assert.NoError(t, err)
  297. client := getWebDavClient(u)
  298. assert.NoError(t, checkBasicFunc(client))
  299. u.Username = defaultUsername + "1"
  300. client = getWebDavClient(u)
  301. assert.Error(t, checkBasicFunc(client))
  302. users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  303. assert.NoError(t, err)
  304. if assert.Len(t, users, 1) {
  305. user := users[0]
  306. assert.Equal(t, defaultUsername, user.Username)
  307. _, err = httpd.RemoveUser(user, http.StatusOK)
  308. assert.NoError(t, err)
  309. err = os.RemoveAll(user.GetHomeDir())
  310. assert.NoError(t, err)
  311. }
  312. err = dataprovider.Close()
  313. assert.NoError(t, err)
  314. err = config.LoadConfig(configDir, "")
  315. assert.NoError(t, err)
  316. providerConf = config.GetProviderConf()
  317. err = dataprovider.Initialize(providerConf, configDir)
  318. assert.NoError(t, err)
  319. err = os.Remove(extAuthPath)
  320. assert.NoError(t, err)
  321. }
  322. func TestPreLoginHook(t *testing.T) {
  323. if runtime.GOOS == osWindows {
  324. t.Skip("this test is not available on Windows")
  325. }
  326. u := getTestUser()
  327. err := dataprovider.Close()
  328. assert.NoError(t, err)
  329. err = config.LoadConfig(configDir, "")
  330. assert.NoError(t, err)
  331. providerConf := config.GetProviderConf()
  332. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  333. assert.NoError(t, err)
  334. providerConf.PreLoginHook = preLoginPath
  335. err = dataprovider.Initialize(providerConf, configDir)
  336. assert.NoError(t, err)
  337. users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  338. assert.NoError(t, err)
  339. assert.Equal(t, 0, len(users))
  340. client := getWebDavClient(u)
  341. assert.NoError(t, checkBasicFunc(client))
  342. users, _, err = httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  343. assert.NoError(t, err)
  344. assert.Equal(t, 1, len(users))
  345. user := users[0]
  346. // test login with an existing user
  347. client = getWebDavClient(user)
  348. assert.NoError(t, checkBasicFunc(client))
  349. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), os.ModePerm)
  350. assert.NoError(t, err)
  351. // update the user to remove it from the cache
  352. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  353. assert.NoError(t, err)
  354. client = getWebDavClient(user)
  355. assert.Error(t, checkBasicFunc(client))
  356. // update the user to remove it from the cache
  357. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  358. assert.NoError(t, err)
  359. user.Status = 0
  360. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  361. assert.NoError(t, err)
  362. client = getWebDavClient(user)
  363. assert.Error(t, checkBasicFunc(client))
  364. _, err = httpd.RemoveUser(user, http.StatusOK)
  365. assert.NoError(t, err)
  366. err = os.RemoveAll(user.GetHomeDir())
  367. assert.NoError(t, err)
  368. err = dataprovider.Close()
  369. assert.NoError(t, err)
  370. err = config.LoadConfig(configDir, "")
  371. assert.NoError(t, err)
  372. providerConf = config.GetProviderConf()
  373. err = dataprovider.Initialize(providerConf, configDir)
  374. assert.NoError(t, err)
  375. err = os.Remove(preLoginPath)
  376. assert.NoError(t, err)
  377. }
  378. func TestPostConnectHook(t *testing.T) {
  379. if runtime.GOOS == osWindows {
  380. t.Skip("this test is not available on Windows")
  381. }
  382. common.Config.PostConnectHook = postConnectPath
  383. u := getTestUser()
  384. user, _, err := httpd.AddUser(u, http.StatusOK)
  385. assert.NoError(t, err)
  386. err = ioutil.WriteFile(postConnectPath, getPostConnectScriptContent(0), os.ModePerm)
  387. assert.NoError(t, err)
  388. client := getWebDavClient(user)
  389. assert.NoError(t, checkBasicFunc(client))
  390. err = ioutil.WriteFile(postConnectPath, getPostConnectScriptContent(1), os.ModePerm)
  391. assert.NoError(t, err)
  392. assert.Error(t, checkBasicFunc(client))
  393. common.Config.PostConnectHook = "http://127.0.0.1:8078/api/v1/version"
  394. assert.NoError(t, checkBasicFunc(client))
  395. common.Config.PostConnectHook = "http://127.0.0.1:8078/notfound"
  396. assert.Error(t, checkBasicFunc(client))
  397. _, err = httpd.RemoveUser(user, http.StatusOK)
  398. assert.NoError(t, err)
  399. err = os.RemoveAll(user.GetHomeDir())
  400. assert.NoError(t, err)
  401. common.Config.PostConnectHook = ""
  402. }
  403. func TestMaxSessions(t *testing.T) {
  404. u := getTestUser()
  405. u.MaxSessions = 1
  406. user, _, err := httpd.AddUser(u, http.StatusOK)
  407. assert.NoError(t, err)
  408. client := getWebDavClient(user)
  409. assert.NoError(t, checkBasicFunc(client))
  410. // now add a fake connection
  411. fs := vfs.NewOsFs("id", os.TempDir(), nil)
  412. connection := &webdavd.Connection{
  413. BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, user, fs),
  414. }
  415. common.Connections.Add(connection)
  416. assert.Error(t, checkBasicFunc(client))
  417. common.Connections.Remove(connection.GetID())
  418. _, err = httpd.RemoveUser(user, http.StatusOK)
  419. assert.NoError(t, err)
  420. err = os.RemoveAll(user.GetHomeDir())
  421. assert.NoError(t, err)
  422. assert.Len(t, common.Connections.GetStats(), 0)
  423. }
  424. func TestLoginWithIPilters(t *testing.T) {
  425. u := getTestUser()
  426. u.Filters.DeniedIP = []string{"192.167.0.0/24", "172.18.0.0/16"}
  427. u.Filters.AllowedIP = []string{"172.19.0.0/16"}
  428. user, _, err := httpd.AddUser(u, http.StatusOK)
  429. assert.NoError(t, err)
  430. client := getWebDavClient(user)
  431. assert.Error(t, checkBasicFunc(client))
  432. _, err = httpd.RemoveUser(user, http.StatusOK)
  433. assert.NoError(t, err)
  434. err = os.RemoveAll(user.GetHomeDir())
  435. assert.NoError(t, err)
  436. }
  437. func TestDownloadErrors(t *testing.T) {
  438. u := getTestUser()
  439. u.QuotaFiles = 1
  440. subDir1 := "sub1"
  441. subDir2 := "sub2"
  442. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  443. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  444. dataprovider.PermDelete, dataprovider.PermDownload}
  445. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  446. {
  447. Path: "/sub2",
  448. AllowedExtensions: []string{},
  449. DeniedExtensions: []string{".zip"},
  450. },
  451. }
  452. user, _, err := httpd.AddUser(u, http.StatusOK)
  453. assert.NoError(t, err)
  454. client := getWebDavClient(user)
  455. testFilePath1 := filepath.Join(user.HomeDir, subDir1, "file.zip")
  456. testFilePath2 := filepath.Join(user.HomeDir, subDir2, "file.zip")
  457. err = os.MkdirAll(filepath.Dir(testFilePath1), os.ModePerm)
  458. assert.NoError(t, err)
  459. err = os.MkdirAll(filepath.Dir(testFilePath2), os.ModePerm)
  460. assert.NoError(t, err)
  461. err = ioutil.WriteFile(testFilePath1, []byte("file1"), os.ModePerm)
  462. assert.NoError(t, err)
  463. err = ioutil.WriteFile(testFilePath2, []byte("file2"), os.ModePerm)
  464. assert.NoError(t, err)
  465. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  466. err = downloadFile(path.Join("/", subDir1, "file.zip"), localDownloadPath, 5, client)
  467. assert.Error(t, err)
  468. err = downloadFile(path.Join("/", subDir2, "file.zip"), localDownloadPath, 5, client)
  469. assert.Error(t, err)
  470. err = downloadFile(path.Join("missing.zip"), localDownloadPath, 5, client)
  471. assert.Error(t, err)
  472. err = os.Remove(localDownloadPath)
  473. assert.NoError(t, err)
  474. _, err = httpd.RemoveUser(user, http.StatusOK)
  475. assert.NoError(t, err)
  476. err = os.RemoveAll(user.GetHomeDir())
  477. assert.NoError(t, err)
  478. }
  479. func TestUploadErrors(t *testing.T) {
  480. u := getTestUser()
  481. u.QuotaSize = 65535
  482. subDir1 := "sub1"
  483. subDir2 := "sub2"
  484. // we need download permission to get size since PROPFIND will open the file
  485. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems, dataprovider.PermDownload}
  486. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  487. dataprovider.PermDelete, dataprovider.PermDownload}
  488. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  489. {
  490. Path: "/sub2",
  491. AllowedExtensions: []string{},
  492. DeniedExtensions: []string{".zip"},
  493. },
  494. }
  495. user, _, err := httpd.AddUser(u, http.StatusOK)
  496. assert.NoError(t, err)
  497. client := getWebDavClient(user)
  498. testFilePath := filepath.Join(homeBasePath, testFileName)
  499. testFileSize := user.QuotaSize
  500. err = createTestFile(testFilePath, testFileSize)
  501. assert.NoError(t, err)
  502. err = client.Mkdir(subDir1, os.ModePerm)
  503. assert.NoError(t, err)
  504. err = client.Mkdir(subDir2, os.ModePerm)
  505. assert.NoError(t, err)
  506. err = uploadFile(testFilePath, path.Join(subDir1, testFileName), testFileSize, client)
  507. assert.Error(t, err)
  508. err = uploadFile(testFilePath, path.Join(subDir2, testFileName+".zip"), testFileSize, client)
  509. assert.Error(t, err)
  510. err = uploadFile(testFilePath, path.Join(subDir2, testFileName), testFileSize, client)
  511. assert.NoError(t, err)
  512. err = client.Rename(path.Join(subDir2, testFileName), path.Join(subDir1, testFileName), false)
  513. assert.Error(t, err)
  514. err = uploadFile(testFilePath, path.Join(subDir2, testFileName), testFileSize, client)
  515. assert.Error(t, err)
  516. err = uploadFile(testFilePath, subDir1, testFileSize, client)
  517. assert.Error(t, err)
  518. // overquota
  519. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  520. assert.Error(t, err)
  521. err = client.Remove(path.Join(subDir2, testFileName))
  522. assert.NoError(t, err)
  523. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  524. assert.NoError(t, err)
  525. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  526. assert.Error(t, err)
  527. err = os.Remove(testFilePath)
  528. assert.NoError(t, err)
  529. _, err = httpd.RemoveUser(user, http.StatusOK)
  530. assert.NoError(t, err)
  531. err = os.RemoveAll(user.GetHomeDir())
  532. assert.NoError(t, err)
  533. }
  534. func TestDeniedLoginMethod(t *testing.T) {
  535. u := getTestUser()
  536. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  537. user, _, err := httpd.AddUser(u, http.StatusOK)
  538. assert.NoError(t, err)
  539. client := getWebDavClient(user)
  540. assert.Error(t, checkBasicFunc(client))
  541. user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodKeyAndKeyboardInt}
  542. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  543. assert.NoError(t, err)
  544. client = getWebDavClient(user)
  545. assert.NoError(t, checkBasicFunc(client))
  546. _, err = httpd.RemoveUser(user, http.StatusOK)
  547. assert.NoError(t, err)
  548. err = os.RemoveAll(user.GetHomeDir())
  549. assert.NoError(t, err)
  550. }
  551. func TestDeniedProtocols(t *testing.T) {
  552. u := getTestUser()
  553. u.Filters.DeniedProtocols = []string{common.ProtocolWebDAV}
  554. user, _, err := httpd.AddUser(u, http.StatusOK)
  555. assert.NoError(t, err)
  556. client := getWebDavClient(user)
  557. assert.Error(t, checkBasicFunc(client))
  558. user.Filters.DeniedProtocols = []string{common.ProtocolSSH, common.ProtocolFTP}
  559. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  560. assert.NoError(t, err)
  561. client = getWebDavClient(user)
  562. assert.NoError(t, checkBasicFunc(client))
  563. _, err = httpd.RemoveUser(user, http.StatusOK)
  564. assert.NoError(t, err)
  565. err = os.RemoveAll(user.GetHomeDir())
  566. assert.NoError(t, err)
  567. }
  568. func TestQuotaLimits(t *testing.T) {
  569. u := getTestUser()
  570. u.QuotaFiles = 1
  571. user, _, err := httpd.AddUser(u, http.StatusOK)
  572. assert.NoError(t, err)
  573. testFileSize := int64(65535)
  574. testFilePath := filepath.Join(homeBasePath, testFileName)
  575. err = createTestFile(testFilePath, testFileSize)
  576. assert.NoError(t, err)
  577. testFileSize1 := int64(131072)
  578. testFileName1 := "test_file1.dat"
  579. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  580. err = createTestFile(testFilePath1, testFileSize1)
  581. assert.NoError(t, err)
  582. testFileSize2 := int64(32768)
  583. testFileName2 := "test_file2.dat"
  584. testFilePath2 := filepath.Join(homeBasePath, testFileName2)
  585. err = createTestFile(testFilePath2, testFileSize2)
  586. assert.NoError(t, err)
  587. client := getWebDavClient(user)
  588. // test quota files
  589. err = uploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  590. assert.NoError(t, err)
  591. err = uploadFile(testFilePath, testFileName+".quota1", testFileSize, client)
  592. assert.Error(t, err)
  593. err = client.Rename(testFileName+".quota", testFileName, false)
  594. assert.NoError(t, err)
  595. // test quota size
  596. user.QuotaSize = testFileSize - 1
  597. user.QuotaFiles = 0
  598. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  599. assert.NoError(t, err)
  600. err = uploadFile(testFilePath, testFileName+".quota", testFileSize, client)
  601. assert.Error(t, err)
  602. err = client.Rename(testFileName, testFileName+".quota", false)
  603. assert.NoError(t, err)
  604. // now test quota limits while uploading the current file, we have 1 bytes remaining
  605. user.QuotaSize = testFileSize + 1
  606. user.QuotaFiles = 0
  607. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  608. assert.NoError(t, err)
  609. err = uploadFile(testFilePath1, testFileName1, testFileSize1, client)
  610. assert.Error(t, err)
  611. _, err = client.Stat(testFileName1)
  612. assert.Error(t, err)
  613. err = client.Rename(testFileName+".quota", testFileName, false)
  614. assert.NoError(t, err)
  615. // overwriting an existing file will work if the resulting size is lesser or equal than the current one
  616. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  617. assert.NoError(t, err)
  618. err = uploadFile(testFilePath2, testFileName, testFileSize2, client)
  619. assert.NoError(t, err)
  620. err = uploadFile(testFilePath1, testFileName, testFileSize1, client)
  621. assert.Error(t, err)
  622. err = uploadFile(testFilePath2, testFileName, testFileSize2, client)
  623. assert.NoError(t, err)
  624. err = os.Remove(testFilePath)
  625. assert.NoError(t, err)
  626. err = os.Remove(testFilePath1)
  627. assert.NoError(t, err)
  628. err = os.Remove(testFilePath2)
  629. assert.NoError(t, err)
  630. _, err = httpd.RemoveUser(user, http.StatusOK)
  631. assert.NoError(t, err)
  632. err = os.RemoveAll(user.GetHomeDir())
  633. assert.NoError(t, err)
  634. }
  635. func TestUploadMaxSize(t *testing.T) {
  636. testFileSize := int64(65535)
  637. u := getTestUser()
  638. u.Filters.MaxUploadFileSize = testFileSize + 1
  639. user, _, err := httpd.AddUser(u, http.StatusOK)
  640. assert.NoError(t, err)
  641. testFilePath := filepath.Join(homeBasePath, testFileName)
  642. err = createTestFile(testFilePath, testFileSize)
  643. assert.NoError(t, err)
  644. testFileSize1 := int64(131072)
  645. testFileName1 := "test_file_dav1.dat"
  646. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  647. err = createTestFile(testFilePath1, testFileSize1)
  648. assert.NoError(t, err)
  649. client := getWebDavClient(user)
  650. err = uploadFile(testFilePath1, testFileName1, testFileSize1, client)
  651. assert.Error(t, err)
  652. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  653. assert.NoError(t, err)
  654. err = os.Remove(testFilePath)
  655. assert.NoError(t, err)
  656. err = os.Remove(testFilePath1)
  657. assert.NoError(t, err)
  658. _, err = httpd.RemoveUser(user, http.StatusOK)
  659. assert.NoError(t, err)
  660. err = os.RemoveAll(user.GetHomeDir())
  661. assert.NoError(t, err)
  662. }
  663. func TestClientClose(t *testing.T) {
  664. u := getTestUser()
  665. u.UploadBandwidth = 64
  666. u.DownloadBandwidth = 64
  667. user, _, err := httpd.AddUser(u, http.StatusOK)
  668. assert.NoError(t, err)
  669. testFileSize := int64(1048576)
  670. testFilePath := filepath.Join(homeBasePath, testFileName)
  671. err = createTestFile(testFilePath, testFileSize)
  672. assert.NoError(t, err)
  673. client := getWebDavClient(user)
  674. assert.NoError(t, checkBasicFunc(client))
  675. var wg sync.WaitGroup
  676. wg.Add(1)
  677. go func() {
  678. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  679. assert.Error(t, err)
  680. wg.Done()
  681. }()
  682. assert.Eventually(t, func() bool {
  683. for _, stat := range common.Connections.GetStats() {
  684. if len(stat.Transfers) > 0 {
  685. return true
  686. }
  687. }
  688. return false
  689. }, 1*time.Second, 50*time.Millisecond)
  690. for _, stat := range common.Connections.GetStats() {
  691. common.Connections.Close(stat.ConnectionID)
  692. }
  693. wg.Wait()
  694. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  695. 1*time.Second, 100*time.Millisecond)
  696. err = os.Remove(testFilePath)
  697. assert.NoError(t, err)
  698. testFilePath = filepath.Join(user.HomeDir, testFileName)
  699. err = createTestFile(testFilePath, testFileSize)
  700. assert.NoError(t, err)
  701. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  702. wg.Add(1)
  703. go func() {
  704. err = downloadFile(testFileName, localDownloadPath, testFileSize, client)
  705. assert.Error(t, err)
  706. wg.Done()
  707. }()
  708. assert.Eventually(t, func() bool {
  709. for _, stat := range common.Connections.GetStats() {
  710. if len(stat.Transfers) > 0 {
  711. return true
  712. }
  713. }
  714. return false
  715. }, 1*time.Second, 50*time.Millisecond)
  716. for _, stat := range common.Connections.GetStats() {
  717. common.Connections.Close(stat.ConnectionID)
  718. }
  719. wg.Wait()
  720. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  721. 1*time.Second, 100*time.Millisecond)
  722. err = os.Remove(localDownloadPath)
  723. assert.NoError(t, err)
  724. _, err = httpd.RemoveUser(user, http.StatusOK)
  725. assert.NoError(t, err)
  726. err = os.RemoveAll(user.GetHomeDir())
  727. assert.NoError(t, err)
  728. }
  729. func TestLoginWithDatabaseCredentials(t *testing.T) {
  730. u := getTestUser()
  731. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  732. u.FsConfig.GCSConfig.Bucket = "test"
  733. u.FsConfig.GCSConfig.Credentials = []byte(`{ "type": "service_account" }`)
  734. providerConf := config.GetProviderConf()
  735. providerConf.PreferDatabaseCredentials = true
  736. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  737. if !filepath.IsAbs(credentialsFile) {
  738. credentialsFile = filepath.Join(configDir, credentialsFile)
  739. }
  740. assert.NoError(t, dataprovider.Close())
  741. err := dataprovider.Initialize(providerConf, configDir)
  742. assert.NoError(t, err)
  743. if _, err = os.Stat(credentialsFile); err == nil {
  744. // remove the credentials file
  745. assert.NoError(t, os.Remove(credentialsFile))
  746. }
  747. user, _, err := httpd.AddUser(u, http.StatusOK)
  748. assert.NoError(t, err)
  749. _, err = os.Stat(credentialsFile)
  750. assert.Error(t, err)
  751. client := getWebDavClient(user)
  752. err = client.Connect()
  753. assert.NoError(t, err)
  754. _, err = httpd.RemoveUser(user, http.StatusOK)
  755. assert.NoError(t, err)
  756. err = os.RemoveAll(user.GetHomeDir())
  757. assert.NoError(t, err)
  758. assert.NoError(t, dataprovider.Close())
  759. assert.NoError(t, config.LoadConfig(configDir, ""))
  760. providerConf = config.GetProviderConf()
  761. assert.NoError(t, dataprovider.Initialize(providerConf, configDir))
  762. }
  763. func TestLoginInvalidFs(t *testing.T) {
  764. u := getTestUser()
  765. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  766. u.FsConfig.GCSConfig.Bucket = "test"
  767. u.FsConfig.GCSConfig.Credentials = []byte("invalid JSON for credentials")
  768. user, _, err := httpd.AddUser(u, http.StatusOK)
  769. assert.NoError(t, err)
  770. providerConf := config.GetProviderConf()
  771. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  772. if !filepath.IsAbs(credentialsFile) {
  773. credentialsFile = filepath.Join(configDir, credentialsFile)
  774. }
  775. // now remove the credentials file so the filesystem creation will fail
  776. err = os.Remove(credentialsFile)
  777. assert.NoError(t, err)
  778. client := getWebDavClient(user)
  779. assert.Error(t, checkBasicFunc(client))
  780. _, err = httpd.RemoveUser(user, http.StatusOK)
  781. assert.NoError(t, err)
  782. err = os.RemoveAll(user.GetHomeDir())
  783. assert.NoError(t, err)
  784. }
  785. func TestBytesRangeRequests(t *testing.T) {
  786. u := getTestUser()
  787. user, _, err := httpd.AddUser(u, http.StatusOK)
  788. assert.NoError(t, err)
  789. testFileName := "test_file.txt"
  790. testFilePath := filepath.Join(homeBasePath, testFileName)
  791. fileContent := []byte("test file contents")
  792. err = ioutil.WriteFile(testFilePath, fileContent, os.ModePerm)
  793. assert.NoError(t, err)
  794. client := getWebDavClient(user)
  795. err = uploadFile(testFilePath, testFileName, int64(len(fileContent)), client)
  796. assert.NoError(t, err)
  797. remotePath := fmt.Sprintf("http://%v/%v/%v", webDavServerAddr, user.Username, testFileName)
  798. req, err := http.NewRequest(http.MethodGet, remotePath, nil)
  799. if assert.NoError(t, err) {
  800. httpClient := httpclient.GetHTTPClient()
  801. req.SetBasicAuth(user.Username, defaultPassword)
  802. req.Header.Set("Range", "bytes=5-")
  803. resp, err := httpClient.Do(req)
  804. if assert.NoError(t, err) {
  805. defer resp.Body.Close()
  806. assert.Equal(t, http.StatusPartialContent, resp.StatusCode)
  807. bodyBytes, err := ioutil.ReadAll(resp.Body)
  808. assert.NoError(t, err)
  809. assert.Equal(t, "file contents", string(bodyBytes))
  810. }
  811. req.Header.Set("Range", "bytes=5-8")
  812. resp, err = httpClient.Do(req)
  813. if assert.NoError(t, err) {
  814. defer resp.Body.Close()
  815. assert.Equal(t, http.StatusPartialContent, resp.StatusCode)
  816. bodyBytes, err := ioutil.ReadAll(resp.Body)
  817. assert.NoError(t, err)
  818. assert.Equal(t, "file", string(bodyBytes))
  819. }
  820. }
  821. assert.NoError(t, err)
  822. err = os.Remove(testFilePath)
  823. assert.NoError(t, err)
  824. _, err = httpd.RemoveUser(user, http.StatusOK)
  825. assert.NoError(t, err)
  826. err = os.RemoveAll(user.GetHomeDir())
  827. assert.NoError(t, err)
  828. }
  829. func TestGETAsPROPFIND(t *testing.T) {
  830. u := getTestUser()
  831. subDir1 := "/sub1"
  832. u.Permissions[subDir1] = []string{dataprovider.PermUpload, dataprovider.PermCreateDirs}
  833. user, _, err := httpd.AddUser(u, http.StatusOK)
  834. assert.NoError(t, err)
  835. rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username)
  836. httpClient := httpclient.GetHTTPClient()
  837. req, err := http.NewRequest(http.MethodGet, rootPath, nil)
  838. if assert.NoError(t, err) {
  839. req.SetBasicAuth(u.Username, u.Password)
  840. resp, err := httpClient.Do(req)
  841. if assert.NoError(t, err) {
  842. assert.Equal(t, http.StatusMultiStatus, resp.StatusCode)
  843. resp.Body.Close()
  844. }
  845. }
  846. client := getWebDavClient(user)
  847. err = client.MkdirAll(path.Join(subDir1, "sub"), os.ModePerm)
  848. assert.NoError(t, err)
  849. subPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, path.Join(user.Username, subDir1))
  850. req, err = http.NewRequest(http.MethodGet, subPath, nil)
  851. if assert.NoError(t, err) {
  852. req.SetBasicAuth(u.Username, u.Password)
  853. resp, err := httpClient.Do(req)
  854. if assert.NoError(t, err) {
  855. assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
  856. resp.Body.Close()
  857. }
  858. }
  859. _, err = httpd.RemoveUser(user, http.StatusOK)
  860. assert.NoError(t, err)
  861. err = os.RemoveAll(user.GetHomeDir())
  862. assert.NoError(t, err)
  863. }
  864. func TestStat(t *testing.T) {
  865. u := getTestUser()
  866. u.Permissions["/subdir"] = []string{dataprovider.PermUpload, dataprovider.PermListItems, dataprovider.PermDownload}
  867. user, _, err := httpd.AddUser(u, http.StatusOK)
  868. assert.NoError(t, err)
  869. client := getWebDavClient(user)
  870. subDir := "subdir"
  871. testFilePath := filepath.Join(homeBasePath, testFileName)
  872. testFileSize := int64(65535)
  873. err = createTestFile(testFilePath, testFileSize)
  874. assert.NoError(t, err)
  875. err = client.Mkdir(subDir, os.ModePerm)
  876. assert.NoError(t, err)
  877. err = uploadFile(testFilePath, testFileName, testFileSize, client)
  878. assert.NoError(t, err)
  879. err = uploadFile(testFilePath, path.Join("/", subDir, testFileName), testFileSize, client)
  880. assert.NoError(t, err)
  881. user.Permissions["/subdir"] = []string{dataprovider.PermUpload, dataprovider.PermDownload}
  882. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  883. assert.NoError(t, err)
  884. _, err = client.Stat(testFileName)
  885. assert.NoError(t, err)
  886. _, err = client.Stat(path.Join("/", subDir, testFileName))
  887. assert.Error(t, err)
  888. err = os.Remove(testFilePath)
  889. assert.NoError(t, err)
  890. _, err = httpd.RemoveUser(user, http.StatusOK)
  891. assert.NoError(t, err)
  892. err = os.RemoveAll(user.GetHomeDir())
  893. assert.NoError(t, err)
  894. }
  895. func TestUploadOverwriteVfolder(t *testing.T) {
  896. u := getTestUser()
  897. vdir := "/vdir"
  898. mappedPath := filepath.Join(os.TempDir(), "mappedDir")
  899. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  900. BaseVirtualFolder: vfs.BaseVirtualFolder{
  901. MappedPath: mappedPath,
  902. },
  903. VirtualPath: vdir,
  904. QuotaSize: -1,
  905. QuotaFiles: -1,
  906. })
  907. err := os.MkdirAll(mappedPath, os.ModePerm)
  908. assert.NoError(t, err)
  909. user, _, err := httpd.AddUser(u, http.StatusOK)
  910. assert.NoError(t, err)
  911. client := getWebDavClient(user)
  912. files, err := client.ReadDir(".")
  913. assert.NoError(t, err)
  914. vdirFound := false
  915. for _, info := range files {
  916. if info.Name() == path.Base(vdir) {
  917. vdirFound = true
  918. break
  919. }
  920. }
  921. assert.True(t, vdirFound)
  922. info, err := client.Stat(vdir)
  923. if assert.NoError(t, err) {
  924. assert.Equal(t, path.Base(vdir), info.Name())
  925. }
  926. testFilePath := filepath.Join(homeBasePath, testFileName)
  927. testFileSize := int64(65535)
  928. err = createTestFile(testFilePath, testFileSize)
  929. assert.NoError(t, err)
  930. err = uploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client)
  931. assert.NoError(t, err)
  932. folder, _, err := httpd.GetFolders(0, 0, mappedPath, http.StatusOK)
  933. assert.NoError(t, err)
  934. if assert.Len(t, folder, 1) {
  935. f := folder[0]
  936. assert.Equal(t, testFileSize, f.UsedQuotaSize)
  937. assert.Equal(t, 1, f.UsedQuotaFiles)
  938. }
  939. err = uploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client)
  940. assert.NoError(t, err)
  941. folder, _, err = httpd.GetFolders(0, 0, mappedPath, http.StatusOK)
  942. assert.NoError(t, err)
  943. if assert.Len(t, folder, 1) {
  944. f := folder[0]
  945. assert.Equal(t, testFileSize, f.UsedQuotaSize)
  946. assert.Equal(t, 1, f.UsedQuotaFiles)
  947. }
  948. err = os.Remove(testFilePath)
  949. assert.NoError(t, err)
  950. _, err = httpd.RemoveUser(user, http.StatusOK)
  951. assert.NoError(t, err)
  952. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: mappedPath}, http.StatusOK)
  953. assert.NoError(t, err)
  954. err = os.RemoveAll(user.GetHomeDir())
  955. assert.NoError(t, err)
  956. err = os.RemoveAll(mappedPath)
  957. assert.NoError(t, err)
  958. }
  959. func TestMiscCommands(t *testing.T) {
  960. u := getTestUser()
  961. u.QuotaFiles = 100
  962. user, _, err := httpd.AddUser(u, http.StatusOK)
  963. assert.NoError(t, err)
  964. dir := "testDir"
  965. client := getWebDavClient(user)
  966. err = client.MkdirAll(path.Join(dir, "sub1", "sub2"), os.ModePerm)
  967. assert.NoError(t, err)
  968. testFilePath := filepath.Join(homeBasePath, testFileName)
  969. testFileSize := int64(65535)
  970. err = createTestFile(testFilePath, testFileSize)
  971. assert.NoError(t, err)
  972. err = uploadFile(testFilePath, path.Join(dir, testFileName), testFileSize, client)
  973. assert.NoError(t, err)
  974. err = uploadFile(testFilePath, path.Join(dir, "sub1", testFileName), testFileSize, client)
  975. assert.NoError(t, err)
  976. err = uploadFile(testFilePath, path.Join(dir, "sub1", "sub2", testFileName), testFileSize, client)
  977. assert.NoError(t, err)
  978. err = client.Copy(dir, dir+"_copy", false)
  979. assert.NoError(t, err)
  980. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  981. assert.NoError(t, err)
  982. assert.Equal(t, 6, user.UsedQuotaFiles)
  983. assert.Equal(t, 6*testFileSize, user.UsedQuotaSize)
  984. err = client.Copy(dir, dir+"_copy1", false)
  985. assert.NoError(t, err)
  986. err = client.Copy(dir+"_copy", dir+"_copy1", false)
  987. assert.Error(t, err)
  988. err = client.Copy(dir+"_copy", dir+"_copy1", true)
  989. assert.NoError(t, err)
  990. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  991. assert.NoError(t, err)
  992. assert.Equal(t, 9, user.UsedQuotaFiles)
  993. assert.Equal(t, 9*testFileSize, user.UsedQuotaSize)
  994. err = client.Rename(dir+"_copy1", dir+"_copy2", false)
  995. assert.NoError(t, err)
  996. err = client.Remove(path.Join(dir+"_copy", testFileName))
  997. assert.NoError(t, err)
  998. err = client.Rename(dir+"_copy2", dir+"_copy", true)
  999. assert.NoError(t, err)
  1000. err = client.Copy(dir+"_copy", dir+"_copy1", false)
  1001. assert.NoError(t, err)
  1002. err = client.RemoveAll(dir + "_copy1")
  1003. assert.NoError(t, err)
  1004. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  1005. assert.NoError(t, err)
  1006. assert.Equal(t, 6, user.UsedQuotaFiles)
  1007. assert.Equal(t, 6*testFileSize, user.UsedQuotaSize)
  1008. err = os.Remove(testFilePath)
  1009. assert.NoError(t, err)
  1010. _, err = httpd.RemoveUser(user, http.StatusOK)
  1011. assert.NoError(t, err)
  1012. err = os.RemoveAll(user.GetHomeDir())
  1013. assert.NoError(t, err)
  1014. }
  1015. func checkBasicFunc(client *gowebdav.Client) error {
  1016. err := client.Connect()
  1017. if err != nil {
  1018. return err
  1019. }
  1020. _, err = client.ReadDir("/")
  1021. return err
  1022. }
  1023. func uploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *gowebdav.Client) error {
  1024. srcFile, err := os.Open(localSourcePath)
  1025. if err != nil {
  1026. return err
  1027. }
  1028. defer srcFile.Close()
  1029. err = client.WriteStream(remoteDestPath, srcFile, os.ModePerm)
  1030. if err != nil {
  1031. return err
  1032. }
  1033. if expectedSize > 0 {
  1034. info, err := client.Stat(remoteDestPath)
  1035. if err != nil {
  1036. return err
  1037. }
  1038. if info.Size() != expectedSize {
  1039. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", info.Size(), expectedSize)
  1040. }
  1041. }
  1042. return nil
  1043. }
  1044. func downloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *gowebdav.Client) error {
  1045. downloadDest, err := os.Create(localDestPath)
  1046. if err != nil {
  1047. return err
  1048. }
  1049. defer downloadDest.Close()
  1050. reader, err := client.ReadStream(remoteSourcePath)
  1051. if err != nil {
  1052. return err
  1053. }
  1054. defer reader.Close()
  1055. written, err := io.Copy(downloadDest, reader)
  1056. if err != nil {
  1057. return err
  1058. }
  1059. if written != expectedSize {
  1060. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", written, expectedSize)
  1061. }
  1062. return nil
  1063. }
  1064. func getWebDavClient(user dataprovider.User) *gowebdav.Client {
  1065. rootPath := fmt.Sprintf("http://%v/%v", webDavServerAddr, user.Username)
  1066. pwd := defaultPassword
  1067. if len(user.Password) > 0 {
  1068. pwd = user.Password
  1069. }
  1070. client := gowebdav.NewClient(rootPath, user.Username, pwd)
  1071. client.SetTimeout(5 * time.Second)
  1072. return client
  1073. }
  1074. func waitTCPListening(address string) {
  1075. for {
  1076. conn, err := net.Dial("tcp", address)
  1077. if err != nil {
  1078. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  1079. time.Sleep(100 * time.Millisecond)
  1080. continue
  1081. }
  1082. logger.InfoToConsole("tcp server %v now listening\n", address)
  1083. conn.Close()
  1084. break
  1085. }
  1086. }
  1087. func getTestUser() dataprovider.User {
  1088. user := dataprovider.User{
  1089. Username: defaultUsername,
  1090. Password: defaultPassword,
  1091. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  1092. Status: 1,
  1093. ExpirationDate: 0,
  1094. }
  1095. user.Permissions = make(map[string][]string)
  1096. user.Permissions["/"] = allPerms
  1097. return user
  1098. }
  1099. func getExtAuthScriptContent(user dataprovider.User, nonJSONResponse bool, username string) []byte {
  1100. extAuthContent := []byte("#!/bin/sh\n\n")
  1101. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
  1102. if len(username) > 0 {
  1103. user.Username = username
  1104. }
  1105. u, _ := json.Marshal(user)
  1106. if nonJSONResponse {
  1107. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1108. } else {
  1109. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1110. }
  1111. extAuthContent = append(extAuthContent, []byte("else\n")...)
  1112. if nonJSONResponse {
  1113. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1114. } else {
  1115. extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
  1116. }
  1117. extAuthContent = append(extAuthContent, []byte("fi\n")...)
  1118. return extAuthContent
  1119. }
  1120. func getPreLoginScriptContent(user dataprovider.User, nonJSONResponse bool) []byte {
  1121. content := []byte("#!/bin/sh\n\n")
  1122. if nonJSONResponse {
  1123. content = append(content, []byte("echo 'text response'\n")...)
  1124. return content
  1125. }
  1126. if len(user.Username) > 0 {
  1127. u, _ := json.Marshal(user)
  1128. content = append(content, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1129. }
  1130. return content
  1131. }
  1132. func getPostConnectScriptContent(exitCode int) []byte {
  1133. content := []byte("#!/bin/sh\n\n")
  1134. content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
  1135. return content
  1136. }
  1137. func createTestFile(path string, size int64) error {
  1138. baseDir := filepath.Dir(path)
  1139. if _, err := os.Stat(baseDir); os.IsNotExist(err) {
  1140. err = os.MkdirAll(baseDir, os.ModePerm)
  1141. if err != nil {
  1142. return err
  1143. }
  1144. }
  1145. content := make([]byte, size)
  1146. _, err := rand.Read(content)
  1147. if err != nil {
  1148. return err
  1149. }
  1150. return ioutil.WriteFile(path, content, os.ModePerm)
  1151. }