eventmanager_test.go 52 KB

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