eventmanager_test.go 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765
  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. "bytes"
  17. "crypto/rand"
  18. "fmt"
  19. "io"
  20. "mime/multipart"
  21. "net/http"
  22. "os"
  23. "path"
  24. "path/filepath"
  25. "runtime"
  26. "strings"
  27. "testing"
  28. "time"
  29. "github.com/klauspost/compress/zip"
  30. "github.com/sftpgo/sdk"
  31. sdkkms "github.com/sftpgo/sdk/kms"
  32. "github.com/stretchr/testify/assert"
  33. "github.com/stretchr/testify/require"
  34. "github.com/drakkan/sftpgo/v2/internal/dataprovider"
  35. "github.com/drakkan/sftpgo/v2/internal/kms"
  36. "github.com/drakkan/sftpgo/v2/internal/util"
  37. "github.com/drakkan/sftpgo/v2/internal/vfs"
  38. )
  39. func TestEventRuleMatch(t *testing.T) {
  40. role := "role1"
  41. conditions := dataprovider.EventConditions{
  42. ProviderEvents: []string{"add", "update"},
  43. Options: dataprovider.ConditionOptions{
  44. Names: []dataprovider.ConditionPattern{
  45. {
  46. Pattern: "user1",
  47. InverseMatch: true,
  48. },
  49. },
  50. RoleNames: []dataprovider.ConditionPattern{
  51. {
  52. Pattern: role,
  53. },
  54. },
  55. },
  56. }
  57. res := eventManager.checkProviderEventMatch(conditions, EventParams{
  58. Name: "user1",
  59. Role: role,
  60. Event: "add",
  61. })
  62. assert.False(t, res)
  63. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  64. Name: "user2",
  65. Role: role,
  66. Event: "update",
  67. })
  68. assert.True(t, res)
  69. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  70. Name: "user2",
  71. Role: role,
  72. Event: "delete",
  73. })
  74. assert.False(t, res)
  75. conditions.Options.ProviderObjects = []string{"api_key"}
  76. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  77. Name: "user2",
  78. Event: "update",
  79. Role: role,
  80. ObjectType: "share",
  81. })
  82. assert.False(t, res)
  83. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  84. Name: "user2",
  85. Event: "update",
  86. Role: role,
  87. ObjectType: "api_key",
  88. })
  89. assert.True(t, res)
  90. res = eventManager.checkProviderEventMatch(conditions, EventParams{
  91. Name: "user2",
  92. Event: "update",
  93. Role: role + "1",
  94. ObjectType: "api_key",
  95. })
  96. assert.False(t, res)
  97. // now test fs events
  98. conditions = dataprovider.EventConditions{
  99. FsEvents: []string{operationUpload, operationDownload},
  100. Options: dataprovider.ConditionOptions{
  101. Names: []dataprovider.ConditionPattern{
  102. {
  103. Pattern: "user*",
  104. },
  105. {
  106. Pattern: "tester*",
  107. },
  108. },
  109. RoleNames: []dataprovider.ConditionPattern{
  110. {
  111. Pattern: role,
  112. InverseMatch: true,
  113. },
  114. },
  115. FsPaths: []dataprovider.ConditionPattern{
  116. {
  117. Pattern: "*.txt",
  118. },
  119. },
  120. Protocols: []string{ProtocolSFTP},
  121. MinFileSize: 10,
  122. MaxFileSize: 30,
  123. },
  124. }
  125. params := EventParams{
  126. Name: "tester4",
  127. Event: operationDelete,
  128. VirtualPath: "/path.txt",
  129. Protocol: ProtocolSFTP,
  130. ObjectName: "path.txt",
  131. FileSize: 20,
  132. }
  133. res = eventManager.checkFsEventMatch(conditions, params)
  134. assert.False(t, res)
  135. params.Event = operationDownload
  136. res = eventManager.checkFsEventMatch(conditions, params)
  137. assert.True(t, res)
  138. params.Role = role
  139. res = eventManager.checkFsEventMatch(conditions, params)
  140. assert.False(t, res)
  141. params.Role = ""
  142. params.Name = "name"
  143. res = eventManager.checkFsEventMatch(conditions, params)
  144. assert.False(t, res)
  145. params.Name = "user5"
  146. res = eventManager.checkFsEventMatch(conditions, params)
  147. assert.True(t, res)
  148. params.VirtualPath = "/sub/f.jpg"
  149. params.ObjectName = path.Base(params.VirtualPath)
  150. res = eventManager.checkFsEventMatch(conditions, params)
  151. assert.False(t, res)
  152. params.VirtualPath = "/sub/f.txt"
  153. params.ObjectName = path.Base(params.VirtualPath)
  154. res = eventManager.checkFsEventMatch(conditions, params)
  155. assert.True(t, res)
  156. params.Protocol = ProtocolHTTP
  157. res = eventManager.checkFsEventMatch(conditions, params)
  158. assert.False(t, res)
  159. params.Protocol = ProtocolSFTP
  160. params.FileSize = 5
  161. res = eventManager.checkFsEventMatch(conditions, params)
  162. assert.False(t, res)
  163. params.FileSize = 50
  164. res = eventManager.checkFsEventMatch(conditions, params)
  165. assert.False(t, res)
  166. params.FileSize = 25
  167. res = eventManager.checkFsEventMatch(conditions, params)
  168. assert.True(t, res)
  169. // bad pattern
  170. conditions.Options.Names = []dataprovider.ConditionPattern{
  171. {
  172. Pattern: "[-]",
  173. },
  174. }
  175. res = eventManager.checkFsEventMatch(conditions, params)
  176. assert.False(t, res)
  177. // check fs events with group name filters
  178. conditions = dataprovider.EventConditions{
  179. FsEvents: []string{operationUpload, operationDownload},
  180. Options: dataprovider.ConditionOptions{
  181. GroupNames: []dataprovider.ConditionPattern{
  182. {
  183. Pattern: "group*",
  184. },
  185. {
  186. Pattern: "testgroup*",
  187. },
  188. },
  189. },
  190. }
  191. params = EventParams{
  192. Name: "user1",
  193. Event: operationUpload,
  194. }
  195. res = eventManager.checkFsEventMatch(conditions, params)
  196. assert.False(t, res)
  197. params.Groups = []sdk.GroupMapping{
  198. {
  199. Name: "g1",
  200. Type: sdk.GroupTypePrimary,
  201. },
  202. {
  203. Name: "g2",
  204. Type: sdk.GroupTypeSecondary,
  205. },
  206. }
  207. res = eventManager.checkFsEventMatch(conditions, params)
  208. assert.False(t, res)
  209. params.Groups = []sdk.GroupMapping{
  210. {
  211. Name: "testgroup2",
  212. Type: sdk.GroupTypePrimary,
  213. },
  214. {
  215. Name: "g2",
  216. Type: sdk.GroupTypeSecondary,
  217. },
  218. }
  219. res = eventManager.checkFsEventMatch(conditions, params)
  220. assert.True(t, res)
  221. // check user conditions
  222. user := dataprovider.User{}
  223. user.Username = "u1"
  224. res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{})
  225. assert.True(t, res)
  226. res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
  227. Names: []dataprovider.ConditionPattern{
  228. {
  229. Pattern: "user",
  230. },
  231. },
  232. })
  233. assert.False(t, res)
  234. res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
  235. RoleNames: []dataprovider.ConditionPattern{
  236. {
  237. Pattern: role,
  238. },
  239. },
  240. })
  241. assert.False(t, res)
  242. user.Role = role
  243. res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
  244. RoleNames: []dataprovider.ConditionPattern{
  245. {
  246. Pattern: role,
  247. },
  248. },
  249. })
  250. assert.True(t, res)
  251. res = checkUserConditionOptions(&user, &dataprovider.ConditionOptions{
  252. GroupNames: []dataprovider.ConditionPattern{
  253. {
  254. Pattern: "group",
  255. },
  256. },
  257. RoleNames: []dataprovider.ConditionPattern{
  258. {
  259. Pattern: role,
  260. },
  261. },
  262. })
  263. assert.False(t, res)
  264. }
  265. func TestEventManager(t *testing.T) {
  266. startEventScheduler()
  267. action := &dataprovider.BaseEventAction{
  268. Name: "test_action",
  269. Type: dataprovider.ActionTypeHTTP,
  270. Options: dataprovider.BaseEventActionOptions{
  271. HTTPConfig: dataprovider.EventActionHTTPConfig{
  272. Endpoint: "http://localhost",
  273. Timeout: 20,
  274. Method: http.MethodGet,
  275. },
  276. },
  277. }
  278. err := dataprovider.AddEventAction(action, "", "", "")
  279. assert.NoError(t, err)
  280. rule := &dataprovider.EventRule{
  281. Name: "rule",
  282. Trigger: dataprovider.EventTriggerFsEvent,
  283. Conditions: dataprovider.EventConditions{
  284. FsEvents: []string{operationUpload},
  285. },
  286. Actions: []dataprovider.EventAction{
  287. {
  288. BaseEventAction: dataprovider.BaseEventAction{
  289. Name: action.Name,
  290. },
  291. Order: 1,
  292. },
  293. },
  294. }
  295. err = dataprovider.AddEventRule(rule, "", "", "")
  296. assert.NoError(t, err)
  297. eventManager.RLock()
  298. assert.Len(t, eventManager.FsEvents, 1)
  299. assert.Len(t, eventManager.ProviderEvents, 0)
  300. assert.Len(t, eventManager.Schedules, 0)
  301. assert.Len(t, eventManager.schedulesMapping, 0)
  302. eventManager.RUnlock()
  303. rule.Trigger = dataprovider.EventTriggerProviderEvent
  304. rule.Conditions = dataprovider.EventConditions{
  305. ProviderEvents: []string{"add"},
  306. }
  307. err = dataprovider.UpdateEventRule(rule, "", "", "")
  308. assert.NoError(t, err)
  309. eventManager.RLock()
  310. assert.Len(t, eventManager.FsEvents, 0)
  311. assert.Len(t, eventManager.ProviderEvents, 1)
  312. assert.Len(t, eventManager.Schedules, 0)
  313. assert.Len(t, eventManager.schedulesMapping, 0)
  314. eventManager.RUnlock()
  315. rule.Trigger = dataprovider.EventTriggerSchedule
  316. rule.Conditions = dataprovider.EventConditions{
  317. Schedules: []dataprovider.Schedule{
  318. {
  319. Hours: "0",
  320. DayOfWeek: "*",
  321. DayOfMonth: "*",
  322. Month: "*",
  323. },
  324. },
  325. }
  326. rule.DeletedAt = util.GetTimeAsMsSinceEpoch(time.Now().Add(-12 * time.Hour))
  327. eventManager.addUpdateRuleInternal(*rule)
  328. eventManager.RLock()
  329. assert.Len(t, eventManager.FsEvents, 0)
  330. assert.Len(t, eventManager.ProviderEvents, 0)
  331. assert.Len(t, eventManager.Schedules, 0)
  332. assert.Len(t, eventManager.schedulesMapping, 0)
  333. eventManager.RUnlock()
  334. assert.Eventually(t, func() bool {
  335. _, err = dataprovider.EventRuleExists(rule.Name)
  336. _, ok := err.(*util.RecordNotFoundError)
  337. return ok
  338. }, 2*time.Second, 100*time.Millisecond)
  339. rule.DeletedAt = 0
  340. err = dataprovider.AddEventRule(rule, "", "", "")
  341. assert.NoError(t, err)
  342. eventManager.RLock()
  343. assert.Len(t, eventManager.FsEvents, 0)
  344. assert.Len(t, eventManager.ProviderEvents, 0)
  345. assert.Len(t, eventManager.Schedules, 1)
  346. assert.Len(t, eventManager.schedulesMapping, 1)
  347. eventManager.RUnlock()
  348. err = dataprovider.DeleteEventRule(rule.Name, "", "", "")
  349. assert.NoError(t, err)
  350. eventManager.RLock()
  351. assert.Len(t, eventManager.FsEvents, 0)
  352. assert.Len(t, eventManager.ProviderEvents, 0)
  353. assert.Len(t, eventManager.Schedules, 0)
  354. assert.Len(t, eventManager.schedulesMapping, 0)
  355. eventManager.RUnlock()
  356. err = dataprovider.DeleteEventAction(action.Name, "", "", "")
  357. assert.NoError(t, err)
  358. stopEventScheduler()
  359. }
  360. func TestEventManagerErrors(t *testing.T) {
  361. startEventScheduler()
  362. providerConf := dataprovider.GetProviderConfig()
  363. err := dataprovider.Close()
  364. assert.NoError(t, err)
  365. params := EventParams{
  366. sender: "sender",
  367. }
  368. _, err = params.getUsers()
  369. assert.Error(t, err)
  370. _, err = params.getFolders()
  371. assert.Error(t, err)
  372. err = executeUsersQuotaResetRuleAction(dataprovider.ConditionOptions{}, &EventParams{})
  373. assert.Error(t, err)
  374. err = executeFoldersQuotaResetRuleAction(dataprovider.ConditionOptions{}, &EventParams{})
  375. assert.Error(t, err)
  376. err = executeTransferQuotaResetRuleAction(dataprovider.ConditionOptions{}, &EventParams{})
  377. assert.Error(t, err)
  378. err = executeMetadataCheckRuleAction(dataprovider.ConditionOptions{}, &EventParams{})
  379. assert.Error(t, err)
  380. err = executeDeleteFsRuleAction(nil, nil, dataprovider.ConditionOptions{}, &EventParams{})
  381. assert.Error(t, err)
  382. err = executeMkdirFsRuleAction(nil, nil, dataprovider.ConditionOptions{}, &EventParams{})
  383. assert.Error(t, err)
  384. err = executeRenameFsRuleAction(nil, nil, dataprovider.ConditionOptions{}, &EventParams{})
  385. assert.Error(t, err)
  386. err = executeExistFsRuleAction(nil, nil, dataprovider.ConditionOptions{}, &EventParams{})
  387. assert.Error(t, err)
  388. err = executeCopyFsRuleAction(nil, nil, dataprovider.ConditionOptions{}, &EventParams{})
  389. assert.Error(t, err)
  390. err = executeCompressFsRuleAction(dataprovider.EventActionFsCompress{}, nil, dataprovider.ConditionOptions{}, &EventParams{})
  391. assert.Error(t, err)
  392. err = executePwdExpirationCheckRuleAction(dataprovider.EventActionPasswordExpiration{},
  393. dataprovider.ConditionOptions{}, &EventParams{})
  394. assert.Error(t, err)
  395. groupName := "agroup"
  396. err = executeQuotaResetForUser(&dataprovider.User{
  397. Groups: []sdk.GroupMapping{
  398. {
  399. Name: groupName,
  400. Type: sdk.GroupTypePrimary,
  401. },
  402. },
  403. })
  404. assert.Error(t, err)
  405. err = executeMetadataCheckForUser(&dataprovider.User{
  406. Groups: []sdk.GroupMapping{
  407. {
  408. Name: groupName,
  409. Type: sdk.GroupTypePrimary,
  410. },
  411. },
  412. })
  413. assert.Error(t, err)
  414. err = executeDataRetentionCheckForUser(dataprovider.User{
  415. Groups: []sdk.GroupMapping{
  416. {
  417. Name: groupName,
  418. Type: sdk.GroupTypePrimary,
  419. },
  420. },
  421. }, nil, &EventParams{}, "")
  422. assert.Error(t, err)
  423. err = executeDeleteFsActionForUser(nil, nil, dataprovider.User{
  424. Groups: []sdk.GroupMapping{
  425. {
  426. Name: groupName,
  427. Type: sdk.GroupTypePrimary,
  428. },
  429. },
  430. })
  431. assert.Error(t, err)
  432. err = executeMkDirsFsActionForUser(nil, nil, dataprovider.User{
  433. Groups: []sdk.GroupMapping{
  434. {
  435. Name: groupName,
  436. Type: sdk.GroupTypePrimary,
  437. },
  438. },
  439. })
  440. assert.Error(t, err)
  441. err = executeRenameFsActionForUser(nil, nil, dataprovider.User{
  442. Groups: []sdk.GroupMapping{
  443. {
  444. Name: groupName,
  445. Type: sdk.GroupTypePrimary,
  446. },
  447. },
  448. })
  449. assert.Error(t, err)
  450. err = executeExistFsActionForUser(nil, nil, dataprovider.User{
  451. Groups: []sdk.GroupMapping{
  452. {
  453. Name: groupName,
  454. Type: sdk.GroupTypePrimary,
  455. },
  456. },
  457. })
  458. assert.Error(t, err)
  459. err = executeCopyFsActionForUser(nil, nil, dataprovider.User{
  460. Groups: []sdk.GroupMapping{
  461. {
  462. Name: groupName,
  463. Type: sdk.GroupTypePrimary,
  464. },
  465. },
  466. })
  467. assert.Error(t, err)
  468. err = executeCompressFsActionForUser(dataprovider.EventActionFsCompress{}, nil, dataprovider.User{
  469. Groups: []sdk.GroupMapping{
  470. {
  471. Name: groupName,
  472. Type: sdk.GroupTypePrimary,
  473. },
  474. },
  475. })
  476. assert.Error(t, err)
  477. _, err = getMailAttachments(dataprovider.User{
  478. Groups: []sdk.GroupMapping{
  479. {
  480. Name: groupName,
  481. Type: sdk.GroupTypePrimary,
  482. },
  483. }}, []string{"/a", "/b"}, nil)
  484. assert.Error(t, err)
  485. err = executePwdExpirationCheckForUser(&dataprovider.User{
  486. Groups: []sdk.GroupMapping{
  487. {
  488. Name: groupName,
  489. Type: sdk.GroupTypePrimary,
  490. },
  491. }}, dataprovider.EventActionPasswordExpiration{})
  492. assert.Error(t, err)
  493. _, _, err = getHTTPRuleActionBody(dataprovider.EventActionHTTPConfig{
  494. Method: http.MethodPost,
  495. Parts: []dataprovider.HTTPPart{
  496. {
  497. Name: "p1",
  498. },
  499. },
  500. }, nil, nil, dataprovider.User{
  501. BaseUser: sdk.BaseUser{
  502. Username: "u",
  503. },
  504. Groups: []sdk.GroupMapping{
  505. {
  506. Name: groupName,
  507. Type: sdk.GroupTypePrimary,
  508. },
  509. },
  510. }, &EventParams{})
  511. assert.Error(t, err)
  512. dataRetentionAction := dataprovider.BaseEventAction{
  513. Type: dataprovider.ActionTypeDataRetentionCheck,
  514. Options: dataprovider.BaseEventActionOptions{
  515. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  516. Folders: []dataprovider.FolderRetention{
  517. {
  518. Path: "/",
  519. Retention: 24,
  520. },
  521. },
  522. },
  523. },
  524. }
  525. err = executeRuleAction(dataRetentionAction, &EventParams{}, dataprovider.ConditionOptions{
  526. Names: []dataprovider.ConditionPattern{
  527. {
  528. Pattern: "username1",
  529. },
  530. },
  531. })
  532. if assert.Error(t, err) {
  533. assert.Contains(t, err.Error(), "unable to get users")
  534. }
  535. eventManager.loadRules()
  536. eventManager.RLock()
  537. assert.Len(t, eventManager.FsEvents, 0)
  538. assert.Len(t, eventManager.ProviderEvents, 0)
  539. assert.Len(t, eventManager.Schedules, 0)
  540. eventManager.RUnlock()
  541. // rule with invalid trigger
  542. eventManager.addUpdateRuleInternal(dataprovider.EventRule{
  543. Name: "test rule",
  544. Trigger: -1,
  545. })
  546. eventManager.RLock()
  547. assert.Len(t, eventManager.FsEvents, 0)
  548. assert.Len(t, eventManager.ProviderEvents, 0)
  549. assert.Len(t, eventManager.Schedules, 0)
  550. eventManager.RUnlock()
  551. // rule with invalid cronspec
  552. eventManager.addUpdateRuleInternal(dataprovider.EventRule{
  553. Name: "test rule",
  554. Trigger: dataprovider.EventTriggerSchedule,
  555. Conditions: dataprovider.EventConditions{
  556. Schedules: []dataprovider.Schedule{
  557. {
  558. Hours: "1000",
  559. },
  560. },
  561. },
  562. })
  563. eventManager.RLock()
  564. assert.Len(t, eventManager.FsEvents, 0)
  565. assert.Len(t, eventManager.ProviderEvents, 0)
  566. assert.Len(t, eventManager.Schedules, 0)
  567. eventManager.RUnlock()
  568. err = dataprovider.Initialize(providerConf, configDir, true)
  569. assert.NoError(t, err)
  570. stopEventScheduler()
  571. }
  572. func TestEventRuleActions(t *testing.T) {
  573. actionName := "test rule action"
  574. action := dataprovider.BaseEventAction{
  575. Name: actionName,
  576. Type: dataprovider.ActionTypeBackup,
  577. }
  578. err := executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{})
  579. assert.NoError(t, err)
  580. action.Type = -1
  581. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{})
  582. assert.Error(t, err)
  583. action = dataprovider.BaseEventAction{
  584. Name: actionName,
  585. Type: dataprovider.ActionTypeHTTP,
  586. Options: dataprovider.BaseEventActionOptions{
  587. HTTPConfig: dataprovider.EventActionHTTPConfig{
  588. Endpoint: "http://foo\x7f.com/", // invalid URL
  589. SkipTLSVerify: true,
  590. Body: "{{ObjectData}}",
  591. Method: http.MethodPost,
  592. QueryParameters: []dataprovider.KeyValue{
  593. {
  594. Key: "param",
  595. Value: "value",
  596. },
  597. },
  598. Timeout: 5,
  599. Headers: []dataprovider.KeyValue{
  600. {
  601. Key: "Content-Type",
  602. Value: "application/json",
  603. },
  604. },
  605. Username: "httpuser",
  606. },
  607. },
  608. }
  609. action.Options.SetEmptySecretsIfNil()
  610. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{})
  611. if assert.Error(t, err) {
  612. assert.Contains(t, err.Error(), "invalid endpoint")
  613. }
  614. action.Options.HTTPConfig.Endpoint = fmt.Sprintf("http://%v", httpAddr)
  615. params := &EventParams{
  616. Name: "a",
  617. Object: &dataprovider.User{
  618. BaseUser: sdk.BaseUser{
  619. Username: "test user",
  620. },
  621. },
  622. }
  623. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  624. assert.NoError(t, err)
  625. action.Options.HTTPConfig.Method = http.MethodGet
  626. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  627. assert.NoError(t, err)
  628. action.Options.HTTPConfig.Endpoint = fmt.Sprintf("http://%v/404", httpAddr)
  629. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  630. if assert.Error(t, err) {
  631. assert.Contains(t, err.Error(), "unexpected status code: 404")
  632. }
  633. action.Options.HTTPConfig.Endpoint = "http://invalid:1234"
  634. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  635. assert.Error(t, err)
  636. action.Options.HTTPConfig.QueryParameters = nil
  637. action.Options.HTTPConfig.Endpoint = "http://bar\x7f.com/"
  638. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  639. assert.Error(t, err)
  640. action.Options.HTTPConfig.Password = kms.NewSecret(sdkkms.SecretStatusSecretBox, "payload", "key", "data")
  641. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  642. if assert.Error(t, err) {
  643. assert.Contains(t, err.Error(), "unable to decrypt HTTP password")
  644. }
  645. action.Options.HTTPConfig.Password = kms.NewEmptySecret()
  646. action.Options.HTTPConfig.Body = ""
  647. action.Options.HTTPConfig.Parts = []dataprovider.HTTPPart{
  648. {
  649. Name: "p1",
  650. Filepath: "path",
  651. },
  652. }
  653. err = executeRuleAction(action, params, dataprovider.ConditionOptions{})
  654. assert.Contains(t, getErrorString(err), "error getting user")
  655. action.Options.HTTPConfig.Parts = nil
  656. action.Options.HTTPConfig.Body = "{{ObjectData}}"
  657. // test disk and transfer quota reset
  658. username1 := "user1"
  659. username2 := "user2"
  660. user1 := dataprovider.User{
  661. BaseUser: sdk.BaseUser{
  662. Username: username1,
  663. HomeDir: filepath.Join(os.TempDir(), username1),
  664. Status: 1,
  665. Permissions: map[string][]string{
  666. "/": {dataprovider.PermAny},
  667. },
  668. },
  669. }
  670. user2 := dataprovider.User{
  671. BaseUser: sdk.BaseUser{
  672. Username: username2,
  673. HomeDir: filepath.Join(os.TempDir(), username2),
  674. Status: 1,
  675. Permissions: map[string][]string{
  676. "/": {dataprovider.PermAny},
  677. },
  678. },
  679. }
  680. user2.Filters.PasswordExpiration = 10
  681. err = dataprovider.AddUser(&user1, "", "", "")
  682. assert.NoError(t, err)
  683. err = dataprovider.AddUser(&user2, "", "", "")
  684. assert.NoError(t, err)
  685. err = executePwdExpirationCheckRuleAction(dataprovider.EventActionPasswordExpiration{
  686. Threshold: 20,
  687. }, dataprovider.ConditionOptions{
  688. Names: []dataprovider.ConditionPattern{
  689. {
  690. Pattern: user2.Username,
  691. },
  692. },
  693. }, &EventParams{})
  694. // smtp not configured
  695. assert.Error(t, err)
  696. action = dataprovider.BaseEventAction{
  697. Type: dataprovider.ActionTypeUserQuotaReset,
  698. }
  699. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  700. Names: []dataprovider.ConditionPattern{
  701. {
  702. Pattern: username1,
  703. },
  704. },
  705. })
  706. assert.Error(t, err) // no home dir
  707. // create the home dir
  708. err = os.MkdirAll(user1.GetHomeDir(), os.ModePerm)
  709. assert.NoError(t, err)
  710. err = os.WriteFile(filepath.Join(user1.GetHomeDir(), "file.txt"), []byte("user"), 0666)
  711. assert.NoError(t, err)
  712. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  713. Names: []dataprovider.ConditionPattern{
  714. {
  715. Pattern: username1,
  716. },
  717. },
  718. })
  719. assert.NoError(t, err)
  720. userGet, err := dataprovider.UserExists(username1, "")
  721. assert.NoError(t, err)
  722. assert.Equal(t, 1, userGet.UsedQuotaFiles)
  723. assert.Equal(t, int64(4), userGet.UsedQuotaSize)
  724. // simulate another quota scan in progress
  725. assert.True(t, QuotaScans.AddUserQuotaScan(username1, ""))
  726. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  727. Names: []dataprovider.ConditionPattern{
  728. {
  729. Pattern: username1,
  730. },
  731. },
  732. })
  733. assert.Error(t, err)
  734. assert.True(t, QuotaScans.RemoveUserQuotaScan(username1))
  735. // non matching pattern
  736. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  737. Names: []dataprovider.ConditionPattern{
  738. {
  739. Pattern: "don't match",
  740. },
  741. },
  742. })
  743. assert.Error(t, err)
  744. assert.Contains(t, getErrorString(err), "no user quota reset executed")
  745. action = dataprovider.BaseEventAction{
  746. Type: dataprovider.ActionTypeMetadataCheck,
  747. }
  748. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  749. Names: []dataprovider.ConditionPattern{
  750. {
  751. Pattern: "don't match",
  752. },
  753. },
  754. })
  755. assert.Error(t, err)
  756. assert.Contains(t, getErrorString(err), "no metadata check executed")
  757. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  758. Names: []dataprovider.ConditionPattern{
  759. {
  760. Pattern: username1,
  761. },
  762. },
  763. })
  764. assert.NoError(t, err)
  765. // simulate another metadata check in progress
  766. assert.True(t, ActiveMetadataChecks.Add(username1, ""))
  767. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  768. Names: []dataprovider.ConditionPattern{
  769. {
  770. Pattern: username1,
  771. },
  772. },
  773. })
  774. assert.Error(t, err)
  775. assert.True(t, ActiveMetadataChecks.Remove(username1))
  776. dataRetentionAction := dataprovider.BaseEventAction{
  777. Type: dataprovider.ActionTypeDataRetentionCheck,
  778. Options: dataprovider.BaseEventActionOptions{
  779. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  780. Folders: []dataprovider.FolderRetention{
  781. {
  782. Path: "",
  783. Retention: 24,
  784. },
  785. },
  786. },
  787. },
  788. }
  789. err = executeRuleAction(dataRetentionAction, &EventParams{}, dataprovider.ConditionOptions{
  790. Names: []dataprovider.ConditionPattern{
  791. {
  792. Pattern: username1,
  793. },
  794. },
  795. })
  796. assert.Error(t, err) // invalid config, no folder path specified
  797. retentionDir := "testretention"
  798. dataRetentionAction = dataprovider.BaseEventAction{
  799. Type: dataprovider.ActionTypeDataRetentionCheck,
  800. Options: dataprovider.BaseEventActionOptions{
  801. RetentionConfig: dataprovider.EventActionDataRetentionConfig{
  802. Folders: []dataprovider.FolderRetention{
  803. {
  804. Path: path.Join("/", retentionDir),
  805. Retention: 24,
  806. DeleteEmptyDirs: true,
  807. },
  808. },
  809. },
  810. },
  811. }
  812. // create some test files
  813. file1 := filepath.Join(user1.GetHomeDir(), "file1.txt")
  814. file2 := filepath.Join(user1.GetHomeDir(), retentionDir, "file2.txt")
  815. file3 := filepath.Join(user1.GetHomeDir(), retentionDir, "file3.txt")
  816. file4 := filepath.Join(user1.GetHomeDir(), retentionDir, "sub", "file4.txt")
  817. err = os.MkdirAll(filepath.Dir(file4), os.ModePerm)
  818. assert.NoError(t, err)
  819. for _, f := range []string{file1, file2, file3, file4} {
  820. err = os.WriteFile(f, []byte(""), 0666)
  821. assert.NoError(t, err)
  822. }
  823. timeBeforeRetention := time.Now().Add(-48 * time.Hour)
  824. err = os.Chtimes(file1, timeBeforeRetention, timeBeforeRetention)
  825. assert.NoError(t, err)
  826. err = os.Chtimes(file2, timeBeforeRetention, timeBeforeRetention)
  827. assert.NoError(t, err)
  828. err = os.Chtimes(file4, timeBeforeRetention, timeBeforeRetention)
  829. assert.NoError(t, err)
  830. err = executeRuleAction(dataRetentionAction, &EventParams{}, dataprovider.ConditionOptions{
  831. Names: []dataprovider.ConditionPattern{
  832. {
  833. Pattern: username1,
  834. },
  835. },
  836. })
  837. assert.NoError(t, err)
  838. assert.FileExists(t, file1)
  839. assert.NoFileExists(t, file2)
  840. assert.FileExists(t, file3)
  841. assert.NoDirExists(t, filepath.Dir(file4))
  842. // simulate another check in progress
  843. c := RetentionChecks.Add(RetentionCheck{}, &user1)
  844. assert.NotNil(t, c)
  845. err = executeRuleAction(dataRetentionAction, &EventParams{}, dataprovider.ConditionOptions{
  846. Names: []dataprovider.ConditionPattern{
  847. {
  848. Pattern: username1,
  849. },
  850. },
  851. })
  852. assert.Error(t, err)
  853. RetentionChecks.remove(user1.Username)
  854. err = executeRuleAction(dataRetentionAction, &EventParams{}, dataprovider.ConditionOptions{
  855. Names: []dataprovider.ConditionPattern{
  856. {
  857. Pattern: "no match",
  858. },
  859. },
  860. })
  861. assert.Error(t, err)
  862. assert.Contains(t, getErrorString(err), "no retention check executed")
  863. // test file exists action
  864. action = dataprovider.BaseEventAction{
  865. Type: dataprovider.ActionTypeFilesystem,
  866. Options: dataprovider.BaseEventActionOptions{
  867. FsConfig: dataprovider.EventActionFilesystemConfig{
  868. Type: dataprovider.FilesystemActionExist,
  869. Exist: []string{"/file1.txt", path.Join("/", retentionDir, "file3.txt")},
  870. },
  871. },
  872. }
  873. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  874. Names: []dataprovider.ConditionPattern{
  875. {
  876. Pattern: "no match",
  877. },
  878. },
  879. })
  880. assert.Error(t, err)
  881. assert.Contains(t, getErrorString(err), "no existence check executed")
  882. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  883. Names: []dataprovider.ConditionPattern{
  884. {
  885. Pattern: username1,
  886. },
  887. },
  888. })
  889. assert.NoError(t, err)
  890. action.Options.FsConfig.Exist = []string{"/file1.txt", path.Join("/", retentionDir, "file2.txt")}
  891. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  892. Names: []dataprovider.ConditionPattern{
  893. {
  894. Pattern: username1,
  895. },
  896. },
  897. })
  898. assert.Error(t, err)
  899. err = os.RemoveAll(user1.GetHomeDir())
  900. assert.NoError(t, err)
  901. err = dataprovider.UpdateUserTransferQuota(&user1, 100, 100, true)
  902. assert.NoError(t, err)
  903. action.Type = dataprovider.ActionTypeTransferQuotaReset
  904. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  905. Names: []dataprovider.ConditionPattern{
  906. {
  907. Pattern: username1,
  908. },
  909. },
  910. })
  911. assert.NoError(t, err)
  912. userGet, err = dataprovider.UserExists(username1, "")
  913. assert.NoError(t, err)
  914. assert.Equal(t, int64(0), userGet.UsedDownloadDataTransfer)
  915. assert.Equal(t, int64(0), userGet.UsedUploadDataTransfer)
  916. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  917. Names: []dataprovider.ConditionPattern{
  918. {
  919. Pattern: "no match",
  920. },
  921. },
  922. })
  923. assert.Error(t, err)
  924. assert.Contains(t, getErrorString(err), "no transfer quota reset executed")
  925. action.Type = dataprovider.ActionTypeFilesystem
  926. action.Options = dataprovider.BaseEventActionOptions{
  927. FsConfig: dataprovider.EventActionFilesystemConfig{
  928. Type: dataprovider.FilesystemActionRename,
  929. Renames: []dataprovider.KeyValue{
  930. {
  931. Key: "/source",
  932. Value: "/target",
  933. },
  934. },
  935. },
  936. }
  937. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  938. Names: []dataprovider.ConditionPattern{
  939. {
  940. Pattern: "no match",
  941. },
  942. },
  943. })
  944. assert.Error(t, err)
  945. assert.Contains(t, getErrorString(err), "no rename executed")
  946. action.Options = dataprovider.BaseEventActionOptions{
  947. FsConfig: dataprovider.EventActionFilesystemConfig{
  948. Type: dataprovider.FilesystemActionDelete,
  949. Deletes: []string{"/dir1"},
  950. },
  951. }
  952. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  953. Names: []dataprovider.ConditionPattern{
  954. {
  955. Pattern: "no match",
  956. },
  957. },
  958. })
  959. assert.Error(t, err)
  960. assert.Contains(t, getErrorString(err), "no delete executed")
  961. action.Options = dataprovider.BaseEventActionOptions{
  962. FsConfig: dataprovider.EventActionFilesystemConfig{
  963. Type: dataprovider.FilesystemActionMkdirs,
  964. Deletes: []string{"/dir1"},
  965. },
  966. }
  967. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  968. Names: []dataprovider.ConditionPattern{
  969. {
  970. Pattern: "no match",
  971. },
  972. },
  973. })
  974. assert.Error(t, err)
  975. assert.Contains(t, getErrorString(err), "no mkdir executed")
  976. action.Options = dataprovider.BaseEventActionOptions{
  977. FsConfig: dataprovider.EventActionFilesystemConfig{
  978. Type: dataprovider.FilesystemActionCompress,
  979. Compress: dataprovider.EventActionFsCompress{
  980. Name: "test.zip",
  981. Paths: []string{"/{{VirtualPath}}"},
  982. },
  983. },
  984. }
  985. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  986. Names: []dataprovider.ConditionPattern{
  987. {
  988. Pattern: "no match",
  989. },
  990. },
  991. })
  992. assert.Error(t, err)
  993. assert.Contains(t, getErrorString(err), "no file/folder compressed")
  994. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  995. GroupNames: []dataprovider.ConditionPattern{
  996. {
  997. Pattern: "no match",
  998. },
  999. },
  1000. })
  1001. assert.Error(t, err)
  1002. assert.Contains(t, getErrorString(err), "no file/folder compressed")
  1003. err = dataprovider.DeleteUser(username1, "", "", "")
  1004. assert.NoError(t, err)
  1005. err = dataprovider.DeleteUser(username2, "", "", "")
  1006. assert.NoError(t, err)
  1007. // test folder quota reset
  1008. foldername1 := "f1"
  1009. foldername2 := "f2"
  1010. folder1 := vfs.BaseVirtualFolder{
  1011. Name: foldername1,
  1012. MappedPath: filepath.Join(os.TempDir(), foldername1),
  1013. }
  1014. folder2 := vfs.BaseVirtualFolder{
  1015. Name: foldername2,
  1016. MappedPath: filepath.Join(os.TempDir(), foldername2),
  1017. }
  1018. err = dataprovider.AddFolder(&folder1, "", "", "")
  1019. assert.NoError(t, err)
  1020. err = dataprovider.AddFolder(&folder2, "", "", "")
  1021. assert.NoError(t, err)
  1022. action = dataprovider.BaseEventAction{
  1023. Type: dataprovider.ActionTypeFolderQuotaReset,
  1024. }
  1025. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  1026. Names: []dataprovider.ConditionPattern{
  1027. {
  1028. Pattern: foldername1,
  1029. },
  1030. },
  1031. })
  1032. assert.Error(t, err) // no home dir
  1033. err = os.MkdirAll(folder1.MappedPath, os.ModePerm)
  1034. assert.NoError(t, err)
  1035. err = os.WriteFile(filepath.Join(folder1.MappedPath, "file.txt"), []byte("folder"), 0666)
  1036. assert.NoError(t, err)
  1037. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  1038. Names: []dataprovider.ConditionPattern{
  1039. {
  1040. Pattern: foldername1,
  1041. },
  1042. },
  1043. })
  1044. assert.NoError(t, err)
  1045. folderGet, err := dataprovider.GetFolderByName(foldername1)
  1046. assert.NoError(t, err)
  1047. assert.Equal(t, 1, folderGet.UsedQuotaFiles)
  1048. assert.Equal(t, int64(6), folderGet.UsedQuotaSize)
  1049. // simulate another quota scan in progress
  1050. assert.True(t, QuotaScans.AddVFolderQuotaScan(foldername1))
  1051. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  1052. Names: []dataprovider.ConditionPattern{
  1053. {
  1054. Pattern: foldername1,
  1055. },
  1056. },
  1057. })
  1058. assert.Error(t, err)
  1059. assert.True(t, QuotaScans.RemoveVFolderQuotaScan(foldername1))
  1060. err = executeRuleAction(action, &EventParams{}, dataprovider.ConditionOptions{
  1061. Names: []dataprovider.ConditionPattern{
  1062. {
  1063. Pattern: "no folder match",
  1064. },
  1065. },
  1066. })
  1067. if assert.Error(t, err) {
  1068. assert.Contains(t, err.Error(), "no folder quota reset executed")
  1069. }
  1070. body, _, err := getHTTPRuleActionBody(dataprovider.EventActionHTTPConfig{
  1071. Method: http.MethodPost,
  1072. }, nil, nil, dataprovider.User{}, &EventParams{})
  1073. assert.NoError(t, err)
  1074. assert.Nil(t, body)
  1075. err = os.RemoveAll(folder1.MappedPath)
  1076. assert.NoError(t, err)
  1077. err = dataprovider.DeleteFolder(foldername1, "", "", "")
  1078. assert.NoError(t, err)
  1079. err = dataprovider.DeleteFolder(foldername2, "", "", "")
  1080. assert.NoError(t, err)
  1081. }
  1082. func TestEventRuleActionsNoGroupMatching(t *testing.T) {
  1083. username := "test_user_action_group_matching"
  1084. user := dataprovider.User{
  1085. BaseUser: sdk.BaseUser{
  1086. Username: username,
  1087. Permissions: map[string][]string{
  1088. "/": {dataprovider.PermAny},
  1089. },
  1090. HomeDir: filepath.Join(os.TempDir(), username),
  1091. },
  1092. }
  1093. err := dataprovider.AddUser(&user, "", "", "")
  1094. assert.NoError(t, err)
  1095. conditions := dataprovider.ConditionOptions{
  1096. GroupNames: []dataprovider.ConditionPattern{
  1097. {
  1098. Pattern: "agroup",
  1099. },
  1100. },
  1101. }
  1102. err = executeDeleteFsRuleAction(nil, nil, conditions, &EventParams{})
  1103. if assert.Error(t, err) {
  1104. assert.Contains(t, err.Error(), "no delete executed")
  1105. }
  1106. err = executeMkdirFsRuleAction(nil, nil, conditions, &EventParams{})
  1107. if assert.Error(t, err) {
  1108. assert.Contains(t, err.Error(), "no mkdir executed")
  1109. }
  1110. err = executeRenameFsRuleAction(nil, nil, conditions, &EventParams{})
  1111. if assert.Error(t, err) {
  1112. assert.Contains(t, err.Error(), "no rename executed")
  1113. }
  1114. err = executeExistFsRuleAction(nil, nil, conditions, &EventParams{})
  1115. if assert.Error(t, err) {
  1116. assert.Contains(t, err.Error(), "no existence check executed")
  1117. }
  1118. err = executeCopyFsRuleAction(nil, nil, conditions, &EventParams{})
  1119. if assert.Error(t, err) {
  1120. assert.Contains(t, err.Error(), "no copy executed")
  1121. }
  1122. err = executeUsersQuotaResetRuleAction(conditions, &EventParams{})
  1123. if assert.Error(t, err) {
  1124. assert.Contains(t, err.Error(), "no user quota reset executed")
  1125. }
  1126. err = executeMetadataCheckRuleAction(conditions, &EventParams{})
  1127. if assert.Error(t, err) {
  1128. assert.Contains(t, err.Error(), "no metadata check executed")
  1129. }
  1130. err = executeTransferQuotaResetRuleAction(conditions, &EventParams{})
  1131. if assert.Error(t, err) {
  1132. assert.Contains(t, err.Error(), "no transfer quota reset executed")
  1133. }
  1134. err = executeDataRetentionCheckRuleAction(dataprovider.EventActionDataRetentionConfig{}, conditions, &EventParams{}, "")
  1135. if assert.Error(t, err) {
  1136. assert.Contains(t, err.Error(), "no retention check executed")
  1137. }
  1138. err = dataprovider.DeleteUser(username, "", "", "")
  1139. assert.NoError(t, err)
  1140. err = os.RemoveAll(user.GetHomeDir())
  1141. assert.NoError(t, err)
  1142. }
  1143. func TestGetFileContent(t *testing.T) {
  1144. username := "test_user_get_file_content"
  1145. user := dataprovider.User{
  1146. BaseUser: sdk.BaseUser{
  1147. Username: username,
  1148. Permissions: map[string][]string{
  1149. "/": {dataprovider.PermAny},
  1150. },
  1151. HomeDir: filepath.Join(os.TempDir(), username),
  1152. },
  1153. }
  1154. err := dataprovider.AddUser(&user, "", "", "")
  1155. assert.NoError(t, err)
  1156. err = os.MkdirAll(user.GetHomeDir(), os.ModePerm)
  1157. assert.NoError(t, err)
  1158. fileContent := []byte("test file content")
  1159. err = os.WriteFile(filepath.Join(user.GetHomeDir(), "file.txt"), fileContent, 0666)
  1160. assert.NoError(t, err)
  1161. replacer := strings.NewReplacer("old", "new")
  1162. files, err := getMailAttachments(user, []string{"/file.txt"}, replacer)
  1163. assert.NoError(t, err)
  1164. if assert.Len(t, files, 1) {
  1165. assert.Equal(t, fileContent, files[0].Data)
  1166. }
  1167. // missing file
  1168. _, err = getMailAttachments(user, []string{"/file1.txt"}, replacer)
  1169. assert.Error(t, err)
  1170. // directory
  1171. _, err = getMailAttachments(user, []string{"/"}, replacer)
  1172. assert.Error(t, err)
  1173. // files too large
  1174. content := make([]byte, maxAttachmentsSize/2+1)
  1175. _, err = rand.Read(content)
  1176. assert.NoError(t, err)
  1177. err = os.WriteFile(filepath.Join(user.GetHomeDir(), "file1.txt"), content, 0666)
  1178. assert.NoError(t, err)
  1179. err = os.WriteFile(filepath.Join(user.GetHomeDir(), "file2.txt"), content, 0666)
  1180. assert.NoError(t, err)
  1181. files, err = getMailAttachments(user, []string{"/file1.txt"}, replacer)
  1182. assert.NoError(t, err)
  1183. if assert.Len(t, files, 1) {
  1184. assert.Equal(t, content, files[0].Data)
  1185. }
  1186. _, err = getMailAttachments(user, []string{"/file1.txt", "/file2.txt"}, replacer)
  1187. if assert.Error(t, err) {
  1188. assert.Contains(t, err.Error(), "size too large")
  1189. }
  1190. // change the filesystem provider
  1191. user.FsConfig.Provider = sdk.CryptedFilesystemProvider
  1192. user.FsConfig.CryptConfig.Passphrase = kms.NewPlainSecret("pwd")
  1193. err = dataprovider.UpdateUser(&user, "", "", "")
  1194. assert.NoError(t, err)
  1195. // the file is not encrypted so reading the encryption header will fail
  1196. _, err = getMailAttachments(user, []string{"/file.txt"}, replacer)
  1197. assert.Error(t, err)
  1198. err = dataprovider.DeleteUser(username, "", "", "")
  1199. assert.NoError(t, err)
  1200. err = os.RemoveAll(user.GetHomeDir())
  1201. assert.NoError(t, err)
  1202. }
  1203. func TestFilesystemActionErrors(t *testing.T) {
  1204. err := executeFsRuleAction(dataprovider.EventActionFilesystemConfig{}, dataprovider.ConditionOptions{}, &EventParams{})
  1205. if assert.Error(t, err) {
  1206. assert.Contains(t, err.Error(), "unsupported filesystem action")
  1207. }
  1208. username := "test_user_for_actions"
  1209. testReplacer := strings.NewReplacer("old", "new")
  1210. user := dataprovider.User{
  1211. BaseUser: sdk.BaseUser{
  1212. Username: username,
  1213. Permissions: map[string][]string{
  1214. "/": {dataprovider.PermAny},
  1215. },
  1216. HomeDir: filepath.Join(os.TempDir(), username),
  1217. },
  1218. FsConfig: vfs.Filesystem{
  1219. Provider: sdk.SFTPFilesystemProvider,
  1220. SFTPConfig: vfs.SFTPFsConfig{
  1221. BaseSFTPFsConfig: sdk.BaseSFTPFsConfig{
  1222. Endpoint: "127.0.0.1:4022",
  1223. Username: username,
  1224. },
  1225. Password: kms.NewPlainSecret("pwd"),
  1226. },
  1227. },
  1228. }
  1229. err = executeEmailRuleAction(dataprovider.EventActionEmailConfig{
  1230. Recipients: []string{"[email protected]"},
  1231. Subject: "subject",
  1232. Body: "body",
  1233. Attachments: []string{"/file.txt"},
  1234. }, &EventParams{
  1235. sender: username,
  1236. })
  1237. assert.Error(t, err)
  1238. conn := NewBaseConnection("", protocolEventAction, "", "", user)
  1239. err = executeDeleteFileFsAction(conn, "", nil)
  1240. assert.Error(t, err)
  1241. err = dataprovider.AddUser(&user, "", "", "")
  1242. assert.NoError(t, err)
  1243. // check root fs fails
  1244. err = executeDeleteFsActionForUser(nil, testReplacer, user)
  1245. assert.Error(t, err)
  1246. err = executeMkDirsFsActionForUser(nil, testReplacer, user)
  1247. assert.Error(t, err)
  1248. err = executeRenameFsActionForUser(nil, testReplacer, user)
  1249. assert.Error(t, err)
  1250. err = executeExistFsActionForUser(nil, testReplacer, user)
  1251. assert.Error(t, err)
  1252. err = executeCopyFsActionForUser(nil, testReplacer, user)
  1253. assert.Error(t, err)
  1254. err = executeCompressFsActionForUser(dataprovider.EventActionFsCompress{}, testReplacer, user)
  1255. assert.Error(t, err)
  1256. _, _, _, _, err = getFileWriter(conn, "/path.txt", -1) //nolint:dogsled
  1257. assert.Error(t, err)
  1258. err = executeEmailRuleAction(dataprovider.EventActionEmailConfig{
  1259. Recipients: []string{"[email protected]"},
  1260. Subject: "subject",
  1261. Body: "body",
  1262. Attachments: []string{"/file1.txt"},
  1263. }, &EventParams{
  1264. sender: username,
  1265. })
  1266. assert.Error(t, err)
  1267. _, err = getFileContent(NewBaseConnection("", protocolEventAction, "", "", user), "/f.txt", 1234)
  1268. assert.Error(t, err)
  1269. err = executeHTTPRuleAction(dataprovider.EventActionHTTPConfig{
  1270. Endpoint: "http://127.0.0.1:9999/",
  1271. Method: http.MethodPost,
  1272. Parts: []dataprovider.HTTPPart{
  1273. {
  1274. Name: "p1",
  1275. Filepath: "/filepath",
  1276. },
  1277. },
  1278. }, &EventParams{
  1279. sender: username,
  1280. })
  1281. assert.Error(t, err)
  1282. user.FsConfig.Provider = sdk.LocalFilesystemProvider
  1283. user.Permissions["/"] = []string{dataprovider.PermUpload}
  1284. err = dataprovider.DeleteUser(username, "", "", "")
  1285. assert.NoError(t, err)
  1286. err = dataprovider.AddUser(&user, "", "", "")
  1287. assert.NoError(t, err)
  1288. err = executeRenameFsActionForUser([]dataprovider.KeyValue{
  1289. {
  1290. Key: "/p1",
  1291. Value: "/p1",
  1292. },
  1293. }, testReplacer, user)
  1294. if assert.Error(t, err) {
  1295. assert.Contains(t, err.Error(), "the rename source and target cannot be the same")
  1296. }
  1297. err = executeRuleAction(dataprovider.BaseEventAction{
  1298. Type: dataprovider.ActionTypeFilesystem,
  1299. Options: dataprovider.BaseEventActionOptions{
  1300. FsConfig: dataprovider.EventActionFilesystemConfig{
  1301. Type: dataprovider.FilesystemActionRename,
  1302. Renames: []dataprovider.KeyValue{
  1303. {
  1304. Key: "/p2",
  1305. Value: "/p2",
  1306. },
  1307. },
  1308. },
  1309. },
  1310. }, &EventParams{}, dataprovider.ConditionOptions{
  1311. Names: []dataprovider.ConditionPattern{
  1312. {
  1313. Pattern: username,
  1314. },
  1315. },
  1316. })
  1317. assert.Error(t, err)
  1318. if runtime.GOOS != osWindows {
  1319. dirPath := filepath.Join(user.HomeDir, "adir", "sub")
  1320. err := os.MkdirAll(dirPath, os.ModePerm)
  1321. assert.NoError(t, err)
  1322. filePath := filepath.Join(dirPath, "f.dat")
  1323. err = os.WriteFile(filePath, []byte("test file content"), 0666)
  1324. assert.NoError(t, err)
  1325. err = os.Chmod(dirPath, 0001)
  1326. assert.NoError(t, err)
  1327. err = executeDeleteFsActionForUser([]string{"/adir/sub"}, testReplacer, user)
  1328. assert.Error(t, err)
  1329. err = executeDeleteFsActionForUser([]string{"/adir/sub/f.dat"}, testReplacer, user)
  1330. assert.Error(t, err)
  1331. err = os.Chmod(dirPath, 0555)
  1332. assert.NoError(t, err)
  1333. err = executeDeleteFsActionForUser([]string{"/adir/sub/f.dat"}, testReplacer, user)
  1334. if assert.Error(t, err) {
  1335. assert.Contains(t, err.Error(), "unable to remove file")
  1336. }
  1337. err = executeRuleAction(dataprovider.BaseEventAction{
  1338. Type: dataprovider.ActionTypeFilesystem,
  1339. Options: dataprovider.BaseEventActionOptions{
  1340. FsConfig: dataprovider.EventActionFilesystemConfig{
  1341. Type: dataprovider.FilesystemActionDelete,
  1342. Deletes: []string{"/adir/sub/f.dat"},
  1343. },
  1344. },
  1345. }, &EventParams{}, dataprovider.ConditionOptions{
  1346. Names: []dataprovider.ConditionPattern{
  1347. {
  1348. Pattern: username,
  1349. },
  1350. },
  1351. })
  1352. assert.Error(t, err)
  1353. err = executeMkDirsFsActionForUser([]string{"/adir/sub/sub"}, testReplacer, user)
  1354. if assert.Error(t, err) {
  1355. assert.Contains(t, err.Error(), "unable to create dir")
  1356. }
  1357. err = executeMkDirsFsActionForUser([]string{"/adir/sub/sub/sub"}, testReplacer, user)
  1358. if assert.Error(t, err) {
  1359. assert.Contains(t, err.Error(), "unable to check parent dirs")
  1360. }
  1361. err = executeRuleAction(dataprovider.BaseEventAction{
  1362. Type: dataprovider.ActionTypeFilesystem,
  1363. Options: dataprovider.BaseEventActionOptions{
  1364. FsConfig: dataprovider.EventActionFilesystemConfig{
  1365. Type: dataprovider.FilesystemActionMkdirs,
  1366. MkDirs: []string{"/adir/sub/sub1"},
  1367. },
  1368. },
  1369. }, &EventParams{}, dataprovider.ConditionOptions{
  1370. Names: []dataprovider.ConditionPattern{
  1371. {
  1372. Pattern: username,
  1373. },
  1374. },
  1375. })
  1376. assert.Error(t, err)
  1377. err = os.Chmod(dirPath, os.ModePerm)
  1378. assert.NoError(t, err)
  1379. conn = NewBaseConnection("", protocolEventAction, "", "", user)
  1380. wr := &zipWriterWrapper{
  1381. Name: "test.zip",
  1382. Writer: zip.NewWriter(bytes.NewBuffer(nil)),
  1383. Entries: map[string]bool{},
  1384. }
  1385. err = addZipEntry(wr, conn, "/adir/sub/f.dat", "/adir/sub/sub")
  1386. assert.Error(t, err)
  1387. assert.Contains(t, getErrorString(err), "is outside base dir")
  1388. }
  1389. err = dataprovider.DeleteUser(username, "", "", "")
  1390. assert.NoError(t, err)
  1391. err = os.RemoveAll(user.GetHomeDir())
  1392. assert.NoError(t, err)
  1393. }
  1394. func TestQuotaActionsWithQuotaTrackDisabled(t *testing.T) {
  1395. oldProviderConf := dataprovider.GetProviderConfig()
  1396. providerConf := dataprovider.GetProviderConfig()
  1397. providerConf.TrackQuota = 0
  1398. err := dataprovider.Close()
  1399. assert.NoError(t, err)
  1400. err = dataprovider.Initialize(providerConf, configDir, true)
  1401. assert.NoError(t, err)
  1402. username := "u1"
  1403. user := dataprovider.User{
  1404. BaseUser: sdk.BaseUser{
  1405. Username: username,
  1406. HomeDir: filepath.Join(os.TempDir(), username),
  1407. Status: 1,
  1408. Permissions: map[string][]string{
  1409. "/": {dataprovider.PermAny},
  1410. },
  1411. },
  1412. FsConfig: vfs.Filesystem{
  1413. Provider: sdk.LocalFilesystemProvider,
  1414. },
  1415. }
  1416. err = dataprovider.AddUser(&user, "", "", "")
  1417. assert.NoError(t, err)
  1418. err = os.MkdirAll(user.GetHomeDir(), os.ModePerm)
  1419. assert.NoError(t, err)
  1420. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeUserQuotaReset},
  1421. &EventParams{}, dataprovider.ConditionOptions{
  1422. Names: []dataprovider.ConditionPattern{
  1423. {
  1424. Pattern: username,
  1425. },
  1426. },
  1427. })
  1428. assert.Error(t, err)
  1429. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeTransferQuotaReset},
  1430. &EventParams{}, dataprovider.ConditionOptions{
  1431. Names: []dataprovider.ConditionPattern{
  1432. {
  1433. Pattern: username,
  1434. },
  1435. },
  1436. })
  1437. assert.Error(t, err)
  1438. err = os.RemoveAll(user.GetHomeDir())
  1439. assert.NoError(t, err)
  1440. err = dataprovider.DeleteUser(username, "", "", "")
  1441. assert.NoError(t, err)
  1442. foldername := "f1"
  1443. folder := vfs.BaseVirtualFolder{
  1444. Name: foldername,
  1445. MappedPath: filepath.Join(os.TempDir(), foldername),
  1446. }
  1447. err = dataprovider.AddFolder(&folder, "", "", "")
  1448. assert.NoError(t, err)
  1449. err = os.MkdirAll(folder.MappedPath, os.ModePerm)
  1450. assert.NoError(t, err)
  1451. err = executeRuleAction(dataprovider.BaseEventAction{Type: dataprovider.ActionTypeFolderQuotaReset},
  1452. &EventParams{}, dataprovider.ConditionOptions{
  1453. Names: []dataprovider.ConditionPattern{
  1454. {
  1455. Pattern: foldername,
  1456. },
  1457. },
  1458. })
  1459. assert.Error(t, err)
  1460. err = os.RemoveAll(folder.MappedPath)
  1461. assert.NoError(t, err)
  1462. err = dataprovider.DeleteFolder(foldername, "", "", "")
  1463. assert.NoError(t, err)
  1464. err = dataprovider.Close()
  1465. assert.NoError(t, err)
  1466. err = dataprovider.Initialize(oldProviderConf, configDir, true)
  1467. assert.NoError(t, err)
  1468. }
  1469. func TestScheduledActions(t *testing.T) {
  1470. startEventScheduler()
  1471. backupsPath := filepath.Join(os.TempDir(), "backups")
  1472. err := os.RemoveAll(backupsPath)
  1473. assert.NoError(t, err)
  1474. action := &dataprovider.BaseEventAction{
  1475. Name: "action",
  1476. Type: dataprovider.ActionTypeBackup,
  1477. }
  1478. err = dataprovider.AddEventAction(action, "", "", "")
  1479. assert.NoError(t, err)
  1480. rule := &dataprovider.EventRule{
  1481. Name: "rule",
  1482. Trigger: dataprovider.EventTriggerSchedule,
  1483. Conditions: dataprovider.EventConditions{
  1484. Schedules: []dataprovider.Schedule{
  1485. {
  1486. Hours: "11",
  1487. DayOfWeek: "*",
  1488. DayOfMonth: "*",
  1489. Month: "*",
  1490. },
  1491. },
  1492. },
  1493. Actions: []dataprovider.EventAction{
  1494. {
  1495. BaseEventAction: dataprovider.BaseEventAction{
  1496. Name: action.Name,
  1497. },
  1498. Order: 1,
  1499. },
  1500. },
  1501. }
  1502. job := eventCronJob{
  1503. ruleName: rule.Name,
  1504. }
  1505. job.Run() // rule not found
  1506. assert.NoDirExists(t, backupsPath)
  1507. err = dataprovider.AddEventRule(rule, "", "", "")
  1508. assert.NoError(t, err)
  1509. job.Run()
  1510. assert.DirExists(t, backupsPath)
  1511. action.Type = dataprovider.ActionTypeEmail
  1512. action.Options = dataprovider.BaseEventActionOptions{
  1513. EmailConfig: dataprovider.EventActionEmailConfig{
  1514. Recipients: []string{"[email protected]"},
  1515. Subject: "test with attachments",
  1516. Body: "body",
  1517. Attachments: []string{"/file1.txt"},
  1518. },
  1519. }
  1520. err = dataprovider.UpdateEventAction(action, "", "", "")
  1521. assert.NoError(t, err)
  1522. job.Run() // action is not compatible with a scheduled rule
  1523. err = dataprovider.DeleteEventRule(rule.Name, "", "", "")
  1524. assert.NoError(t, err)
  1525. err = dataprovider.DeleteEventAction(action.Name, "", "", "")
  1526. assert.NoError(t, err)
  1527. err = os.RemoveAll(backupsPath)
  1528. assert.NoError(t, err)
  1529. stopEventScheduler()
  1530. }
  1531. func TestEventParamsCopy(t *testing.T) {
  1532. params := EventParams{
  1533. Name: "name",
  1534. Event: "event",
  1535. Status: 1,
  1536. errors: []string{"error1"},
  1537. retentionChecks: []executedRetentionCheck{},
  1538. }
  1539. paramsCopy := params.getACopy()
  1540. assert.Equal(t, params, *paramsCopy)
  1541. params.Name = "name mod"
  1542. paramsCopy.Event = "event mod"
  1543. paramsCopy.Status = 2
  1544. params.errors = append(params.errors, "error2")
  1545. paramsCopy.errors = append(paramsCopy.errors, "error3")
  1546. assert.Equal(t, []string{"error1", "error3"}, paramsCopy.errors)
  1547. assert.Equal(t, []string{"error1", "error2"}, params.errors)
  1548. assert.Equal(t, "name mod", params.Name)
  1549. assert.Equal(t, "name", paramsCopy.Name)
  1550. assert.Equal(t, "event", params.Event)
  1551. assert.Equal(t, "event mod", paramsCopy.Event)
  1552. assert.Equal(t, 1, params.Status)
  1553. assert.Equal(t, 2, paramsCopy.Status)
  1554. params = EventParams{
  1555. retentionChecks: []executedRetentionCheck{
  1556. {
  1557. Username: "u",
  1558. ActionName: "a",
  1559. Results: []folderRetentionCheckResult{
  1560. {
  1561. Path: "p",
  1562. Retention: 1,
  1563. },
  1564. },
  1565. },
  1566. },
  1567. }
  1568. paramsCopy = params.getACopy()
  1569. require.Len(t, paramsCopy.retentionChecks, 1)
  1570. paramsCopy.retentionChecks[0].Username = "u_copy"
  1571. paramsCopy.retentionChecks[0].ActionName = "a_copy"
  1572. require.Len(t, paramsCopy.retentionChecks[0].Results, 1)
  1573. paramsCopy.retentionChecks[0].Results[0].Path = "p_copy"
  1574. paramsCopy.retentionChecks[0].Results[0].Retention = 2
  1575. assert.Equal(t, "u", params.retentionChecks[0].Username)
  1576. assert.Equal(t, "a", params.retentionChecks[0].ActionName)
  1577. assert.Equal(t, "p", params.retentionChecks[0].Results[0].Path)
  1578. assert.Equal(t, 1, params.retentionChecks[0].Results[0].Retention)
  1579. assert.Equal(t, "u_copy", paramsCopy.retentionChecks[0].Username)
  1580. assert.Equal(t, "a_copy", paramsCopy.retentionChecks[0].ActionName)
  1581. assert.Equal(t, "p_copy", paramsCopy.retentionChecks[0].Results[0].Path)
  1582. assert.Equal(t, 2, paramsCopy.retentionChecks[0].Results[0].Retention)
  1583. }
  1584. func TestEventParamsStatusFromError(t *testing.T) {
  1585. params := EventParams{Status: 1}
  1586. params.AddError(os.ErrNotExist)
  1587. assert.Equal(t, 1, params.Status)
  1588. params = EventParams{Status: 1, updateStatusFromError: true}
  1589. params.AddError(os.ErrNotExist)
  1590. assert.Equal(t, 2, params.Status)
  1591. }
  1592. type testWriter struct {
  1593. errTest error
  1594. sentinel string
  1595. }
  1596. func (w *testWriter) Write(p []byte) (int, error) {
  1597. if w.errTest != nil {
  1598. return 0, w.errTest
  1599. }
  1600. if w.sentinel == string(p) {
  1601. return 0, io.ErrUnexpectedEOF
  1602. }
  1603. return len(p), nil
  1604. }
  1605. func TestWriteHTTPPartsError(t *testing.T) {
  1606. m := multipart.NewWriter(&testWriter{
  1607. errTest: io.ErrShortWrite,
  1608. })
  1609. err := writeHTTPPart(m, dataprovider.HTTPPart{}, nil, nil, nil, &EventParams{})
  1610. assert.ErrorIs(t, err, io.ErrShortWrite)
  1611. body := "test body"
  1612. m = multipart.NewWriter(&testWriter{sentinel: body})
  1613. err = writeHTTPPart(m, dataprovider.HTTPPart{
  1614. Body: body,
  1615. }, nil, nil, nil, &EventParams{})
  1616. assert.ErrorIs(t, err, io.ErrUnexpectedEOF)
  1617. }
  1618. func TestReplacePathsPlaceholders(t *testing.T) {
  1619. replacer := strings.NewReplacer("{{VirtualPath}}", "/path1")
  1620. paths := []string{"{{VirtualPath}}", "/path1"}
  1621. paths = replacePathsPlaceholders(paths, replacer)
  1622. assert.Equal(t, []string{"/path1"}, paths)
  1623. paths = []string{"{{VirtualPath}}", "/path2"}
  1624. paths = replacePathsPlaceholders(paths, replacer)
  1625. assert.Equal(t, []string{"/path1", "/path2"}, paths)
  1626. }
  1627. func TestEstimateZipSizeErrors(t *testing.T) {
  1628. u := dataprovider.User{
  1629. BaseUser: sdk.BaseUser{
  1630. Username: "u",
  1631. HomeDir: filepath.Join(os.TempDir(), "u"),
  1632. Status: 1,
  1633. Permissions: map[string][]string{
  1634. "/": {dataprovider.PermAny},
  1635. },
  1636. QuotaSize: 1000,
  1637. },
  1638. }
  1639. err := dataprovider.AddUser(&u, "", "", "")
  1640. assert.NoError(t, err)
  1641. err = os.MkdirAll(u.GetHomeDir(), os.ModePerm)
  1642. assert.NoError(t, err)
  1643. conn := NewBaseConnection("", ProtocolFTP, "", "", u)
  1644. _, err = getSizeForPath(conn, "/missing", vfs.NewFileInfo("missing", true, 0, time.Now(), false))
  1645. assert.True(t, conn.IsNotExistError(err))
  1646. if runtime.GOOS != osWindows {
  1647. err = os.MkdirAll(filepath.Join(u.HomeDir, "d1", "d2", "sub"), os.ModePerm)
  1648. assert.NoError(t, err)
  1649. err = os.WriteFile(filepath.Join(u.HomeDir, "d1", "d2", "sub", "file.txt"), []byte("data"), 0666)
  1650. assert.NoError(t, err)
  1651. err = os.Chmod(filepath.Join(u.HomeDir, "d1", "d2"), 0001)
  1652. assert.NoError(t, err)
  1653. size, err := estimateZipSize(conn, "/archive.zip", []string{"/d1"})
  1654. assert.Error(t, err, "size %d", size)
  1655. err = os.Chmod(filepath.Join(u.HomeDir, "d1", "d2"), os.ModePerm)
  1656. assert.NoError(t, err)
  1657. }
  1658. err = dataprovider.DeleteUser(u.Username, "", "", "")
  1659. assert.NoError(t, err)
  1660. err = os.RemoveAll(u.GetHomeDir())
  1661. assert.NoError(t, err)
  1662. }
  1663. func getErrorString(err error) string {
  1664. if err == nil {
  1665. return ""
  1666. }
  1667. return err.Error()
  1668. }