synapse 2.161.0__py311-none-any.whl → 2.163.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 (53) hide show
  1. synapse/axon.py +48 -40
  2. synapse/cortex.py +4 -0
  3. synapse/daemon.py +7 -2
  4. synapse/lib/cell.py +70 -3
  5. synapse/lib/layer.py +20 -1
  6. synapse/lib/oauth.py +1 -7
  7. synapse/lib/rstorm.py +16 -0
  8. synapse/lib/schemas.py +10 -0
  9. synapse/lib/storm.py +17 -1
  10. synapse/lib/stormhttp.py +52 -28
  11. synapse/lib/stormlib/stix.py +6 -3
  12. synapse/lib/stormtypes.py +336 -26
  13. synapse/lib/version.py +2 -2
  14. synapse/lib/view.py +15 -2
  15. synapse/models/inet.py +9 -0
  16. synapse/models/infotech.py +28 -26
  17. synapse/models/orgs.py +3 -0
  18. synapse/models/proj.py +9 -2
  19. synapse/models/risk.py +32 -0
  20. synapse/telepath.py +2 -0
  21. synapse/tests/files/rstorm/testsvc.py +8 -1
  22. synapse/tests/files/stormpkg/testpkg.yaml +4 -0
  23. synapse/tests/test_axon.py +4 -4
  24. synapse/tests/test_cortex.py +8 -8
  25. synapse/tests/test_daemon.py +19 -0
  26. synapse/tests/test_lib_ast.py +17 -17
  27. synapse/tests/test_lib_grammar.py +4 -4
  28. synapse/tests/test_lib_rstorm.py +38 -2
  29. synapse/tests/test_lib_storm.py +15 -15
  30. synapse/tests/test_lib_stormhttp.py +182 -19
  31. synapse/tests/test_lib_stormlib_auth.py +3 -3
  32. synapse/tests/test_lib_stormlib_cell.py +1 -1
  33. synapse/tests/test_lib_stormlib_cortex.py +50 -2
  34. synapse/tests/test_lib_stormlib_json.py +2 -2
  35. synapse/tests/test_lib_stormlib_macro.py +1 -1
  36. synapse/tests/test_lib_stormlib_modelext.py +37 -37
  37. synapse/tests/test_lib_stormlib_oauth.py +20 -20
  38. synapse/tests/test_lib_stormlib_stix.py +3 -1
  39. synapse/tests/test_lib_stormtypes.py +159 -52
  40. synapse/tests/test_lib_stormwhois.py +1 -1
  41. synapse/tests/test_lib_trigger.py +11 -11
  42. synapse/tests/test_lib_view.py +23 -1
  43. synapse/tests/test_model_crypto.py +1 -1
  44. synapse/tests/test_model_inet.py +6 -0
  45. synapse/tests/test_model_orgs.py +2 -1
  46. synapse/tests/test_model_proj.py +6 -0
  47. synapse/tests/test_model_risk.py +10 -0
  48. synapse/tests/test_tools_storm.py +1 -1
  49. {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/METADATA +3 -1
  50. {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/RECORD +53 -53
  51. {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/LICENSE +0 -0
  52. {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/WHEEL +0 -0
  53. {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/top_level.txt +0 -0
@@ -735,9 +735,9 @@ class StormTest(s_t_utils.SynTest):
735
735
  # check that the feed API uses toprim
736
736
  email = await core.callStorm('''
737
737
  $iden = $lib.guid()
738
- $props = $lib.dict(email=visi@vertex.link)
738
+ $props = ({"email": "visi@vertex.link"})
739
739
  $lib.feed.ingest(syn.nodes, (
740
- ( (ps:contact, $iden), $lib.dict(props=$props)),
740
+ ( (ps:contact, $iden), ({"props": $props})),
741
741
  ))
742
742
  ps:contact=$iden
743
743
  return(:email)
@@ -746,9 +746,9 @@ class StormTest(s_t_utils.SynTest):
746
746
 
747
747
  email = await core.callStorm('''
748
748
  $iden = $lib.guid()
749
- $props = $lib.dict(email=visi@vertex.link)
749
+ $props = ({"email": "visi@vertex.link"})
750
750
  yield $lib.feed.genr(syn.nodes, (
751
- ( (ps:contact, $iden), $lib.dict(props=$props)),
751
+ ( (ps:contact, $iden), ({"props": $props})),
752
752
  ))
753
753
  return(:email)
754
754
  ''')
@@ -777,7 +777,7 @@ class StormTest(s_t_utils.SynTest):
777
777
  # and again to test *not* creating it...
778
778
  self.eq(0, await core.callStorm('return($lib.queue.gen(woot).size())'))
779
779
 
780
- self.eq({'foo': 'bar'}, await core.callStorm('return($lib.dict( foo = bar ))'))
780
+ self.eq({'foo': 'bar'}, await core.callStorm('return(({ "foo" : "bar" }))'))
781
781
 
782
782
  ddef0 = await core.callStorm('return($lib.dmon.add(${ $lib.queue.gen(hehedmon).put(lolz) $lib.time.sleep(10) }, name=hehedmon))')
783
783
  ddef1 = await core.callStorm('return($lib.dmon.get($iden))', opts={'vars': {'iden': ddef0.get('iden')}})
@@ -1226,12 +1226,12 @@ class StormTest(s_t_utils.SynTest):
1226
1226
  await core.nodes('cron.list')
1227
1227
 
1228
1228
  self.eq({'foo': 'bar', 'baz': 'faz'}, await core.callStorm('''
1229
- return($lib.dict( // do foo thing
1230
- foo /* hehe */ = /* haha */ bar, //lol
1231
- baz // hehe
1232
- = // haha
1233
- faz // hehe
1234
- ))
1229
+ return(({ // do foo thing
1230
+ "foo" /* hehe */ : /* haha */ "bar", //lol
1231
+ "baz" // hehe
1232
+ : // haha
1233
+ "faz" // hehe
1234
+ }))
1235
1235
  '''))
1236
1236
 
1237
1237
  self.eq(('foo', 'bar', 'baz'), await core.callStorm('''
@@ -1805,7 +1805,7 @@ class StormTest(s_t_utils.SynTest):
1805
1805
 
1806
1806
  # Headers as list of tuples, params as dict
1807
1807
  q = '''
1808
- $params=$lib.dict(key=valu, foo=bar)
1808
+ $params=({"key": "valu", "foo": "bar"})
1809
1809
  $hdr = (
1810
1810
  ("User-Agent", "my fav ua"),
1811
1811
  )|
@@ -2045,7 +2045,7 @@ class StormTest(s_t_utils.SynTest):
2045
2045
  self.none(await core.callStorm('''
2046
2046
  [ ps:contact = * ]
2047
2047
  if $node {
2048
- $foo = $lib.dict()
2048
+ $foo = ({})
2049
2049
  $foo.bar = $lib.undef
2050
2050
  return($foo.bar)
2051
2051
  }
@@ -2064,7 +2064,7 @@ class StormTest(s_t_utils.SynTest):
2064
2064
  # runtsafe variants
2065
2065
  self.eq(('foo', 'baz'), await core.callStorm('$foo = (foo, bar, baz) $foo.1 = $lib.undef return($foo)'))
2066
2066
  self.eq(('foo', 'bar'), await core.callStorm('$foo = (foo, bar, baz) $foo."-1" = $lib.undef return($foo)'))
2067
- self.none(await core.callStorm('$foo = $lib.dict() $foo.bar = 10 $foo.bar = $lib.undef return($foo.bar)'))
2067
+ self.none(await core.callStorm('$foo = ({}) $foo.bar = 10 $foo.bar = $lib.undef return($foo.bar)'))
2068
2068
  self.eq(('woot',), await core.callStorm('''
2069
2069
  $foo = (foo, bar, baz)
2070
2070
  $foo.0 = $lib.undef
@@ -4513,7 +4513,7 @@ class StormTest(s_t_utils.SynTest):
4513
4513
  visi = await core.auth.addUser('visi')
4514
4514
  await visi.addRule((True, ('node',)))
4515
4515
 
4516
- size, sha256 = await core.callStorm('return($lib.bytes.put($buf))', {'vars': {'buf': b'asdfasdf'}})
4516
+ size, sha256 = await core.callStorm('return($lib.axon.put($buf))', {'vars': {'buf': b'asdfasdf'}})
4517
4517
 
4518
4518
  self.len(1, await core.nodes(f'[ file:bytes={sha256} ]'))
4519
4519
 
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import ssl
2
3
  import json
3
4
  import shutil
4
5
 
@@ -64,8 +65,8 @@ class StormHttpTest(s_test.SynTest):
64
65
 
65
66
  # Header and params as dict
66
67
  q = '''
67
- $params=$lib.dict(key=valu, foo=bar, baz=$lib.false)
68
- $hdr = $lib.dict(true=$lib.true)
68
+ $params=({"key": "valu", "foo": "bar", "baz": $lib.false})
69
+ $hdr = ({"true": $lib.true})
69
70
  $hdr."User-Agent"="Storm HTTP Stuff"
70
71
  $k = (0)
71
72
  $hdr.$k="Why"
@@ -240,7 +241,7 @@ class StormHttpTest(s_test.SynTest):
240
241
  opts = {'vars': {'url': url, 'noauth_url': noauth_url, 'newp_url': newp_url}}
241
242
 
242
243
  q = '''
243
- $params=$lib.dict(key=valu, foo=bar)
244
+ $params=({"key": "valu", "foo": "bar"})
244
245
  $hdr = (
245
246
  ("User-Agent", "Storm HTTP Stuff"),
246
247
  )
@@ -256,7 +257,7 @@ class StormHttpTest(s_test.SynTest):
256
257
  self.eq('1', headers.get('Head'))
257
258
 
258
259
  q = '''
259
- $params=$lib.dict(key=valu, redirect='http://test.newp/')
260
+ $params=({"key": "valu", "redirect": 'http://test.newp/'})
260
261
  $hdr = (
261
262
  ("User-Agent", "Storm HTTP Stuff"),
262
263
  )
@@ -273,7 +274,7 @@ class StormHttpTest(s_test.SynTest):
273
274
  self.eq('http://test.newp/', headers.get('Location'))
274
275
 
275
276
  q = '''
276
- $params=$lib.dict(key=valu, redirect=$noauth_url)
277
+ $params=({"key": "valu", "redirect": $noauth_url})
277
278
  $hdr = (
278
279
  ("User-Agent", "Storm HTTP Stuff"),
279
280
  )
@@ -286,7 +287,7 @@ class StormHttpTest(s_test.SynTest):
286
287
  self.eq(b'', body)
287
288
 
288
289
  q = '''
289
- $params=$lib.dict(key=valu, redirect=$newp_url)
290
+ $params=({"key": "valu", "redirect": $newp_url})
290
291
  $hdr = (
291
292
  ("User-Agent", "Storm HTTP Stuff"),
292
293
  )
@@ -299,7 +300,7 @@ class StormHttpTest(s_test.SynTest):
299
300
  self.eq(b'', body)
300
301
 
301
302
  q = '''
302
- $params=$lib.dict(key=valu, redirect="http://127.0.0.1/newp")
303
+ $params=({"key": "valu", "redirect": "http://127.0.0.1/newp"})
303
304
  $hdr = (
304
305
  ("User-Agent", "Storm HTTP Stuff"),
305
306
  )
@@ -321,7 +322,7 @@ class StormHttpTest(s_test.SynTest):
321
322
  url = f'https://root:root@127.0.0.1:{port}/api/v0/test'
322
323
  opts = {'vars': {'url': url}}
323
324
  q = '''
324
- $params=$lib.dict(key=valu, foo=bar)
325
+ $params=({"key": "valu", "foo": "bar"})
325
326
  $hdr = (
326
327
  ("User-Agent", "Storm HTTP Stuff"),
327
328
  )
@@ -337,7 +338,7 @@ class StormHttpTest(s_test.SynTest):
337
338
  url = f'https://root:root@127.0.0.1:{port}/api/v0/test'
338
339
  opts = {'vars': {'url': url, 'sleep': 1, 'timeout': 2}}
339
340
  q = '''
340
- $params=$lib.dict(key=valu, foo=bar, sleep=$sleep)
341
+ $params=({"key": "valu", "foo": "bar", "sleep": $sleep})
341
342
  $hdr = (
342
343
  ("User-Agent", "Storm HTTP Stuff"),
343
344
  )
@@ -351,7 +352,7 @@ class StormHttpTest(s_test.SynTest):
351
352
  url = f'https://root:root@127.0.0.1:{port}/api/v0/test'
352
353
  opts = {'vars': {'url': url, 'sleep': 10, 'timeout': 1}}
353
354
  q = '''
354
- $params=$lib.dict(key=valu, foo=bar, sleep=$sleep)
355
+ $params=({"key": "valu", "foo": "bar", "sleep": $sleep})
355
356
  $hdr = (
356
357
  ("User-Agent", "Storm HTTP Stuff"),
357
358
  )
@@ -374,7 +375,7 @@ class StormHttpTest(s_test.SynTest):
374
375
 
375
376
  adduser = '''
376
377
  $url = $lib.str.format("https://root:root@127.0.0.1:{port}/api/v1/auth/adduser", port=$port)
377
- $user = $lib.dict(name=$name, passwd=$passwd)
378
+ $user = ({"name": $name, "passwd": $passwd})
378
379
  $post = $lib.inet.http.post($url, json=$user, ssl_verify=$(0)).json().result.name
379
380
  $lib.print($post)
380
381
  [ test:str=$post ]
@@ -387,7 +388,7 @@ class StormHttpTest(s_test.SynTest):
387
388
  adduser = '''
388
389
  $url = $lib.str.format("https://root:root@127.0.0.1:{port}/api/v1/auth/adduser", port=$port)
389
390
  $user = $lib.str.format('{"name": "{name}", "passwd": "{passwd}"}', name=$name, passwd=$passwd)
390
- $header = $lib.dict("Content-Type"="application/json")
391
+ $header = ({"Content-Type": "application/json"})
391
392
  $post = $lib.inet.http.post($url, headers=$header, body=$user, ssl_verify=$(0)).json().result.name
392
393
  [ test:str=$post ]
393
394
  '''
@@ -400,7 +401,7 @@ class StormHttpTest(s_test.SynTest):
400
401
  url = f'https://root:root@127.0.0.1:{port}/api/v0/test'
401
402
  opts = {'vars': {'url': url, 'buf': b'1234'}}
402
403
  q = '''
403
- $params=$lib.dict(key=valu, foo=bar)
404
+ $params=({"key": "valu", "foo": "bar"})
404
405
  $resp = $lib.inet.http.post($url, params=$params, body=$buf, ssl_verify=$lib.false)
405
406
  return ( $resp.json() )
406
407
  '''
@@ -411,9 +412,9 @@ class StormHttpTest(s_test.SynTest):
411
412
 
412
413
  q = '''
413
414
  $fields=$lib.list(
414
- $lib.dict(name=foo, value=bar),
415
- $lib.dict(name=foo, value=bar2),
416
- $lib.dict(name=baz, value=cool)
415
+ ({"name": "foo", "value": "bar"}),
416
+ ({"name": "foo", "value": "bar2"}),
417
+ ({"name": "baz", "value": "cool"})
417
418
  )
418
419
  $resp = $lib.inet.http.post($url, fields=$fields, ssl_verify=$lib.false)
419
420
  return ( $resp.json() )
@@ -466,8 +467,8 @@ class StormHttpTest(s_test.SynTest):
466
467
  await root.setPasswd('root')
467
468
  text = '''
468
469
  $url = $lib.str.format("https://root:root@127.0.0.1:{port}/api/v1/storm", port=$port)
469
- $stormq = "($size, $sha2) = $lib.bytes.put($lib.base64.decode('dmVydGV4')) [ test:str = $sha2 ] [ test:int = $size ]"
470
- $json = $lib.dict(query=$stormq)
470
+ $stormq = "($size, $sha2) = $lib.axon.put($lib.base64.decode('dmVydGV4')) [ test:str = $sha2 ] [ test:int = $size ]"
471
+ $json = ({"query": $stormq})
471
472
  $bytez = $lib.inet.http.post($url, json=$json, ssl_verify=$(0))
472
473
  '''
473
474
  opts = {'vars': {'port': port}}
@@ -482,7 +483,7 @@ class StormHttpTest(s_test.SynTest):
482
483
 
483
484
  text = '''
484
485
  $url = $lib.str.format("https://root:root@127.0.0.1:{port}/api/v1/storm", port=$port)
485
- $json = $lib.dict(query="test:str")
486
+ $json = ({"query": "test:str"})
486
487
  $body = $json
487
488
  $resp=$lib.inet.http.post($url, json=$json, body=$body, ssl_verify=$(0))
488
489
  return ( ($resp.code, $resp.err) )
@@ -672,3 +673,165 @@ class StormHttpTest(s_test.SynTest):
672
673
  with self.raises(s_stormctrl.StormExit) as cm:
673
674
  await core.callStorm(query, opts=opts)
674
675
  self.isin('connect to proxy 127.0.0.1:1', str(cm.exception))
676
+
677
+ async def test_storm_http_mtls(self):
678
+
679
+ with self.getTestDir() as dirn:
680
+
681
+ cdir = s_common.gendir(dirn, 'certs')
682
+ cadir = s_common.gendir(cdir, 'cas')
683
+ tdir = s_certdir.CertDir(cdir)
684
+ tdir.genCaCert('somelocalca')
685
+ tdir.genHostCert('localhost', signas='somelocalca')
686
+
687
+ localkeyfp = tdir.getHostKeyPath('localhost')
688
+ localcertfp = tdir.getHostCertPath('localhost')
689
+ pkeypath = shutil.copyfile(localkeyfp, s_common.genpath(dirn, 'sslkey.pem'))
690
+ certpath = shutil.copyfile(localcertfp, s_common.genpath(dirn, 'sslcert.pem'))
691
+
692
+ tlscadir = s_common.gendir(dirn, 'cadir')
693
+ cacertpath = shutil.copyfile(os.path.join(cadir, 'somelocalca.crt'), os.path.join(tlscadir, 'somelocalca.crt'))
694
+
695
+ pkey, cert = tdir.genUserCert('someuser', signas='somelocalca')
696
+ user_pkey = tdir._pkeyToByts(pkey).decode()
697
+ user_cert = tdir._certToByts(cert).decode()
698
+
699
+ user_fullchain = user_cert + s_common.getbytes(cacertpath).decode()
700
+ user_fullchain_key = user_fullchain + user_pkey
701
+
702
+ conf = {'tls:ca:dir': tlscadir}
703
+ async with self.getTestCore(dirn=dirn, conf=conf) as core:
704
+
705
+ sslctx = core.initSslCtx(certpath, pkeypath)
706
+ sslctx.load_verify_locations(cafile=cacertpath)
707
+
708
+ addr, port = await core.addHttpsPort(0, sslctx=sslctx)
709
+ root = await core.auth.getUserByName('root')
710
+ await root.setPasswd('root')
711
+
712
+ core.addHttpApi('/api/v0/test', s_test.HttpReflector, {'cell': core})
713
+ core.addHttpApi('/test/ws', TstWebSock, {})
714
+
715
+ sslopts = {}
716
+
717
+ opts = {
718
+ 'vars': {
719
+ 'url': f'https://root:root@localhost:{port}/api/v0/test',
720
+ 'ws': f'https://localhost:{port}/test/ws',
721
+ 'verify': True,
722
+ 'sslopts': sslopts,
723
+ },
724
+ }
725
+
726
+ q = 'return($lib.inet.http.get($url, ssl_verify=$verify, ssl_opts=$sslopts))'
727
+
728
+ size, sha256 = await core.callStorm('return($lib.bytes.put($lib.base64.decode(Zm9v)))')
729
+ opts['vars']['sha256'] = sha256
730
+
731
+ # mtls required
732
+
733
+ sslctx.verify_mode = ssl.CERT_REQUIRED
734
+
735
+ ## no client cert provided
736
+ resp = await core.callStorm(q, opts=opts)
737
+ self.eq(-1, resp['code'])
738
+ self.isin('tlsv13 alert certificate required', resp['reason'])
739
+
740
+ ## full chain cert w/key
741
+ sslopts['client_cert'] = user_fullchain_key
742
+ resp = await core.callStorm(q, opts=opts)
743
+ self.eq(200, resp['code'])
744
+
745
+ ## separate cert and key
746
+ sslopts['client_cert'] = user_fullchain
747
+ sslopts['client_key'] = user_pkey
748
+ resp = await core.callStorm(q, opts=opts)
749
+ self.eq(200, resp['code'])
750
+
751
+ ## sslctx's are cached
752
+ self.len(3, core._sslctx_cache)
753
+ resp = await core.callStorm(q, opts=opts)
754
+ self.eq(200, resp['code'])
755
+ self.len(3, core._sslctx_cache)
756
+
757
+ ## remaining methods
758
+ self.eq(200, await core.callStorm('return($lib.inet.http.post($url, ssl_opts=$sslopts).code)', opts=opts))
759
+ self.eq(200, await core.callStorm('return($lib.inet.http.head($url, ssl_opts=$sslopts).code)', opts=opts))
760
+ self.eq(200, await core.callStorm('return($lib.inet.http.request(get, $url, ssl_opts=$sslopts).code)', opts=opts))
761
+
762
+ ## connect
763
+ ret = await core.callStorm('''
764
+ ($ok, $sock) = $lib.inet.http.connect($ws, ssl_opts=$sslopts)
765
+ if (not $ok) { return(($ok, $sock)) }
766
+ ($ok, $mesg) = $sock.rx()
767
+ return(($ok, $mesg))
768
+ ''', opts=opts)
769
+ self.true(ret[0])
770
+ self.eq('woot', ret[1]['hi'])
771
+
772
+ # Axon APIs
773
+
774
+ axon_queries = {
775
+ 'postfile': '''
776
+ $fields = ([{"name": "file", "sha256": $sha256}])
777
+ return($lib.inet.http.post($url, fields=$fields, ssl_opts=$sslopts).code)
778
+ ''',
779
+ 'wget': 'return($lib.axon.wget($url, ssl_opts=$sslopts).code)',
780
+ 'wput': 'return($lib.axon.wput($sha256, $url, method=POST, ssl_opts=$sslopts).code)',
781
+ 'urlfile': 'yield $lib.axon.urlfile($url, ssl_opts=$sslopts)',
782
+ }
783
+
784
+ ## version check fails
785
+ try:
786
+ oldv = core.axoninfo['synapse']['version']
787
+ core.axoninfo['synapse']['version'] = (2, 161, 0)
788
+ await self.asyncraises(s_exc.BadVersion, core.callStorm(axon_queries['postfile'], opts=opts))
789
+ await self.asyncraises(s_exc.BadVersion, core.callStorm(axon_queries['wget'], opts=opts))
790
+ await self.asyncraises(s_exc.BadVersion, core.callStorm(axon_queries['wput'], opts=opts))
791
+ await self.asyncraises(s_exc.BadVersion, core.nodes(axon_queries['urlfile'], opts=opts))
792
+ finally:
793
+ core.axoninfo['synapse']['version'] = oldv
794
+
795
+ ## version check succeeds
796
+ # todo: setting the synapse version can be removed once ssl_opts is released
797
+ try:
798
+ oldv = core.axoninfo['synapse']['version']
799
+ core.axoninfo['synapse']['version'] = (oldv[0], oldv[1] + 1, oldv[2])
800
+ self.eq(200, await core.callStorm(axon_queries['postfile'], opts=opts))
801
+ self.eq(200, await core.callStorm(axon_queries['wget'], opts=opts))
802
+ self.eq(200, await core.callStorm(axon_queries['wput'], opts=opts))
803
+ self.len(1, await core.nodes(axon_queries['urlfile'], opts=opts))
804
+ finally:
805
+ core.axoninfo['synapse']['version'] = oldv
806
+
807
+ # verify arg precedence
808
+
809
+ core.conf.pop('tls:ca:dir')
810
+ core._sslctx_cache.clear()
811
+
812
+ ## fail w/o ca
813
+ resp = await core.callStorm(q, opts=opts)
814
+ self.eq(-1, resp['code'])
815
+ self.isin('self-signed certificate', resp['reason'])
816
+
817
+ ## verify arg wins
818
+ opts['vars']['verify'] = False
819
+ sslopts['verify'] = True
820
+ resp = await core.callStorm(q, opts=opts)
821
+ self.eq(200, resp['code'])
822
+
823
+ # bad opts
824
+
825
+ ## schema violation
826
+ sslopts['newp'] = 'wut'
827
+ await self.asyncraises(s_exc.SchemaViolation, core.callStorm(q, opts=opts))
828
+ sslopts.pop('newp')
829
+
830
+ ## missing key
831
+ sslopts['client_cert'] = user_fullchain
832
+ sslopts['client_key'] = None
833
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
834
+
835
+ ## bad cert
836
+ sslopts['client_cert'] = 'not-gonna-work'
837
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
@@ -420,8 +420,8 @@ class StormLibAuthTest(s_test.SynTest):
420
420
  async with self.getTestCore() as core:
421
421
  self.none(await core.callStorm('return($lib.user.json.get(foo))'))
422
422
  self.none(await core.callStorm('return($lib.user.json.get(foo, prop=bar))'))
423
- self.true(await core.callStorm('return($lib.user.json.set(hi, $lib.dict(foo=bar, baz=faz)))'))
424
- self.true(await core.callStorm('return($lib.user.json.set(bye/bye, $lib.dict(zip=zop, bip=bop)))'))
423
+ self.true(await core.callStorm('return($lib.user.json.set(hi, ({"foo": "bar", "baz": "faz"})))'))
424
+ self.true(await core.callStorm('return($lib.user.json.set(bye/bye, ({"zip": "zop", "bip": "bop"})))'))
425
425
  self.eq('bar', await core.callStorm('return($lib.user.json.get(hi, prop=foo))'))
426
426
  self.eq({'foo': 'bar', 'baz': 'faz'}, await core.callStorm('return($lib.user.json.get(hi))'))
427
427
 
@@ -454,7 +454,7 @@ class StormLibAuthTest(s_test.SynTest):
454
454
  await core.callStorm('return($lib.auth.users.byname(root).json.get(bye/bye, prop=zip))', opts=asvisi)
455
455
 
456
456
  self.none(await core.callStorm('return($lib.user.json.get(hi))', opts=asvisi))
457
- await core.callStorm('if (not $lib.user.json.has(hehe)) { $lib.user.json.set(hehe, $lib.dict()) }', opts=asvisi)
457
+ await core.callStorm('if (not $lib.user.json.has(hehe)) { $lib.user.json.set(hehe, ({})) }', opts=asvisi)
458
458
 
459
459
  self.true(await core.callStorm('return($lib.user.json.set(hehe, haha, prop=foo))', opts=asvisi))
460
460
  self.true(await core.callStorm('return($lib.user.json.set(hehe, haha, prop=foo))', opts=asvisi))
@@ -187,7 +187,7 @@ class StormCellTest(s_test.SynTest):
187
187
  }
188
188
  $lib.exit('No view found for name={name}', name=$name)
189
189
  }
190
- $ret = $lib.dict()
190
+ $ret = ({})
191
191
  $ret.baseview=$get_view(default)
192
192
  $ret.fork1a=$get_view(base1a)
193
193
  $ret.fork2a=$get_view(base2a)
@@ -429,6 +429,44 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
429
429
  '''
430
430
  iden3 = await core.callStorm(q)
431
431
 
432
+ # $lib.dict accessor methods
433
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.keys($api.vars))'
434
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
435
+ self.eq(valu, ('hehe', 'items'))
436
+
437
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.values($api.vars))'
438
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
439
+ self.eq(valu, ('wow', ('1', '2', 3)))
440
+
441
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.has($api.vars, anotherKey))'
442
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
443
+ self.false(valu)
444
+
445
+ q = '''$api=$lib.cortex.httpapi.get($iden)
446
+ return ($lib.dict.update($api.vars, ({"hehe": "haha", "anotherKey": "anotherValu"}) ))'''
447
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
448
+ self.none(valu)
449
+
450
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.has($api.vars, anotherKey))'
451
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
452
+ self.true(valu)
453
+
454
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.values($api.vars))'
455
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
456
+ self.eq(valu, ('haha', ('1', '2', 3), 'anotherValu'))
457
+
458
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.pop($api.vars, anotherKey))'
459
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
460
+ self.eq(valu, 'anotherValu')
461
+
462
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.pop($api.vars, anotherKey, missingKey))'
463
+ valu = await core.callStorm(q, opts={'vars': {'iden': iden3}})
464
+ self.eq(valu, 'missingKey')
465
+
466
+ with self.raises(s_exc.BadArg):
467
+ q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.pop($api.vars, anotherKey))'
468
+ await core.callStorm(q, opts={'vars': {'iden': iden3}})
469
+
432
470
  msgs = await core.stormlist('cortex.httpapi.list')
