synapse 2.191.0__py311-none-any.whl → 2.193.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.
- synapse/axon.py +54 -23
- synapse/common.py +15 -0
- synapse/cortex.py +18 -20
- synapse/exc.py +6 -1
- synapse/lib/agenda.py +0 -2
- synapse/lib/ast.py +30 -12
- synapse/lib/cell.py +79 -85
- synapse/lib/cli.py +20 -11
- synapse/lib/nexus.py +2 -1
- synapse/lib/parser.py +1 -1
- synapse/lib/snap.py +4 -4
- synapse/lib/storm.py +34 -17
- synapse/lib/stormhttp.py +32 -35
- synapse/lib/stormlib/json.py +5 -2
- synapse/lib/stormtypes.py +121 -20
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +17 -1
- synapse/models/infotech.py +14 -4
- synapse/models/risk.py +16 -2
- synapse/tests/test_axon.py +10 -0
- synapse/tests/test_cortex.py +55 -3
- synapse/tests/test_exc.py +3 -0
- synapse/tests/test_lib_agenda.py +157 -1
- synapse/tests/test_lib_ast.py +49 -1
- synapse/tests/test_lib_cell.py +106 -1
- synapse/tests/test_lib_httpapi.py +9 -2
- synapse/tests/test_lib_storm.py +72 -30
- synapse/tests/test_lib_stormhttp.py +57 -12
- synapse/tests/test_lib_stormlib_json.py +20 -0
- synapse/tests/test_lib_stormlib_scrape.py +2 -2
- synapse/tests/test_model_inet.py +40 -5
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_servers_univ.py +0 -12
- synapse/tests/test_tools_apikey.py +227 -0
- synapse/tests/test_tools_storm.py +95 -0
- synapse/tests/test_utils_getrefs.py +1 -1
- synapse/tools/apikey.py +93 -0
- synapse/utils/getrefs.py +14 -3
- synapse/vendor/cpython/lib/http/__init__.py +0 -0
- synapse/vendor/cpython/lib/http/cookies.py +59 -0
- synapse/vendor/cpython/lib/test/test_http_cookies.py +49 -0
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/METADATA +2 -2
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/RECORD +46 -41
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/WHEEL +1 -1
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/LICENSE +0 -0
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ import synapse.common as s_common
|
|
|
9
9
|
import synapse.lib.certdir as s_certdir
|
|
10
10
|
import synapse.lib.httpapi as s_httpapi
|
|
11
11
|
import synapse.lib.stormctrl as s_stormctrl
|
|
12
|
-
import synapse.lib.
|
|
12
|
+
import synapse.lib.stormtypes as s_stormtypes
|
|
13
13
|
|
|
14
14
|
import synapse.tests.utils as s_test
|
|
15
15
|
|
|
@@ -606,11 +606,39 @@ class StormHttpTest(s_test.SynTest):
|
|
|
606
606
|
self.false(resp.get('ok'))
|
|
607
607
|
self.ne(-1, resp['mesg'].find('connect to proxy 127.0.0.1:1'))
|
|
608
608
|
|
|
609
|
+
msgs = await core.stormlist('$resp=$lib.axon.wget("http://vertex.link", proxy=(null)) $lib.print($resp.mesg)')
|
|
610
|
+
self.stormIsInWarn('HTTP proxy argument to $lib.null is deprecated', msgs)
|
|
611
|
+
self.stormIsInPrint('connect to proxy 127.0.0.1:1', msgs)
|
|
612
|
+
|
|
613
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('$lib.axon.wget("http://vertex.link", proxy=(1.1))'))
|
|
614
|
+
|
|
615
|
+
# todo: setting the synapse version can be removed once proxy=true support is released
|
|
616
|
+
try:
|
|
617
|
+
oldv = core.axoninfo['synapse']['version']
|
|
618
|
+
core.axoninfo['synapse']['version'] = (oldv[0], oldv[1] + 1, oldv[2])
|
|
619
|
+
resp = await core.callStorm('return($lib.axon.wget("http://vertex.link", proxy=(null)))')
|
|
620
|
+
self.false(resp.get('ok'))
|
|
621
|
+
self.ne(-1, resp['mesg'].find('connect to proxy 127.0.0.1:1'))
|
|
622
|
+
finally:
|
|
623
|
+
core.axoninfo['synapse']['version'] = oldv
|
|
624
|
+
|
|
625
|
+
size, sha256 = await core.axon.put(b'asdf')
|
|
626
|
+
opts = {'vars': {'sha256': s_common.ehex(sha256)}}
|
|
627
|
+
resp = await core.callStorm(f'return($lib.axon.wput($sha256, http://vertex.link))', opts=opts)
|
|
628
|
+
self.false(resp.get('ok'))
|
|
629
|
+
self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
|
|
630
|
+
|
|
609
631
|
q = '$resp=$lib.inet.http.get("http://vertex.link") return(($resp.code, $resp.err))'
|
|
610
632
|
code, (errname, _) = await core.callStorm(q)
|
|
611
633
|
self.eq(code, -1)
|
|
612
634
|
self.eq('ProxyConnectionError', errname)
|
|
613
635
|
|
|
636
|
+
msgs = await core.stormlist('$resp=$lib.inet.http.get("http://vertex.link", proxy=(null)) $lib.print($resp.err)')
|
|
637
|
+
self.stormIsInWarn('HTTP proxy argument to $lib.null is deprecated', msgs)
|
|
638
|
+
self.stormIsInPrint('connect to proxy 127.0.0.1:1', msgs)
|
|
639
|
+
|
|
640
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('$lib.inet.http.get("http://vertex.link", proxy=(1.1))'))
|
|
641
|
+
|
|
614
642
|
async with self.getTestCore() as core:
|
|
615
643
|
|
|
616
644
|
visi = await core.auth.addUser('visi')
|
|
@@ -654,6 +682,24 @@ class StormHttpTest(s_test.SynTest):
|
|
|
654
682
|
self.false(resp.get('ok'))
|
|
655
683
|
self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
|
|
656
684
|
|
|
685
|
+
host, port = await core.addHttpsPort(0)
|
|
686
|
+
opts = {
|
|
687
|
+
'vars': {
|
|
688
|
+
'url': f'https://loop.vertex.link:{port}',
|
|
689
|
+
'proxy': 'socks5://user:pass@127.0.0.1:1',
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
try:
|
|
693
|
+
oldv = core.axoninfo['synapse']['version']
|
|
694
|
+
minver = s_stormtypes.AXON_MINVERS_PROXY
|
|
695
|
+
core.axoninfo['synapse']['version'] = minver[2], minver[1] - 1, minver[0]
|
|
696
|
+
q = '$resp=$lib.axon.wget($url, ssl=(false), proxy=$proxy) $lib.print(`code={$resp.code}`)'
|
|
697
|
+
mesgs = await core.stormlist(q, opts=opts)
|
|
698
|
+
self.stormIsInPrint('code=404', mesgs)
|
|
699
|
+
self.stormIsInWarn('Axon version does not support proxy argument', mesgs)
|
|
700
|
+
finally:
|
|
701
|
+
core.axoninfo['synapse']['version'] = oldv
|
|
702
|
+
|
|
657
703
|
async with self.getTestCore(conf=conf) as core:
|
|
658
704
|
# Proxy permission tests in this section
|
|
659
705
|
|
|
@@ -762,10 +808,15 @@ class StormHttpTest(s_test.SynTest):
|
|
|
762
808
|
($ok, $valu) = $sock.tx(lololol)
|
|
763
809
|
return($sock.rx())
|
|
764
810
|
'''
|
|
765
|
-
opts = {'vars': {'port': port, 'proxy':
|
|
811
|
+
opts = {'vars': {'port': port, 'proxy': True}}
|
|
766
812
|
self.eq((True, ('echo', 'lololol')),
|
|
767
813
|
await core.callStorm(query, opts=opts))
|
|
768
814
|
|
|
815
|
+
opts = {'vars': {'port': port, 'proxy': None}}
|
|
816
|
+
mesgs = await core.stormlist(query, opts=opts)
|
|
817
|
+
self.stormIsInWarn('proxy argument to $lib.null is deprecated', mesgs)
|
|
818
|
+
self.true(mesgs[-2][0] == 'err' and mesgs[-2][1][1]['mesg'] == "(True, ['echo', 'lololol'])")
|
|
819
|
+
|
|
769
820
|
visi = await core.auth.addUser('visi')
|
|
770
821
|
|
|
771
822
|
opts = {'user': visi.iden, 'vars': {'port': port, 'proxy': False}}
|
|
@@ -903,16 +954,10 @@ class StormHttpTest(s_test.SynTest):
|
|
|
903
954
|
core.axoninfo['synapse']['version'] = oldv
|
|
904
955
|
|
|
905
956
|
## version check succeeds
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
self.eq(200, await core.callStorm(axon_queries['postfile'], opts=opts))
|
|
911
|
-
self.eq(200, await core.callStorm(axon_queries['wget'], opts=opts))
|
|
912
|
-
self.eq(200, await core.callStorm(axon_queries['wput'], opts=opts))
|
|
913
|
-
self.len(1, await core.nodes(axon_queries['urlfile'], opts=opts))
|
|
914
|
-
finally:
|
|
915
|
-
core.axoninfo['synapse']['version'] = oldv
|
|
957
|
+
self.eq(200, await core.callStorm(axon_queries['postfile'], opts=opts))
|
|
958
|
+
self.eq(200, await core.callStorm(axon_queries['wget'], opts=opts))
|
|
959
|
+
self.eq(200, await core.callStorm(axon_queries['wput'], opts=opts))
|
|
960
|
+
self.len(1, await core.nodes(axon_queries['urlfile'], opts=opts))
|
|
916
961
|
|
|
917
962
|
# verify arg precedence
|
|
918
963
|
|
|
@@ -12,6 +12,26 @@ class JsonTest(s_test.SynTest):
|
|
|
12
12
|
|
|
13
13
|
self.eq(((1, 2, 3)), await core.callStorm('return($lib.json.load("[1, 2, 3]"))'))
|
|
14
14
|
self.eq(('["foo", "bar", "baz"]'), await core.callStorm('return($lib.json.save((foo, bar, baz)))'))
|
|
15
|
+
self.eq(('{"foo": 1, "bar": {"baz": "hello"}}'), await core.callStorm('return($lib.json.save(({"foo": 1, "bar": {"baz": "hello"}})))'))
|
|
16
|
+
self.eq(('{"foo": 1, "bar": {"baz": "hello"}}'), await core.callStorm('return($lib.json.save(({"foo": 1, "bar": {"baz": "hello"}}), (null)))'))
|
|
17
|
+
self.eq((
|
|
18
|
+
'''{
|
|
19
|
+
"foo": 1,
|
|
20
|
+
"bar": {
|
|
21
|
+
"baz": "hello"
|
|
22
|
+
}
|
|
23
|
+
}'''), await core.callStorm('return($lib.json.save(({"foo": 1, "bar": {"baz": "hello"}}), indent=(4)))'))
|
|
24
|
+
|
|
25
|
+
self.eq((
|
|
26
|
+
'''{
|
|
27
|
+
"foo": 1,
|
|
28
|
+
"bar": {
|
|
29
|
+
"baz": "hello"
|
|
30
|
+
}
|
|
31
|
+
}'''), await core.callStorm('return($lib.json.save(({"foo": 1, "bar": {"baz": "hello"}}), indent=2))'))
|
|
32
|
+
|
|
33
|
+
with self.raises(s_exc.BadCast):
|
|
34
|
+
await core.callStorm('return($lib.json.save(({"foo": 1, "bar": {"baz": "hello"}}), indent=x))')
|
|
15
35
|
|
|
16
36
|
with self.raises(s_exc.BadJsonText):
|
|
17
37
|
await core.callStorm('return($lib.json.load(foo))')
|
|
@@ -92,7 +92,7 @@ class StormScrapeTest(s_test.SynTest):
|
|
|
92
92
|
self.len(0, mods)
|
|
93
93
|
self.len(0, core.modsbyiface.get('scrape'))
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
core.loadStormPkg(pkgdef)
|
|
96
96
|
|
|
97
97
|
mods = await core.getStormIfaces('scrape')
|
|
98
98
|
self.len(2, mods)
|
|
@@ -131,7 +131,7 @@ class StormScrapeTest(s_test.SynTest):
|
|
|
131
131
|
conf = {'storm:interface:scrape': False, }
|
|
132
132
|
async with self.getTestCore(conf=conf) as core:
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
core.loadStormPkg(pkgdef)
|
|
135
135
|
|
|
136
136
|
mods = await core.getStormIfaces('scrape')
|
|
137
137
|
self.len(2, mods)
|
synapse/tests/test_model_inet.py
CHANGED
|
@@ -10,17 +10,40 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
10
10
|
|
|
11
11
|
async def test_model_inet_basics(self):
|
|
12
12
|
async with self.getTestCore() as core:
|
|
13
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#🫠" ]'))
|
|
14
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#🫠🫠" ]'))
|
|
15
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#·bar"]'))
|
|
16
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#foo·"]'))
|
|
17
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#foo〜"]'))
|
|
13
18
|
self.len(1, await core.nodes('[ inet:web:hashtag="#hehe" ]'))
|
|
14
19
|
self.len(1, await core.nodes('[ inet:web:hashtag="#foo·bar"]')) # note the interpunct
|
|
20
|
+
self.len(1, await core.nodes('[ inet:web:hashtag="#foo〜bar"]')) # note the wave dash
|
|
15
21
|
self.len(1, await core.nodes('[ inet:web:hashtag="#fo·o·······b·ar"]'))
|
|
16
22
|
with self.raises(s_exc.BadTypeValu):
|
|
17
23
|
await core.nodes('[ inet:web:hashtag="foo" ]')
|
|
24
|
+
|
|
18
25
|
with self.raises(s_exc.BadTypeValu):
|
|
19
|
-
await core.nodes('[ inet:web:hashtag="#foo
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
await core.nodes('[ inet:web:hashtag="#foo#bar" ]')
|
|
27
|
+
|
|
28
|
+
# All unicode whitespace from:
|
|
29
|
+
# https://www.compart.com/en/unicode/category/Zl
|
|
30
|
+
# https://www.compart.com/en/unicode/category/Zp
|
|
31
|
+
# https://www.compart.com/en/unicode/category/Zs
|
|
32
|
+
whitespace = [
|
|
33
|
+
'\u0020', '\u00a0', '\u1680', '\u2000', '\u2001', '\u2002', '\u2003', '\u2004',
|
|
34
|
+
'\u2005', '\u2006', '\u2007', '\u2008', '\u2009', '\u200a', '\u202f', '\u205f',
|
|
35
|
+
'\u3000', '\u2028', '\u2029',
|
|
36
|
+
]
|
|
37
|
+
for char in whitespace:
|
|
38
|
+
with self.raises(s_exc.BadTypeValu):
|
|
39
|
+
await core.callStorm(f'[ inet:web:hashtag="#foo{char}bar" ]')
|
|
40
|
+
|
|
41
|
+
with self.raises(s_exc.BadTypeValu):
|
|
42
|
+
await core.callStorm(f'[ inet:web:hashtag="#{char}bar" ]')
|
|
43
|
+
|
|
44
|
+
# These are allowed because strip=True
|
|
45
|
+
await core.callStorm(f'[ inet:web:hashtag="#foo{char}" ]')
|
|
46
|
+
await core.callStorm(f'[ inet:web:hashtag=" #foo{char}" ]')
|
|
24
47
|
|
|
25
48
|
nodes = await core.nodes('''
|
|
26
49
|
[ inet:web:instance=(foo,)
|
|
@@ -457,6 +480,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
457
480
|
:raw=((10), (20))
|
|
458
481
|
:src:txfiles={[ file:attachment=* :name=foo.exe ]}
|
|
459
482
|
:dst:txfiles={[ file:attachment=* :name=bar.exe ]}
|
|
483
|
+
:capture:host=*
|
|
460
484
|
)]'''
|
|
461
485
|
nodes = await core.nodes(q, opts={'vars': {'valu': valu, 'p': props}})
|
|
462
486
|
self.len(1, nodes)
|
|
@@ -500,11 +524,13 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
500
524
|
self.eq(node.get('src:rdp:hostname'), 'syncoder')
|
|
501
525
|
self.eq(node.get('src:rdp:keyboard:layout'), 'azerty')
|
|
502
526
|
self.eq(node.get('raw'), (10, 20))
|
|
527
|
+
self.nn(node.get('capture:host'))
|
|
503
528
|
self.len(2, await core.nodes('inet:flow -> crypto:x509:cert'))
|
|
504
529
|
self.len(1, await core.nodes('inet:flow :src:ssh:key -> crypto:key'))
|
|
505
530
|
self.len(1, await core.nodes('inet:flow :dst:ssh:key -> crypto:key'))
|
|
506
531
|
self.len(1, await core.nodes('inet:flow :src:txfiles -> file:attachment +:name=foo.exe'))
|
|
507
532
|
self.len(1, await core.nodes('inet:flow :dst:txfiles -> file:attachment +:name=bar.exe'))
|
|
533
|
+
self.len(1, await core.nodes('inet:flow :capture:host -> it:host'))
|
|
508
534
|
|
|
509
535
|
async def test_fqdn(self):
|
|
510
536
|
formname = 'inet:fqdn'
|
|
@@ -2746,6 +2772,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
2746
2772
|
q = '''
|
|
2747
2773
|
[
|
|
2748
2774
|
inet:email:message="*"
|
|
2775
|
+
:id="Woot-12345 "
|
|
2749
2776
|
:to=woot@woot.com
|
|
2750
2777
|
:from=visi@vertex.link
|
|
2751
2778
|
:replyto=root@root.com
|
|
@@ -2767,6 +2794,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
2767
2794
|
nodes = await core.nodes(q, opts={'vars': {'flow': flow}})
|
|
2768
2795
|
self.len(1, nodes)
|
|
2769
2796
|
|
|
2797
|
+
self.eq(nodes[0].get('id'), 'Woot-12345')
|
|
2770
2798
|
self.eq(nodes[0].get('cc'), ('baz@faz.org', 'foo@bar.com'))
|
|
2771
2799
|
self.eq(nodes[0].get('received:from:ipv6'), '::1')
|
|
2772
2800
|
self.eq(nodes[0].get('received:from:ipv4'), 0x01020304)
|
|
@@ -2847,6 +2875,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
2847
2875
|
nodes = await core.nodes('''
|
|
2848
2876
|
[ inet:egress=*
|
|
2849
2877
|
:host = *
|
|
2878
|
+
:host:iface = *
|
|
2850
2879
|
:client=1.2.3.4
|
|
2851
2880
|
:client:ipv6="::1"
|
|
2852
2881
|
]
|
|
@@ -2854,10 +2883,14 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
2854
2883
|
|
|
2855
2884
|
self.len(1, nodes)
|
|
2856
2885
|
self.nn(nodes[0].get('host'))
|
|
2886
|
+
self.nn(nodes[0].get('host:iface'))
|
|
2857
2887
|
self.eq(nodes[0].get('client'), 'tcp://1.2.3.4')
|
|
2858
2888
|
self.eq(nodes[0].get('client:ipv4'), 0x01020304)
|
|
2859
2889
|
self.eq(nodes[0].get('client:ipv6'), '::1')
|
|
2860
2890
|
|
|
2891
|
+
self.len(1, await core.nodes('inet:egress -> it:host'))
|
|
2892
|
+
self.len(1, await core.nodes('inet:egress -> inet:iface'))
|
|
2893
|
+
|
|
2861
2894
|
async def test_model_inet_tls_handshake(self):
|
|
2862
2895
|
|
|
2863
2896
|
async with self.getTestCore() as core:
|
|
@@ -2976,6 +3009,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
2976
3009
|
(inet:service:account=(blackout, account, vertex, slack)
|
|
2977
3010
|
:id=U7RN51U1J
|
|
2978
3011
|
:user=blackout
|
|
3012
|
+
:url=https://vertex.link/users/blackout
|
|
2979
3013
|
:email=blackout@vertex.link
|
|
2980
3014
|
:profile={ gen.ps.contact.email vertex.employee blackout@vertex.link }
|
|
2981
3015
|
:tenant={[ inet:service:tenant=({"id": "VS-31337"}) ]}
|
|
@@ -3003,6 +3037,7 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3003
3037
|
self.eq(accounts[0].ndef, ('inet:service:account', s_common.guid(('blackout', 'account', 'vertex', 'slack'))))
|
|
3004
3038
|
self.eq(accounts[0].get('id'), 'U7RN51U1J')
|
|
3005
3039
|
self.eq(accounts[0].get('user'), 'blackout')
|
|
3040
|
+
self.eq(accounts[0].get('url'), 'https://vertex.link/users/blackout')
|
|
3006
3041
|
self.eq(accounts[0].get('email'), 'blackout@vertex.link')
|
|
3007
3042
|
self.eq(accounts[0].get('profile'), blckprof.ndef[1])
|
|
3008
3043
|
|
synapse/tests/test_model_risk.py
CHANGED
|
@@ -430,6 +430,7 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
430
430
|
:disclosed=20231102
|
|
431
431
|
:owner={ gen.ou.org.hq acme }
|
|
432
432
|
:leaker={ gen.ou.org.hq wikileaks }
|
|
433
|
+
:recipient={ gen.ou.org.hq everyone }
|
|
433
434
|
:type=public
|
|
434
435
|
:goal={[ ou:goal=* :name=publicity ]}
|
|
435
436
|
:compromise={[ risk:compromise=* :target={ gen.ou.org.hq acme } ]}
|
|
@@ -458,6 +459,7 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
458
459
|
self.len(1, await core.nodes('risk:leak -> risk:leak:type:taxonomy'))
|
|
459
460
|
self.len(1, await core.nodes('risk:leak :owner -> ps:contact +:orgname=acme'))
|
|
460
461
|
self.len(1, await core.nodes('risk:leak :leaker -> ps:contact +:orgname=wikileaks'))
|
|
462
|
+
self.len(1, await core.nodes('risk:leak :recipient -> ps:contact +:orgname=everyone'))
|
|
461
463
|
self.len(1, await core.nodes('risk:leak -> ou:goal +:name=publicity'))
|
|
462
464
|
self.len(1, await core.nodes('risk:leak -> risk:compromise :target -> ps:contact +:orgname=acme'))
|
|
463
465
|
self.len(1, await core.nodes('risk:leak :reporter -> ou:org +:name=vertex'))
|
|
@@ -56,18 +56,6 @@ class UnivServerTest(s_t_utils.SynTest):
|
|
|
56
56
|
async with await s_telepath.openurl(f'cell://{dirn}') as proxy:
|
|
57
57
|
self.eq('cell', await proxy.getCellType())
|
|
58
58
|
|
|
59
|
-
argv = [
|
|
60
|
-
'synapse.tests.test_lib_cell.EchoAuth',
|
|
61
|
-
'--telepath', 'tcp://127.0.0.1:0/',
|
|
62
|
-
'--https', '0',
|
|
63
|
-
'--name', 'univtest',
|
|
64
|
-
dirn,
|
|
65
|
-
]
|
|
66
|
-
# Or start the Cortex off a a EchoAuth (don't do this in practice...)
|
|
67
|
-
async with await s_s_univ.main(argv) as cell:
|
|
68
|
-
async with await s_telepath.openurl(f'cell://{dirn}') as proxy:
|
|
69
|
-
self.eq('echoauth', await proxy.getCellType())
|
|
70
|
-
|
|
71
59
|
argv = ['synapse.lib.newp.Newp']
|
|
72
60
|
with self.raises(s_exc.NoSuchCtor):
|
|
73
61
|
async with await s_s_univ.main(argv) as core:
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
|
|
3
|
+
import synapse.exc as s_exc
|
|
4
|
+
import synapse.common as s_common
|
|
5
|
+
|
|
6
|
+
import synapse.lib.time as s_time
|
|
7
|
+
import synapse.lib.output as s_output
|
|
8
|
+
|
|
9
|
+
import synapse.tests.utils as s_test
|
|
10
|
+
import synapse.tools.apikey as s_t_apikey
|
|
11
|
+
|
|
12
|
+
async def getApiKeyByName(core, name):
|
|
13
|
+
keys = {k.get('name'): k async for k in core.getApiKeys()}
|
|
14
|
+
return keys.get(name)
|
|
15
|
+
|
|
16
|
+
class ApiKeyTest(s_test.SynTest):
|
|
17
|
+
|
|
18
|
+
async def test_tools_apikey(self):
|
|
19
|
+
async with self.getTestCore() as core:
|
|
20
|
+
|
|
21
|
+
await core.auth.addUser('blackout')
|
|
22
|
+
|
|
23
|
+
rooturl = core.getLocalUrl()
|
|
24
|
+
blckurl = core.getLocalUrl(user='blackout')
|
|
25
|
+
|
|
26
|
+
# Add API keys
|
|
27
|
+
argv = (
|
|
28
|
+
'--svcurl', rooturl,
|
|
29
|
+
'add',
|
|
30
|
+
'rootkey00',
|
|
31
|
+
'-d', '120',
|
|
32
|
+
)
|
|
33
|
+
outp = s_output.OutPutStr()
|
|
34
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
35
|
+
|
|
36
|
+
self.isin('Successfully added API key with name=rootkey00.', str(outp))
|
|
37
|
+
rootkey00 = await getApiKeyByName(core, 'rootkey00')
|
|
38
|
+
|
|
39
|
+
self.isin(f'Iden: {rootkey00.get("iden")}', str(outp))
|
|
40
|
+
self.isin(' API Key: ', str(outp))
|
|
41
|
+
self.isin(' Name: rootkey00', str(outp))
|
|
42
|
+
self.isin(f' Created: {s_time.repr(rootkey00.get("created"))}', str(outp))
|
|
43
|
+
self.isin(f' Updated: {s_time.repr(rootkey00.get("updated"))}', str(outp))
|
|
44
|
+
self.isin(f' Expires: {s_time.repr(rootkey00.get("expires"))}', str(outp))
|
|
45
|
+
self.eq(rootkey00.get('expires'), rootkey00.get('created') + 120000)
|
|
46
|
+
|
|
47
|
+
argv = (
|
|
48
|
+
'--svcurl', rooturl,
|
|
49
|
+
'add',
|
|
50
|
+
'-u', 'blackout',
|
|
51
|
+
'blckkey00',
|
|
52
|
+
)
|
|
53
|
+
outp = s_output.OutPutStr()
|
|
54
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
55
|
+
|
|
56
|
+
self.isin('Successfully added API key with name=blckkey00.', str(outp))
|
|
57
|
+
blckkey00 = await getApiKeyByName(core, 'blckkey00')
|
|
58
|
+
|
|
59
|
+
self.isin(f'Iden: {blckkey00.get("iden")}', str(outp))
|
|
60
|
+
self.isin(' API Key: ', str(outp))
|
|
61
|
+
self.isin(' Name: blckkey00', str(outp))
|
|
62
|
+
self.isin(f' Created: {s_time.repr(blckkey00.get("created"))}', str(outp))
|
|
63
|
+
self.isin(f' Updated: {s_time.repr(blckkey00.get("updated"))}', str(outp))
|
|
64
|
+
self.notin(' Expires: ', str(outp))
|
|
65
|
+
|
|
66
|
+
argv = (
|
|
67
|
+
'--svcurl', blckurl,
|
|
68
|
+
'add',
|
|
69
|
+
'blckkey01',
|
|
70
|
+
)
|
|
71
|
+
outp = s_output.OutPutStr()
|
|
72
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
73
|
+
|
|
74
|
+
self.isin('Successfully added API key with name=blckkey01.', str(outp))
|
|
75
|
+
blckkey01 = await getApiKeyByName(core, 'blckkey01')
|
|
76
|
+
|
|
77
|
+
self.isin(f'Iden: {blckkey01.get("iden")}', str(outp))
|
|
78
|
+
self.isin(' API Key: ', str(outp))
|
|
79
|
+
self.isin(' Name: blckkey01', str(outp))
|
|
80
|
+
self.isin(f' Created: {s_time.repr(blckkey01.get("created"))}', str(outp))
|
|
81
|
+
self.isin(f' Updated: {s_time.repr(blckkey01.get("updated"))}', str(outp))
|
|
82
|
+
self.notin(' Expires: ', str(outp))
|
|
83
|
+
|
|
84
|
+
# List API keys
|
|
85
|
+
argv = (
|
|
86
|
+
'--svcurl', rooturl,
|
|
87
|
+
'list',
|
|
88
|
+
)
|
|
89
|
+
outp = s_output.OutPutStr()
|
|
90
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
91
|
+
|
|
92
|
+
self.isin(f'Iden: {rootkey00.get("iden")}', str(outp))
|
|
93
|
+
self.notin(' API Key: ', str(outp))
|
|
94
|
+
self.isin(' Name: rootkey00', str(outp))
|
|
95
|
+
self.isin(f' Created: {s_time.repr(rootkey00.get("created"))}', str(outp))
|
|
96
|
+
self.isin(f' Updated: {s_time.repr(rootkey00.get("updated"))}', str(outp))
|
|
97
|
+
self.isin(f' Expires: {s_time.repr(rootkey00.get("expires"))}', str(outp))
|
|
98
|
+
self.eq(rootkey00.get('expires'), rootkey00.get('created') + 120000)
|
|
99
|
+
|
|
100
|
+
argv = (
|
|
101
|
+
'--svcurl', rooturl,
|
|
102
|
+
'list',
|
|
103
|
+
'-u', 'blackout',
|
|
104
|
+
)
|
|
105
|
+
outp = s_output.OutPutStr()
|
|
106
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
107
|
+
|
|
108
|
+
self.isin(f'Iden: {blckkey00.get("iden")}', str(outp))
|
|
109
|
+
self.notin(' API Key: ', str(outp))
|
|
110
|
+
self.isin(' Name: blckkey00', str(outp))
|
|
111
|
+
self.isin(f' Created: {s_time.repr(blckkey00.get("created"))}', str(outp))
|
|
112
|
+
self.isin(f' Updated: {s_time.repr(blckkey00.get("updated"))}', str(outp))
|
|
113
|
+
self.notin(' Expires: ', str(outp))
|
|
114
|
+
|
|
115
|
+
self.isin(f'Iden: {blckkey01.get("iden")}', str(outp))
|
|
116
|
+
self.notin(' API Key: ', str(outp))
|
|
117
|
+
self.isin(' Name: blckkey01', str(outp))
|
|
118
|
+
self.isin(f' Created: {s_time.repr(blckkey01.get("created"))}', str(outp))
|
|
119
|
+
self.isin(f' Updated: {s_time.repr(blckkey01.get("updated"))}', str(outp))
|
|
120
|
+
self.notin(' Expires: ', str(outp))
|
|
121
|
+
|
|
122
|
+
argv = (
|
|
123
|
+
'--svcurl', blckurl,
|
|
124
|
+
'list',
|
|
125
|
+
)
|
|
126
|
+
outp = s_output.OutPutStr()
|
|
127
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
128
|
+
|
|
129
|
+
self.isin(f'Iden: {blckkey00.get("iden")}', str(outp))
|
|
130
|
+
self.notin(' API Key: ', str(outp))
|
|
131
|
+
self.isin(' Name: blckkey00', str(outp))
|
|
132
|
+
self.isin(f' Created: {s_time.repr(blckkey00.get("created"))}', str(outp))
|
|
133
|
+
self.isin(f' Updated: {s_time.repr(blckkey00.get("updated"))}', str(outp))
|
|
134
|
+
self.notin(' Expires: ', str(outp))
|
|
135
|
+
|
|
136
|
+
self.isin(f'Iden: {blckkey01.get("iden")}', str(outp))
|
|
137
|
+
self.notin(' API Key: ', str(outp))
|
|
138
|
+
self.isin(' Name: blckkey01', str(outp))
|
|
139
|
+
self.isin(f' Created: {s_time.repr(blckkey01.get("created"))}', str(outp))
|
|
140
|
+
self.isin(f' Updated: {s_time.repr(blckkey01.get("updated"))}', str(outp))
|
|
141
|
+
self.notin(' Expires: ', str(outp))
|
|
142
|
+
|
|
143
|
+
# Delete API keys
|
|
144
|
+
rootiden00 = rootkey00.get('iden')
|
|
145
|
+
argv = (
|
|
146
|
+
'--svcurl', rooturl,
|
|
147
|
+
'del',
|
|
148
|
+
rootiden00,
|
|
149
|
+
)
|
|
150
|
+
outp = s_output.OutPutStr()
|
|
151
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
152
|
+
self.isin(f'Successfully deleted API key with iden={rootiden00}.', str(outp))
|
|
153
|
+
|
|
154
|
+
blckiden00 = blckkey00.get('iden')
|
|
155
|
+
argv = (
|
|
156
|
+
'--svcurl', rooturl,
|
|
157
|
+
'del',
|
|
158
|
+
blckiden00,
|
|
159
|
+
)
|
|
160
|
+
outp = s_output.OutPutStr()
|
|
161
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
162
|
+
self.isin(f'Successfully deleted API key with iden={blckiden00}.', str(outp))
|
|
163
|
+
|
|
164
|
+
blckiden01 = blckkey01.get('iden')
|
|
165
|
+
argv = (
|
|
166
|
+
'--svcurl', blckurl,
|
|
167
|
+
'del',
|
|
168
|
+
blckiden01,
|
|
169
|
+
)
|
|
170
|
+
outp = s_output.OutPutStr()
|
|
171
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
172
|
+
self.isin(f'Successfully deleted API key with iden={blckiden01}.', str(outp))
|
|
173
|
+
|
|
174
|
+
# List API keys again
|
|
175
|
+
argv = (
|
|
176
|
+
'--svcurl', rooturl,
|
|
177
|
+
'list',
|
|
178
|
+
)
|
|
179
|
+
outp = s_output.OutPutStr()
|
|
180
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
181
|
+
self.isin('No API keys found.', str(outp))
|
|
182
|
+
|
|
183
|
+
argv = (
|
|
184
|
+
'--svcurl', rooturl,
|
|
185
|
+
'list',
|
|
186
|
+
'-u', 'blackout',
|
|
187
|
+
)
|
|
188
|
+
outp = s_output.OutPutStr()
|
|
189
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
190
|
+
self.isin('No API keys found.', str(outp))
|
|
191
|
+
|
|
192
|
+
argv = (
|
|
193
|
+
'--svcurl', blckurl,
|
|
194
|
+
'list',
|
|
195
|
+
)
|
|
196
|
+
outp = s_output.OutPutStr()
|
|
197
|
+
self.eq(0, await s_t_apikey.main(argv, outp=outp))
|
|
198
|
+
self.isin('No API keys found.', str(outp))
|
|
199
|
+
|
|
200
|
+
# Check errors
|
|
201
|
+
argv = (
|
|
202
|
+
'--svcurl', rooturl,
|
|
203
|
+
'list',
|
|
204
|
+
'-u', 'newp',
|
|
205
|
+
)
|
|
206
|
+
outp = s_output.OutPutStr()
|
|
207
|
+
self.eq(1, await s_t_apikey.main(argv, outp=outp))
|
|
208
|
+
self.isin('ERROR: NoSuchUser: No user named newp.', str(outp))
|
|
209
|
+
|
|
210
|
+
argv = (
|
|
211
|
+
'--svcurl', blckurl,
|
|
212
|
+
'list',
|
|
213
|
+
'-u', 'root',
|
|
214
|
+
)
|
|
215
|
+
outp = s_output.OutPutStr()
|
|
216
|
+
self.eq(1, await s_t_apikey.main(argv, outp=outp))
|
|
217
|
+
self.isin('ERROR: AuthDeny: getUserInfo denied for non-admin and non-self', str(outp))
|
|
218
|
+
|
|
219
|
+
newpiden = s_common.guid()
|
|
220
|
+
argv = (
|
|
221
|
+
'--svcurl', rooturl,
|
|
222
|
+
'del',
|
|
223
|
+
newpiden,
|
|
224
|
+
)
|
|
225
|
+
outp = s_output.OutPutStr()
|
|
226
|
+
self.eq(1, await s_t_apikey.main(argv, outp=outp))
|
|
227
|
+
self.isin(f"ERROR: NoSuchIden: User API key with iden='{newpiden}' does not exist.", str(outp))
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import sys
|
|
3
|
+
import signal
|
|
4
|
+
import asyncio
|
|
5
|
+
import multiprocessing
|
|
6
|
+
|
|
2
7
|
import synapse.tests.utils as s_test
|
|
3
8
|
|
|
4
9
|
from prompt_toolkit.document import Document
|
|
@@ -6,10 +11,49 @@ from prompt_toolkit.completion import Completion, CompleteEvent
|
|
|
6
11
|
|
|
7
12
|
import synapse.exc as s_exc
|
|
8
13
|
import synapse.common as s_common
|
|
14
|
+
import synapse.telepath as s_telepath
|
|
15
|
+
|
|
16
|
+
import synapse.lib.coro as s_coro
|
|
9
17
|
import synapse.lib.output as s_output
|
|
10
18
|
import synapse.lib.msgpack as s_msgpack
|
|
11
19
|
import synapse.tools.storm as s_t_storm
|
|
12
20
|
|
|
21
|
+
def run_cli_till_print(url, evt1):
|
|
22
|
+
'''
|
|
23
|
+
Run the stormCLI until we get a print mesg then set the event.
|
|
24
|
+
|
|
25
|
+
This is a Process target.
|
|
26
|
+
'''
|
|
27
|
+
async def main():
|
|
28
|
+
outp = s_output.OutPutStr() # Capture output instead of sending it to stdout
|
|
29
|
+
async with await s_telepath.openurl(url) as proxy:
|
|
30
|
+
async with await s_t_storm.StormCli.anit(proxy, outp=outp) as scli:
|
|
31
|
+
cmdqueue = asyncio.Queue()
|
|
32
|
+
await cmdqueue.put('while (true) { $lib.print(go) $lib.time.sleep(1) }')
|
|
33
|
+
await cmdqueue.put('!quit')
|
|
34
|
+
|
|
35
|
+
async def fake_prompt():
|
|
36
|
+
return await cmdqueue.get()
|
|
37
|
+
|
|
38
|
+
scli.prompt = fake_prompt
|
|
39
|
+
|
|
40
|
+
d = {'evt1': False}
|
|
41
|
+
async def onmesg(event):
|
|
42
|
+
if d.get('evt1'):
|
|
43
|
+
return
|
|
44
|
+
mesg = event[1].get('mesg')
|
|
45
|
+
if mesg[0] != 'print':
|
|
46
|
+
return
|
|
47
|
+
evt1.set()
|
|
48
|
+
d['evt1'] = True
|
|
49
|
+
|
|
50
|
+
with scli.onWith('storm:mesg', onmesg):
|
|
51
|
+
await scli.addSignalHandlers()
|
|
52
|
+
await scli.runCmdLoop()
|
|
53
|
+
|
|
54
|
+
asyncio.run(main())
|
|
55
|
+
sys.exit(137)
|
|
56
|
+
|
|
13
57
|
class StormCliTest(s_test.SynTest):
|
|
14
58
|
|
|
15
59
|
async def test_tools_storm(self):
|
|
@@ -378,3 +422,54 @@ class StormCliTest(s_test.SynTest):
|
|
|
378
422
|
),
|
|
379
423
|
vals
|
|
380
424
|
)
|
|
425
|
+
|
|
426
|
+
async def test_storm_cmdloop_interrupt(self):
|
|
427
|
+
'''
|
|
428
|
+
Test interrupting a long-running query in the command loop
|
|
429
|
+
'''
|
|
430
|
+
async with self.getTestCore() as core:
|
|
431
|
+
|
|
432
|
+
async with core.getLocalProxy() as proxy:
|
|
433
|
+
|
|
434
|
+
outp = s_test.TstOutPut()
|
|
435
|
+
async with await s_t_storm.StormCli.anit(proxy, outp=outp) as scli:
|
|
436
|
+
|
|
437
|
+
cmdqueue = asyncio.Queue()
|
|
438
|
+
await cmdqueue.put('while (true) { $lib.time.sleep(1) }')
|
|
439
|
+
await cmdqueue.put('!quit')
|
|
440
|
+
|
|
441
|
+
async def fake_prompt():
|
|
442
|
+
return await cmdqueue.get()
|
|
443
|
+
scli.prompt = fake_prompt
|
|
444
|
+
|
|
445
|
+
cmdloop_task = asyncio.create_task(scli.runCmdLoop())
|
|
446
|
+
await asyncio.sleep(0.1)
|
|
447
|
+
|
|
448
|
+
if scli.cmdtask is not None:
|
|
449
|
+
scli.cmdtask.cancel()
|
|
450
|
+
|
|
451
|
+
await cmdloop_task
|
|
452
|
+
|
|
453
|
+
outp.expect('<ctrl-c>')
|
|
454
|
+
outp.expect('o/')
|
|
455
|
+
self.true(scli.isfini)
|
|
456
|
+
|
|
457
|
+
async def test_storm_cmdloop_sigint(self):
|
|
458
|
+
'''
|
|
459
|
+
Test interrupting a long-running query in the command loop with a process target and SIGINT.
|
|
460
|
+
'''
|
|
461
|
+
|
|
462
|
+
async with self.getTestCore() as core:
|
|
463
|
+
url = core.getLocalUrl()
|
|
464
|
+
|
|
465
|
+
ctx = multiprocessing.get_context('spawn')
|
|
466
|
+
|
|
467
|
+
evt1 = ctx.Event()
|
|
468
|
+
|
|
469
|
+
proc = ctx.Process(target=run_cli_till_print, args=(url, evt1,))
|
|
470
|
+
proc.start()
|
|
471
|
+
|
|
472
|
+
self.true(await s_coro.executor(evt1.wait, timeout=30))
|
|
473
|
+
os.kill(proc.pid, signal.SIGINT)
|
|
474
|
+
proc.join(timeout=30)
|
|
475
|
+
self.eq(proc.exitcode, 137)
|