synapse 2.152.0__py311-none-any.whl → 2.154.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (87) hide show
  1. synapse/axon.py +19 -16
  2. synapse/cortex.py +203 -15
  3. synapse/exc.py +0 -2
  4. synapse/lib/ast.py +42 -23
  5. synapse/lib/autodoc.py +2 -2
  6. synapse/lib/cache.py +16 -1
  7. synapse/lib/cell.py +5 -5
  8. synapse/lib/httpapi.py +198 -2
  9. synapse/lib/layer.py +5 -2
  10. synapse/lib/modelrev.py +36 -3
  11. synapse/lib/node.py +2 -5
  12. synapse/lib/parser.py +1 -1
  13. synapse/lib/schemas.py +51 -0
  14. synapse/lib/snap.py +10 -0
  15. synapse/lib/storm.lark +24 -4
  16. synapse/lib/storm.py +98 -19
  17. synapse/lib/storm_format.py +1 -1
  18. synapse/lib/stormhttp.py +11 -4
  19. synapse/lib/stormlib/auth.py +16 -2
  20. synapse/lib/stormlib/backup.py +1 -0
  21. synapse/lib/stormlib/basex.py +2 -0
  22. synapse/lib/stormlib/cell.py +7 -0
  23. synapse/lib/stormlib/compression.py +3 -0
  24. synapse/lib/stormlib/cortex.py +1168 -0
  25. synapse/lib/stormlib/ethereum.py +1 -0
  26. synapse/lib/stormlib/graph.py +2 -0
  27. synapse/lib/stormlib/hashes.py +5 -0
  28. synapse/lib/stormlib/hex.py +6 -0
  29. synapse/lib/stormlib/infosec.py +6 -1
  30. synapse/lib/stormlib/ipv6.py +1 -0
  31. synapse/lib/stormlib/iters.py +58 -1
  32. synapse/lib/stormlib/json.py +5 -0
  33. synapse/lib/stormlib/mime.py +1 -0
  34. synapse/lib/stormlib/model.py +19 -3
  35. synapse/lib/stormlib/modelext.py +1 -0
  36. synapse/lib/stormlib/notifications.py +2 -0
  37. synapse/lib/stormlib/pack.py +2 -0
  38. synapse/lib/stormlib/random.py +1 -0
  39. synapse/lib/stormlib/smtp.py +0 -7
  40. synapse/lib/stormlib/stats.py +223 -0
  41. synapse/lib/stormlib/stix.py +8 -0
  42. synapse/lib/stormlib/storm.py +1 -0
  43. synapse/lib/stormlib/version.py +3 -0
  44. synapse/lib/stormlib/xml.py +3 -0
  45. synapse/lib/stormlib/yaml.py +2 -0
  46. synapse/lib/stormtypes.py +250 -170
  47. synapse/lib/trigger.py +180 -4
  48. synapse/lib/types.py +1 -1
  49. synapse/lib/version.py +2 -2
  50. synapse/lib/view.py +55 -6
  51. synapse/models/inet.py +21 -6
  52. synapse/models/orgs.py +48 -2
  53. synapse/models/risk.py +126 -2
  54. synapse/models/syn.py +6 -0
  55. synapse/tests/files/stormpkg/badapidef.yaml +13 -0
  56. synapse/tests/files/stormpkg/storm/modules/apimod +10 -0
  57. synapse/tests/files/stormpkg/testpkg.yaml +23 -0
  58. synapse/tests/test_axon.py +7 -2
  59. synapse/tests/test_cortex.py +231 -35
  60. synapse/tests/test_lib_ast.py +138 -43
  61. synapse/tests/test_lib_autodoc.py +1 -1
  62. synapse/tests/test_lib_modelrev.py +9 -0
  63. synapse/tests/test_lib_node.py +55 -0
  64. synapse/tests/test_lib_storm.py +14 -1
  65. synapse/tests/test_lib_stormhttp.py +65 -6
  66. synapse/tests/test_lib_stormlib_auth.py +12 -3
  67. synapse/tests/test_lib_stormlib_cortex.py +1327 -0
  68. synapse/tests/test_lib_stormlib_iters.py +116 -0
  69. synapse/tests/test_lib_stormlib_stats.py +187 -0
  70. synapse/tests/test_lib_stormlib_storm.py +8 -0
  71. synapse/tests/test_lib_stormsvc.py +24 -1
  72. synapse/tests/test_lib_stormtypes.py +124 -69
  73. synapse/tests/test_lib_trigger.py +315 -0
  74. synapse/tests/test_lib_view.py +1 -2
  75. synapse/tests/test_model_base.py +26 -0
  76. synapse/tests/test_model_inet.py +22 -0
  77. synapse/tests/test_model_orgs.py +28 -0
  78. synapse/tests/test_model_risk.py +73 -0
  79. synapse/tests/test_tools_autodoc.py +25 -0
  80. synapse/tests/test_tools_genpkg.py +9 -3
  81. synapse/tests/utils.py +39 -0
  82. synapse/tools/autodoc.py +42 -2
  83. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/METADATA +2 -2
  84. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/RECORD +87 -79
  85. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/WHEEL +1 -1
  86. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/LICENSE +0 -0
  87. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/top_level.txt +0 -0