433
471
  self.stormIsInPrint(f'0 {iden0}', msgs)
434
472
  self.stormIsInPrint(f'1 {iden1}', msgs)
@@ -569,7 +607,7 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
569
607
  msgs = await core.stormlist('cortex.httpapi.stat $iden', opts={'vars': {'iden': iden3}})
570
608
  self.stormIsInPrint(f'Iden: {iden3}', msgs)
571
609
  self.stormIsInPrint('The handler has the following runtime variables set:', msgs)
572
- self.stormIsInPrint('hehe => wow', msgs)
610
+ self.stormIsInPrint('hehe => haha', msgs)
573
611
  self.stormIsInPrint("items => ('1', '2', 3)", msgs)
574
612
 
575
613
  # Remove a user + view and stat the handler
@@ -999,7 +1037,11 @@ for $i in $values {
999
1037
  }
1000
1038
  // Cannot modify request headers
1001
1039
  $api.methods.post = ${
1002
- $request.headers.newp = haha
1040
+ if $request.headers.dictmethod {
1041
+ $lib.dict.update($request.headers, ({"newp": "haha"}))
1042
+ } else {
1043
+ $request.headers.newp = haha
1044
+ }
1003
1045
  }
1004
1046
  return ( ($api.iden, $api.owner.name) )
