cryptfs_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package ftpd_test
  2. import (
  3. "io/ioutil"
  4. "net/http"
  5. "os"
  6. "path"
  7. "path/filepath"
  8. "testing"
  9. "time"
  10. "github.com/minio/sio"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/drakkan/sftpgo/common"
  13. "github.com/drakkan/sftpgo/dataprovider"
  14. "github.com/drakkan/sftpgo/httpd"
  15. "github.com/drakkan/sftpgo/kms"
  16. )
  17. func TestBasicFTPHandlingCryptFs(t *testing.T) {
  18. u := getTestUserWithCryptFs()
  19. u.QuotaSize = 6553600
  20. user, _, err := httpd.AddUser(u, http.StatusOK)
  21. assert.NoError(t, err)
  22. client, err := getFTPClient(user, true)
  23. if assert.NoError(t, err) {
  24. assert.Len(t, common.Connections.GetStats(), 1)
  25. testFilePath := filepath.Join(homeBasePath, testFileName)
  26. testFileSize := int64(65535)
  27. encryptedFileSize, err := getEncryptedFileSize(testFileSize)
  28. assert.NoError(t, err)
  29. expectedQuotaSize := encryptedFileSize
  30. expectedQuotaFiles := 1
  31. err = createTestFile(testFilePath, testFileSize)
  32. assert.NoError(t, err)
  33. err = checkBasicFTP(client)
  34. assert.NoError(t, err)
  35. err = ftpUploadFile(testFilePath, path.Join("/missing_dir", testFileName), testFileSize, client, 0)
  36. assert.Error(t, err)
  37. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  38. assert.NoError(t, err)
  39. // overwrite an existing file
  40. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  41. assert.NoError(t, err)
  42. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  43. err = ftpDownloadFile(testFileName, localDownloadPath, testFileSize, client, 0)
  44. assert.NoError(t, err)
  45. info, err := os.Stat(localDownloadPath)
  46. if assert.NoError(t, err) {
  47. assert.Equal(t, testFileSize, info.Size())
  48. }
  49. list, err := client.List(".")
  50. if assert.NoError(t, err) {
  51. assert.Len(t, list, 1)
  52. assert.Equal(t, testFileSize, int64(list[0].Size))
  53. }
  54. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  55. assert.NoError(t, err)
  56. assert.Equal(t, expectedQuotaFiles, user.UsedQuotaFiles)
  57. assert.Equal(t, expectedQuotaSize, user.UsedQuotaSize)
  58. err = client.Rename(testFileName, testFileName+"1")
  59. assert.NoError(t, err)
  60. err = client.Delete(testFileName)
  61. assert.Error(t, err)
  62. err = client.Delete(testFileName + "1")
  63. assert.NoError(t, err)
  64. user, _, err = httpd.GetUserByID(user.ID, http.StatusOK)
  65. assert.NoError(t, err)
  66. assert.Equal(t, expectedQuotaFiles-1, user.UsedQuotaFiles)
  67. assert.Equal(t, expectedQuotaSize-encryptedFileSize, user.UsedQuotaSize)
  68. curDir, err := client.CurrentDir()
  69. if assert.NoError(t, err) {
  70. assert.Equal(t, "/", curDir)
  71. }
  72. testDir := "testDir"
  73. err = client.MakeDir(testDir)
  74. assert.NoError(t, err)
  75. err = client.ChangeDir(testDir)
  76. assert.NoError(t, err)
  77. curDir, err = client.CurrentDir()
  78. if assert.NoError(t, err) {
  79. assert.Equal(t, path.Join("/", testDir), curDir)
  80. }
  81. err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
  82. assert.NoError(t, err)
  83. size, err := client.FileSize(path.Join("/", testDir, testFileName))
  84. assert.NoError(t, err)
  85. assert.Equal(t, testFileSize, size)
  86. err = client.ChangeDirToParent()
  87. assert.NoError(t, err)
  88. curDir, err = client.CurrentDir()
  89. if assert.NoError(t, err) {
  90. assert.Equal(t, "/", curDir)
  91. }
  92. err = client.Delete(path.Join("/", testDir, testFileName))
  93. assert.NoError(t, err)
  94. err = client.Delete(testDir)
  95. assert.Error(t, err)
  96. err = client.RemoveDir(testDir)
  97. assert.NoError(t, err)
  98. err = os.Remove(testFilePath)
  99. assert.NoError(t, err)
  100. err = os.Remove(localDownloadPath)
  101. assert.NoError(t, err)
  102. err = client.Quit()
  103. assert.NoError(t, err)
  104. }
  105. _, err = httpd.RemoveUser(user, http.StatusOK)
  106. assert.NoError(t, err)
  107. err = os.RemoveAll(user.GetHomeDir())
  108. assert.NoError(t, err)
  109. assert.Eventually(t, func() bool { return len(common.Connections.GetStats()) == 0 }, 1*time.Second, 50*time.Millisecond)
  110. }
  111. func TestZeroBytesTransfersCryptFs(t *testing.T) {
  112. u := getTestUserWithCryptFs()
  113. user, _, err := httpd.AddUser(u, http.StatusOK)
  114. assert.NoError(t, err)
  115. client, err := getFTPClient(user, true)
  116. if assert.NoError(t, err) {
  117. testFileName := "testfilename"
  118. err = checkBasicFTP(client)
  119. assert.NoError(t, err)
  120. localDownloadPath := filepath.Join(homeBasePath, "emptydownload")
  121. err = ioutil.WriteFile(localDownloadPath, []byte(""), os.ModePerm)
  122. assert.NoError(t, err)
  123. err = ftpUploadFile(localDownloadPath, testFileName, 0, client, 0)
  124. assert.NoError(t, err)
  125. size, err := client.FileSize(testFileName)
  126. assert.NoError(t, err)
  127. assert.Equal(t, int64(0), size)
  128. err = os.Remove(localDownloadPath)
  129. assert.NoError(t, err)
  130. assert.NoFileExists(t, localDownloadPath)
  131. err = ftpDownloadFile(testFileName, localDownloadPath, 0, client, 0)
  132. assert.NoError(t, err)
  133. info, err := os.Stat(localDownloadPath)
  134. if assert.NoError(t, err) {
  135. assert.Equal(t, int64(0), info.Size())
  136. }
  137. err = client.Quit()
  138. assert.NoError(t, err)
  139. err = os.Remove(localDownloadPath)
  140. assert.NoError(t, err)
  141. }
  142. _, err = httpd.RemoveUser(user, http.StatusOK)
  143. assert.NoError(t, err)
  144. err = os.RemoveAll(user.GetHomeDir())
  145. assert.NoError(t, err)
  146. }
  147. func TestResumeCryptFs(t *testing.T) {
  148. u := getTestUserWithCryptFs()
  149. user, _, err := httpd.AddUser(u, http.StatusOK)
  150. assert.NoError(t, err)
  151. client, err := getFTPClient(user, true)
  152. if assert.NoError(t, err) {
  153. testFilePath := filepath.Join(homeBasePath, testFileName)
  154. data := []byte("test data")
  155. err = ioutil.WriteFile(testFilePath, data, os.ModePerm)
  156. assert.NoError(t, err)
  157. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  158. assert.NoError(t, err)
  159. // upload resume is not supported
  160. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)+5), client, 5)
  161. assert.Error(t, err)
  162. localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
  163. err = ftpDownloadFile(testFileName, localDownloadPath, int64(4), client, 5)
  164. assert.NoError(t, err)
  165. readed, err := ioutil.ReadFile(localDownloadPath)
  166. assert.NoError(t, err)
  167. assert.Equal(t, data[5:], readed)
  168. err = ftpDownloadFile(testFileName, localDownloadPath, int64(8), client, 1)
  169. assert.NoError(t, err)
  170. readed, err = ioutil.ReadFile(localDownloadPath)
  171. assert.NoError(t, err)
  172. assert.Equal(t, data[1:], readed)
  173. err = ftpDownloadFile(testFileName, localDownloadPath, int64(0), client, 9)
  174. assert.NoError(t, err)
  175. err = client.Delete(testFileName)
  176. assert.NoError(t, err)
  177. err = ftpUploadFile(testFilePath, testFileName, int64(len(data)), client, 0)
  178. assert.NoError(t, err)
  179. // now append to a file
  180. srcFile, err := os.Open(testFilePath)
  181. if assert.NoError(t, err) {
  182. err = client.Append(testFileName, srcFile)
  183. assert.Error(t, err)
  184. err = srcFile.Close()
  185. assert.NoError(t, err)
  186. size, err := client.FileSize(testFileName)
  187. assert.NoError(t, err)
  188. assert.Equal(t, int64(len(data)), size)
  189. err = ftpDownloadFile(testFileName, localDownloadPath, int64(len(data)), client, 0)
  190. assert.NoError(t, err)
  191. readed, err = ioutil.ReadFile(localDownloadPath)
  192. assert.NoError(t, err)
  193. assert.Equal(t, data, readed)
  194. }
  195. err = client.Quit()
  196. assert.NoError(t, err)
  197. err = os.Remove(testFilePath)
  198. assert.NoError(t, err)
  199. err = os.Remove(localDownloadPath)
  200. assert.NoError(t, err)
  201. }
  202. _, err = httpd.RemoveUser(user, http.StatusOK)
  203. assert.NoError(t, err)
  204. err = os.RemoveAll(user.GetHomeDir())
  205. assert.NoError(t, err)
  206. }
  207. func getTestUserWithCryptFs() dataprovider.User {
  208. user := getTestUser()
  209. user.FsConfig.Provider = dataprovider.CryptedFilesystemProvider
  210. user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("testPassphrase")
  211. return user
  212. }
  213. func getEncryptedFileSize(size int64) (int64, error) {
  214. encSize, err := sio.EncryptedSize(uint64(size))
  215. return int64(encSize) + 33, err
  216. }