common_test.go 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. // Copyright (C) 2019-2022 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package common
  15. import (
  16. "crypto/tls"
  17. "encoding/json"
  18. "fmt"
  19. "net"
  20. "os"
  21. "os/exec"
  22. "path/filepath"
  23. "runtime"
  24. "strings"
  25. "sync/atomic"
  26. "testing"
  27. "time"
  28. "github.com/alexedwards/argon2id"
  29. "github.com/sftpgo/sdk"
  30. "github.com/stretchr/testify/assert"
  31. "github.com/stretchr/testify/require"
  32. "golang.org/x/crypto/bcrypt"
  33. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  34. "github.com/drakkan/sftpgo/v2/internal/kms"
  35. "github.com/drakkan/sftpgo/v2/internal/plugin"
  36. "github.com/drakkan/sftpgo/v2/internal/util"
  37. "github.com/drakkan/sftpgo/v2/internal/vfs"
  38. )
  39. const (
  40. logSenderTest = "common_test"
  41. httpAddr = "127.0.0.1:9999"
  42. osWindows = "windows"
  43. userTestUsername = "common_test_username"
  44. )
  45. var (
  46. configDir = filepath.Join(".", "..", "..")
  47. )
  48. type fakeConnection struct {
  49. *BaseConnection
  50. command string
  51. }
  52. func (c *fakeConnection) AddUser(user dataprovider.User) error {
  53. _, err := user.GetFilesystem(c.GetID())
  54. if err != nil {
  55. return err
  56. }
  57. c.BaseConnection.User = user
  58. return nil
  59. }
  60. func (c *fakeConnection) Disconnect() error {
  61. Connections.Remove(c.GetID())
  62. return nil
  63. }
  64. func (c *fakeConnection) GetClientVersion() string {
  65. return ""
  66. }
  67. func (c *fakeConnection) GetCommand() string {
  68. return c.command
  69. }
  70. func (c *fakeConnection) GetLocalAddress() string {
  71. return ""
  72. }
  73. func (c *fakeConnection) GetRemoteAddress() string {
  74. return ""
  75. }
  76. type customNetConn struct {
  77. net.Conn
  78. id string
  79. isClosed bool
  80. }
  81. func (c *customNetConn) Close() error {
  82. Connections.RemoveSSHConnection(c.id)
  83. c.isClosed = true
  84. return c.Conn.Close()
  85. }
  86. func TestSSHConnections(t *testing.T) {
  87. conn1, conn2 := net.Pipe()
  88. now := time.Now()
  89. sshConn1 := NewSSHConnection("id1", conn1)
  90. sshConn2 := NewSSHConnection("id2", conn2)
  91. sshConn3 := NewSSHConnection("id3", conn2)
  92. assert.Equal(t, "id1", sshConn1.GetID())
  93. assert.Equal(t, "id2", sshConn2.GetID())
  94. assert.Equal(t, "id3", sshConn3.GetID())
  95. sshConn1.UpdateLastActivity()
  96. assert.GreaterOrEqual(t, sshConn1.GetLastActivity().UnixNano(), now.UnixNano())
  97. Connections.AddSSHConnection(sshConn1)
  98. Connections.AddSSHConnection(sshConn2)
  99. Connections.AddSSHConnection(sshConn3)
  100. Connections.RLock()
  101. assert.Len(t, Connections.sshConnections, 3)
  102. Connections.RUnlock()
  103. Connections.RemoveSSHConnection(sshConn1.id)
  104. Connections.RLock()
  105. assert.Len(t, Connections.sshConnections, 2)
  106. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  107. assert.Equal(t, sshConn2.id, Connections.sshConnections[1].id)
  108. Connections.RUnlock()
  109. Connections.RemoveSSHConnection(sshConn1.id)
  110. Connections.RLock()
  111. assert.Len(t, Connections.sshConnections, 2)
  112. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  113. assert.Equal(t, sshConn2.id, Connections.sshConnections[1].id)
  114. Connections.RUnlock()
  115. Connections.RemoveSSHConnection(sshConn2.id)
  116. Connections.RLock()
  117. assert.Len(t, Connections.sshConnections, 1)
  118. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  119. Connections.RUnlock()
  120. Connections.RemoveSSHConnection(sshConn3.id)
  121. Connections.RLock()
  122. assert.Len(t, Connections.sshConnections, 0)
  123. Connections.RUnlock()
  124. assert.NoError(t, sshConn1.Close())
  125. assert.NoError(t, sshConn2.Close())
  126. assert.NoError(t, sshConn3.Close())
  127. }
  128. func TestDefenderIntegration(t *testing.T) {
  129. // by default defender is nil
  130. configCopy := Config
  131. wdPath, err := os.Getwd()
  132. require.NoError(t, err)
  133. pluginsConfig := []plugin.Config{
  134. {
  135. Type: "ipfilter",
  136. Cmd: filepath.Join(wdPath, "..", "..", "tests", "ipfilter", "ipfilter"),
  137. AutoMTLS: true,
  138. },
  139. }
  140. if runtime.GOOS == osWindows {
  141. pluginsConfig[0].Cmd += ".exe"
  142. }
  143. err = plugin.Initialize(pluginsConfig, "debug")
  144. require.NoError(t, err)
  145. ip := "127.1.1.1"
  146. assert.Nil(t, Reload())
  147. // 192.168.1.12 is banned from the ipfilter plugin
  148. assert.True(t, IsBanned("192.168.1.12"))
  149. AddDefenderEvent(ip, HostEventNoLoginTried)
  150. assert.False(t, IsBanned(ip))
  151. banTime, err := GetDefenderBanTime(ip)
  152. assert.NoError(t, err)
  153. assert.Nil(t, banTime)
  154. assert.False(t, DeleteDefenderHost(ip))
  155. score, err := GetDefenderScore(ip)
  156. assert.NoError(t, err)
  157. assert.Equal(t, 0, score)
  158. _, err = GetDefenderHost(ip)
  159. assert.Error(t, err)
  160. hosts, err := GetDefenderHosts()
  161. assert.NoError(t, err)
  162. assert.Nil(t, hosts)
  163. Config.DefenderConfig = DefenderConfig{
  164. Enabled: true,
  165. Driver: DefenderDriverProvider,
  166. BanTime: 10,
  167. BanTimeIncrement: 50,
  168. Threshold: 0,
  169. ScoreInvalid: 2,
  170. ScoreValid: 1,
  171. ObservationTime: 15,
  172. EntriesSoftLimit: 100,
  173. EntriesHardLimit: 150,
  174. }
  175. err = Initialize(Config, 0)
  176. // ScoreInvalid cannot be greater than threshold
  177. assert.Error(t, err)
  178. Config.DefenderConfig.Driver = "unsupported"
  179. err = Initialize(Config, 0)
  180. if assert.Error(t, err) {
  181. assert.Contains(t, err.Error(), "unsupported defender driver")
  182. }
  183. Config.DefenderConfig.Driver = DefenderDriverMemory
  184. err = Initialize(Config, 0)
  185. // ScoreInvalid cannot be greater than threshold
  186. assert.Error(t, err)
  187. Config.DefenderConfig.Threshold = 3
  188. Config.DefenderConfig.SafeListFile = filepath.Join(os.TempDir(), "sl.json")
  189. err = os.WriteFile(Config.DefenderConfig.SafeListFile, []byte(`{}`), 0644)
  190. assert.NoError(t, err)
  191. defer os.Remove(Config.DefenderConfig.SafeListFile)
  192. err = Initialize(Config, 0)
  193. assert.NoError(t, err)
  194. assert.Nil(t, Reload())
  195. err = os.WriteFile(Config.DefenderConfig.SafeListFile, []byte(`{`), 0644)
  196. assert.NoError(t, err)
  197. err = Reload()
  198. assert.Error(t, err)
  199. AddDefenderEvent(ip, HostEventNoLoginTried)
  200. assert.False(t, IsBanned(ip))
  201. score, err = GetDefenderScore(ip)
  202. assert.NoError(t, err)
  203. assert.Equal(t, 2, score)
  204. entry, err := GetDefenderHost(ip)
  205. assert.NoError(t, err)
  206. asJSON, err := json.Marshal(&entry)
  207. assert.NoError(t, err)
  208. assert.Equal(t, `{"id":"3132372e312e312e31","ip":"127.1.1.1","score":2}`, string(asJSON), "entry %v", entry)
  209. assert.True(t, DeleteDefenderHost(ip))
  210. banTime, err = GetDefenderBanTime(ip)
  211. assert.NoError(t, err)
  212. assert.Nil(t, banTime)
  213. AddDefenderEvent(ip, HostEventLoginFailed)
  214. AddDefenderEvent(ip, HostEventNoLoginTried)
  215. assert.True(t, IsBanned(ip))
  216. score, err = GetDefenderScore(ip)
  217. assert.NoError(t, err)
  218. assert.Equal(t, 0, score)
  219. banTime, err = GetDefenderBanTime(ip)
  220. assert.NoError(t, err)
  221. assert.NotNil(t, banTime)
  222. hosts, err = GetDefenderHosts()
  223. assert.NoError(t, err)
  224. assert.Len(t, hosts, 1)
  225. entry, err = GetDefenderHost(ip)
  226. assert.NoError(t, err)
  227. assert.False(t, entry.BanTime.IsZero())
  228. assert.True(t, DeleteDefenderHost(ip))
  229. hosts, err = GetDefenderHosts()
  230. assert.NoError(t, err)
  231. assert.Len(t, hosts, 0)
  232. banTime, err = GetDefenderBanTime(ip)
  233. assert.NoError(t, err)
  234. assert.Nil(t, banTime)
  235. assert.False(t, DeleteDefenderHost(ip))
  236. Config = configCopy
  237. }
  238. func TestRateLimitersIntegration(t *testing.T) {
  239. // by default defender is nil
  240. configCopy := Config
  241. Config.RateLimitersConfig = []RateLimiterConfig{
  242. {
  243. Average: 100,
  244. Period: 10,
  245. Burst: 5,
  246. Type: int(rateLimiterTypeGlobal),
  247. Protocols: rateLimiterProtocolValues,
  248. },
  249. {
  250. Average: 1,
  251. Period: 1000,
  252. Burst: 1,
  253. Type: int(rateLimiterTypeSource),
  254. Protocols: []string{ProtocolWebDAV, ProtocolWebDAV, ProtocolFTP},
  255. GenerateDefenderEvents: true,
  256. EntriesSoftLimit: 100,
  257. EntriesHardLimit: 150,
  258. },
  259. }
  260. err := Initialize(Config, 0)
  261. assert.Error(t, err)
  262. Config.RateLimitersConfig[0].Period = 1000
  263. Config.RateLimitersConfig[0].AllowList = []string{"1.1.1", "1.1.1.2"}
  264. err = Initialize(Config, 0)
  265. if assert.Error(t, err) {
  266. assert.Contains(t, err.Error(), "unable to parse rate limiter allow list")
  267. }
  268. Config.RateLimitersConfig[0].AllowList = []string{"172.16.24.7"}
  269. Config.RateLimitersConfig[1].AllowList = []string{"172.16.0.0/16"}
  270. err = Initialize(Config, 0)
  271. assert.NoError(t, err)
  272. assert.Len(t, rateLimiters, 4)
  273. assert.Len(t, rateLimiters[ProtocolSSH], 1)
  274. assert.Len(t, rateLimiters[ProtocolFTP], 2)
  275. assert.Len(t, rateLimiters[ProtocolWebDAV], 2)
  276. assert.Len(t, rateLimiters[ProtocolHTTP], 1)
  277. source1 := "127.1.1.1"
  278. source2 := "127.1.1.2"
  279. source3 := "172.16.24.7" // whitelisted
  280. _, err = LimitRate(ProtocolSSH, source1)
  281. assert.NoError(t, err)
  282. _, err = LimitRate(ProtocolFTP, source1)
  283. assert.NoError(t, err)
  284. // sleep to allow the add configured burst to the token.
  285. // This sleep is not enough to add the per-source burst
  286. time.Sleep(20 * time.Millisecond)
  287. _, err = LimitRate(ProtocolWebDAV, source2)
  288. assert.NoError(t, err)
  289. _, err = LimitRate(ProtocolFTP, source1)
  290. assert.Error(t, err)
  291. _, err = LimitRate(ProtocolWebDAV, source2)
  292. assert.Error(t, err)
  293. _, err = LimitRate(ProtocolSSH, source1)
  294. assert.NoError(t, err)
  295. _, err = LimitRate(ProtocolSSH, source2)
  296. assert.NoError(t, err)
  297. for i := 0; i < 10; i++ {
  298. _, err = LimitRate(ProtocolWebDAV, source3)
  299. assert.NoError(t, err)
  300. }
  301. Config = configCopy
  302. }
  303. func TestWhitelist(t *testing.T) {
  304. configCopy := Config
  305. Config.whitelist = &whitelist{}
  306. err := Config.whitelist.reload()
  307. if assert.Error(t, err) {
  308. assert.Contains(t, err.Error(), "cannot accept a nil whitelist")
  309. }
  310. wlFile := filepath.Join(os.TempDir(), "wl.json")
  311. Config.WhiteListFile = wlFile
  312. err = os.WriteFile(wlFile, []byte(`invalid list file`), 0664)
  313. assert.NoError(t, err)
  314. err = Initialize(Config, 0)
  315. assert.Error(t, err)
  316. wl := HostListFile{
  317. IPAddresses: []string{"172.18.1.1", "172.18.1.2"},
  318. CIDRNetworks: []string{"10.8.7.0/24"},
  319. }
  320. data, err := json.Marshal(wl)
  321. assert.NoError(t, err)
  322. err = os.WriteFile(wlFile, data, 0664)
  323. assert.NoError(t, err)
  324. defer os.Remove(wlFile)
  325. err = Initialize(Config, 0)
  326. assert.NoError(t, err)
  327. assert.True(t, Connections.IsNewConnectionAllowed("172.18.1.1"))
  328. assert.False(t, Connections.IsNewConnectionAllowed("172.18.1.3"))
  329. assert.True(t, Connections.IsNewConnectionAllowed("10.8.7.3"))
  330. assert.False(t, Connections.IsNewConnectionAllowed("10.8.8.2"))
  331. wl.IPAddresses = append(wl.IPAddresses, "172.18.1.3")
  332. wl.CIDRNetworks = append(wl.CIDRNetworks, "10.8.8.0/24")
  333. data, err = json.Marshal(wl)
  334. assert.NoError(t, err)
  335. err = os.WriteFile(wlFile, data, 0664)
  336. assert.NoError(t, err)
  337. assert.False(t, Connections.IsNewConnectionAllowed("10.8.8.3"))
  338. err = Reload()
  339. assert.NoError(t, err)
  340. assert.True(t, Connections.IsNewConnectionAllowed("10.8.8.3"))
  341. assert.True(t, Connections.IsNewConnectionAllowed("172.18.1.3"))
  342. assert.True(t, Connections.IsNewConnectionAllowed("172.18.1.2"))
  343. assert.False(t, Connections.IsNewConnectionAllowed("172.18.1.12"))
  344. Config = configCopy
  345. }
  346. func TestUserMaxSessions(t *testing.T) {
  347. c := NewBaseConnection("id", ProtocolSFTP, "", "", dataprovider.User{
  348. BaseUser: sdk.BaseUser{
  349. Username: userTestUsername,
  350. MaxSessions: 1,
  351. },
  352. })
  353. fakeConn := &fakeConnection{
  354. BaseConnection: c,
  355. }
  356. err := Connections.Add(fakeConn)
  357. assert.NoError(t, err)
  358. err = Connections.Add(fakeConn)
  359. assert.Error(t, err)
  360. err = Connections.Swap(fakeConn)
  361. assert.NoError(t, err)
  362. Connections.Remove(fakeConn.GetID())
  363. Connections.Lock()
  364. Connections.removeUserConnection(userTestUsername)
  365. Connections.Unlock()
  366. assert.Len(t, Connections.GetStats(), 0)
  367. }
  368. func TestMaxConnections(t *testing.T) {
  369. oldValue := Config.MaxTotalConnections
  370. perHost := Config.MaxPerHostConnections
  371. Config.MaxPerHostConnections = 0
  372. ipAddr := "192.168.7.8"
  373. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  374. Config.MaxTotalConnections = 1
  375. Config.MaxPerHostConnections = perHost
  376. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  377. c := NewBaseConnection("id", ProtocolSFTP, "", "", dataprovider.User{})
  378. fakeConn := &fakeConnection{
  379. BaseConnection: c,
  380. }
  381. err := Connections.Add(fakeConn)
  382. assert.NoError(t, err)
  383. assert.Len(t, Connections.GetStats(), 1)
  384. assert.False(t, Connections.IsNewConnectionAllowed(ipAddr))
  385. res := Connections.Close(fakeConn.GetID())
  386. assert.True(t, res)
  387. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 300*time.Millisecond, 50*time.Millisecond)
  388. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  389. Connections.AddClientConnection(ipAddr)
  390. Connections.AddClientConnection(ipAddr)
  391. assert.False(t, Connections.IsNewConnectionAllowed(ipAddr))
  392. Connections.RemoveClientConnection(ipAddr)
  393. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  394. Connections.RemoveClientConnection(ipAddr)
  395. Config.MaxTotalConnections = oldValue
  396. }
  397. func TestMaxConnectionPerHost(t *testing.T) {
  398. oldValue := Config.MaxPerHostConnections
  399. Config.MaxPerHostConnections = 2
  400. ipAddr := "192.168.9.9"
  401. Connections.AddClientConnection(ipAddr)
  402. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  403. Connections.AddClientConnection(ipAddr)
  404. assert.True(t, Connections.IsNewConnectionAllowed(ipAddr))
  405. Connections.AddClientConnection(ipAddr)
  406. assert.False(t, Connections.IsNewConnectionAllowed(ipAddr))
  407. assert.Equal(t, int32(3), Connections.GetClientConnections())
  408. Connections.RemoveClientConnection(ipAddr)
  409. Connections.RemoveClientConnection(ipAddr)
  410. Connections.RemoveClientConnection(ipAddr)
  411. assert.Equal(t, int32(0), Connections.GetClientConnections())
  412. Config.MaxPerHostConnections = oldValue
  413. }
  414. func TestIdleConnections(t *testing.T) {
  415. configCopy := Config
  416. Config.IdleTimeout = 1
  417. err := Initialize(Config, 0)
  418. assert.NoError(t, err)
  419. conn1, conn2 := net.Pipe()
  420. customConn1 := &customNetConn{
  421. Conn: conn1,
  422. id: "id1",
  423. }
  424. customConn2 := &customNetConn{
  425. Conn: conn2,
  426. id: "id2",
  427. }
  428. sshConn1 := NewSSHConnection(customConn1.id, customConn1)
  429. sshConn2 := NewSSHConnection(customConn2.id, customConn2)
  430. username := "test_user"
  431. user := dataprovider.User{
  432. BaseUser: sdk.BaseUser{
  433. Username: username,
  434. },
  435. }
  436. c := NewBaseConnection(sshConn1.id+"_1", ProtocolSFTP, "", "", user)
  437. c.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  438. fakeConn := &fakeConnection{
  439. BaseConnection: c,
  440. }
  441. // both ssh connections are expired but they should get removed only
  442. // if there is no associated connection
  443. sshConn1.lastActivity = c.lastActivity
  444. sshConn2.lastActivity = c.lastActivity
  445. Connections.AddSSHConnection(sshConn1)
  446. err = Connections.Add(fakeConn)
  447. assert.NoError(t, err)
  448. assert.Equal(t, Connections.GetActiveSessions(username), 1)
  449. c = NewBaseConnection(sshConn2.id+"_1", ProtocolSSH, "", "", user)
  450. fakeConn = &fakeConnection{
  451. BaseConnection: c,
  452. }
  453. Connections.AddSSHConnection(sshConn2)
  454. err = Connections.Add(fakeConn)
  455. assert.NoError(t, err)
  456. assert.Equal(t, Connections.GetActiveSessions(username), 2)
  457. cFTP := NewBaseConnection("id2", ProtocolFTP, "", "", dataprovider.User{})
  458. cFTP.lastActivity = time.Now().UnixNano()
  459. fakeConn = &fakeConnection{
  460. BaseConnection: cFTP,
  461. }
  462. err = Connections.Add(fakeConn)
  463. assert.NoError(t, err)
  464. assert.Equal(t, Connections.GetActiveSessions(username), 2)
  465. assert.Len(t, Connections.GetStats(), 3)
  466. Connections.RLock()
  467. assert.Len(t, Connections.sshConnections, 2)
  468. Connections.RUnlock()
  469. startPeriodicChecks(100 * time.Millisecond)
  470. assert.Eventually(t, func() bool { return Connections.GetActiveSessions(username) == 1 }, 2*time.Second, 200*time.Millisecond)
  471. assert.Eventually(t, func() bool {
  472. Connections.RLock()
  473. defer Connections.RUnlock()
  474. return len(Connections.sshConnections) == 1
  475. }, 1*time.Second, 200*time.Millisecond)
  476. stopEventScheduler()
  477. assert.Len(t, Connections.GetStats(), 2)
  478. c.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  479. cFTP.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  480. sshConn2.lastActivity = c.lastActivity
  481. startPeriodicChecks(100 * time.Millisecond)
  482. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 2*time.Second, 200*time.Millisecond)
  483. assert.Eventually(t, func() bool {
  484. Connections.RLock()
  485. defer Connections.RUnlock()
  486. return len(Connections.sshConnections) == 0
  487. }, 1*time.Second, 200*time.Millisecond)
  488. assert.Equal(t, int32(0), Connections.GetClientConnections())
  489. stopEventScheduler()
  490. assert.True(t, customConn1.isClosed)
  491. assert.True(t, customConn2.isClosed)
  492. Config = configCopy
  493. }
  494. func TestCloseConnection(t *testing.T) {
  495. c := NewBaseConnection("id", ProtocolSFTP, "", "", dataprovider.User{})
  496. fakeConn := &fakeConnection{
  497. BaseConnection: c,
  498. }
  499. assert.True(t, Connections.IsNewConnectionAllowed("127.0.0.1"))
  500. err := Connections.Add(fakeConn)
  501. assert.NoError(t, err)
  502. assert.Len(t, Connections.GetStats(), 1)
  503. res := Connections.Close(fakeConn.GetID())
  504. assert.True(t, res)
  505. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 300*time.Millisecond, 50*time.Millisecond)
  506. res = Connections.Close(fakeConn.GetID())
  507. assert.False(t, res)
  508. Connections.Remove(fakeConn.GetID())
  509. }
  510. func TestSwapConnection(t *testing.T) {
  511. c := NewBaseConnection("id", ProtocolFTP, "", "", dataprovider.User{})
  512. fakeConn := &fakeConnection{
  513. BaseConnection: c,
  514. }
  515. err := Connections.Add(fakeConn)
  516. assert.NoError(t, err)
  517. if assert.Len(t, Connections.GetStats(), 1) {
  518. assert.Equal(t, "", Connections.GetStats()[0].Username)
  519. }
  520. c = NewBaseConnection("id", ProtocolFTP, "", "", dataprovider.User{
  521. BaseUser: sdk.BaseUser{
  522. Username: userTestUsername,
  523. MaxSessions: 1,
  524. },
  525. })
  526. fakeConn = &fakeConnection{
  527. BaseConnection: c,
  528. }
  529. c1 := NewBaseConnection("id1", ProtocolFTP, "", "", dataprovider.User{
  530. BaseUser: sdk.BaseUser{
  531. Username: userTestUsername,
  532. },
  533. })
  534. fakeConn1 := &fakeConnection{
  535. BaseConnection: c1,
  536. }
  537. err = Connections.Add(fakeConn1)
  538. assert.NoError(t, err)
  539. err = Connections.Swap(fakeConn)
  540. assert.Error(t, err)
  541. Connections.Remove(fakeConn1.ID)
  542. err = Connections.Swap(fakeConn)
  543. assert.NoError(t, err)
  544. if assert.Len(t, Connections.GetStats(), 1) {
  545. assert.Equal(t, userTestUsername, Connections.GetStats()[0].Username)
  546. }
  547. res := Connections.Close(fakeConn.GetID())
  548. assert.True(t, res)
  549. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 300*time.Millisecond, 50*time.Millisecond)
  550. err = Connections.Swap(fakeConn)
  551. assert.Error(t, err)
  552. }
  553. func TestAtomicUpload(t *testing.T) {
  554. configCopy := Config
  555. Config.UploadMode = UploadModeStandard
  556. assert.False(t, Config.IsAtomicUploadEnabled())
  557. Config.UploadMode = UploadModeAtomic
  558. assert.True(t, Config.IsAtomicUploadEnabled())
  559. Config.UploadMode = UploadModeAtomicWithResume
  560. assert.True(t, Config.IsAtomicUploadEnabled())
  561. Config = configCopy
  562. }
  563. func TestConnectionStatus(t *testing.T) {
  564. username := "test_user"
  565. user := dataprovider.User{
  566. BaseUser: sdk.BaseUser{
  567. Username: username,
  568. },
  569. }
  570. fs := vfs.NewOsFs("", os.TempDir(), "")
  571. c1 := NewBaseConnection("id1", ProtocolSFTP, "", "", user)
  572. fakeConn1 := &fakeConnection{
  573. BaseConnection: c1,
  574. }
  575. t1 := NewBaseTransfer(nil, c1, nil, "/p1", "/p1", "/r1", TransferUpload, 0, 0, 0, 0, true, fs, dataprovider.TransferQuota{})
  576. t1.BytesReceived = 123
  577. t2 := NewBaseTransfer(nil, c1, nil, "/p2", "/p2", "/r2", TransferDownload, 0, 0, 0, 0, true, fs, dataprovider.TransferQuota{})
  578. t2.BytesSent = 456
  579. c2 := NewBaseConnection("id2", ProtocolSSH, "", "", user)
  580. fakeConn2 := &fakeConnection{
  581. BaseConnection: c2,
  582. command: "md5sum",
  583. }
  584. c3 := NewBaseConnection("id3", ProtocolWebDAV, "", "", user)
  585. fakeConn3 := &fakeConnection{
  586. BaseConnection: c3,
  587. command: "PROPFIND",
  588. }
  589. t3 := NewBaseTransfer(nil, c3, nil, "/p2", "/p2", "/r2", TransferDownload, 0, 0, 0, 0, true, fs, dataprovider.TransferQuota{})
  590. err := Connections.Add(fakeConn1)
  591. assert.NoError(t, err)
  592. err = Connections.Add(fakeConn2)
  593. assert.NoError(t, err)
  594. err = Connections.Add(fakeConn3)
  595. assert.NoError(t, err)
  596. stats := Connections.GetStats()
  597. assert.Len(t, stats, 3)
  598. for _, stat := range stats {
  599. assert.Equal(t, stat.Username, username)
  600. assert.True(t, strings.HasPrefix(stat.GetConnectionInfo(), stat.Protocol))
  601. assert.True(t, strings.HasPrefix(stat.GetConnectionDuration(), "00:"))
  602. if stat.ConnectionID == "SFTP_id1" {
  603. assert.Len(t, stat.Transfers, 2)
  604. assert.Greater(t, len(stat.GetTransfersAsString()), 0)
  605. for _, tr := range stat.Transfers {
  606. if tr.OperationType == operationDownload {
  607. assert.True(t, strings.HasPrefix(tr.getConnectionTransferAsString(), "DL"))
  608. } else if tr.OperationType == operationUpload {
  609. assert.True(t, strings.HasPrefix(tr.getConnectionTransferAsString(), "UL"))
  610. }
  611. }
  612. } else if stat.ConnectionID == "DAV_id3" {
  613. assert.Len(t, stat.Transfers, 1)
  614. assert.Greater(t, len(stat.GetTransfersAsString()), 0)
  615. } else {
  616. assert.Equal(t, 0, len(stat.GetTransfersAsString()))
  617. }
  618. }
  619. err = t1.Close()
  620. assert.NoError(t, err)
  621. err = t2.Close()
  622. assert.NoError(t, err)
  623. err = fakeConn3.SignalTransfersAbort()
  624. assert.NoError(t, err)
  625. assert.Equal(t, int32(1), atomic.LoadInt32(&t3.AbortTransfer))
  626. err = t3.Close()
  627. assert.NoError(t, err)
  628. err = fakeConn3.SignalTransfersAbort()
  629. assert.Error(t, err)
  630. Connections.Remove(fakeConn1.GetID())
  631. stats = Connections.GetStats()
  632. assert.Len(t, stats, 2)
  633. assert.Equal(t, fakeConn3.GetID(), stats[0].ConnectionID)
  634. assert.Equal(t, fakeConn2.GetID(), stats[1].ConnectionID)
  635. Connections.Remove(fakeConn2.GetID())
  636. stats = Connections.GetStats()
  637. assert.Len(t, stats, 1)
  638. assert.Equal(t, fakeConn3.GetID(), stats[0].ConnectionID)
  639. Connections.Remove(fakeConn3.GetID())
  640. stats = Connections.GetStats()
  641. assert.Len(t, stats, 0)
  642. }
  643. func TestQuotaScans(t *testing.T) {
  644. username := "username"
  645. assert.True(t, QuotaScans.AddUserQuotaScan(username))
  646. assert.False(t, QuotaScans.AddUserQuotaScan(username))
  647. usersScans := QuotaScans.GetUsersQuotaScans()
  648. if assert.Len(t, usersScans, 1) {
  649. assert.Equal(t, usersScans[0].Username, username)
  650. assert.Equal(t, QuotaScans.UserScans[0].StartTime, usersScans[0].StartTime)
  651. QuotaScans.UserScans[0].StartTime = 0
  652. assert.NotEqual(t, QuotaScans.UserScans[0].StartTime, usersScans[0].StartTime)
  653. }
  654. assert.True(t, QuotaScans.RemoveUserQuotaScan(username))
  655. assert.False(t, QuotaScans.RemoveUserQuotaScan(username))
  656. assert.Len(t, QuotaScans.GetUsersQuotaScans(), 0)
  657. assert.Len(t, usersScans, 1)
  658. folderName := "folder"
  659. assert.True(t, QuotaScans.AddVFolderQuotaScan(folderName))
  660. assert.False(t, QuotaScans.AddVFolderQuotaScan(folderName))
  661. if assert.Len(t, QuotaScans.GetVFoldersQuotaScans(), 1) {
  662. assert.Equal(t, QuotaScans.GetVFoldersQuotaScans()[0].Name, folderName)
  663. }
  664. assert.True(t, QuotaScans.RemoveVFolderQuotaScan(folderName))
  665. assert.False(t, QuotaScans.RemoveVFolderQuotaScan(folderName))
  666. assert.Len(t, QuotaScans.GetVFoldersQuotaScans(), 0)
  667. }
  668. func TestProxyProtocolVersion(t *testing.T) {
  669. c := Configuration{
  670. ProxyProtocol: 0,
  671. }
  672. _, err := c.GetProxyListener(nil)
  673. if assert.Error(t, err) {
  674. assert.Contains(t, err.Error(), "proxy protocol not configured")
  675. }
  676. c.ProxyProtocol = 1
  677. proxyListener, err := c.GetProxyListener(nil)
  678. assert.NoError(t, err)
  679. assert.Nil(t, proxyListener.Policy)
  680. c.ProxyProtocol = 2
  681. proxyListener, err = c.GetProxyListener(nil)
  682. assert.NoError(t, err)
  683. assert.NotNil(t, proxyListener.Policy)
  684. c.ProxyProtocol = 1
  685. c.ProxyAllowed = []string{"invalid"}
  686. _, err = c.GetProxyListener(nil)
  687. assert.Error(t, err)
  688. c.ProxyProtocol = 2
  689. _, err = c.GetProxyListener(nil)
  690. assert.Error(t, err)
  691. }
  692. func TestStartupHook(t *testing.T) {
  693. Config.StartupHook = ""
  694. assert.NoError(t, Config.ExecuteStartupHook())
  695. Config.StartupHook = "http://foo\x7f.com/startup"
  696. assert.Error(t, Config.ExecuteStartupHook())
  697. Config.StartupHook = "http://invalid:5678/"
  698. assert.Error(t, Config.ExecuteStartupHook())
  699. Config.StartupHook = fmt.Sprintf("http://%v", httpAddr)
  700. assert.NoError(t, Config.ExecuteStartupHook())
  701. Config.StartupHook = "invalidhook"
  702. assert.Error(t, Config.ExecuteStartupHook())
  703. if runtime.GOOS != osWindows {
  704. hookCmd, err := exec.LookPath("true")
  705. assert.NoError(t, err)
  706. Config.StartupHook = hookCmd
  707. assert.NoError(t, Config.ExecuteStartupHook())
  708. }
  709. Config.StartupHook = ""
  710. }
  711. func TestPostDisconnectHook(t *testing.T) {
  712. Config.PostDisconnectHook = "http://127.0.0.1/"
  713. remoteAddr := "127.0.0.1:80"
  714. Config.checkPostDisconnectHook(remoteAddr, ProtocolHTTP, "", "", time.Now())
  715. Config.checkPostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  716. Config.PostDisconnectHook = "http://bar\x7f.com/"
  717. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  718. Config.PostDisconnectHook = fmt.Sprintf("http://%v", httpAddr)
  719. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  720. Config.PostDisconnectHook = "relativePath"
  721. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  722. if runtime.GOOS == osWindows {
  723. Config.PostDisconnectHook = "C:\\a\\bad\\command"
  724. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  725. } else {
  726. Config.PostDisconnectHook = "/invalid/path"
  727. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  728. hookCmd, err := exec.LookPath("true")
  729. assert.NoError(t, err)
  730. Config.PostDisconnectHook = hookCmd
  731. Config.executePostDisconnectHook(remoteAddr, ProtocolSFTP, "", "", time.Now())
  732. }
  733. Config.PostDisconnectHook = ""
  734. }
  735. func TestPostConnectHook(t *testing.T) {
  736. Config.PostConnectHook = ""
  737. ipAddr := "127.0.0.1"
  738. assert.NoError(t, Config.ExecutePostConnectHook(ipAddr, ProtocolFTP))
  739. Config.PostConnectHook = "http://foo\x7f.com/"
  740. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolSFTP))
  741. Config.PostConnectHook = "http://invalid:1234/"
  742. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolSFTP))
  743. Config.PostConnectHook = fmt.Sprintf("http://%v/404", httpAddr)
  744. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolFTP))
  745. Config.PostConnectHook = fmt.Sprintf("http://%v", httpAddr)
  746. assert.NoError(t, Config.ExecutePostConnectHook(ipAddr, ProtocolFTP))
  747. Config.PostConnectHook = "invalid"
  748. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolFTP))
  749. if runtime.GOOS == osWindows {
  750. Config.PostConnectHook = "C:\\bad\\command"
  751. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolSFTP))
  752. } else {
  753. Config.PostConnectHook = "/invalid/path"
  754. assert.Error(t, Config.ExecutePostConnectHook(ipAddr, ProtocolSFTP))
  755. hookCmd, err := exec.LookPath("true")
  756. assert.NoError(t, err)
  757. Config.PostConnectHook = hookCmd
  758. assert.NoError(t, Config.ExecutePostConnectHook(ipAddr, ProtocolSFTP))
  759. }
  760. Config.PostConnectHook = ""
  761. }
  762. func TestCryptoConvertFileInfo(t *testing.T) {
  763. name := "name"
  764. fs, err := vfs.NewCryptFs("connID1", os.TempDir(), "", vfs.CryptFsConfig{
  765. Passphrase: kms.NewPlainSecret("secret"),
  766. })
  767. require.NoError(t, err)
  768. cryptFs := fs.(*vfs.CryptFs)
  769. info := vfs.NewFileInfo(name, true, 48, time.Now(), false)
  770. assert.Equal(t, info, cryptFs.ConvertFileInfo(info))
  771. info = vfs.NewFileInfo(name, false, 48, time.Now(), false)
  772. assert.NotEqual(t, info.Size(), cryptFs.ConvertFileInfo(info).Size())
  773. info = vfs.NewFileInfo(name, false, 33, time.Now(), false)
  774. assert.Equal(t, int64(0), cryptFs.ConvertFileInfo(info).Size())
  775. info = vfs.NewFileInfo(name, false, 1, time.Now(), false)
  776. assert.Equal(t, int64(0), cryptFs.ConvertFileInfo(info).Size())
  777. }
  778. func TestFolderCopy(t *testing.T) {
  779. folder := vfs.BaseVirtualFolder{
  780. ID: 1,
  781. Name: "name",
  782. MappedPath: filepath.Clean(os.TempDir()),
  783. UsedQuotaSize: 4096,
  784. UsedQuotaFiles: 2,
  785. LastQuotaUpdate: util.GetTimeAsMsSinceEpoch(time.Now()),
  786. Users: []string{"user1", "user2"},
  787. }
  788. folderCopy := folder.GetACopy()
  789. folder.ID = 2
  790. folder.Users = []string{"user3"}
  791. require.Len(t, folderCopy.Users, 2)
  792. require.True(t, util.Contains(folderCopy.Users, "user1"))
  793. require.True(t, util.Contains(folderCopy.Users, "user2"))
  794. require.Equal(t, int64(1), folderCopy.ID)
  795. require.Equal(t, folder.Name, folderCopy.Name)
  796. require.Equal(t, folder.MappedPath, folderCopy.MappedPath)
  797. require.Equal(t, folder.UsedQuotaSize, folderCopy.UsedQuotaSize)
  798. require.Equal(t, folder.UsedQuotaFiles, folderCopy.UsedQuotaFiles)
  799. require.Equal(t, folder.LastQuotaUpdate, folderCopy.LastQuotaUpdate)
  800. folder.FsConfig = vfs.Filesystem{
  801. CryptConfig: vfs.CryptFsConfig{
  802. Passphrase: kms.NewPlainSecret("crypto secret"),
  803. },
  804. }
  805. folderCopy = folder.GetACopy()
  806. folder.FsConfig.CryptConfig.Passphrase = kms.NewEmptySecret()
  807. require.Len(t, folderCopy.Users, 1)
  808. require.True(t, util.Contains(folderCopy.Users, "user3"))
  809. require.Equal(t, int64(2), folderCopy.ID)
  810. require.Equal(t, folder.Name, folderCopy.Name)
  811. require.Equal(t, folder.MappedPath, folderCopy.MappedPath)
  812. require.Equal(t, folder.UsedQuotaSize, folderCopy.UsedQuotaSize)
  813. require.Equal(t, folder.UsedQuotaFiles, folderCopy.UsedQuotaFiles)
  814. require.Equal(t, folder.LastQuotaUpdate, folderCopy.LastQuotaUpdate)
  815. require.Equal(t, "crypto secret", folderCopy.FsConfig.CryptConfig.Passphrase.GetPayload())
  816. }
  817. func TestCachedFs(t *testing.T) {
  818. user := dataprovider.User{
  819. BaseUser: sdk.BaseUser{
  820. HomeDir: filepath.Clean(os.TempDir()),
  821. },
  822. }
  823. conn := NewBaseConnection("id", ProtocolSFTP, "", "", user)
  824. // changing the user should not affect the connection
  825. user.HomeDir = filepath.Join(os.TempDir(), "temp")
  826. err := os.Mkdir(user.HomeDir, os.ModePerm)
  827. assert.NoError(t, err)
  828. fs, err := user.GetFilesystem("")
  829. assert.NoError(t, err)
  830. p, err := fs.ResolvePath("/")
  831. assert.NoError(t, err)
  832. assert.Equal(t, user.GetHomeDir(), p)
  833. _, p, err = conn.GetFsAndResolvedPath("/")
  834. assert.NoError(t, err)
  835. assert.Equal(t, filepath.Clean(os.TempDir()), p)
  836. // the filesystem is cached changing the provider will not affect the connection
  837. conn.User.FsConfig.Provider = sdk.S3FilesystemProvider
  838. _, p, err = conn.GetFsAndResolvedPath("/")
  839. assert.NoError(t, err)
  840. assert.Equal(t, filepath.Clean(os.TempDir()), p)
  841. user = dataprovider.User{}
  842. user.HomeDir = filepath.Join(os.TempDir(), "temp")
  843. user.FsConfig.Provider = sdk.S3FilesystemProvider
  844. _, err = user.GetFilesystem("")
  845. assert.Error(t, err)
  846. err = os.Remove(user.HomeDir)
  847. assert.NoError(t, err)
  848. }
  849. func TestParseAllowedIPAndRanges(t *testing.T) {
  850. _, err := util.ParseAllowedIPAndRanges([]string{"1.1.1.1", "not an ip"})
  851. assert.Error(t, err)
  852. _, err = util.ParseAllowedIPAndRanges([]string{"1.1.1.5", "192.168.1.0/240"})
  853. assert.Error(t, err)
  854. allow, err := util.ParseAllowedIPAndRanges([]string{"192.168.1.2", "172.16.0.0/24"})
  855. assert.NoError(t, err)
  856. assert.True(t, allow[0](net.ParseIP("192.168.1.2")))
  857. assert.False(t, allow[0](net.ParseIP("192.168.2.2")))
  858. assert.True(t, allow[1](net.ParseIP("172.16.0.1")))
  859. assert.False(t, allow[1](net.ParseIP("172.16.1.1")))
  860. }
  861. func TestHideConfidentialData(t *testing.T) {
  862. for _, provider := range []sdk.FilesystemProvider{sdk.LocalFilesystemProvider,
  863. sdk.CryptedFilesystemProvider, sdk.S3FilesystemProvider, sdk.GCSFilesystemProvider,
  864. sdk.AzureBlobFilesystemProvider, sdk.SFTPFilesystemProvider,
  865. } {
  866. u := dataprovider.User{
  867. FsConfig: vfs.Filesystem{
  868. Provider: provider,
  869. },
  870. }
  871. u.PrepareForRendering()
  872. f := vfs.BaseVirtualFolder{
  873. FsConfig: vfs.Filesystem{
  874. Provider: provider,
  875. },
  876. }
  877. f.PrepareForRendering()
  878. }
  879. a := dataprovider.Admin{}
  880. a.HideConfidentialData()
  881. }
  882. func TestUserPerms(t *testing.T) {
  883. u := dataprovider.User{}
  884. u.Permissions = make(map[string][]string)
  885. u.Permissions["/"] = []string{dataprovider.PermUpload, dataprovider.PermDelete}
  886. assert.True(t, u.HasAnyPerm([]string{dataprovider.PermRename, dataprovider.PermDelete}, "/"))
  887. assert.False(t, u.HasAnyPerm([]string{dataprovider.PermRename, dataprovider.PermCreateDirs}, "/"))
  888. u.Permissions["/"] = []string{dataprovider.PermDelete, dataprovider.PermCreateDirs}
  889. assert.True(t, u.HasPermsDeleteAll("/"))
  890. assert.False(t, u.HasPermsRenameAll("/"))
  891. u.Permissions["/"] = []string{dataprovider.PermDeleteDirs, dataprovider.PermDeleteFiles, dataprovider.PermRenameDirs}
  892. assert.True(t, u.HasPermsDeleteAll("/"))
  893. assert.False(t, u.HasPermsRenameAll("/"))
  894. u.Permissions["/"] = []string{dataprovider.PermDeleteDirs, dataprovider.PermRenameFiles, dataprovider.PermRenameDirs}
  895. assert.False(t, u.HasPermsDeleteAll("/"))
  896. assert.True(t, u.HasPermsRenameAll("/"))
  897. }
  898. func TestGetTLSVersion(t *testing.T) {
  899. tlsVer := util.GetTLSVersion(0)
  900. assert.Equal(t, uint16(tls.VersionTLS12), tlsVer)
  901. tlsVer = util.GetTLSVersion(12)
  902. assert.Equal(t, uint16(tls.VersionTLS12), tlsVer)
  903. tlsVer = util.GetTLSVersion(2)
  904. assert.Equal(t, uint16(tls.VersionTLS12), tlsVer)
  905. tlsVer = util.GetTLSVersion(13)
  906. assert.Equal(t, uint16(tls.VersionTLS13), tlsVer)
  907. }
  908. func TestCleanPath(t *testing.T) {
  909. assert.Equal(t, "/", util.CleanPath("/"))
  910. assert.Equal(t, "/", util.CleanPath("."))
  911. assert.Equal(t, "/", util.CleanPath(""))
  912. assert.Equal(t, "/", util.CleanPath("/."))
  913. assert.Equal(t, "/", util.CleanPath("/a/.."))
  914. assert.Equal(t, "/a", util.CleanPath("/a/"))
  915. assert.Equal(t, "/a", util.CleanPath("a/"))
  916. // filepath.ToSlash does not touch \ as char on unix systems
  917. // so os.PathSeparator is used for windows compatible tests
  918. bslash := string(os.PathSeparator)
  919. assert.Equal(t, "/", util.CleanPath(bslash))
  920. assert.Equal(t, "/", util.CleanPath(bslash+bslash))
  921. assert.Equal(t, "/a", util.CleanPath(bslash+"a"+bslash))
  922. assert.Equal(t, "/a", util.CleanPath("a"+bslash))
  923. assert.Equal(t, "/a/b/c", util.CleanPath(bslash+"a"+bslash+bslash+"b"+bslash+bslash+"c"+bslash))
  924. assert.Equal(t, "/C:/a", util.CleanPath("C:"+bslash+"a"))
  925. }
  926. func TestUserRecentActivity(t *testing.T) {
  927. u := dataprovider.User{}
  928. res := u.HasRecentActivity()
  929. assert.False(t, res)
  930. u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now())
  931. res = u.HasRecentActivity()
  932. assert.True(t, res)
  933. u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Minute))
  934. res = u.HasRecentActivity()
  935. assert.False(t, res)
  936. u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Second))
  937. res = u.HasRecentActivity()
  938. assert.True(t, res)
  939. }
  940. func TestVfsSameResource(t *testing.T) {
  941. fs := vfs.Filesystem{}
  942. other := vfs.Filesystem{}
  943. res := fs.IsSameResource(other)
  944. assert.True(t, res)
  945. fs = vfs.Filesystem{
  946. Provider: sdk.S3FilesystemProvider,
  947. S3Config: vfs.S3FsConfig{
  948. BaseS3FsConfig: sdk.BaseS3FsConfig{
  949. Bucket: "a",
  950. Region: "b",
  951. },
  952. },
  953. }
  954. other = vfs.Filesystem{
  955. Provider: sdk.S3FilesystemProvider,
  956. S3Config: vfs.S3FsConfig{
  957. BaseS3FsConfig: sdk.BaseS3FsConfig{
  958. Bucket: "a",
  959. Region: "c",
  960. },
  961. },
  962. }
  963. res = fs.IsSameResource(other)
  964. assert.False(t, res)
  965. other = vfs.Filesystem{
  966. Provider: sdk.S3FilesystemProvider,
  967. S3Config: vfs.S3FsConfig{
  968. BaseS3FsConfig: sdk.BaseS3FsConfig{
  969. Bucket: "a",
  970. Region: "b",
  971. },
  972. },
  973. }
  974. res = fs.IsSameResource(other)
  975. assert.True(t, res)
  976. fs = vfs.Filesystem{
  977. Provider: sdk.GCSFilesystemProvider,
  978. GCSConfig: vfs.GCSFsConfig{
  979. BaseGCSFsConfig: sdk.BaseGCSFsConfig{
  980. Bucket: "b",
  981. },
  982. },
  983. }
  984. other = vfs.Filesystem{
  985. Provider: sdk.GCSFilesystemProvider,
  986. GCSConfig: vfs.GCSFsConfig{
  987. BaseGCSFsConfig: sdk.BaseGCSFsConfig{
  988. Bucket: "c",
  989. },
  990. },
  991. }
  992. res = fs.IsSameResource(other)
  993. assert.False(t, res)
  994. other = vfs.Filesystem{
  995. Provider: sdk.GCSFilesystemProvider,
  996. GCSConfig: vfs.GCSFsConfig{
  997. BaseGCSFsConfig: sdk.BaseGCSFsConfig{
  998. Bucket: "b",
  999. },
  1000. },
  1001. }
  1002. res = fs.IsSameResource(other)
  1003. assert.True(t, res)
  1004. sasURL := kms.NewPlainSecret("http://127.0.0.1/sasurl")
  1005. fs = vfs.Filesystem{
  1006. Provider: sdk.AzureBlobFilesystemProvider,
  1007. AzBlobConfig: vfs.AzBlobFsConfig{
  1008. BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{
  1009. AccountName: "a",
  1010. },
  1011. SASURL: sasURL,
  1012. },
  1013. }
  1014. err := fs.Validate("data1")
  1015. assert.NoError(t, err)
  1016. other = vfs.Filesystem{
  1017. Provider: sdk.AzureBlobFilesystemProvider,
  1018. AzBlobConfig: vfs.AzBlobFsConfig{
  1019. BaseAzBlobFsConfig: sdk.BaseAzBlobFsConfig{
  1020. AccountName: "a",
  1021. },
  1022. SASURL: sasURL,
  1023. },
  1024. }
  1025. err = other.Validate("data2")
  1026. assert.NoError(t, err)
  1027. err = fs.AzBlobConfig.SASURL.TryDecrypt()
  1028. assert.NoError(t, err)
  1029. err = other.AzBlobConfig.SASURL.TryDecrypt()
  1030. assert.NoError(t, err)
  1031. res = fs.IsSameResource(other)
  1032. assert.True(t, res)
  1033. fs.AzBlobConfig.AccountName = "b"
  1034. res = fs.IsSameResource(other)
  1035. assert.False(t, res)
  1036. fs.AzBlobConfig.AccountName = "a"
  1037. other.AzBlobConfig.SASURL = kms.NewPlainSecret("http://127.1.1.1/sasurl")
  1038. err = other.Validate("data2")
  1039. assert.NoError(t, err)
  1040. err = other.AzBlobConfig.SASURL.TryDecrypt()
  1041. assert.NoError(t, err)
  1042. res = fs.IsSameResource(other)
  1043. assert.False(t, res)
  1044. fs = vfs.Filesystem{
  1045. Provider: sdk.HTTPFilesystemProvider,
  1046. HTTPConfig: vfs.HTTPFsConfig{
  1047. BaseHTTPFsConfig: sdk.BaseHTTPFsConfig{
  1048. Endpoint: "http://127.0.0.1/httpfs",
  1049. Username: "a",
  1050. },
  1051. },
  1052. }
  1053. other = vfs.Filesystem{
  1054. Provider: sdk.HTTPFilesystemProvider,
  1055. HTTPConfig: vfs.HTTPFsConfig{
  1056. BaseHTTPFsConfig: sdk.BaseHTTPFsConfig{
  1057. Endpoint: "http://127.0.0.1/httpfs",
  1058. Username: "b",
  1059. },
  1060. },
  1061. }
  1062. res = fs.IsSameResource(other)
  1063. assert.True(t, res)
  1064. fs.HTTPConfig.EqualityCheckMode = 1
  1065. res = fs.IsSameResource(other)
  1066. assert.False(t, res)
  1067. }
  1068. func BenchmarkBcryptHashing(b *testing.B) {
  1069. bcryptPassword := "bcryptpassword"
  1070. for i := 0; i < b.N; i++ {
  1071. _, err := bcrypt.GenerateFromPassword([]byte(bcryptPassword), 10)
  1072. if err != nil {
  1073. panic(err)
  1074. }
  1075. }
  1076. }
  1077. func BenchmarkCompareBcryptPassword(b *testing.B) {
  1078. bcryptPassword := "$2a$10$lPDdnDimJZ7d5/GwL6xDuOqoZVRXok6OHHhivCnanWUtcgN0Zafki"
  1079. for i := 0; i < b.N; i++ {
  1080. err := bcrypt.CompareHashAndPassword([]byte(bcryptPassword), []byte("password"))
  1081. if err != nil {
  1082. panic(err)
  1083. }
  1084. }
  1085. }
  1086. func BenchmarkArgon2Hashing(b *testing.B) {
  1087. argonPassword := "argon2password"
  1088. for i := 0; i < b.N; i++ {
  1089. _, err := argon2id.CreateHash(argonPassword, argon2id.DefaultParams)
  1090. if err != nil {
  1091. panic(err)
  1092. }
  1093. }
  1094. }
  1095. func BenchmarkCompareArgon2Password(b *testing.B) {
  1096. argon2Password := "$argon2id$v=19$m=65536,t=1,p=2$aOoAOdAwvzhOgi7wUFjXlw$wn/y37dBWdKHtPXHR03nNaKHWKPXyNuVXOknaU+YZ+s"
  1097. for i := 0; i < b.N; i++ {
  1098. _, err := argon2id.ComparePasswordAndHash("password", argon2Password)
  1099. if err != nil {
  1100. panic(err)
  1101. }
  1102. }
  1103. }