@@ -1,17 +1,13 @@
1
1
  import json
2
2
  import math
3
3
  import asyncio
4
- import contextlib
5
- import collections
6
4
 
7
5
  from unittest import mock
8
6
 
9
7
  import synapse.exc as s_exc
10
8
  import synapse.common as s_common
11
- import synapse.cortex as s_cortex
12
9
 
13
10
  import synapse.lib.ast as s_ast
14
- import synapse.lib.base as s_base
15
11
  import synapse.lib.snap as s_snap
16
12
 
17
13
  import synapse.tests.utils as s_test
@@ -125,44 +121,6 @@ foo_stormpkg = {
125
121
  ],
126
122
  }
127
123
 
128
- @contextlib.asynccontextmanager
129
- async def matchContexts(testself):
130
- origenter = s_base.Base.__aenter__
131
- origexit = s_base.Base.__aexit__
132
- origstorm = s_cortex.Cortex.storm
133
- orignodes = s_cortex.Cortex.nodes
134
-
135
- contexts = collections.defaultdict(int)
136
-
137
- async def enter(self):
138
- contexts[type(self)] += 1
139
- return await origenter(self)
140
-
141
- async def exit(self, exc, cls, tb):
142
- contexts[type(self)] -= 1
143
- await origexit(self, exc, cls, tb)
144
-
145
- async def storm(self, text, opts=None):
146
- async for mesg in origstorm(self, text, opts=opts):
147
- yield mesg
148
-
149
- for cont, refs in contexts.items():
150
- testself.eq(0, refs)
151
-
152
- async def nodes(self, text, opts=None):
153
- nodes = await orignodes(self, text, opts=opts)
154
-
155
- for cont, refs in contexts.items():
156
- testself.eq(0, refs)
157
-
158
- return nodes
159
-
160
- with mock.patch('synapse.lib.base.Base.__aenter__', enter):
161
- with mock.patch('synapse.lib.base.Base.__aexit__', exit):
162
- with mock.patch('synapse.cortex.Cortex.nodes', nodes):
163
- with mock.patch('synapse.cortex.Cortex.storm', storm):
164
- yield
165
-
166
124
  class AstTest(s_test.SynTest):
167
125
 
168
126
  async def test_mode_search(self):
@@ -2099,6 +2057,13 @@ class AstTest(s_test.SynTest):
2099
2057
  else { $lib.print(no) }
