common_test.go 35 KB

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