exprlib_test.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362
  1. package exprhelpers
  2. import (
  3. "context"
  4. "fmt"
  5. "os"
  6. "testing"
  7. "time"
  8. "github.com/antonmedv/expr"
  9. "github.com/pkg/errors"
  10. log "github.com/sirupsen/logrus"
  11. "github.com/stretchr/testify/assert"
  12. "github.com/stretchr/testify/require"
  13. "github.com/crowdsecurity/crowdsec/pkg/csconfig"
  14. "github.com/crowdsecurity/crowdsec/pkg/cstest"
  15. "github.com/crowdsecurity/crowdsec/pkg/database"
  16. "github.com/crowdsecurity/crowdsec/pkg/models"
  17. "github.com/crowdsecurity/crowdsec/pkg/types"
  18. )
  19. var (
  20. TestFolder = "tests"
  21. )
  22. func getDBClient(t *testing.T) *database.Client {
  23. t.Helper()
  24. dbPath, err := os.CreateTemp("", "*sqlite")
  25. require.NoError(t, err)
  26. testDbClient, err := database.NewClient(&csconfig.DatabaseCfg{
  27. Type: "sqlite",
  28. DbName: "crowdsec",
  29. DbPath: dbPath.Name(),
  30. })
  31. require.NoError(t, err)
  32. return testDbClient
  33. }
  34. func TestVisitor(t *testing.T) {
  35. err := Init(nil)
  36. require.NoError(t, err)
  37. tests := []struct {
  38. name string
  39. filter string
  40. result bool
  41. env map[string]interface{}
  42. err error
  43. }{
  44. {
  45. name: "debug : no variable",
  46. filter: "'crowdsec' startsWith 'crowdse'",
  47. result: true,
  48. err: nil,
  49. env: map[string]interface{}{},
  50. },
  51. {
  52. name: "debug : simple variable",
  53. filter: "'crowdsec' startsWith static_one && 1 == 1",
  54. result: true,
  55. err: nil,
  56. env: map[string]interface{}{"static_one": string("crowdse")},
  57. },
  58. {
  59. name: "debug : simple variable re-used",
  60. filter: "static_one.foo == 'bar' && static_one.foo != 'toto'",
  61. result: true,
  62. err: nil,
  63. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  64. },
  65. {
  66. name: "debug : can't compile",
  67. filter: "static_one.foo.toto == 'lol'",
  68. result: false,
  69. err: fmt.Errorf("bad syntax"),
  70. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  71. },
  72. {
  73. name: "debug : can't compile #2",
  74. filter: "static_one.f!oo.to/to == 'lol'",
  75. result: false,
  76. err: fmt.Errorf("bad syntax"),
  77. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  78. },
  79. {
  80. name: "debug : can't compile #3",
  81. filter: "",
  82. result: false,
  83. err: fmt.Errorf("bad syntax"),
  84. env: map[string]interface{}{"static_one": map[string]string{"foo": "bar"}},
  85. },
  86. }
  87. log.SetLevel(log.DebugLevel)
  88. clog := log.WithFields(log.Fields{
  89. "type": "test",
  90. })
  91. for _, test := range tests {
  92. compiledFilter, err := expr.Compile(test.filter, GetExprOptions(test.env)...)
  93. if err != nil && test.err == nil {
  94. log.Fatalf("compile: %s", err)
  95. }
  96. debugFilter, err := NewDebugger(test.filter, GetExprOptions(test.env)...)
  97. if err != nil && test.err == nil {
  98. log.Fatalf("debug: %s", err)
  99. }
  100. if compiledFilter != nil {
  101. result, err := expr.Run(compiledFilter, test.env)
  102. if err != nil && test.err == nil {
  103. log.Fatalf("run : %s", err)
  104. }
  105. if isOk := assert.Equal(t, test.result, result); !isOk {
  106. t.Fatalf("test '%s' : NOK", test.filter)
  107. }
  108. }
  109. if debugFilter != nil {
  110. debugFilter.Run(clog, test.result, test.env)
  111. }
  112. }
  113. }
  114. func TestMatch(t *testing.T) {
  115. err := Init(nil)
  116. require.NoError(t, err)
  117. tests := []struct {
  118. glob string
  119. val string
  120. ret bool
  121. expr string
  122. }{
  123. {"foo", "foo", true, `Match(pattern, name)`},
  124. {"foo", "bar", false, `Match(pattern, name)`},
  125. {"foo*", "foo", true, `Match(pattern, name)`},
  126. {"foo*", "foobar", true, `Match(pattern, name)`},
  127. {"foo*", "barfoo", false, `Match(pattern, name)`},
  128. {"foo*", "bar", false, `Match(pattern, name)`},
  129. {"*foo", "foo", true, `Match(pattern, name)`},
  130. {"*foo", "barfoo", true, `Match(pattern, name)`},
  131. {"foo*r", "foobar", true, `Match(pattern, name)`},
  132. {"foo*r", "foobazr", true, `Match(pattern, name)`},
  133. {"foo?ar", "foobar", true, `Match(pattern, name)`},
  134. {"foo?ar", "foobazr", false, `Match(pattern, name)`},
  135. {"foo?ar", "foobaz", false, `Match(pattern, name)`},
  136. {"*foo?ar?", "foobar", false, `Match(pattern, name)`},
  137. {"*foo?ar?", "foobare", true, `Match(pattern, name)`},
  138. {"*foo?ar?", "rafoobar", false, `Match(pattern, name)`},
  139. {"*foo?ar?", "rafoobare", true, `Match(pattern, name)`},
  140. }
  141. for _, test := range tests {
  142. env := map[string]interface{}{
  143. "pattern": test.glob,
  144. "name": test.val,
  145. }
  146. vm, err := expr.Compile(test.expr, GetExprOptions(env)...)
  147. if err != nil {
  148. t.Fatalf("pattern:%s val:%s NOK %s", test.glob, test.val, err)
  149. }
  150. ret, err := expr.Run(vm, env)
  151. assert.NoError(t, err)
  152. if isOk := assert.Equal(t, test.ret, ret); !isOk {
  153. t.Fatalf("pattern:%s val:%s NOK %t != %t", test.glob, test.val, ret, test.ret)
  154. }
  155. }
  156. }
  157. func TestDistanceHelper(t *testing.T) {
  158. err := Init(nil)
  159. require.NoError(t, err)
  160. tests := []struct {
  161. lat1 string
  162. lon1 string
  163. lat2 string
  164. lon2 string
  165. dist float64
  166. valid bool
  167. expr string
  168. name string
  169. }{
  170. {"51.45", "1.15", "41.54", "12.27", 1389.1793118293067, true, `Distance(lat1, lon1, lat2, lon2)`, "valid"},
  171. {"lol", "1.15", "41.54", "12.27", 0.0, false, `Distance(lat1, lon1, lat2, lon2)`, "invalid lat1"},
  172. {"0.0", "0.0", "12.1", "12.1", 0.0, true, `Distance(lat1, lon1, lat2, lon2)`, "empty coord"},
  173. }
  174. for _, test := range tests {
  175. t.Run(test.name, func(t *testing.T) {
  176. env := map[string]interface{}{
  177. "lat1": test.lat1,
  178. "lon1": test.lon1,
  179. "lat2": test.lat2,
  180. "lon2": test.lon2,
  181. }
  182. vm, err := expr.Compile(test.expr, GetExprOptions(env)...)
  183. if err != nil {
  184. t.Fatalf("pattern:%s val:%s NOK %s", test.lat1, test.lon1, err)
  185. }
  186. ret, err := expr.Run(vm, env)
  187. if test.valid {
  188. assert.NoError(t, err)
  189. assert.Equal(t, test.dist, ret)
  190. } else {
  191. assert.NotNil(t, err)
  192. }
  193. })
  194. }
  195. }
  196. func TestRegexpCacheBehavior(t *testing.T) {
  197. err := Init(nil)
  198. require.NoError(t, err)
  199. filename := "test_data_re.txt"
  200. err = FileInit(TestFolder, filename, "regex")
  201. require.NoError(t, err)
  202. //cache with no TTL
  203. err = RegexpCacheInit(filename, types.DataSource{Type: "regex", Size: types.IntPtr(1)})
  204. require.NoError(t, err)
  205. ret, _ := RegexpInFile("crowdsec", filename)
  206. assert.False(t, ret.(bool))
  207. assert.Equal(t, 1, dataFileRegexCache[filename].Len(false))
  208. ret, _ = RegexpInFile("Crowdsec", filename)
  209. assert.True(t, ret.(bool))
  210. assert.Equal(t, 1, dataFileRegexCache[filename].Len(false))
  211. //cache with TTL
  212. ttl := 500 * time.Millisecond
  213. err = RegexpCacheInit(filename, types.DataSource{Type: "regex", Size: types.IntPtr(2), TTL: &ttl})
  214. require.NoError(t, err)
  215. ret, _ = RegexpInFile("crowdsec", filename)
  216. assert.False(t, ret.(bool))
  217. assert.Equal(t, 1, dataFileRegexCache[filename].Len(true))
  218. time.Sleep(1 * time.Second)
  219. assert.Equal(t, 0, dataFileRegexCache[filename].Len(true))
  220. }
  221. func TestRegexpInFile(t *testing.T) {
  222. if err := Init(nil); err != nil {
  223. log.Fatal(err)
  224. }
  225. err := FileInit(TestFolder, "test_data_re.txt", "regex")
  226. if err != nil {
  227. log.Fatal(err)
  228. }
  229. tests := []struct {
  230. name string
  231. filter string
  232. result bool
  233. err error
  234. }{
  235. {
  236. name: "RegexpInFile() test: lower case word in data file",
  237. filter: "RegexpInFile('crowdsec', 'test_data_re.txt')",
  238. result: false,
  239. err: nil,
  240. },
  241. {
  242. name: "RegexpInFile() test: Match exactly",
  243. filter: "RegexpInFile('Crowdsec', 'test_data_re.txt')",
  244. result: true,
  245. err: nil,
  246. },
  247. {
  248. name: "RegexpInFile() test: match with word before",
  249. filter: "RegexpInFile('test Crowdsec', 'test_data_re.txt')",
  250. result: true,
  251. err: nil,
  252. },
  253. {
  254. name: "RegexpInFile() test: match with word before and other case",
  255. filter: "RegexpInFile('test CrowdSec', 'test_data_re.txt')",
  256. result: true,
  257. err: nil,
  258. },
  259. }
  260. for _, test := range tests {
  261. compiledFilter, err := expr.Compile(test.filter, GetExprOptions(map[string]interface{}{})...)
  262. if err != nil {
  263. log.Fatal(err)
  264. }
  265. result, err := expr.Run(compiledFilter, map[string]interface{}{})
  266. if err != nil {
  267. log.Fatal(err)
  268. }
  269. if isOk := assert.Equal(t, test.result, result); !isOk {
  270. t.Fatalf("test '%s' : NOK", test.name)
  271. }
  272. }
  273. }
  274. func TestFileInit(t *testing.T) {
  275. if err := Init(nil); err != nil {
  276. log.Fatal(err)
  277. }
  278. tests := []struct {
  279. name string
  280. filename string
  281. types string
  282. result int
  283. err error
  284. }{
  285. {
  286. name: "file with type:string",
  287. filename: "test_data.txt",
  288. types: "string",
  289. result: 3,
  290. },
  291. {
  292. name: "file with type:string and empty lines + commentaries",
  293. filename: "test_empty_line.txt",
  294. types: "string",
  295. result: 3,
  296. },
  297. {
  298. name: "file with type:re",
  299. filename: "test_data_re.txt",
  300. types: "regex",
  301. result: 2,
  302. },
  303. {
  304. name: "file without type",
  305. filename: "test_data_no_type.txt",
  306. types: "",
  307. },
  308. }
  309. for _, test := range tests {
  310. err := FileInit(TestFolder, test.filename, test.types)
  311. if err != nil {
  312. log.Fatal(err)
  313. }
  314. if test.types == "string" {
  315. if _, ok := dataFile[test.filename]; !ok {
  316. t.Fatalf("test '%s' : NOK", test.name)
  317. }
  318. if isOk := assert.Equal(t, test.result, len(dataFile[test.filename])); !isOk {
  319. t.Fatalf("test '%s' : NOK", test.name)
  320. }
  321. } else if test.types == "regex" {
  322. if _, ok := dataFileRegex[test.filename]; !ok {
  323. t.Fatalf("test '%s' : NOK", test.name)
  324. }
  325. if isOk := assert.Equal(t, test.result, len(dataFileRegex[test.filename])); !isOk {
  326. t.Fatalf("test '%s' : NOK", test.name)
  327. }
  328. } else {
  329. if _, ok := dataFileRegex[test.filename]; ok {
  330. t.Fatalf("test '%s' : NOK", test.name)
  331. }
  332. if _, ok := dataFile[test.filename]; ok {
  333. t.Fatalf("test '%s' : NOK", test.name)
  334. }
  335. }
  336. log.Printf("test '%s' : OK", test.name)
  337. }
  338. }
  339. func TestFile(t *testing.T) {
  340. if err := Init(nil); err != nil {
  341. log.Fatal(err)
  342. }
  343. err := FileInit(TestFolder, "test_data.txt", "string")
  344. if err != nil {
  345. log.Fatal(err)
  346. }
  347. tests := []struct {
  348. name string
  349. filter string
  350. result bool
  351. err error
  352. }{
  353. {
  354. name: "File() test: word in file",
  355. filter: "'Crowdsec' in File('test_data.txt')",
  356. result: true,
  357. err: nil,
  358. },
  359. {
  360. name: "File() test: word in file but different case",
  361. filter: "'CrowdSecurity' in File('test_data.txt')",
  362. result: false,
  363. err: nil,
  364. },
  365. {
  366. name: "File() test: word not in file",
  367. filter: "'test' in File('test_data.txt')",
  368. result: false,
  369. err: nil,
  370. },
  371. {
  372. name: "File() test: filepath provided doesn't exist",
  373. filter: "'test' in File('non_existing_data.txt')",
  374. result: false,
  375. err: nil,
  376. },
  377. }
  378. for _, test := range tests {
  379. compiledFilter, err := expr.Compile(test.filter, GetExprOptions(map[string]interface{}{})...)
  380. if err != nil {
  381. log.Fatal(err)
  382. }
  383. result, err := expr.Run(compiledFilter, map[string]interface{}{})
  384. if err != nil {
  385. log.Fatal(err)
  386. }
  387. if isOk := assert.Equal(t, test.result, result); !isOk {
  388. t.Fatalf("test '%s' : NOK", test.name)
  389. }
  390. log.Printf("test '%s' : OK", test.name)
  391. }
  392. }
  393. func TestIpInRange(t *testing.T) {
  394. err := Init(nil)
  395. assert.NoError(t, err)
  396. tests := []struct {
  397. name string
  398. env map[string]interface{}
  399. code string
  400. result bool
  401. err string
  402. }{
  403. {
  404. name: "IpInRange() test: basic test",
  405. env: map[string]interface{}{
  406. "ip": "192.168.0.1",
  407. "ipRange": "192.168.0.0/24",
  408. },
  409. code: "IpInRange(ip, ipRange)",
  410. result: true,
  411. err: "",
  412. },
  413. {
  414. name: "IpInRange() test: malformed IP",
  415. env: map[string]interface{}{
  416. "ip": "192.168.0",
  417. "ipRange": "192.168.0.0/24",
  418. },
  419. code: "IpInRange(ip, ipRange)",
  420. result: false,
  421. err: "",
  422. },
  423. {
  424. name: "IpInRange() test: malformed IP range",
  425. env: map[string]interface{}{
  426. "ip": "192.168.0.0/255",
  427. "ipRange": "192.168.0.0/24",
  428. },
  429. code: "IpInRange(ip, ipRange)",
  430. result: false,
  431. err: "",
  432. },
  433. }
  434. for _, test := range tests {
  435. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  436. require.NoError(t, err)
  437. output, err := expr.Run(program, test.env)
  438. require.NoError(t, err)
  439. require.Equal(t, test.result, output)
  440. log.Printf("test '%s' : OK", test.name)
  441. }
  442. }
  443. func TestIpToRange(t *testing.T) {
  444. err := Init(nil)
  445. assert.NoError(t, err)
  446. tests := []struct {
  447. name string
  448. env map[string]interface{}
  449. code string
  450. result string
  451. err string
  452. }{
  453. {
  454. name: "IpToRange() test: IPv4",
  455. env: map[string]interface{}{
  456. "ip": "192.168.1.1",
  457. "netmask": "16",
  458. },
  459. code: "IpToRange(ip, netmask)",
  460. result: "192.168.0.0/16",
  461. err: "",
  462. },
  463. {
  464. name: "IpToRange() test: IPv6",
  465. env: map[string]interface{}{
  466. "ip": "2001:db8::1",
  467. "netmask": "/64",
  468. },
  469. code: "IpToRange(ip, netmask)",
  470. result: "2001:db8::/64",
  471. err: "",
  472. },
  473. {
  474. name: "IpToRange() test: malformed netmask",
  475. env: map[string]interface{}{
  476. "ip": "192.168.0.1",
  477. "netmask": "test",
  478. },
  479. code: "IpToRange(ip, netmask)",
  480. result: "",
  481. err: "",
  482. },
  483. {
  484. name: "IpToRange() test: malformed IP",
  485. env: map[string]interface{}{
  486. "ip": "a.b.c.d",
  487. "netmask": "24",
  488. },
  489. code: "IpToRange(ip, netmask)",
  490. result: "",
  491. err: "",
  492. },
  493. {
  494. name: "IpToRange() test: too high netmask",
  495. env: map[string]interface{}{
  496. "ip": "192.168.1.1",
  497. "netmask": "35",
  498. },
  499. code: "IpToRange(ip, netmask)",
  500. result: "",
  501. err: "",
  502. },
  503. }
  504. for _, test := range tests {
  505. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  506. require.NoError(t, err)
  507. output, err := expr.Run(program, test.env)
  508. require.NoError(t, err)
  509. require.Equal(t, test.result, output)
  510. log.Printf("test '%s' : OK", test.name)
  511. }
  512. }
  513. func TestAtof(t *testing.T) {
  514. err := Init(nil)
  515. assert.NoError(t, err)
  516. tests := []struct {
  517. name string
  518. env map[string]interface{}
  519. code string
  520. result float64
  521. }{
  522. {
  523. name: "Atof() test: basic test",
  524. env: map[string]interface{}{
  525. "testFloat": "1.5",
  526. },
  527. code: "Atof(testFloat)",
  528. result: 1.5,
  529. },
  530. {
  531. name: "Atof() test: bad float",
  532. env: map[string]interface{}{
  533. "testFloat": "1aaa.5",
  534. },
  535. code: "Atof(testFloat)",
  536. result: 0.0,
  537. },
  538. }
  539. for _, test := range tests {
  540. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  541. require.NoError(t, err)
  542. output, err := expr.Run(program, test.env)
  543. require.NoError(t, err)
  544. require.Equal(t, test.result, output)
  545. }
  546. }
  547. func TestUpper(t *testing.T) {
  548. testStr := "test"
  549. expectedStr := "TEST"
  550. env := map[string]interface{}{
  551. "testStr": testStr,
  552. }
  553. err := Init(nil)
  554. assert.NoError(t, err)
  555. vm, err := expr.Compile("Upper(testStr)", GetExprOptions(env)...)
  556. assert.NoError(t, err)
  557. out, err := expr.Run(vm, env)
  558. assert.NoError(t, err)
  559. v, ok := out.(string)
  560. if !ok {
  561. t.Fatalf("Upper() should return a string")
  562. }
  563. if v != expectedStr {
  564. t.Fatalf("Upper() should return test in upper case")
  565. }
  566. }
  567. func TestTimeNow(t *testing.T) {
  568. now, _ := TimeNow()
  569. ti, err := time.Parse(time.RFC3339, now.(string))
  570. if err != nil {
  571. t.Fatalf("Error parsing the return value of TimeNow: %s", err)
  572. }
  573. if -1*time.Until(ti) > time.Second {
  574. t.Fatalf("TimeNow func should return time.Now().UTC()")
  575. }
  576. log.Printf("test 'TimeNow()' : OK")
  577. }
  578. func TestParseUri(t *testing.T) {
  579. tests := []struct {
  580. name string
  581. env map[string]interface{}
  582. code string
  583. result map[string][]string
  584. err string
  585. }{
  586. {
  587. name: "ParseUri() test: basic test",
  588. env: map[string]interface{}{
  589. "uri": "/foo?a=1&b=2",
  590. "ParseUri": ParseUri,
  591. },
  592. code: "ParseUri(uri)",
  593. result: map[string][]string{"a": {"1"}, "b": {"2"}},
  594. err: "",
  595. },
  596. {
  597. name: "ParseUri() test: no param",
  598. env: map[string]interface{}{
  599. "uri": "/foo",
  600. "ParseUri": ParseUri,
  601. },
  602. code: "ParseUri(uri)",
  603. result: map[string][]string{},
  604. err: "",
  605. },
  606. {
  607. name: "ParseUri() test: extra question mark",
  608. env: map[string]interface{}{
  609. "uri": "/foo?a=1&b=2?",
  610. "ParseUri": ParseUri,
  611. },
  612. code: "ParseUri(uri)",
  613. result: map[string][]string{"a": {"1"}, "b": {"2?"}},
  614. err: "",
  615. },
  616. {
  617. name: "ParseUri() test: weird params",
  618. env: map[string]interface{}{
  619. "uri": "/foo?&?&&&&?=123",
  620. "ParseUri": ParseUri,
  621. },
  622. code: "ParseUri(uri)",
  623. result: map[string][]string{"?": {"", "123"}},
  624. err: "",
  625. },
  626. {
  627. name: "ParseUri() test: bad encoding",
  628. env: map[string]interface{}{
  629. "uri": "/foo?a=%%F",
  630. "ParseUri": ParseUri,
  631. },
  632. code: "ParseUri(uri)",
  633. result: map[string][]string{},
  634. err: "",
  635. },
  636. }
  637. for _, test := range tests {
  638. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  639. require.NoError(t, err)
  640. output, err := expr.Run(program, test.env)
  641. require.NoError(t, err)
  642. require.Equal(t, test.result, output)
  643. log.Printf("test '%s' : OK", test.name)
  644. }
  645. }
  646. func TestQueryEscape(t *testing.T) {
  647. tests := []struct {
  648. name string
  649. env map[string]interface{}
  650. code string
  651. result string
  652. err string
  653. }{
  654. {
  655. name: "QueryEscape() test: basic test",
  656. env: map[string]interface{}{
  657. "uri": "/foo?a=1&b=2",
  658. "QueryEscape": QueryEscape,
  659. },
  660. code: "QueryEscape(uri)",
  661. result: "%2Ffoo%3Fa%3D1%26b%3D2",
  662. err: "",
  663. },
  664. {
  665. name: "QueryEscape() test: basic test",
  666. env: map[string]interface{}{
  667. "uri": "/foo?a=1&&b=<>'\"",
  668. "QueryEscape": QueryEscape,
  669. },
  670. code: "QueryEscape(uri)",
  671. result: "%2Ffoo%3Fa%3D1%26%26b%3D%3C%3E%27%22",
  672. err: "",
  673. },
  674. }
  675. for _, test := range tests {
  676. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  677. require.NoError(t, err)
  678. output, err := expr.Run(program, test.env)
  679. require.NoError(t, err)
  680. require.Equal(t, test.result, output)
  681. log.Printf("test '%s' : OK", test.name)
  682. }
  683. }
  684. func TestPathEscape(t *testing.T) {
  685. tests := []struct {
  686. name string
  687. env map[string]interface{}
  688. code string
  689. result string
  690. err string
  691. }{
  692. {
  693. name: "PathEscape() test: basic test",
  694. env: map[string]interface{}{
  695. "uri": "/foo?a=1&b=2",
  696. "PathEscape": PathEscape,
  697. },
  698. code: "PathEscape(uri)",
  699. result: "%2Ffoo%3Fa=1&b=2",
  700. err: "",
  701. },
  702. {
  703. name: "PathEscape() test: basic test with more special chars",
  704. env: map[string]interface{}{
  705. "uri": "/foo?a=1&&b=<>'\"",
  706. "PathEscape": PathEscape,
  707. },
  708. code: "PathEscape(uri)",
  709. result: "%2Ffoo%3Fa=1&&b=%3C%3E%27%22",
  710. err: "",
  711. },
  712. }
  713. for _, test := range tests {
  714. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  715. require.NoError(t, err)
  716. output, err := expr.Run(program, test.env)
  717. require.NoError(t, err)
  718. require.Equal(t, test.result, output)
  719. log.Printf("test '%s' : OK", test.name)
  720. }
  721. }
  722. func TestPathUnescape(t *testing.T) {
  723. tests := []struct {
  724. name string
  725. env map[string]interface{}
  726. code string
  727. result string
  728. err string
  729. }{
  730. {
  731. name: "PathUnescape() test: basic test",
  732. env: map[string]interface{}{
  733. "uri": "%2Ffoo%3Fa=1&b=%3C%3E%27%22",
  734. "PathUnescape": PathUnescape,
  735. },
  736. code: "PathUnescape(uri)",
  737. result: "/foo?a=1&b=<>'\"",
  738. err: "",
  739. },
  740. {
  741. name: "PathUnescape() test: basic test with more special chars",
  742. env: map[string]interface{}{
  743. "uri": "/$%7Bjndi",
  744. "PathUnescape": PathUnescape,
  745. },
  746. code: "PathUnescape(uri)",
  747. result: "/${jndi",
  748. err: "",
  749. },
  750. }
  751. for _, test := range tests {
  752. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  753. require.NoError(t, err)
  754. output, err := expr.Run(program, test.env)
  755. require.NoError(t, err)
  756. require.Equal(t, test.result, output)
  757. log.Printf("test '%s' : OK", test.name)
  758. }
  759. }
  760. func TestQueryUnescape(t *testing.T) {
  761. tests := []struct {
  762. name string
  763. env map[string]interface{}
  764. code string
  765. result string
  766. err string
  767. }{
  768. {
  769. name: "QueryUnescape() test: basic test",
  770. env: map[string]interface{}{
  771. "uri": "%2Ffoo%3Fa=1&b=%3C%3E%27%22",
  772. "QueryUnescape": QueryUnescape,
  773. },
  774. code: "QueryUnescape(uri)",
  775. result: "/foo?a=1&b=<>'\"",
  776. err: "",
  777. },
  778. {
  779. name: "QueryUnescape() test: basic test with more special chars",
  780. env: map[string]interface{}{
  781. "uri": "/$%7Bjndi",
  782. "QueryUnescape": QueryUnescape,
  783. },
  784. code: "QueryUnescape(uri)",
  785. result: "/${jndi",
  786. err: "",
  787. },
  788. }
  789. for _, test := range tests {
  790. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  791. require.NoError(t, err)
  792. output, err := expr.Run(program, test.env)
  793. require.NoError(t, err)
  794. require.Equal(t, test.result, output)
  795. log.Printf("test '%s' : OK", test.name)
  796. }
  797. }
  798. func TestLower(t *testing.T) {
  799. tests := []struct {
  800. name string
  801. env map[string]interface{}
  802. code string
  803. result string
  804. err string
  805. }{
  806. {
  807. name: "Lower() test: basic test",
  808. env: map[string]interface{}{
  809. "name": "ABCDEFG",
  810. "Lower": Lower,
  811. },
  812. code: "Lower(name)",
  813. result: "abcdefg",
  814. err: "",
  815. },
  816. {
  817. name: "Lower() test: basic test with more special chars",
  818. env: map[string]interface{}{
  819. "name": "AbcDefG!#",
  820. "Lower": Lower,
  821. },
  822. code: "Lower(name)",
  823. result: "abcdefg!#",
  824. err: "",
  825. },
  826. }
  827. for _, test := range tests {
  828. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  829. require.NoError(t, err)
  830. output, err := expr.Run(program, test.env)
  831. require.NoError(t, err)
  832. require.Equal(t, test.result, output)
  833. log.Printf("test '%s' : OK", test.name)
  834. }
  835. }
  836. func TestGetDecisionsCount(t *testing.T) {
  837. var err error
  838. var start_ip, start_sfx, end_ip, end_sfx int64
  839. var ip_sz int
  840. existingIP := "1.2.3.4"
  841. unknownIP := "1.2.3.5"
  842. ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(existingIP)
  843. if err != nil {
  844. t.Errorf("unable to convert '%s' to int: %s", existingIP, err)
  845. }
  846. // Add sample data to DB
  847. dbClient = getDBClient(t)
  848. decision := dbClient.Ent.Decision.Create().
  849. SetUntil(time.Now().Add(time.Hour)).
  850. SetScenario("crowdsec/test").
  851. SetStartIP(start_ip).
  852. SetStartSuffix(start_sfx).
  853. SetEndIP(end_ip).
  854. SetEndSuffix(end_sfx).
  855. SetIPSize(int64(ip_sz)).
  856. SetType("ban").
  857. SetScope("IP").
  858. SetValue(existingIP).
  859. SetOrigin("CAPI").
  860. SaveX(context.Background())
  861. if decision == nil {
  862. assert.Error(t, errors.Errorf("Failed to create sample decision"))
  863. }
  864. err = Init(dbClient)
  865. assert.NoError(t, err)
  866. tests := []struct {
  867. name string
  868. env map[string]interface{}
  869. code string
  870. result string
  871. err string
  872. }{
  873. {
  874. name: "GetDecisionsCount() test: existing IP count",
  875. env: map[string]interface{}{
  876. "Alert": &models.Alert{
  877. Source: &models.Source{
  878. Value: &existingIP,
  879. },
  880. Decisions: []*models.Decision{
  881. {
  882. Value: &existingIP,
  883. },
  884. },
  885. },
  886. },
  887. code: "Sprintf('%d', GetDecisionsCount(Alert.GetValue()))",
  888. result: "1",
  889. err: "",
  890. },
  891. {
  892. name: "GetDecisionsCount() test: unknown IP count",
  893. env: map[string]interface{}{
  894. "Alert": &models.Alert{
  895. Source: &models.Source{
  896. Value: &unknownIP,
  897. },
  898. Decisions: []*models.Decision{
  899. {
  900. Value: &unknownIP,
  901. },
  902. },
  903. },
  904. },
  905. code: "Sprintf('%d', GetDecisionsCount(Alert.GetValue()))",
  906. result: "0",
  907. err: "",
  908. },
  909. }
  910. for _, test := range tests {
  911. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  912. require.NoError(t, err)
  913. output, err := expr.Run(program, test.env)
  914. require.NoError(t, err)
  915. require.Equal(t, test.result, output)
  916. log.Printf("test '%s' : OK", test.name)
  917. }
  918. }
  919. func TestGetDecisionsSinceCount(t *testing.T) {
  920. var err error
  921. var start_ip, start_sfx, end_ip, end_sfx int64
  922. var ip_sz int
  923. existingIP := "1.2.3.4"
  924. unknownIP := "1.2.3.5"
  925. ip_sz, start_ip, start_sfx, end_ip, end_sfx, err = types.Addr2Ints(existingIP)
  926. if err != nil {
  927. t.Errorf("unable to convert '%s' to int: %s", existingIP, err)
  928. }
  929. // Add sample data to DB
  930. dbClient = getDBClient(t)
  931. decision := dbClient.Ent.Decision.Create().
  932. SetUntil(time.Now().Add(time.Hour)).
  933. SetScenario("crowdsec/test").
  934. SetStartIP(start_ip).
  935. SetStartSuffix(start_sfx).
  936. SetEndIP(end_ip).
  937. SetEndSuffix(end_sfx).
  938. SetIPSize(int64(ip_sz)).
  939. SetType("ban").
  940. SetScope("IP").
  941. SetValue(existingIP).
  942. SetOrigin("CAPI").
  943. SaveX(context.Background())
  944. if decision == nil {
  945. assert.Error(t, errors.Errorf("Failed to create sample decision"))
  946. }
  947. decision2 := dbClient.Ent.Decision.Create().
  948. SetCreatedAt(time.Now().AddDate(0, 0, -1)).
  949. SetUntil(time.Now().AddDate(0, 0, -1)).
  950. SetScenario("crowdsec/test").
  951. SetStartIP(start_ip).
  952. SetStartSuffix(start_sfx).
  953. SetEndIP(end_ip).
  954. SetEndSuffix(end_sfx).
  955. SetIPSize(int64(ip_sz)).
  956. SetType("ban").
  957. SetScope("IP").
  958. SetValue(existingIP).
  959. SetOrigin("CAPI").
  960. SaveX(context.Background())
  961. if decision2 == nil {
  962. assert.Error(t, errors.Errorf("Failed to create sample decision"))
  963. }
  964. err = Init(dbClient)
  965. assert.NoError(t, err)
  966. tests := []struct {
  967. name string
  968. env map[string]interface{}
  969. code string
  970. result string
  971. err string
  972. }{
  973. {
  974. name: "GetDecisionsSinceCount() test: existing IP count since more than 1 day",
  975. env: map[string]interface{}{
  976. "Alert": &models.Alert{
  977. Source: &models.Source{
  978. Value: &existingIP,
  979. },
  980. Decisions: []*models.Decision{
  981. {
  982. Value: &existingIP,
  983. },
  984. },
  985. },
  986. },
  987. code: "Sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '25h'))",
  988. result: "2",
  989. err: "",
  990. },
  991. {
  992. name: "GetDecisionsSinceCount() test: existing IP count since more than 1 hour",
  993. env: map[string]interface{}{
  994. "Alert": &models.Alert{
  995. Source: &models.Source{
  996. Value: &existingIP,
  997. },
  998. Decisions: []*models.Decision{
  999. {
  1000. Value: &existingIP,
  1001. },
  1002. },
  1003. },
  1004. },
  1005. code: "Sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '1h'))",
  1006. result: "1",
  1007. err: "",
  1008. },
  1009. {
  1010. name: "GetDecisionsSinceCount() test: unknown IP count",
  1011. env: map[string]interface{}{
  1012. "Alert": &models.Alert{
  1013. Source: &models.Source{
  1014. Value: &unknownIP,
  1015. },
  1016. Decisions: []*models.Decision{
  1017. {
  1018. Value: &unknownIP,
  1019. },
  1020. },
  1021. },
  1022. },
  1023. code: "Sprintf('%d', GetDecisionsSinceCount(Alert.GetValue(), '1h'))",
  1024. result: "0",
  1025. err: "",
  1026. },
  1027. }
  1028. for _, test := range tests {
  1029. program, err := expr.Compile(test.code, GetExprOptions(test.env)...)
  1030. require.NoError(t, err)
  1031. output, err := expr.Run(program, test.env)
  1032. require.NoError(t, err)
  1033. require.Equal(t, test.result, output)
  1034. log.Printf("test '%s' : OK", test.name)
  1035. }
  1036. }
  1037. func TestParseUnixTime(t *testing.T) {
  1038. tests := []struct {
  1039. name string
  1040. value string
  1041. expected time.Time
  1042. expectedErr string
  1043. }{
  1044. {
  1045. name: "ParseUnix() test: valid value with milli",
  1046. value: "1672239773.3590894",
  1047. expected: time.Date(2022, 12, 28, 15, 02, 53, 0, time.UTC),
  1048. },
  1049. {
  1050. name: "ParseUnix() test: valid value without milli",
  1051. value: "1672239773",
  1052. expected: time.Date(2022, 12, 28, 15, 02, 53, 0, time.UTC),
  1053. },
  1054. {
  1055. name: "ParseUnix() test: invalid input",
  1056. value: "AbcDefG!#",
  1057. expected: time.Time{},
  1058. expectedErr: "unable to parse AbcDefG!# as unix timestamp",
  1059. },
  1060. {
  1061. name: "ParseUnix() test: negative value",
  1062. value: "-1000",
  1063. expected: time.Time{},
  1064. expectedErr: "unable to parse -1000 as unix timestamp",
  1065. },
  1066. }
  1067. for _, tc := range tests {
  1068. tc := tc
  1069. t.Run(tc.name, func(t *testing.T) {
  1070. output, err := ParseUnixTime(tc.value)
  1071. cstest.RequireErrorContains(t, err, tc.expectedErr)
  1072. if tc.expectedErr != "" {
  1073. return
  1074. }
  1075. require.WithinDuration(t, tc.expected, output.(time.Time), time.Second)
  1076. })
  1077. }
  1078. }
  1079. func TestIsIp(t *testing.T) {
  1080. if err := Init(nil); err != nil {
  1081. log.Fatal(err)
  1082. }
  1083. tests := []struct {
  1084. name string
  1085. expr string
  1086. value string
  1087. expected bool
  1088. expectedBuildErr bool
  1089. }{
  1090. {
  1091. name: "IsIPV4() test: valid IPv4",
  1092. expr: `IsIPV4(value)`,
  1093. value: "1.2.3.4",
  1094. expected: true,
  1095. },
  1096. {
  1097. name: "IsIPV6() test: valid IPv6",
  1098. expr: `IsIPV6(value)`,
  1099. value: "1.2.3.4",
  1100. expected: false,
  1101. },
  1102. {
  1103. name: "IsIPV6() test: valid IPv6",
  1104. expr: `IsIPV6(value)`,
  1105. value: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  1106. expected: true,
  1107. },
  1108. {
  1109. name: "IsIPV4() test: valid IPv6",
  1110. expr: `IsIPV4(value)`,
  1111. value: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  1112. expected: false,
  1113. },
  1114. {
  1115. name: "IsIP() test: invalid IP",
  1116. expr: `IsIP(value)`,
  1117. value: "foo.bar",
  1118. expected: false,
  1119. },
  1120. {
  1121. name: "IsIP() test: valid IPv4",
  1122. expr: `IsIP(value)`,
  1123. value: "1.2.3.4",
  1124. expected: true,
  1125. },
  1126. {
  1127. name: "IsIP() test: valid IPv6",
  1128. expr: `IsIP(value)`,
  1129. value: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
  1130. expected: true,
  1131. },
  1132. {
  1133. name: "IsIPV4() test: invalid IPv4",
  1134. expr: `IsIPV4(value)`,
  1135. value: "foo.bar",
  1136. expected: false,
  1137. },
  1138. {
  1139. name: "IsIPV6() test: invalid IPv6",
  1140. expr: `IsIPV6(value)`,
  1141. value: "foo.bar",
  1142. expected: false,
  1143. },
  1144. {
  1145. name: "IsIPV4() test: invalid type",
  1146. expr: `IsIPV4(42)`,
  1147. value: "",
  1148. expected: false,
  1149. expectedBuildErr: true,
  1150. },
  1151. {
  1152. name: "IsIP() test: invalid type",
  1153. expr: `IsIP(42)`,
  1154. value: "",
  1155. expected: false,
  1156. expectedBuildErr: true,
  1157. },
  1158. {
  1159. name: "IsIPV6() test: invalid type",
  1160. expr: `IsIPV6(42)`,
  1161. value: "",
  1162. expected: false,
  1163. expectedBuildErr: true,
  1164. },
  1165. }
  1166. for _, tc := range tests {
  1167. tc := tc
  1168. t.Run(tc.name, func(t *testing.T) {
  1169. vm, err := expr.Compile(tc.expr, GetExprOptions(map[string]interface{}{"value": tc.value})...)
  1170. if tc.expectedBuildErr {
  1171. assert.Error(t, err)
  1172. return
  1173. }
  1174. assert.NoError(t, err)
  1175. output, err := expr.Run(vm, map[string]interface{}{"value": tc.value})
  1176. assert.NoError(t, err)
  1177. assert.IsType(t, tc.expected, output)
  1178. assert.Equal(t, tc.expected, output.(bool))
  1179. })
  1180. }
  1181. }
  1182. func TestToString(t *testing.T) {
  1183. err := Init(nil)
  1184. require.NoError(t, err)
  1185. tests := []struct {
  1186. name string
  1187. value interface{}
  1188. expected string
  1189. expr string
  1190. }{
  1191. {
  1192. name: "ToString() test: valid string",
  1193. value: "foo",
  1194. expected: "foo",
  1195. expr: `ToString(value)`,
  1196. },
  1197. {
  1198. name: "ToString() test: valid string",
  1199. value: interface{}("foo"),
  1200. expected: "foo",
  1201. expr: `ToString(value)`,
  1202. },
  1203. {
  1204. name: "ToString() test: invalid type",
  1205. value: 1,
  1206. expected: "",
  1207. expr: `ToString(value)`,
  1208. },
  1209. {
  1210. name: "ToString() test: invalid type 2",
  1211. value: interface{}(nil),
  1212. expected: "",
  1213. expr: `ToString(value)`,
  1214. },
  1215. }
  1216. for _, tc := range tests {
  1217. tc := tc
  1218. t.Run(tc.name, func(t *testing.T) {
  1219. vm, err := expr.Compile(tc.expr, GetExprOptions(map[string]interface{}{"value": tc.value})...)
  1220. assert.NoError(t, err)
  1221. output, err := expr.Run(vm, map[string]interface{}{"value": tc.value})
  1222. assert.NoError(t, err)
  1223. require.Equal(t, tc.expected, output)
  1224. })
  1225. }
  1226. }
  1227. func TestB64Decode(t *testing.T) {
  1228. err := Init(nil)
  1229. require.NoError(t, err)
  1230. tests := []struct {
  1231. name string
  1232. value interface{}
  1233. expected string
  1234. expr string
  1235. expectedBuildErr bool
  1236. expectedRuntimeErr bool
  1237. }{
  1238. {
  1239. name: "B64Decode() test: valid string",
  1240. value: "Zm9v",
  1241. expected: "foo",
  1242. expr: `B64Decode(value)`,
  1243. expectedBuildErr: false,
  1244. },
  1245. {
  1246. name: "B64Decode() test: invalid string",
  1247. value: "foo",
  1248. expected: "",
  1249. expr: `B64Decode(value)`,
  1250. expectedBuildErr: false,
  1251. expectedRuntimeErr: true,
  1252. },
  1253. {
  1254. name: "B64Decode() test: invalid type",
  1255. value: 1,
  1256. expected: "",
  1257. expr: `B64Decode(value)`,
  1258. expectedBuildErr: true,
  1259. },
  1260. }
  1261. for _, tc := range tests {
  1262. tc := tc
  1263. t.Run(tc.name, func(t *testing.T) {
  1264. vm, err := expr.Compile(tc.expr, GetExprOptions(map[string]interface{}{"value": tc.value})...)
  1265. if tc.expectedBuildErr {
  1266. assert.Error(t, err)
  1267. return
  1268. }
  1269. assert.NoError(t, err)
  1270. output, err := expr.Run(vm, map[string]interface{}{"value": tc.value})
  1271. if tc.expectedRuntimeErr {
  1272. assert.Error(t, err)
  1273. return
  1274. }
  1275. assert.NoError(t, err)
  1276. require.Equal(t, tc.expected, output)
  1277. })
  1278. }
  1279. }