2100
2058
  '''
2101
2059
  msgs = await core.stormlist(q)
2060
+ self.stormIsInPrint('yes', msgs)
2061
+
2062
+ q = '''test:str $data=$node.value()
2063
+ if ($data ~= "(?-i:brown)") { $lib.print(yes) }
2064
+ else { $lib.print(no) }
2065
+ '''
2066
+ msgs = await core.stormlist(q)
2102
2067
  self.stormIsInPrint('no', msgs)
2103
2068
 
2104
2069
  q = '''test:str $data=$node.value()
@@ -2320,7 +2285,7 @@ class AstTest(s_test.SynTest):
2320
2285
 
2321
2286
  await core.nodes('[ inet:fqdn=vertex.link ]')
2322
2287
 
2323
- async with matchContexts(self):
2288
+ async with s_test.matchContexts(self):
2324
2289
 
2325
2290
  await core.nodes("inet:fqdn -> { inet:fqdn=vertex.link } | limit 1")
2326
2291
  await core.nodes("function x() { inet:fqdn=vertex.link } yield $x() | limit 1")
@@ -2561,3 +2526,133 @@ class AstTest(s_test.SynTest):
2561
2526
  self.len(0, nodes[0][1]['path']['edges'])
2562
2527
  # one for the refs edge (via doedges) and one for the rule..
2563
2528
  self.len(2, nodes[1][1]['path']['edges'])
