webdavd_test.go 39 KB

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