ftpd_test.go 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  1. package ftpd_test
  2. import (
  3. "crypto/rand"
  4. "crypto/tls"
  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. "testing"
  17. "time"
  18. "github.com/jlaffaye/ftp"
  19. "github.com/rs/zerolog"
  20. "github.com/stretchr/testify/assert"
  21. "github.com/drakkan/sftpgo/common"
  22. "github.com/drakkan/sftpgo/config"
  23. "github.com/drakkan/sftpgo/dataprovider"
  24. "github.com/drakkan/sftpgo/ftpd"
  25. "github.com/drakkan/sftpgo/httpd"
  26. "github.com/drakkan/sftpgo/kms"
  27. "github.com/drakkan/sftpgo/logger"
  28. "github.com/drakkan/sftpgo/vfs"
  29. )
  30. const (
  31. logSender = "ftpdTesting"
  32. ftpServerAddr = "127.0.0.1:2121"
  33. sftpServerAddr = "127.0.0.1:2122"
  34. defaultUsername = "test_user_ftp"
  35. defaultPassword = "test_password"
  36. configDir = ".."
  37. osWindows = "windows"
  38. ftpsCert = `-----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. ftpsKey = `-----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_ftp.dat"
  62. testDLFileName = "test_download_ftp.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. )
  73. func TestMain(m *testing.M) {
  74. logFilePath = filepath.Join(configDir, "sftpgo_ftpd_test.log")
  75. bannerFileName := "banner_file"
  76. bannerFile := filepath.Join(configDir, bannerFileName)
  77. logger.InitLogger(logFilePath, 5, 1, 28, false, zerolog.DebugLevel)
  78. err := ioutil.WriteFile(bannerFile, []byte("SFTPGo test ready\nsimple banner line\n"), os.ModePerm)
  79. if err != nil {
  80. logger.ErrorToConsole("error creating banner file: %v", err)
  81. }
  82. err = config.LoadConfig(configDir, "")
  83. if err != nil {
  84. logger.ErrorToConsole("error loading configuration: %v", err)
  85. os.Exit(1)
  86. }
  87. providerConf := config.GetProviderConf()
  88. logger.InfoToConsole("Starting FTPD tests, provider: %v", providerConf.Driver)
  89. commonConf := config.GetCommonConfig()
  90. // we run the test cases with UploadMode atomic and resume support. The non atomic code path
  91. // simply does not execute some code so if it works in atomic mode will
  92. // work in non atomic mode too
  93. commonConf.UploadMode = 2
  94. homeBasePath = os.TempDir()
  95. if runtime.GOOS != osWindows {
  96. commonConf.Actions.ExecuteOn = []string{"download", "upload", "rename", "delete"}
  97. commonConf.Actions.Hook = hookCmdPath
  98. hookCmdPath, err = exec.LookPath("true")
  99. if err != nil {
  100. logger.Warn(logSender, "", "unable to get hook command: %v", err)
  101. logger.WarnToConsole("unable to get hook command: %v", err)
  102. }
  103. }
  104. certPath := filepath.Join(os.TempDir(), "test_ftpd.crt")
  105. keyPath := filepath.Join(os.TempDir(), "test_ftpd.key")
  106. err = ioutil.WriteFile(certPath, []byte(ftpsCert), os.ModePerm)
  107. if err != nil {
  108. logger.ErrorToConsole("error writing FTPS certificate: %v", err)
  109. os.Exit(1)
  110. }
  111. err = ioutil.WriteFile(keyPath, []byte(ftpsKey), os.ModePerm)
  112. if err != nil {
  113. logger.ErrorToConsole("error writing FTPS private key: %v", err)
  114. os.Exit(1)
  115. }
  116. common.Initialize(commonConf)
  117. err = dataprovider.Initialize(providerConf, configDir)
  118. if err != nil {
  119. logger.ErrorToConsole("error initializing data provider: %v", err)
  120. os.Exit(1)
  121. }
  122. httpConfig := config.GetHTTPConfig()
  123. httpConfig.Initialize(configDir)
  124. kmsConfig := config.GetKMSConfig()
  125. err = kmsConfig.Initialize()
  126. if err != nil {
  127. logger.ErrorToConsole("error initializing kms: %v", err)
  128. os.Exit(1)
  129. }
  130. httpdConf := config.GetHTTPDConfig()
  131. httpdConf.BindPort = 8079
  132. httpd.SetBaseURLAndCredentials("http://127.0.0.1:8079", "", "")
  133. ftpdConf := config.GetFTPDConfig()
  134. ftpdConf.BindPort = 2121
  135. ftpdConf.PassivePortRange.Start = 0
  136. ftpdConf.PassivePortRange.End = 0
  137. ftpdConf.BannerFile = bannerFileName
  138. ftpdConf.CertificateFile = certPath
  139. ftpdConf.CertificateKeyFile = keyPath
  140. // required to test sftpfs
  141. sftpdConf := config.GetSFTPDConfig()
  142. sftpdConf.BindPort = 2122
  143. sftpdConf.HostKeys = []string{filepath.Join(os.TempDir(), "id_ed25519")}
  144. extAuthPath = filepath.Join(homeBasePath, "extauth.sh")
  145. preLoginPath = filepath.Join(homeBasePath, "prelogin.sh")
  146. postConnectPath = filepath.Join(homeBasePath, "postconnect.sh")
  147. status := ftpd.GetStatus()
  148. if status.IsActive {
  149. logger.ErrorToConsole("ftpd is already active")
  150. os.Exit(1)
  151. }
  152. go func() {
  153. logger.Debug(logSender, "", "initializing FTP server with config %+v", ftpdConf)
  154. if err := ftpdConf.Initialize(configDir); err != nil {
  155. logger.ErrorToConsole("could not start FTP server: %v", err)
  156. os.Exit(1)
  157. }
  158. }()
  159. go func() {
  160. logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
  161. if err := sftpdConf.Initialize(configDir); err != nil {
  162. logger.ErrorToConsole("could not start SFTP server: %v", err)
  163. os.Exit(1)
  164. }
  165. }()
  166. go func() {
  167. if err := httpdConf.Initialize(configDir, false); err != nil {
  168. logger.ErrorToConsole("could not start HTTP server: %v", err)
  169. os.Exit(1)
  170. }
  171. }()
  172. waitTCPListening(fmt.Sprintf("%s:%d", ftpdConf.BindAddress, ftpdConf.BindPort))
  173. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  174. waitTCPListening(fmt.Sprintf("%s:%d", sftpdConf.BindAddress, sftpdConf.BindPort))
  175. ftpd.ReloadTLSCertificate() //nolint:errcheck
  176. exitCode := m.Run()
  177. os.Remove(logFilePath)
  178. os.Remove(bannerFile)
  179. os.Remove(extAuthPath)
  180. os.Remove(preLoginPath)
  181. os.Remove(postConnectPath)
  182. os.Remove(certPath)
  183. os.Remove(keyPath)
  184. os.Exit(exitCode)
  185. }
  186. func TestInitialization(t *testing.T) {
  187. ftpdConf := config.GetFTPDConfig()
  188. ftpdConf.BindPort = 2121
  189. ftpdConf.CertificateFile = filepath.Join(os.TempDir(), "test_ftpd.crt")
  190. ftpdConf.CertificateKeyFile = filepath.Join(os.TempDir(), "test_ftpd.key")
  191. ftpdConf.TLSMode = 1
  192. err := ftpdConf.Initialize(configDir)
  193. assert.Error(t, err)
  194. status := ftpd.GetStatus()
  195. assert.True(t, status.IsActive)
  196. }
  197. func TestBasicFTPHandling(t *testing.T) {
  198. u := getTestUser()
  199. u.QuotaSize = 6553600
  200. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  201. assert.NoError(t, err)
  202. u = getTestSFTPUser()
  203. u.QuotaSize = 6553600
  204. sftpUser, _, err := httpd.AddUser(u, http.StatusOK)
  205. assert.NoError(t, err)
  206. for _, user := range []dataprovider.User{localUser, sftpUser} {
  207. client, err := getFTPClient(user, true)
  208. if assert.NoError(t, err) {
  209. if user.Username == defaultUsername {
  210. assert.Len(t, common.Connections.GetStats(), 1)
  211. } else {
  212. assert.Len(t, common.Connections.GetStats(), 2)
  213. }
  214. testFilePath := filepath.Join(homeBasePath, testFileName)
  215. testFileSize := int64(65535)
  216. expectedQuotaSize := testFileSize
  217. expectedQuotaFiles := 1
  218. err = createTestFile(testFilePath, testFileSize)
  219. assert.NoError(t, err)
  220. err = checkBasicFTP(client)
  221. assert.NoError(t, err)
  222. err = ftpUploadFile(testFilePath, path.Join("/missing_dir", testFileName), testFileSize, client, 0)
  223. assert.Error(t, err)
  224. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  225. assert.NoError(t, err)
  226. // overwrite an existing file
  227. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  228. assert.NoError(t, err)
  229. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  230. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  231. assert.NoError(t, err)
  232. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  233. assert.NoError(t, err)
  234. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  235. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  236. err = client.Rename(testFileName, testFileName+"1")
  237. assert.NoError(t, err)
  238. err = client.Delete(testFileName)
  239. assert.Error(t, err)
  240. err = client.Delete(testFileName + "1")
  241. assert.NoError(t, err)
  242. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  243. assert.NoError(t, err)
  244. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  245. assert.Equal(t, expectedQuotaSize-testFileSize, user.UsedQuotaSize)
  246. curDir, err := client.CurrentDir()
  247. if assert.NoError(t, err) {
  248. assert.Equal(t, "/", curDir)
  249. }
  250. testDir := "testDir"
  251. err = client.MakeDir(testDir)
  252. assert.NoError(t, err)
  253. err = client.ChangeDir(testDir)
  254. assert.NoError(t, err)
  255. curDir, err = client.CurrentDir()
  256. if assert.NoError(t, err) {
  257. assert.Equal(t, path.Join("/", testDir), curDir)
  258. }
  259. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  260. assert.NoError(t, err)
  261. size, err := client.FileSize(path.Join("/", testDir, testFileName))
  262. assert.NoError(t, err)
  263. assert.Equal(t, testFileSize, size)
  264. err = client.ChangeDirToParent()
  265. assert.NoError(t, err)
  266. curDir, err = client.CurrentDir()
  267. if assert.NoError(t, err) {
  268. assert.Equal(t, "/", curDir)
  269. }
  270. err = client.Delete(path.Join("/", testDir, testFileName))
  271. assert.NoError(t, err)
  272. err = client.Delete(testDir)
  273. assert.Error(t, err)
  274. err = client.RemoveDir(testDir)
  275. assert.NoError(t, err)
  276. err = os.Remove(testFilePath)
  277. assert.NoError(t, err)
  278. err = os.Remove(localDownloadPath)
  279. assert.NoError(t, err)
  280. err = client.Quit()
  281. assert.NoError(t, err)
  282. }
  283. }
  284. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  285. assert.NoError(t, err)
  286. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  287. assert.NoError(t, err)
  288. err = os.RemoveAll(localUser.GetHomeDir())
  289. assert.NoError(t, err)
  290. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  291. }
  292. func TestLoginInvalidPwd(t *testing.T) {
  293. u := getTestUser()
  294. user, _, err := httpd.AddUser(u, http.StatusOK)
  295. assert.NoError(t, err)
  296. user.Password = "wrong"
  297. _, err = getFTPClient(user, false)
  298. assert.Error(t, err)
  299. _, err = httpd.RemoveUser(user, http.StatusOK)
  300. assert.NoError(t, err)
  301. }
  302. func TestLoginExternalAuth(t *testing.T) {
  303. if runtime.GOOS == osWindows {
  304. t.Skip("this test is not available on Windows")
  305. }
  306. u := getTestUser()
  307. err := dataprovider.Close()
  308. assert.NoError(t, err)
  309. err = config.LoadConfig(configDir, "")
  310. assert.NoError(t, err)
  311. providerConf := config.GetProviderConf()
  312. err = ioutil.WriteFile(extAuthPath, getExtAuthScriptContent(u, false, ""), os.ModePerm)
  313. assert.NoError(t, err)
  314. providerConf.ExternalAuthHook = extAuthPath
  315. providerConf.ExternalAuthScope = 0
  316. err = dataprovider.Initialize(providerConf, configDir)
  317. assert.NoError(t, err)
  318. client, err := getFTPClient(u, true)
  319. if assert.NoError(t, err) {
  320. err = checkBasicFTP(client)
  321. assert.NoError(t, err)
  322. err := client.Quit()
  323. assert.NoError(t, err)
  324. }
  325. u.Username = defaultUsername + "1"
  326. client, err = getFTPClient(u, true)
  327. if !assert.Error(t, err) {
  328. err := client.Quit()
  329. assert.NoError(t, err)
  330. }
  331. users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  332. assert.NoError(t, err)
  333. if assert.Len(t, users, 1) {
  334. user := users[0]
  335. assert.Equal(t, defaultUsername, user.Username)
  336. _, err = httpd.RemoveUser(user, http.StatusOK)
  337. assert.NoError(t, err)
  338. err = os.RemoveAll(user.GetHomeDir())
  339. assert.NoError(t, err)
  340. }
  341. err = dataprovider.Close()
  342. assert.NoError(t, err)
  343. err = config.LoadConfig(configDir, "")
  344. assert.NoError(t, err)
  345. providerConf = config.GetProviderConf()
  346. err = dataprovider.Initialize(providerConf, configDir)
  347. assert.NoError(t, err)
  348. err = os.Remove(extAuthPath)
  349. assert.NoError(t, err)
  350. }
  351. func TestPreLoginHook(t *testing.T) {
  352. if runtime.GOOS == osWindows {
  353. t.Skip("this test is not available on Windows")
  354. }
  355. u := getTestUser()
  356. err := dataprovider.Close()
  357. assert.NoError(t, err)
  358. err = config.LoadConfig(configDir, "")
  359. assert.NoError(t, err)
  360. providerConf := config.GetProviderConf()
  361. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(u, false), os.ModePerm)
  362. assert.NoError(t, err)
  363. providerConf.PreLoginHook = preLoginPath
  364. err = dataprovider.Initialize(providerConf, configDir)
  365. assert.NoError(t, err)
  366. users, _, err := httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  367. assert.NoError(t, err)
  368. assert.Equal(t, 0, len(users))
  369. client, err := getFTPClient(u, false)
  370. if assert.NoError(t, err) {
  371. err = checkBasicFTP(client)
  372. assert.NoError(t, err)
  373. err := client.Quit()
  374. assert.NoError(t, err)
  375. }
  376. users, _, err = httpd.GetUsers(0, 0, defaultUsername, http.StatusOK)
  377. assert.NoError(t, err)
  378. assert.Equal(t, 1, len(users))
  379. user := users[0]
  380. // test login with an existing user
  381. client, err = getFTPClient(user, true)
  382. if assert.NoError(t, err) {
  383. err = checkBasicFTP(client)
  384. assert.NoError(t, err)
  385. err := client.Quit()
  386. assert.NoError(t, err)
  387. }
  388. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, true), os.ModePerm)
  389. assert.NoError(t, err)
  390. client, err = getFTPClient(u, false)
  391. if !assert.Error(t, err) {
  392. err := client.Quit()
  393. assert.NoError(t, err)
  394. }
  395. user.Status = 0
  396. err = ioutil.WriteFile(preLoginPath, getPreLoginScriptContent(user, false), os.ModePerm)
  397. assert.NoError(t, err)
  398. client, err = getFTPClient(u, false)
  399. if !assert.Error(t, err, "pre-login script returned a disabled user, login must fail") {
  400. err := client.Quit()
  401. assert.NoError(t, err)
  402. }
  403. _, err = httpd.RemoveUser(user, http.StatusOK)
  404. assert.NoError(t, err)
  405. err = os.RemoveAll(user.GetHomeDir())
  406. assert.NoError(t, err)
  407. err = dataprovider.Close()
  408. assert.NoError(t, err)
  409. err = config.LoadConfig(configDir, "")
  410. assert.NoError(t, err)
  411. providerConf = config.GetProviderConf()
  412. err = dataprovider.Initialize(providerConf, configDir)
  413. assert.NoError(t, err)
  414. err = os.Remove(preLoginPath)
  415. assert.NoError(t, err)
  416. }
  417. func TestPostConnectHook(t *testing.T) {
  418. if runtime.GOOS == osWindows {
  419. t.Skip("this test is not available on Windows")
  420. }
  421. common.Config.PostConnectHook = postConnectPath
  422. u := getTestUser()
  423. user, _, err := httpd.AddUser(u, http.StatusOK)
  424. assert.NoError(t, err)
  425. err = ioutil.WriteFile(postConnectPath, getPostConnectScriptContent(0), os.ModePerm)
  426. assert.NoError(t, err)
  427. client, err := getFTPClient(user, true)
  428. if assert.NoError(t, err) {
  429. err = checkBasicFTP(client)
  430. assert.NoError(t, err)
  431. err := client.Quit()
  432. assert.NoError(t, err)
  433. }
  434. err = ioutil.WriteFile(postConnectPath, getPostConnectScriptContent(1), os.ModePerm)
  435. assert.NoError(t, err)
  436. client, err = getFTPClient(user, true)
  437. if !assert.Error(t, err) {
  438. err := client.Quit()
  439. assert.NoError(t, err)
  440. }
  441. common.Config.PostConnectHook = "http://127.0.0.1:8079/api/v1/version"
  442. client, err = getFTPClient(user, false)
  443. if assert.NoError(t, err) {
  444. err = checkBasicFTP(client)
  445. assert.NoError(t, err)
  446. err := client.Quit()
  447. assert.NoError(t, err)
  448. }
  449. common.Config.PostConnectHook = "http://127.0.0.1:8079/notfound"
  450. client, err = getFTPClient(user, true)
  451. if !assert.Error(t, err) {
  452. err := client.Quit()
  453. assert.NoError(t, err)
  454. }
  455. _, err = httpd.RemoveUser(user, http.StatusOK)
  456. assert.NoError(t, err)
  457. err = os.RemoveAll(user.GetHomeDir())
  458. assert.NoError(t, err)
  459. common.Config.PostConnectHook = ""
  460. }
  461. func TestMaxSessions(t *testing.T) {
  462. u := getTestUser()
  463. u.MaxSessions = 1
  464. user, _, err := httpd.AddUser(u, http.StatusOK)
  465. assert.NoError(t, err)
  466. client, err := getFTPClient(user, true)
  467. if assert.NoError(t, err) {
  468. err = checkBasicFTP(client)
  469. assert.NoError(t, err)
  470. _, err = getFTPClient(user, false)
  471. assert.Error(t, err)
  472. err = client.Quit()
  473. assert.NoError(t, err)
  474. }
  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 TestZeroBytesTransfers(t *testing.T) {
  481. u := getTestUser()
  482. user, _, err := httpd.AddUser(u, http.StatusOK)
  483. assert.NoError(t, err)
  484. for _, useTLS := range []bool{true, false} {
  485. client, err := getFTPClient(user, useTLS)
  486. if assert.NoError(t, err) {
  487. testFileName := "testfilename"
  488. err = checkBasicFTP(client)
  489. assert.NoError(t, err)
  490. localDownloadPath := filepath.Join(homeBasePath, "empty_download")
  491. err = ioutil.WriteFile(localDownloadPath, []byte(""), os.ModePerm)
  492. assert.NoError(t, err)
  493. err = ftpUploadFile(localDownloadPath, testFileName, 0, client, 0)
  494. assert.NoError(t, err)
  495. size, err := client.FileSize(testFileName)
  496. assert.NoError(t, err)
  497. assert.Equal(t, int64(0), size)
  498. err = os.Remove(localDownloadPath)
  499. assert.NoError(t, err)
  500. assert.NoFileExists(t, localDownloadPath)
  501. err = ftpDownloadFile(testFileName, localDownloadPath, 0, client, 0)
  502. assert.NoError(t, err)
  503. assert.FileExists(t, localDownloadPath)
  504. err = client.Quit()
  505. assert.NoError(t, err)
  506. err = os.Remove(localDownloadPath)
  507. assert.NoError(t, err)
  508. }
  509. }
  510. _, err = httpd.RemoveUser(user, http.StatusOK)
  511. assert.NoError(t, err)
  512. err = os.RemoveAll(user.GetHomeDir())
  513. assert.NoError(t, err)
  514. }
  515. func TestDownloadErrors(t *testing.T) {
  516. u := getTestUser()
  517. u.QuotaFiles = 1
  518. subDir1 := "sub1"
  519. subDir2 := "sub2"
  520. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  521. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  522. dataprovider.PermDelete, dataprovider.PermDownload}
  523. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  524. {
  525. Path: "/sub2",
  526. AllowedExtensions: []string{},
  527. DeniedExtensions: []string{".zip"},
  528. },
  529. }
  530. u.Filters.FilePatterns = []dataprovider.PatternsFilter{
  531. {
  532. Path: "/sub2",
  533. AllowedPatterns: []string{},
  534. DeniedPatterns: []string{"*.jpg"},
  535. },
  536. }
  537. user, _, err := httpd.AddUser(u, http.StatusOK)
  538. assert.NoError(t, err)
  539. client, err := getFTPClient(user, true)
  540. if assert.NoError(t, err) {
  541. testFilePath1 := filepath.Join(user.HomeDir, subDir1, "file.zip")
  542. testFilePath2 := filepath.Join(user.HomeDir, subDir2, "file.zip")
  543. testFilePath3 := filepath.Join(user.HomeDir, subDir2, "file.jpg")
  544. err = os.MkdirAll(filepath.Dir(testFilePath1), os.ModePerm)
  545. assert.NoError(t, err)
  546. err = os.MkdirAll(filepath.Dir(testFilePath2), os.ModePerm)
  547. assert.NoError(t, err)
  548. err = ioutil.WriteFile(testFilePath1, []byte("file1"), os.ModePerm)
  549. assert.NoError(t, err)
  550. err = ioutil.WriteFile(testFilePath2, []byte("file2"), os.ModePerm)
  551. assert.NoError(t, err)
  552. err = ioutil.WriteFile(testFilePath3, []byte("file3"), os.ModePerm)
  553. assert.NoError(t, err)
  554. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  555. err = ftpDownloadFile(path.Join("/", subDir1, "file.zip"), localDownloadPath, 5, client, 0)
  556. assert.Error(t, err)
  557. err = ftpDownloadFile(path.Join("/", subDir2, "file.zip"), localDownloadPath, 5, client, 0)
  558. assert.Error(t, err)
  559. err = ftpDownloadFile(path.Join("/", subDir2, "file.jpg"), localDownloadPath, 5, client, 0)
  560. assert.Error(t, err)
  561. err = ftpDownloadFile("/missing.zip", localDownloadPath, 5, client, 0)
  562. assert.Error(t, err)
  563. err = client.Quit()
  564. assert.NoError(t, err)
  565. err = os.Remove(localDownloadPath)
  566. assert.NoError(t, err)
  567. }
  568. _, err = httpd.RemoveUser(user, http.StatusOK)
  569. assert.NoError(t, err)
  570. err = os.RemoveAll(user.GetHomeDir())
  571. assert.NoError(t, err)
  572. }
  573. func TestUploadErrors(t *testing.T) {
  574. u := getTestUser()
  575. u.QuotaSize = 65535
  576. subDir1 := "sub1"
  577. subDir2 := "sub2"
  578. u.Permissions[path.Join("/", subDir1)] = []string{dataprovider.PermListItems}
  579. u.Permissions[path.Join("/", subDir2)] = []string{dataprovider.PermListItems, dataprovider.PermUpload,
  580. dataprovider.PermDelete}
  581. u.Filters.FileExtensions = []dataprovider.ExtensionsFilter{
  582. {
  583. Path: "/sub2",
  584. AllowedExtensions: []string{},
  585. DeniedExtensions: []string{".zip"},
  586. },
  587. }
  588. user, _, err := httpd.AddUser(u, http.StatusOK)
  589. assert.NoError(t, err)
  590. client, err := getFTPClient(user, true)
  591. if assert.NoError(t, err) {
  592. testFilePath := filepath.Join(homeBasePath, testFileName)
  593. testFileSize := user.QuotaSize
  594. err = createTestFile(testFilePath, testFileSize)
  595. assert.NoError(t, err)
  596. err = client.MakeDir(subDir1)
  597. assert.NoError(t, err)
  598. err = client.MakeDir(subDir2)
  599. assert.NoError(t, err)
  600. err = client.ChangeDir(subDir1)
  601. assert.NoError(t, err)
  602. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  603. assert.Error(t, err)
  604. err = client.ChangeDirToParent()
  605. assert.NoError(t, err)
  606. err = client.ChangeDir(subDir2)
  607. assert.NoError(t, err)
  608. err = ftpUploadFile(testFilePath, testFileName+".zip", testFileSize, client, 0)
  609. assert.Error(t, err)
  610. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  611. assert.NoError(t, err)
  612. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  613. assert.Error(t, err)
  614. err = client.ChangeDir("/")
  615. assert.NoError(t, err)
  616. err = ftpUploadFile(testFilePath, subDir1, testFileSize, client, 0)
  617. assert.Error(t, err)
  618. // overquota
  619. err = ftpUploadFile(testFilePath, testFileName+"1", testFileSize, client, 0)
  620. assert.Error(t, err)
  621. err = client.Delete(path.Join("/", subDir2, testFileName))
  622. assert.NoError(t, err)
  623. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  624. assert.NoError(t, err)
  625. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  626. assert.Error(t, err)
  627. err = client.Quit()
  628. assert.NoError(t, err)
  629. err = os.Remove(testFilePath)
  630. assert.NoError(t, err)
  631. }
  632. _, err = httpd.RemoveUser(user, http.StatusOK)
  633. assert.NoError(t, err)
  634. err = os.RemoveAll(user.GetHomeDir())
  635. assert.NoError(t, err)
  636. }
  637. func TestResume(t *testing.T) {
  638. u := getTestUser()
  639. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  640. assert.NoError(t, err)
  641. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  642. assert.NoError(t, err)
  643. for _, user := range []dataprovider.User{localUser, sftpUser} {
  644. client, err := getFTPClient(user, true)
  645. if assert.NoError(t, err) {
  646. testFilePath := filepath.Join(homeBasePath, testFileName)
  647. data := []byte("test data")
  648. err = ioutil.WriteFile(testFilePath, data, os.ModePerm)
  649. assert.NoError(t, err)
  650. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  651. assert.NoError(t, err)
  652. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  653. assert.NoError(t, err)
  654. readed, err := ioutil.ReadFile(filepath.Join(user.GetHomeDir(), testFileName))
  655. assert.NoError(t, err)
  656. assert.Equal(t, "test test data", string(readed))
  657. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  658. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 5)
  659. assert.NoError(t, err)
  660. readed, err = ioutil.ReadFile(localDownloadPath)
  661. assert.NoError(t, err)
  662. assert.Equal(t, data, readed)
  663. err = client.Delete(testFileName)
  664. assert.NoError(t, err)
  665. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  666. assert.NoError(t, err)
  667. // now append to a file
  668. srcFile, err := os.Open(testFilePath)
  669. if assert.NoError(t, err) {
  670. err = client.Append(testFileName, srcFile)
  671. assert.NoError(t, err)
  672. err = srcFile.Close()
  673. assert.NoError(t, err)
  674. size, err := client.FileSize(testFileName)
  675. assert.NoError(t, err)
  676. assert.Equal(t, int64(2*len(data)), size)
  677. err = ftpDownloadFile(testFileName, localDownloadPath, int64(2*len(data)), client, 0)
  678. assert.NoError(t, err)
  679. readed, err = ioutil.ReadFile(localDownloadPath)
  680. assert.NoError(t, err)
  681. expected := append(data, data...)
  682. assert.Equal(t, expected, readed)
  683. }
  684. err = client.Quit()
  685. assert.NoError(t, err)
  686. err = os.Remove(testFilePath)
  687. assert.NoError(t, err)
  688. err = os.Remove(localDownloadPath)
  689. assert.NoError(t, err)
  690. if user.Username == defaultUsername {
  691. err = os.RemoveAll(user.GetHomeDir())
  692. assert.NoError(t, err)
  693. }
  694. }
  695. }
  696. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  697. assert.NoError(t, err)
  698. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  699. assert.NoError(t, err)
  700. err = os.RemoveAll(localUser.GetHomeDir())
  701. assert.NoError(t, err)
  702. }
  703. //nolint:dupl
  704. func TestDeniedLoginMethod(t *testing.T) {
  705. u := getTestUser()
  706. u.Filters.DeniedLoginMethods = []string{dataprovider.LoginMethodPassword}
  707. user, _, err := httpd.AddUser(u, http.StatusOK)
  708. assert.NoError(t, err)
  709. _, err = getFTPClient(user, false)
  710. assert.Error(t, err)
  711. user.Filters.DeniedLoginMethods = []string{dataprovider.SSHLoginMethodPublicKey, dataprovider.SSHLoginMethodKeyAndPassword}
  712. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  713. assert.NoError(t, err)
  714. client, err := getFTPClient(user, true)
  715. if assert.NoError(t, err) {
  716. assert.NoError(t, checkBasicFTP(client))
  717. err = client.Quit()
  718. assert.NoError(t, err)
  719. }
  720. _, err = httpd.RemoveUser(user, http.StatusOK)
  721. assert.NoError(t, err)
  722. err = os.RemoveAll(user.GetHomeDir())
  723. assert.NoError(t, err)
  724. }
  725. //nolint:dupl
  726. func TestDeniedProtocols(t *testing.T) {
  727. u := getTestUser()
  728. u.Filters.DeniedProtocols = []string{common.ProtocolFTP}
  729. user, _, err := httpd.AddUser(u, http.StatusOK)
  730. assert.NoError(t, err)
  731. _, err = getFTPClient(user, false)
  732. assert.Error(t, err)
  733. user.Filters.DeniedProtocols = []string{common.ProtocolSSH, common.ProtocolWebDAV}
  734. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  735. assert.NoError(t, err)
  736. client, err := getFTPClient(user, true)
  737. if assert.NoError(t, err) {
  738. assert.NoError(t, checkBasicFTP(client))
  739. err = client.Quit()
  740. assert.NoError(t, err)
  741. }
  742. _, err = httpd.RemoveUser(user, http.StatusOK)
  743. assert.NoError(t, err)
  744. err = os.RemoveAll(user.GetHomeDir())
  745. assert.NoError(t, err)
  746. }
  747. func TestQuotaLimits(t *testing.T) {
  748. u := getTestUser()
  749. u.QuotaFiles = 1
  750. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  751. assert.NoError(t, err)
  752. u = getTestSFTPUser()
  753. u.QuotaFiles = 1
  754. sftpUser, _, err := httpd.AddUser(u, http.StatusOK)
  755. assert.NoError(t, err)
  756. for _, user := range []dataprovider.User{localUser, sftpUser} {
  757. testFileSize := int64(65535)
  758. testFilePath := filepath.Join(homeBasePath, testFileName)
  759. err = createTestFile(testFilePath, testFileSize)
  760. assert.NoError(t, err)
  761. testFileSize1 := int64(131072)
  762. testFileName1 := "test_file1.dat"
  763. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  764. err = createTestFile(testFilePath1, testFileSize1)
  765. assert.NoError(t, err)
  766. testFileSize2 := int64(32768)
  767. testFileName2 := "test_file2.dat"
  768. testFilePath2 := filepath.Join(homeBasePath, testFileName2)
  769. err = createTestFile(testFilePath2, testFileSize2)
  770. assert.NoError(t, err)
  771. // test quota files
  772. client, err := getFTPClient(user, false)
  773. if assert.NoError(t, err) {
  774. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  775. assert.NoError(t, err)
  776. err = ftpUploadFile(testFilePath, testFileName+".quota1", testFileSize, client, 0)
  777. assert.Error(t, err)
  778. err = client.Rename(testFileName+".quota", testFileName)
  779. assert.NoError(t, err)
  780. err = client.Quit()
  781. assert.NoError(t, err)
  782. }
  783. // test quota size
  784. user.QuotaSize = testFileSize - 1
  785. user.QuotaFiles = 0
  786. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  787. assert.NoError(t, err)
  788. client, err = getFTPClient(user, true)
  789. if assert.NoError(t, err) {
  790. err = ftpUploadFile(testFilePath, testFileName+".quota", testFileSize, client, 0)
  791. assert.Error(t, err)
  792. err = client.Rename(testFileName, testFileName+".quota")
  793. assert.NoError(t, err)
  794. err = client.Quit()
  795. assert.NoError(t, err)
  796. }
  797. // now test quota limits while uploading the current file, we have 1 bytes remaining
  798. user.QuotaSize = testFileSize + 1
  799. user.QuotaFiles = 0
  800. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  801. assert.NoError(t, err)
  802. client, err = getFTPClient(user, false)
  803. if assert.NoError(t, err) {
  804. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  805. assert.Error(t, err)
  806. _, err = client.FileSize(testFileName1)
  807. assert.Error(t, err)
  808. err = client.Rename(testFileName+".quota", testFileName)
  809. assert.NoError(t, err)
  810. // overwriting an existing file will work if the resulting size is lesser or equal than the current one
  811. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  812. assert.NoError(t, err)
  813. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  814. assert.NoError(t, err)
  815. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 0)
  816. assert.Error(t, err)
  817. err = ftpUploadFile(testFilePath1, testFileName, testFileSize1, client, 10)
  818. assert.Error(t, err)
  819. err = ftpUploadFile(testFilePath2, testFileName, testFileSize2, client, 0)
  820. assert.NoError(t, err)
  821. err = client.Quit()
  822. assert.NoError(t, err)
  823. }
  824. err = os.Remove(testFilePath)
  825. assert.NoError(t, err)
  826. err = os.Remove(testFilePath1)
  827. assert.NoError(t, err)
  828. err = os.Remove(testFilePath2)
  829. assert.NoError(t, err)
  830. if user.Username == defaultUsername {
  831. err = os.RemoveAll(user.GetHomeDir())
  832. assert.NoError(t, err)
  833. user.QuotaFiles = 0
  834. user.QuotaSize = 0
  835. _, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  836. assert.NoError(t, err)
  837. }
  838. }
  839. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  840. assert.NoError(t, err)
  841. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  842. assert.NoError(t, err)
  843. err = os.RemoveAll(localUser.GetHomeDir())
  844. assert.NoError(t, err)
  845. }
  846. func TestUploadMaxSize(t *testing.T) {
  847. testFileSize := int64(65535)
  848. u := getTestUser()
  849. u.Filters.MaxUploadFileSize = testFileSize + 1
  850. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  851. assert.NoError(t, err)
  852. u = getTestSFTPUser()
  853. u.Filters.MaxUploadFileSize = testFileSize + 1
  854. sftpUser, _, err := httpd.AddUser(u, http.StatusOK)
  855. assert.NoError(t, err)
  856. for _, user := range []dataprovider.User{localUser, sftpUser} {
  857. testFilePath := filepath.Join(homeBasePath, testFileName)
  858. err = createTestFile(testFilePath, testFileSize)
  859. assert.NoError(t, err)
  860. testFileSize1 := int64(131072)
  861. testFileName1 := "test_file1.dat"
  862. testFilePath1 := filepath.Join(homeBasePath, testFileName1)
  863. err = createTestFile(testFilePath1, testFileSize1)
  864. assert.NoError(t, err)
  865. client, err := getFTPClient(user, false)
  866. if assert.NoError(t, err) {
  867. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  868. assert.Error(t, err)
  869. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  870. assert.NoError(t, err)
  871. // now test overwrite an existing file with a size bigger than the allowed one
  872. err = createTestFile(filepath.Join(user.GetHomeDir(), testFileName1), testFileSize1)
  873. assert.NoError(t, err)
  874. err = ftpUploadFile(testFilePath1, testFileName1, testFileSize1, client, 0)
  875. assert.Error(t, err)
  876. err = client.Quit()
  877. assert.NoError(t, err)
  878. }
  879. err = os.Remove(testFilePath)
  880. assert.NoError(t, err)
  881. err = os.Remove(testFilePath1)
  882. assert.NoError(t, err)
  883. if user.Username == defaultUsername {
  884. err = os.RemoveAll(user.GetHomeDir())
  885. assert.NoError(t, err)
  886. user.Filters.MaxUploadFileSize = 65536000
  887. _, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  888. assert.NoError(t, err)
  889. }
  890. }
  891. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  892. assert.NoError(t, err)
  893. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  894. assert.NoError(t, err)
  895. err = os.RemoveAll(localUser.GetHomeDir())
  896. assert.NoError(t, err)
  897. }
  898. func TestLoginWithIPilters(t *testing.T) {
  899. u := getTestUser()
  900. u.Filters.DeniedIP = []string{"192.167.0.0/24", "172.18.0.0/16"}
  901. u.Filters.AllowedIP = []string{"172.19.0.0/16"}
  902. user, _, err := httpd.AddUser(u, http.StatusOK)
  903. assert.NoError(t, err)
  904. client, err := getFTPClient(user, true)
  905. if !assert.Error(t, err) {
  906. err = client.Quit()
  907. assert.NoError(t, err)
  908. }
  909. _, err = httpd.RemoveUser(user, http.StatusOK)
  910. assert.NoError(t, err)
  911. err = os.RemoveAll(user.GetHomeDir())
  912. assert.NoError(t, err)
  913. }
  914. func TestLoginWithDatabaseCredentials(t *testing.T) {
  915. u := getTestUser()
  916. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  917. u.FsConfig.GCSConfig.Bucket = "test"
  918. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret(`{ "type": "service_account" }`)
  919. providerConf := config.GetProviderConf()
  920. providerConf.PreferDatabaseCredentials = true
  921. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  922. if !filepath.IsAbs(credentialsFile) {
  923. credentialsFile = filepath.Join(configDir, credentialsFile)
  924. }
  925. assert.NoError(t, dataprovider.Close())
  926. err := dataprovider.Initialize(providerConf, configDir)
  927. assert.NoError(t, err)
  928. if _, err = os.Stat(credentialsFile); err == nil {
  929. // remove the credentials file
  930. assert.NoError(t, os.Remove(credentialsFile))
  931. }
  932. user, _, err := httpd.AddUser(u, http.StatusOK)
  933. assert.NoError(t, err)
  934. assert.Equal(t, kms.SecretStatusSecretBox, user.FsConfig.GCSConfig.Credentials.GetStatus())
  935. assert.NotEmpty(t, user.FsConfig.GCSConfig.Credentials.GetPayload())
  936. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetAdditionalData())
  937. assert.Empty(t, user.FsConfig.GCSConfig.Credentials.GetKey())
  938. assert.NoFileExists(t, credentialsFile)
  939. client, err := getFTPClient(user, false)
  940. if assert.NoError(t, err) {
  941. err = client.Quit()
  942. assert.NoError(t, err)
  943. }
  944. _, err = httpd.RemoveUser(user, http.StatusOK)
  945. assert.NoError(t, err)
  946. err = os.RemoveAll(user.GetHomeDir())
  947. assert.NoError(t, err)
  948. assert.NoError(t, dataprovider.Close())
  949. assert.NoError(t, config.LoadConfig(configDir, ""))
  950. providerConf = config.GetProviderConf()
  951. assert.NoError(t, dataprovider.Initialize(providerConf, configDir))
  952. }
  953. func TestLoginInvalidFs(t *testing.T) {
  954. u := getTestUser()
  955. u.FsConfig.Provider = dataprovider.GCSFilesystemProvider
  956. u.FsConfig.GCSConfig.Bucket = "test"
  957. u.FsConfig.GCSConfig.Credentials = kms.NewPlainSecret("invalid JSON for credentials")
  958. user, _, err := httpd.AddUser(u, http.StatusOK)
  959. assert.NoError(t, err)
  960. providerConf := config.GetProviderConf()
  961. credentialsFile := filepath.Join(providerConf.CredentialsPath, fmt.Sprintf("%v_gcs_credentials.json", u.Username))
  962. if !filepath.IsAbs(credentialsFile) {
  963. credentialsFile = filepath.Join(configDir, credentialsFile)
  964. }
  965. // now remove the credentials file so the filesystem creation will fail
  966. err = os.Remove(credentialsFile)
  967. assert.NoError(t, err)
  968. client, err := getFTPClient(user, false)
  969. if !assert.Error(t, err) {
  970. err = client.Quit()
  971. assert.NoError(t, err)
  972. }
  973. _, err = httpd.RemoveUser(user, http.StatusOK)
  974. assert.NoError(t, err)
  975. err = os.RemoveAll(user.GetHomeDir())
  976. assert.NoError(t, err)
  977. }
  978. func TestClientClose(t *testing.T) {
  979. u := getTestUser()
  980. user, _, err := httpd.AddUser(u, http.StatusOK)
  981. assert.NoError(t, err)
  982. client, err := getFTPClient(user, true)
  983. if assert.NoError(t, err) {
  984. err = checkBasicFTP(client)
  985. assert.NoError(t, err)
  986. stats := common.Connections.GetStats()
  987. if assert.Len(t, stats, 1) {
  988. common.Connections.Close(stats[0].ConnectionID)
  989. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 },
  990. 1*time.Second, 50*time.Millisecond)
  991. }
  992. }
  993. _, err = httpd.RemoveUser(user, http.StatusOK)
  994. assert.NoError(t, err)
  995. err = os.RemoveAll(user.GetHomeDir())
  996. assert.NoError(t, err)
  997. }
  998. func TestRename(t *testing.T) {
  999. u := getTestUser()
  1000. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  1001. assert.NoError(t, err)
  1002. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  1003. assert.NoError(t, err)
  1004. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1005. testDir := "adir"
  1006. testFilePath := filepath.Join(homeBasePath, testFileName)
  1007. testFileSize := int64(65535)
  1008. err = createTestFile(testFilePath, testFileSize)
  1009. assert.NoError(t, err)
  1010. client, err := getFTPClient(user, false)
  1011. if assert.NoError(t, err) {
  1012. err = checkBasicFTP(client)
  1013. assert.NoError(t, err)
  1014. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1015. assert.NoError(t, err)
  1016. err = client.MakeDir(testDir)
  1017. assert.NoError(t, err)
  1018. err = client.Rename(testFileName, path.Join("missing", testFileName))
  1019. assert.Error(t, err)
  1020. err = client.Rename(testFileName, path.Join(testDir, testFileName))
  1021. assert.NoError(t, err)
  1022. size, err := client.FileSize(path.Join(testDir, testFileName))
  1023. assert.NoError(t, err)
  1024. assert.Equal(t, testFileSize, size)
  1025. if runtime.GOOS != osWindows {
  1026. otherDir := "dir"
  1027. err = client.MakeDir(otherDir)
  1028. assert.NoError(t, err)
  1029. err = client.MakeDir(path.Join(otherDir, testDir))
  1030. assert.NoError(t, err)
  1031. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  1032. assert.NoError(t, err)
  1033. assert.Equal(t, ftp.StatusCommandOK, code)
  1034. assert.Equal(t, "SITE CHMOD command successful", response)
  1035. err = client.Rename(testDir, path.Join(otherDir, testDir))
  1036. assert.Error(t, err)
  1037. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  1038. assert.NoError(t, err)
  1039. assert.Equal(t, ftp.StatusCommandOK, code)
  1040. assert.Equal(t, "SITE CHMOD command successful", response)
  1041. }
  1042. err = client.Quit()
  1043. assert.NoError(t, err)
  1044. }
  1045. user.Permissions[path.Join("/", testDir)] = []string{dataprovider.PermListItems}
  1046. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1047. assert.NoError(t, err)
  1048. client, err = getFTPClient(user, false)
  1049. if assert.NoError(t, err) {
  1050. err = client.Rename(path.Join(testDir, testFileName), testFileName)
  1051. assert.Error(t, err)
  1052. err := client.Quit()
  1053. assert.NoError(t, err)
  1054. }
  1055. err = os.Remove(testFilePath)
  1056. assert.NoError(t, err)
  1057. if user.Username == defaultUsername {
  1058. user.Permissions = make(map[string][]string)
  1059. user.Permissions["/"] = allPerms
  1060. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1061. assert.NoError(t, err)
  1062. err = os.RemoveAll(user.GetHomeDir())
  1063. assert.NoError(t, err)
  1064. }
  1065. }
  1066. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  1067. assert.NoError(t, err)
  1068. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  1069. assert.NoError(t, err)
  1070. err = os.RemoveAll(localUser.GetHomeDir())
  1071. assert.NoError(t, err)
  1072. }
  1073. func TestSymlink(t *testing.T) {
  1074. u := getTestUser()
  1075. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  1076. assert.NoError(t, err)
  1077. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  1078. assert.NoError(t, err)
  1079. testFilePath := filepath.Join(homeBasePath, testFileName)
  1080. testFileSize := int64(65535)
  1081. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1082. err = createTestFile(testFilePath, testFileSize)
  1083. assert.NoError(t, err)
  1084. client, err := getFTPClient(user, false)
  1085. if assert.NoError(t, err) {
  1086. err = checkBasicFTP(client)
  1087. assert.NoError(t, err)
  1088. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1089. assert.NoError(t, err)
  1090. code, _, err := client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testFileName, testFileName+".link"))
  1091. assert.NoError(t, err)
  1092. assert.Equal(t, ftp.StatusCommandOK, code)
  1093. if runtime.GOOS != osWindows {
  1094. testDir := "adir"
  1095. otherDir := "dir"
  1096. err = client.MakeDir(otherDir)
  1097. assert.NoError(t, err)
  1098. err = client.MakeDir(path.Join(otherDir, testDir))
  1099. assert.NoError(t, err)
  1100. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 0001 %v", otherDir))
  1101. assert.NoError(t, err)
  1102. assert.Equal(t, ftp.StatusCommandOK, code)
  1103. assert.Equal(t, "SITE CHMOD command successful", response)
  1104. code, _, err = client.SendCustomCommand(fmt.Sprintf("SITE SYMLINK %v %v", testDir, path.Join(otherDir, testDir)))
  1105. assert.NoError(t, err)
  1106. assert.Equal(t, ftp.StatusFileUnavailable, code)
  1107. code, response, err = client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 755 %v", otherDir))
  1108. assert.NoError(t, err)
  1109. assert.Equal(t, ftp.StatusCommandOK, code)
  1110. assert.Equal(t, "SITE CHMOD command successful", response)
  1111. }
  1112. err = client.Quit()
  1113. assert.NoError(t, err)
  1114. if user.Username == defaultUsername {
  1115. err = os.RemoveAll(user.GetHomeDir())
  1116. assert.NoError(t, err)
  1117. }
  1118. }
  1119. err = os.Remove(testFilePath)
  1120. assert.NoError(t, err)
  1121. }
  1122. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  1123. assert.NoError(t, err)
  1124. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  1125. assert.NoError(t, err)
  1126. err = os.RemoveAll(localUser.GetHomeDir())
  1127. assert.NoError(t, err)
  1128. }
  1129. func TestStat(t *testing.T) {
  1130. u := getTestUser()
  1131. u.Permissions["/subdir"] = []string{dataprovider.PermUpload}
  1132. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  1133. assert.NoError(t, err)
  1134. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  1135. assert.NoError(t, err)
  1136. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1137. client, err := getFTPClient(user, false)
  1138. if assert.NoError(t, err) {
  1139. subDir := "subdir"
  1140. testFilePath := filepath.Join(homeBasePath, testFileName)
  1141. testFileSize := int64(65535)
  1142. err = createTestFile(testFilePath, testFileSize)
  1143. assert.NoError(t, err)
  1144. err = client.MakeDir(subDir)
  1145. assert.NoError(t, err)
  1146. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1147. assert.NoError(t, err)
  1148. err = ftpUploadFile(testFilePath, path.Join("/", subDir, testFileName), testFileSize, client, 0)
  1149. assert.Error(t, err)
  1150. size, err := client.FileSize(testFileName)
  1151. assert.NoError(t, err)
  1152. assert.Equal(t, testFileSize, size)
  1153. _, err = client.FileSize(path.Join("/", subDir, testFileName))
  1154. assert.Error(t, err)
  1155. _, err = client.FileSize("missing file")
  1156. assert.Error(t, err)
  1157. err = client.Quit()
  1158. assert.NoError(t, err)
  1159. err = os.Remove(testFilePath)
  1160. assert.NoError(t, err)
  1161. if user.Username == defaultUsername {
  1162. err = os.RemoveAll(user.GetHomeDir())
  1163. assert.NoError(t, err)
  1164. }
  1165. }
  1166. }
  1167. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  1168. assert.NoError(t, err)
  1169. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  1170. assert.NoError(t, err)
  1171. err = os.RemoveAll(localUser.GetHomeDir())
  1172. assert.NoError(t, err)
  1173. }
  1174. func TestUploadOverwriteVfolder(t *testing.T) {
  1175. u := getTestUser()
  1176. vdir := "/vdir"
  1177. mappedPath := filepath.Join(os.TempDir(), "vdir")
  1178. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  1179. BaseVirtualFolder: vfs.BaseVirtualFolder{
  1180. MappedPath: mappedPath,
  1181. },
  1182. VirtualPath: vdir,
  1183. QuotaSize: -1,
  1184. QuotaFiles: -1,
  1185. })
  1186. err := os.MkdirAll(mappedPath, os.ModePerm)
  1187. assert.NoError(t, err)
  1188. user, _, err := httpd.AddUser(u, http.StatusOK)
  1189. assert.NoError(t, err)
  1190. client, err := getFTPClient(user, false)
  1191. if assert.NoError(t, err) {
  1192. testFilePath := filepath.Join(homeBasePath, testFileName)
  1193. testFileSize := int64(65535)
  1194. err = createTestFile(testFilePath, testFileSize)
  1195. assert.NoError(t, err)
  1196. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  1197. assert.NoError(t, err)
  1198. folder, _, err := httpd.GetFolders(0, 0, mappedPath, http.StatusOK)
  1199. assert.NoError(t, err)
  1200. if assert.Len(t, folder, 1) {
  1201. f := folder[0]
  1202. assert.Equal(t, testFileSize, f.UsedQuotaSize)
  1203. assert.Equal(t, 1, f.UsedQuotaFiles)
  1204. }
  1205. err = ftpUploadFile(testFilePath, path.Join(vdir, testFileName), testFileSize, client, 0)
  1206. assert.NoError(t, err)
  1207. folder, _, err = httpd.GetFolders(0, 0, mappedPath, http.StatusOK)
  1208. assert.NoError(t, err)
  1209. if assert.Len(t, folder, 1) {
  1210. f := folder[0]
  1211. assert.Equal(t, testFileSize, f.UsedQuotaSize)
  1212. assert.Equal(t, 1, f.UsedQuotaFiles)
  1213. }
  1214. err = client.Quit()
  1215. assert.NoError(t, err)
  1216. err = os.Remove(testFilePath)
  1217. assert.NoError(t, err)
  1218. }
  1219. _, err = httpd.RemoveUser(user, http.StatusOK)
  1220. assert.NoError(t, err)
  1221. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: mappedPath}, http.StatusOK)
  1222. assert.NoError(t, err)
  1223. err = os.RemoveAll(user.GetHomeDir())
  1224. assert.NoError(t, err)
  1225. err = os.RemoveAll(mappedPath)
  1226. assert.NoError(t, err)
  1227. }
  1228. func TestAllocate(t *testing.T) {
  1229. u := getTestUser()
  1230. mappedPath := filepath.Join(os.TempDir(), "vdir")
  1231. u.VirtualFolders = append(u.VirtualFolders, vfs.VirtualFolder{
  1232. BaseVirtualFolder: vfs.BaseVirtualFolder{
  1233. MappedPath: mappedPath,
  1234. },
  1235. VirtualPath: "/vdir",
  1236. QuotaSize: 110,
  1237. })
  1238. err := os.MkdirAll(mappedPath, os.ModePerm)
  1239. assert.NoError(t, err)
  1240. user, _, err := httpd.AddUser(u, http.StatusOK)
  1241. assert.NoError(t, err)
  1242. client, err := getFTPClient(user, false)
  1243. if assert.NoError(t, err) {
  1244. code, response, err := client.SendCustomCommand("allo 2000000")
  1245. assert.NoError(t, err)
  1246. assert.Equal(t, ftp.StatusCommandOK, code)
  1247. assert.Equal(t, "Done !", response)
  1248. err = client.Quit()
  1249. assert.NoError(t, err)
  1250. }
  1251. user.QuotaSize = 100
  1252. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1253. assert.NoError(t, err)
  1254. client, err = getFTPClient(user, false)
  1255. if assert.NoError(t, err) {
  1256. testFilePath := filepath.Join(homeBasePath, testFileName)
  1257. testFileSize := user.QuotaSize - 1
  1258. err = createTestFile(testFilePath, testFileSize)
  1259. assert.NoError(t, err)
  1260. code, response, err := client.SendCustomCommand("allo 99")
  1261. assert.NoError(t, err)
  1262. assert.Equal(t, ftp.StatusCommandOK, code)
  1263. assert.Equal(t, "Done !", response)
  1264. code, response, err = client.SendCustomCommand("allo 100")
  1265. assert.NoError(t, err)
  1266. assert.Equal(t, ftp.StatusCommandOK, code)
  1267. assert.Equal(t, "Done !", response)
  1268. code, response, err = client.SendCustomCommand("allo 150")
  1269. assert.NoError(t, err)
  1270. assert.Equal(t, ftp.StatusFileUnavailable, code)
  1271. assert.Contains(t, response, common.ErrQuotaExceeded.Error())
  1272. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1273. assert.NoError(t, err)
  1274. // we still have space in vdir
  1275. code, response, err = client.SendCustomCommand("allo 50")
  1276. assert.NoError(t, err)
  1277. assert.Equal(t, ftp.StatusCommandOK, code)
  1278. assert.Equal(t, "Done !", response)
  1279. err = ftpUploadFile(testFilePath, path.Join("/vdir", testFileName), testFileSize, client, 0)
  1280. assert.NoError(t, err)
  1281. code, response, err = client.SendCustomCommand("allo 50")
  1282. assert.NoError(t, err)
  1283. assert.Equal(t, ftp.StatusFileUnavailable, code)
  1284. assert.Contains(t, response, common.ErrQuotaExceeded.Error())
  1285. err = client.Quit()
  1286. assert.NoError(t, err)
  1287. err = os.Remove(testFilePath)
  1288. assert.NoError(t, err)
  1289. }
  1290. user.Filters.MaxUploadFileSize = 100
  1291. user.QuotaSize = 0
  1292. user, _, err = httpd.UpdateUser(user, http.StatusOK, "")
  1293. assert.NoError(t, err)
  1294. client, err = getFTPClient(user, false)
  1295. if assert.NoError(t, err) {
  1296. code, response, err := client.SendCustomCommand("allo 99")
  1297. assert.NoError(t, err)
  1298. assert.Equal(t, ftp.StatusCommandOK, code)
  1299. assert.Equal(t, "Done !", response)
  1300. code, response, err = client.SendCustomCommand("allo 150")
  1301. assert.NoError(t, err)
  1302. assert.Equal(t, ftp.StatusFileUnavailable, code)
  1303. assert.Contains(t, response, common.ErrQuotaExceeded.Error())
  1304. err = client.Quit()
  1305. assert.NoError(t, err)
  1306. }
  1307. _, err = httpd.RemoveUser(user, http.StatusOK)
  1308. assert.NoError(t, err)
  1309. _, err = httpd.RemoveFolder(vfs.BaseVirtualFolder{MappedPath: mappedPath}, http.StatusOK)
  1310. assert.NoError(t, err)
  1311. err = os.RemoveAll(user.GetHomeDir())
  1312. assert.NoError(t, err)
  1313. err = os.RemoveAll(mappedPath)
  1314. assert.NoError(t, err)
  1315. }
  1316. func TestChtimes(t *testing.T) {
  1317. u := getTestUser()
  1318. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  1319. assert.NoError(t, err)
  1320. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  1321. assert.NoError(t, err)
  1322. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1323. client, err := getFTPClient(user, false)
  1324. if assert.NoError(t, err) {
  1325. testFilePath := filepath.Join(homeBasePath, testFileName)
  1326. testFileSize := int64(65535)
  1327. err = createTestFile(testFilePath, testFileSize)
  1328. assert.NoError(t, err)
  1329. err = checkBasicFTP(client)
  1330. assert.NoError(t, err)
  1331. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1332. assert.NoError(t, err)
  1333. mtime := time.Now().Format("20060102150405")
  1334. code, response, err := client.SendCustomCommand(fmt.Sprintf("MFMT %v %v", mtime, testFileName))
  1335. assert.NoError(t, err)
  1336. assert.Equal(t, ftp.StatusFile, code)
  1337. assert.Equal(t, fmt.Sprintf("Modify=%v; %v", mtime, testFileName), response)
  1338. err = client.Quit()
  1339. assert.NoError(t, err)
  1340. err = os.Remove(testFilePath)
  1341. assert.NoError(t, err)
  1342. if user.Username == defaultUsername {
  1343. err = os.RemoveAll(user.GetHomeDir())
  1344. assert.NoError(t, err)
  1345. }
  1346. }
  1347. }
  1348. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  1349. assert.NoError(t, err)
  1350. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  1351. assert.NoError(t, err)
  1352. err = os.RemoveAll(localUser.GetHomeDir())
  1353. assert.NoError(t, err)
  1354. }
  1355. func TestChmod(t *testing.T) {
  1356. if runtime.GOOS == osWindows {
  1357. t.Skip("chmod is partially supported on Windows")
  1358. }
  1359. u := getTestUser()
  1360. localUser, _, err := httpd.AddUser(u, http.StatusOK)
  1361. assert.NoError(t, err)
  1362. sftpUser, _, err := httpd.AddUser(getTestSFTPUser(), http.StatusOK)
  1363. assert.NoError(t, err)
  1364. for _, user := range []dataprovider.User{localUser, sftpUser} {
  1365. client, err := getFTPClient(user, true)
  1366. if assert.NoError(t, err) {
  1367. testFilePath := filepath.Join(homeBasePath, testFileName)
  1368. testFileSize := int64(131072)
  1369. err = createTestFile(testFilePath, testFileSize)
  1370. assert.NoError(t, err)
  1371. err = checkBasicFTP(client)
  1372. assert.NoError(t, err)
  1373. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  1374. assert.NoError(t, err)
  1375. code, response, err := client.SendCustomCommand(fmt.Sprintf("SITE CHMOD 600 %v", testFileName))
  1376. assert.NoError(t, err)
  1377. assert.Equal(t, ftp.StatusCommandOK, code)
  1378. assert.Equal(t, "SITE CHMOD command successful", response)
  1379. fi, err := os.Stat(filepath.Join(user.HomeDir, testFileName))
  1380. if assert.NoError(t, err) {
  1381. assert.Equal(t, os.FileMode(0600), fi.Mode().Perm())
  1382. }
  1383. err = client.Quit()
  1384. assert.NoError(t, err)
  1385. err = os.Remove(testFilePath)
  1386. assert.NoError(t, err)
  1387. if user.Username == defaultUsername {
  1388. err = os.RemoveAll(user.GetHomeDir())
  1389. assert.NoError(t, err)
  1390. }
  1391. }
  1392. }
  1393. _, err = httpd.RemoveUser(sftpUser, http.StatusOK)
  1394. assert.NoError(t, err)
  1395. _, err = httpd.RemoveUser(localUser, http.StatusOK)
  1396. assert.NoError(t, err)
  1397. err = os.RemoveAll(localUser.GetHomeDir())
  1398. assert.NoError(t, err)
  1399. }
  1400. func checkBasicFTP(client *ftp.ServerConn) error {
  1401. _, err := client.CurrentDir()
  1402. if err != nil {
  1403. return err
  1404. }
  1405. err = client.NoOp()
  1406. if err != nil {
  1407. return err
  1408. }
  1409. _, err = client.List(".")
  1410. if err != nil {
  1411. return err
  1412. }
  1413. return nil
  1414. }
  1415. func ftpUploadFile(localSourcePath string, remoteDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  1416. srcFile, err := os.Open(localSourcePath)
  1417. if err != nil {
  1418. return err
  1419. }
  1420. defer srcFile.Close()
  1421. if offset > 0 {
  1422. err = client.StorFrom(remoteDestPath, srcFile, offset)
  1423. } else {
  1424. err = client.Stor(remoteDestPath, srcFile)
  1425. }
  1426. if err != nil {
  1427. return err
  1428. }
  1429. if expectedSize > 0 {
  1430. size, err := client.FileSize(remoteDestPath)
  1431. if err != nil {
  1432. return err
  1433. }
  1434. if size != expectedSize {
  1435. return fmt.Errorf("uploaded file size does not match, actual: %v, expected: %v", size, expectedSize)
  1436. }
  1437. }
  1438. return nil
  1439. }
  1440. func ftpDownloadFile(remoteSourcePath string, localDestPath string, expectedSize int64, client *ftp.ServerConn, offset uint64) error {
  1441. downloadDest, err := os.Create(localDestPath)
  1442. if err != nil {
  1443. return err
  1444. }
  1445. defer downloadDest.Close()
  1446. var r *ftp.Response
  1447. if offset > 0 {
  1448. r, err = client.RetrFrom(remoteSourcePath, offset)
  1449. } else {
  1450. r, err = client.Retr(remoteSourcePath)
  1451. }
  1452. if err != nil {
  1453. return err
  1454. }
  1455. defer r.Close()
  1456. written, err := io.Copy(downloadDest, r)
  1457. if err != nil {
  1458. return err
  1459. }
  1460. if written != expectedSize {
  1461. return fmt.Errorf("downloaded file size does not match, actual: %v, expected: %v", written, expectedSize)
  1462. }
  1463. return nil
  1464. }
  1465. func getFTPClient(user dataprovider.User, useTLS bool) (*ftp.ServerConn, error) {
  1466. ftpOptions := []ftp.DialOption{ftp.DialWithTimeout(5 * time.Second)}
  1467. if useTLS {
  1468. tlsConfig := &tls.Config{
  1469. ServerName: "localhost",
  1470. InsecureSkipVerify: true, // use this for tests only
  1471. MinVersion: tls.VersionTLS12,
  1472. }
  1473. ftpOptions = append(ftpOptions, ftp.DialWithExplicitTLS(tlsConfig))
  1474. }
  1475. client, err := ftp.Dial(ftpServerAddr, ftpOptions...)
  1476. if err != nil {
  1477. return nil, err
  1478. }
  1479. pwd := defaultPassword
  1480. if len(user.Password) > 0 {
  1481. pwd = user.Password
  1482. }
  1483. err = client.Login(user.Username, pwd)
  1484. if err != nil {
  1485. return nil, err
  1486. }
  1487. return client, err
  1488. }
  1489. func waitTCPListening(address string) {
  1490. for {
  1491. conn, err := net.Dial("tcp", address)
  1492. if err != nil {
  1493. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  1494. time.Sleep(100 * time.Millisecond)
  1495. continue
  1496. }
  1497. logger.InfoToConsole("tcp server %v now listening\n", address)
  1498. conn.Close()
  1499. break
  1500. }
  1501. }
  1502. func getTestUser() dataprovider.User {
  1503. user := dataprovider.User{
  1504. Username: defaultUsername,
  1505. Password: defaultPassword,
  1506. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  1507. Status: 1,
  1508. ExpirationDate: 0,
  1509. }
  1510. user.Permissions = make(map[string][]string)
  1511. user.Permissions["/"] = allPerms
  1512. return user
  1513. }
  1514. func getTestSFTPUser() dataprovider.User {
  1515. u := getTestUser()
  1516. u.Username = u.Username + "_sftp"
  1517. u.FsConfig.Provider = dataprovider.SFTPFilesystemProvider
  1518. u.FsConfig.SFTPConfig.Endpoint = sftpServerAddr
  1519. u.FsConfig.SFTPConfig.Username = defaultUsername
  1520. u.FsConfig.SFTPConfig.Password = kms.NewPlainSecret(defaultPassword)
  1521. return u
  1522. }
  1523. func getExtAuthScriptContent(user dataprovider.User, nonJSONResponse bool, username string) []byte {
  1524. extAuthContent := []byte("#!/bin/sh\n\n")
  1525. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("if test \"$SFTPGO_AUTHD_USERNAME\" = \"%v\"; then\n", user.Username))...)
  1526. if len(username) > 0 {
  1527. user.Username = username
  1528. }
  1529. u, _ := json.Marshal(user)
  1530. if nonJSONResponse {
  1531. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1532. } else {
  1533. extAuthContent = append(extAuthContent, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1534. }
  1535. extAuthContent = append(extAuthContent, []byte("else\n")...)
  1536. if nonJSONResponse {
  1537. extAuthContent = append(extAuthContent, []byte("echo 'text response'\n")...)
  1538. } else {
  1539. extAuthContent = append(extAuthContent, []byte("echo '{\"username\":\"\"}'\n")...)
  1540. }
  1541. extAuthContent = append(extAuthContent, []byte("fi\n")...)
  1542. return extAuthContent
  1543. }
  1544. func getPreLoginScriptContent(user dataprovider.User, nonJSONResponse bool) []byte {
  1545. content := []byte("#!/bin/sh\n\n")
  1546. if nonJSONResponse {
  1547. content = append(content, []byte("echo 'text response'\n")...)
  1548. return content
  1549. }
  1550. if len(user.Username) > 0 {
  1551. u, _ := json.Marshal(user)
  1552. content = append(content, []byte(fmt.Sprintf("echo '%v'\n", string(u)))...)
  1553. }
  1554. return content
  1555. }
  1556. func getPostConnectScriptContent(exitCode int) []byte {
  1557. content := []byte("#!/bin/sh\n\n")
  1558. content = append(content, []byte(fmt.Sprintf("exit %v", exitCode))...)
  1559. return content
  1560. }
  1561. func createTestFile(path string, size int64) error {
  1562. baseDir := filepath.Dir(path)
  1563. if _, err := os.Stat(baseDir); os.IsNotExist(err) {
  1564. err = os.MkdirAll(baseDir, os.ModePerm)
  1565. if err != nil {
  1566. return err
  1567. }
  1568. }
  1569. content := make([]byte, size)
  1570. _, err := rand.Read(content)
  1571. if err != nil {
  1572. return err
  1573. }
  1574. return ioutil.WriteFile(path, content, os.ModePerm)
  1575. }