1005
1047
  '''
@@ -1029,6 +1071,12 @@ for $i in $values {
1029
1071
  self.eq(data.get('code'), 'StormRuntimeError')
1030
1072
  self.eq(data.get('mesg'), 'http:api:request:headers may not be modified by the runtime.')
1031
1073
 
1074
+ resp = await sess.post(f'https://localhost:{hport}/api/ext/testpath', headers={'dictmethod': '1'})
1075
+ self.eq(resp.status, 500)
1076
+ data = await resp.json()
1077
+ self.eq(data.get('code'), 'StormRuntimeError')
1078
+ self.eq(data.get('mesg'), 'http:api:request:headers may not be modified by the runtime.')
1079
+
1032
1080
  async def test_libcortex_httpapi_vars(self):
1033
1081
 
1034
1082
  async with self.getTestCore() as core:
@@ -27,7 +27,7 @@ class JsonTest(s_test.SynTest):
27
27
 
28
28
  opts = {'vars': {'schema': s_test.test_schema}}
29
29
  q = '''$schemaObj = $lib.json.schema($schema)
30
- $item=$lib.dict()
30
+ $item=({})
31
31
  $item."key:integer"=(4)
32
32
  return ( $schemaObj.validate($item) )
33
33
  '''
@@ -37,7 +37,7 @@ class JsonTest(s_test.SynTest):
37
37
  self.eq('Default string!', valu.get('key:string'))
38
38
 
39
39
  q = '''$schemaObj = $lib.json.schema($schema)
40
- $item=$lib.dict()
40
+ $item=({})
41
41
  $item."key:integer"=4
42
42
  return ( $schemaObj.validate($item) )
43
43
  '''
@@ -152,7 +152,7 @@ class MacroTest(s_test.SynTest):
152
152
  self.eq([('test:str', 'cooler')], [n.ndef for n in nodes])
153
153
 
154
154
  # Inner vars win on conflict
155
- q = 'macro.set data2 ${ $data=$lib.dict(value=beef) [test:str=$data.value +#cool.story] }'
155
+ q = 'macro.set data2 ${ $data=({"value": "beef"}) [test:str=$data.value +#cool.story] }'
156
156
  msgs = await core.stormlist(q)
157
157
  self.stormIsInPrint('Set macro: data2', msgs)
158
158