2529
+
2530
+ async def test_ast_double_init_fini(self):
2531
+ async with self.getTestCore() as core:
2532
+ q = '''
2533
+ init {$foo = bar $lib.print(`{$foo} {$wow}`) }
2534
+ init {$baz = hehe $lib.print('second init!') }
2535
+ $lib.print($baz)
2536
+ '''
2537
+ msgs = await core.stormlist(q, opts={'vars': {'wow': 'hehe'}})
2538
+ pmesgs = [m[1].get('mesg') for m in msgs if m[0] == 'print']
2539
+ self.eq(pmesgs, ['bar hehe', 'second init!', 'hehe'])
2540
+
2541
+ q = '''
2542
+ init {$foo = bar $lib.print(`{$foo} {$wow}`) }
2543
+ init {$baz = hehe $lib.print('second init!') }
2544
+ $lib.print($baz)
2545
+ [test:str=stuff]
2546
+ $stuff = $node.value()
2547
+ fini { $lib.print(fini1) }
2548
+ fini { $lib.print(`fini {$stuff}`) }
2549
+ '''
2550
+ msgs = await core.stormlist(q, opts={'vars': {'wow': 'hehe', 'stuff': None}})
2551
+ pmesgs = [m[1].get('mesg') for m in msgs if m[0] == 'print']
2552
+ self.eq(pmesgs, ['bar hehe', 'second init!', 'hehe', 'fini1', 'fini stuff'])
2553
+
2554
+ q = '''
2555
+ init { $foo = bar }
2556
+ init { $baz = $lib.str.format('foo={foo}', foo=$foo) }
2557
+ $lib.print($baz)
2558
+ '''
2559
+ msgs = await core.stormlist(q)
2560
+ self.stormIsInPrint('foo=bar', msgs)
2561
+
2562
+ async def test_ast_tagfilters(self):
2563
+
2564
+ async with self.getTestCore() as core:
2565
+
2566
+ await core.addTagProp('score', ('int', {}), {})
2567
+
2568
+ await core.nodes('[ test:str=foo +#tagaa=2023 +#tagaa:score=5 <(foo)+ { test:str=foo } ]')
2569
+ await core.nodes('[ test:str=bar +#tagab=2024 +#tagab:score=6 ]')
2570
+ await core.nodes('[ test:str=baz +#tagba=2023 +#tagba:score=7 ]')
2571
+ await core.nodes('[ test:str=faz +#tagbb=2024 +#tagbb:score=8 ]')
2572
+
2573
+ self.len(2, await core.nodes('test:str +#taga*'))
2574
+ self.len(1, await core.nodes('test:str +#tagaa=2023'))
2575
+ self.len(1, await core.nodes('test:str +#taga* <(*)- *'))
2576
+ self.len(2, await core.nodes('$tag=taga* test:str +#$tag'))
2577
+ self.len(1, await core.nodes('$tag=tagaa test:str +#$tag=2023'))
2578
+
2579
+ with self.raises(s_exc.BadSyntax):
2580
+ await core.nodes('test:str +#taga*=2023')
2581
+
2582
+ with self.raises(s_exc.BadSyntax):
2583
+ await core.nodes('test:str +#taga*@=2023')
2584
+
2585
+ with self.raises(s_exc.BadSyntax):
2586
+ await core.nodes('test:str +#taga*>2023')
2587
+
2588
+ with self.raises(s_exc.BadSyntax):
2589
+ await core.nodes('test:str +#taga*<(3+5)')
2590
+
2591
+ with self.raises(s_exc.NoSuchCmpr):
2592
+ await core.nodes('test:str +#taga<(3+5)')
2593
+
2594
+ with self.raises(s_exc.NoSuchCmpr):
2595
+ await core.nodes('test:str +#taga*min>=2023')
2596
+
2597
+ with self.raises(s_exc.StormRuntimeError):
2598
+ await core.nodes('$tag=taga* test:str +#$tag=2023')
2599
+
2600
+ with self.raises(s_exc.StormRuntimeError):
2601
+ await core.nodes('$tag=taga* test:str +#$"tag"=2023')
2602
+
2603
+ with self.raises(s_exc.StormRuntimeError):
2604
+ await core.nodes('$tag=taga* test:str +#foo.$"tag"=2023')
2605
+
2606
+ with self.raises(s_exc.BadSyntax):
2607
+ await core.nodes('$tag=taga* test:str +#foo*.$"tag"=2023')
2608
+
2609
+ with self.raises(s_exc.BadSyntax):
2610
+ await core.nodes('$tag=taga test:str +#foo.$"tag".*=2023')
2611
+
2612
+ with self.raises(s_exc.BadSyntax):
2613
+ await core.nodes('$tag=taga test:str +#foo.$"tag".*=2023')
2614
+
2615
+ with self.raises(s_exc.BadSyntax):
2616
+ await core.nodes('$tag=taga test:str +#foo.$"tag".$"tag".*=2023')
2617
+
2618
+ self.len(2, await core.nodes('test:str +#taga*:score'))
2619
+ self.len(1, await core.nodes('test:str +#tagaa:score=5'))
2620
+ self.len(1, await core.nodes('test:str +#tagaa:score<(2+4)'))
2621
+ self.len(1, await core.nodes('test:str +#tagaa:score*range=(4,6)'))
2622
+ self.len(1, await core.nodes('test:str +#taga*:score <(*)- *'))
2623
+ self.len(2, await core.nodes('$tag=taga* test:str +#$tag:score'))
2624
+ self.len(1, await core.nodes('$tag=tagaa test:str +#$tag:score=5'))
2625
+ self.len(1, await core.nodes('$tag=tagaa test:str +#$tag:score*range=(4,6)'))
2626
+
2627
+ with self.raises(s_exc.BadSyntax):
2628
+ await core.nodes('test:str +#taga*:score=2023')
2629
+
2630
+ with self.raises(s_exc.BadSyntax):
2631
+ await core.nodes('test:str +#taga*:score@=2023')
2632
+
2633
+ with self.raises(s_exc.BadSyntax):
2634
+ await core.nodes('test:str +#taga*:score>2023')
2635
+
2636
+ with self.raises(s_exc.BadSyntax):
2637
+ await core.nodes('test:str +#taga*:score<(3+5)')
2638
+
2639
+ with self.raises(s_exc.BadSyntax):
2640
+ await core.nodes('test:str +#taga*:score*min>=2023')
2641
+
2642
+ with self.raises(s_exc.NoSuchCmpr):
2643
+ await core.nodes('test:str +#taga:score*min>=2023')
2644
+
2645
+ with self.raises(s_exc.StormRuntimeError):
2646
+ await core.nodes('$tag=taga* test:str +#$tag:score=2023')
2647
+
2648
+ with self.raises(s_exc.StormRuntimeError):
2649
+ await core.nodes('$tag=taga* test:str +#foo.$"tag":score=2023')
2650
+
2651
+ with self.raises(s_exc.BadSyntax):
2652
+ await core.nodes('$tag=taga* test:str +#foo*.$"tag":score=2023')
2653
+
2654
+ with self.raises(s_exc.BadSyntax):
2655
+ await core.nodes('$tag=taga test:str +#foo.$"tag".*:score=2023')
2656
+
2657
+ with self.raises(s_exc.BadSyntax):
2658
+ await core.nodes('$tag=taga test:str +#foo.$"tag".$"tag".*:score=2023')
@@ -62,7 +62,7 @@ shave'''
62
62
  self.eq(s_autodoc.getArgLines({}), [])
63
63
  lines = s_autodoc.getArgLines(rtype)
64
64
  self.eq(lines, ['\n', 'Args:', ' foo (str): The foos!', '\n',
65
- ' bar: The bar. The input type may one one of the following: ``str``, ``int``.',
65
+ ' bar: The bar. The input type may be one of the following: ``str``, ``int``.',
66
66
  '\n', ' \\*\\*kwargs (any): Extra foobars.', '\n'])
67
67
 
68
68
  lines = s_autodoc.getArgLines({'args': [{'name': 'cmplx', 'type': {}, 'desc': 'unsupported'}]})
@@ -419,3 +419,12 @@ class ModelRevTest(s_tests.SynTest):
419
419
 
420
420
  self.len(1, await core.nodes('risk:vulnname="woot woot"'))
421
421
  self.len(1, await core.nodes('risk:vuln:name="woot woot"'))
422
+
423
+ async def test_modelrev_0_2_22(self):
424
+
425
+ async with self.getRegrCore('model-0.2.22') as core:
426
+ nodes = await core.nodes('inet:ipv4=100.64.0.0/10')
427
+ self.len(257, nodes)
428
+
429
+ for node in nodes:
430
+ self.eq(node.props.get('type'), 'shared')
@@ -517,3 +517,58 @@ class NodeTest(s_t_utils.SynTest):
517
517
 
518
518
  msgs = await core.stormlist(edgeq)
519
519
  self.len(1, [m for m in msgs if m[0] == 'print'])
520
+
521
+ async def test_node_remove_missing_basetag(self):
522
+
523
+ async with self.getTestCore() as core:
524
+
525
+ base = await core.callStorm('return($lib.view.get().iden)')
526
+ fork = await core.callStorm('return($lib.view.get().fork().iden)')
527
+
528
+ await core.nodes('[test:str=neato +#foo.one]', opts={'view': base})
529
+ await core.nodes('test:str=neato | [ +#foo.two ]', opts={'view': fork})
530
+
531
+ await core.nodes('test:str=neato | [ -#foo ]', opts={'view': base})
532
+
533
+ othr = await core.nodes('test:str=neato', opts={'view': fork})
534
+ self.len(1, othr)
535
+ self.isin('foo.two', othr[0].tags)
536
+ self.notin('foo', othr[0].tags)
537
+
538
+ msgs = await core.stormlist('test:str=neato | [ -#foo ]', opts={'view': fork})
539
+ edits = [m[1] for m in msgs if m[0] == 'node:edits']
540
+ nodes = [m[1] for m in msgs if m[0] == 'node']
541
+ self.len(1, edits)
542
+ self.len(1, edits[0]['edits'][0][2])
543
+
544
+ self.len(1, nodes)
545
+ self.len(0, nodes[0][1]['tags'])
546
+
547
+ await core.nodes('[test:int=12 +#ping.pong.neato.burrito]', opts={'view': base})
548
+ await core.nodes('test:int=12 | [ +#ping.pong.awesome.possum ]', opts={'view': fork})
549
+
550
+ await core.nodes('test:int=12 | [ -#ping.pong]', opts={'view': base})
551
+
552
+ othr = await core.nodes('test:int=12', opts={'view': fork})
553
+ self.len(1, othr)
554
+ self.isin('ping', othr[0].tags)
555
+ self.isin('ping.pong.awesome', othr[0].tags)
556
+ self.isin('ping.pong.awesome.possum', othr[0].tags)
557
+
558
+ self.notin('ping.pong', othr[0].tags)
559
+
560
+ msgs = await core.stormlist('test:int=12 | [ -#ping.pong ]', opts={'view': fork})
561
+ edits = [m[1] for m in msgs if m[0] == 'node:edits']
562
+ nodes = [m[1] for m in msgs if m[0] == 'node']
563
+
564
+ self.len(1, edits)
565
+ self.len(2, edits[0]['edits'][0][2])
566
+
567
+ self.len(1, nodes)
568
+ self.len(1, nodes[0][1]['tags'])
569
+ self.isin('ping', nodes[0][1]['tags'])
570
+
571
+ nodes = await core.nodes('test:int=12 | [ -#p ]')
572
+ self.len(1, nodes)
573
+ self.len(1, nodes[0].tags)
574
+ self.isin('ping', nodes[0].tags)
@@ -1213,6 +1213,19 @@ class StormTest(s_t_utils.SynTest):
1213
1213
  self.len(1, nodes)
1214
1214
  self.eq(nodes[0].ndef, ('test:str', 'pluto\udcbaneptune'))
1215
1215
 
1216
+ nodes = await core.nodes('[ media:news=* :publisher:name=woot ] $name=:publisher:name [ :publisher={ gen.ou.org $name } ]')
1217
+ self.len(1, nodes)
1218
+ self.nn(nodes[0].get('publisher'))
1219
+
1220
+ # test regular expressions are case insensitive by default
1221
+ self.len(1, await core.nodes('test:str~=Pluto'))
1222
+ self.len(1, await core.nodes('test:str +test:str~=Pluto'))
1223
+ self.true(await core.callStorm('return(("Foo" ~= "foo"))'))
1224
+ self.len(0, await core.nodes('test:str~="(?-i:Pluto)"'))
1225
+ self.len(0, await core.nodes('test:str +test:str~="(?-i:Pluto)"'))
1226
+ self.false(await core.callStorm('return(("Foo" ~= "(?-i:foo)"))'))
1227
+ self.true(await core.callStorm('return(("Foo" ~= "(?-i:Foo)"))'))
1228
+
1216
1229
  async def test_storm_diff_merge(self):
1217
1230
 
1218
1231
  async with self.getTestCore() as core:
@@ -3641,7 +3654,7 @@ class StormTest(s_t_utils.SynTest):
3641
3654
  msgs = await core.stormlist('help list')
3642
3655
  self.stormIsInPrint('***\nlist\n****\nImplements the Storm API for a List instance.', msgs)
3643
3656
  self.stormIsInPrint('append(valu)\nAppend a value to the list.', msgs)
3644
- self.stormIsInPrint('auth.user.list : List all users.', msgs)
3657
+ self.stormIsInPrint('auth.user.list : List all users.', msgs)
3645
3658
 
3646
3659
  # email stor / gettr has a multi value return type
3647
3660
  msgs = await core.stormlist('help -v auth:user')
@@ -509,13 +509,15 @@ class StormHttpTest(s_test.SynTest):
509
509
  await visi.addRule((True, ('storm', 'lib', 'axon', 'wget')))
510
510
  await visi.addRule((True, ('storm', 'lib', 'axon', 'wput')))
511
511
 
512
+ errmsg = f'User {visi.name!r} ({visi.iden}) must have permission {{perm}}'
513
+
512
514
  asvisi = {'user': visi.iden}
513
515
  msgs = await core.stormlist('$lib.inet.http.get(http://vertex.link, proxy=$lib.false)', opts=asvisi)
514
- self.stormIsInErr(s_exc.proxy_admin_mesg, msgs)
516
+ self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
515
517
 
516
518
  asvisi = {'user': visi.iden}
517
519
  msgs = await core.stormlist('$lib.inet.http.get(http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1)', opts=asvisi)
518
- self.stormIsInErr(s_exc.proxy_admin_mesg, msgs)
520
+ self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
519
521
 
520
522
  resp = await core.callStorm('return($lib.inet.http.get(http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1))')
521
523
  self.eq('ProxyConnectionError', resp['err'][0])
@@ -523,15 +525,15 @@ class StormHttpTest(s_test.SynTest):
523
525
  # test $lib.axon proxy API
524
526
  asvisi = {'user': visi.iden}
525
527
  msgs = await core.stormlist('$lib.axon.wget(http://vertex.link, proxy=$lib.false)', opts=asvisi)
526
- self.stormIsInErr(s_exc.proxy_admin_mesg, msgs)
528
+ self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
527
529
 
528
530
  asvisi = {'user': visi.iden}
529
531
  msgs = await core.stormlist('$lib.axon.wget(http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1)', opts=asvisi)
530
- self.stormIsInErr(s_exc.proxy_admin_mesg, msgs)
532
+ self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
531
533
 
532
534
  asvisi = {'user': visi.iden}
533
535
  msgs = await core.stormlist('$lib.axon.wput(asdf, http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1)', opts=asvisi)
534
- self.stormIsInErr(s_exc.proxy_admin_mesg, msgs)
536
+ self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
535
537
 
536
538
  resp = await core.callStorm('return($lib.axon.wget(http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1))')
537
539
  self.false(resp.get('ok'))
@@ -544,6 +546,63 @@ class StormHttpTest(s_test.SynTest):
544
546
  self.false(resp.get('ok'))
545
547
  self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
546
548
 
549
+ async with self.getTestCore(conf=conf) as core:
550
+ # Proxy permission tests in this section
551
+
552
+ visi = await core.auth.addUser('visi')
553
+
554
+ await visi.addRule((True, ('storm', 'lib', 'axon', 'wget')))
555
+ await visi.addRule((True, ('storm', 'lib', 'axon', 'wput')))
556
+
557
+ _, sha256 = await core.axon.put(b'asdf')
558
+ sha256 = s_common.ehex(sha256)
559
+
560
+ host, port = await core.addHttpsPort(0)
561
+
562
+ q1 = f'return($lib.inet.http.get(https://loop.vertex.link:{port}, ssl_verify=$lib.false, proxy=$proxy))'
563
+ q2 = f'return($lib.axon.wget(https://loop.vertex.link:{port}, ssl=$lib.false, proxy=$proxy))'
564
+ q3 = f'return($lib.axon.wput({sha256}, https://loop.vertex.link:{port}, ssl=$lib.false, proxy=$proxy))'
565
+
566
+ for proxy in ('socks5://user:pass@127.0.0.1:1', False):
567
+ opts = {'vars': {'proxy': proxy}, 'user': visi.iden}
568
+
569
+ with self.raises(s_exc.AuthDeny):
570
+ await core.callStorm(q1, opts=opts)
571
+
572
+ with self.raises(s_exc.AuthDeny):
573
+ await core.callStorm(q2, opts=opts)
574
+
575
+ with self.raises(s_exc.AuthDeny):
576
+ await core.callStorm(q3, opts=opts)
577
+
578
+ # Add permissions to use a proxy
579
+ await visi.addRule((True, ('storm', 'lib', 'inet', 'http', 'proxy')))
580
+
581
+ opts = {'vars': {'proxy': 'socks5://user:pass@127.0.0.1:1'}, 'user': visi.iden}
582
+
583
+ resp = await core.callStorm(q1, opts=opts)
584
+ self.eq('ProxyConnectionError', resp['err'][0])
585
+
586
+ resp = await core.callStorm(q2, opts=opts)
587
+ self.eq('ProxyConnectionError', resp['err'][0])
588
+
589
+ resp = await core.callStorm(q3, opts=opts)
590
+ self.eq('ProxyConnectionError', resp['err'][0])
591
+
592
+ opts = {'vars': {'proxy': False}, 'user': visi.iden}
593
+
594
+ resp = await core.callStorm(q1, opts=opts)
595
+ self.eq(resp['code'], 404)
596
+ self.eq(resp['reason'], 'Not Found')
597
+
598
+ resp = await core.callStorm(q2, opts=opts)
599
+ self.eq(resp['code'], 404)
600
+ self.eq(resp['reason'], 'Not Found')
601
+
602
+ resp = await core.callStorm(q3, opts=opts)
603
+ self.eq(resp['code'], 404)
604
+ self.eq(resp['reason'], 'Not Found')
605
+
547
606
  async def test_storm_http_connect(self):
548
607
 
549
608
  async with self.getTestCore() as core:
@@ -604,7 +663,7 @@ class StormHttpTest(s_test.SynTest):
604
663
  opts = {'user': visi.iden, 'vars': {'port': port, 'proxy': False}}
605
664
  with self.raises(s_exc.AuthDeny) as cm:
606
665
  await core.callStorm(query, opts=opts)
607
- self.eq(cm.exception.get('mesg'), s_exc.proxy_admin_mesg)
666
+ self.eq(cm.exception.get('mesg'), f'User {visi.name!r} ({visi.iden}) must have permission storm.lib.inet.http.proxy')
608
667
 
609
668
  await visi.setAdmin(True)
610
669
 
@@ -178,12 +178,21 @@ class StormLibAuthTest(s_test.SynTest):
178
178
  self.stormIsInPrint('allowed: true - Matched user rule (node) on gate 741529fa80e3fb42f63c5320e4bf348f.',
179
179
  msgs, deguid=True)
180
180
 
181
- q = '$lib.auth.users.byname(visi).setAdmin($admin, gateiden=$lib.view.get().layers.0.iden)'
182
- await core.nodes(q, opts={'vars': {'admin': True}})
181
+ msgs = await core.stormlist('auth.user.mod visi --gate $lib.view.get().layers.0.iden')
182
+ self.stormIsInWarn('Granting/revoking admin status on an auth gate, requires the use of `--admin <true|false>` also.', msgs)
183
+
184
+ msgs = await core.stormlist('auth.user.mod visi --admin $lib.true --gate $lib.view.get().layers.0.iden')
185
+ self.stormIsInPrint('User (visi) admin status set to true for auth gate 741529fa80e3fb42f63c5320e4bf348f.',
186
+ msgs, deguid=True)
183
187
  msgs = await core.stormlist('auth.user.allowed visi node.tag.del --gate $lib.view.get().layers.0.iden')
184
188
  self.stormIsInPrint('allowed: true - The user is an admin of auth gate 741529fa80e3fb42f63c5320e4bf348f',
185
189
  msgs, deguid=True)
186
- await core.nodes(q, opts={'vars': {'admin': False}})
190
+ msgs = await core.stormlist('auth.user.mod visi --admin $lib.false --gate $lib.view.get().layers.0.iden')
191
+ self.stormIsInPrint('User (visi) admin status set to false for auth gate 741529fa80e3fb42f63c5320e4bf348f.',
192
+ msgs, deguid=True)
193
+ msgs = await core.stormlist('auth.user.allowed visi node.tag.del --gate $lib.view.get().layers.0.iden')
194
+ self.stormIsInPrint('allowed: true - Matched user rule (node) on gate 741529fa80e3fb42f63c5320e4bf348f',
195
+ msgs, deguid=True)
187
196
 
188
197
  await core.nodes('auth.role.addrule ninjas beep.sys --gate $lib.view.get().layers.0.iden')
189
198
  msgs = await core.stormlist('auth.user.allowed visi beep.sys --gate $lib.view.get().layers.0.iden')