cryptfs_test.go 7.6 KB

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