eventmanager_test.go 43 KB

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