synapse 2.153.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 (69) hide show
  1. synapse/cortex.py +4 -4
  2. synapse/lib/ast.py +10 -5
  3. synapse/lib/autodoc.py +2 -2
  4. synapse/lib/cache.py +16 -1
  5. synapse/lib/layer.py +2 -1
  6. synapse/lib/modelrev.py +36 -3
  7. synapse/lib/node.py +2 -5
  8. synapse/lib/snap.py +10 -0
  9. synapse/lib/storm.py +80 -0
  10. synapse/lib/stormhttp.py +3 -0
  11. synapse/lib/stormlib/backup.py +1 -0
  12. synapse/lib/stormlib/basex.py +2 -0
  13. synapse/lib/stormlib/cell.py +7 -0
  14. synapse/lib/stormlib/compression.py +3 -0
  15. synapse/lib/stormlib/ethereum.py +1 -0
  16. synapse/lib/stormlib/graph.py +2 -0
  17. synapse/lib/stormlib/hashes.py +5 -0
  18. synapse/lib/stormlib/hex.py +6 -0
  19. synapse/lib/stormlib/infosec.py +4 -0
  20. synapse/lib/stormlib/ipv6.py +1 -0
  21. synapse/lib/stormlib/iters.py +2 -0
  22. synapse/lib/stormlib/json.py +5 -0
  23. synapse/lib/stormlib/mime.py +1 -0
  24. synapse/lib/stormlib/model.py +19 -3
  25. synapse/lib/stormlib/modelext.py +1 -0
  26. synapse/lib/stormlib/notifications.py +2 -0
  27. synapse/lib/stormlib/pack.py +2 -0
  28. synapse/lib/stormlib/random.py +1 -0
  29. synapse/lib/stormlib/smtp.py +0 -7
  30. synapse/lib/stormlib/stats.py +4 -0
  31. synapse/lib/stormlib/stix.py +8 -0
  32. synapse/lib/stormlib/storm.py +1 -0
  33. synapse/lib/stormlib/version.py +3 -0
  34. synapse/lib/stormlib/xml.py +3 -0
  35. synapse/lib/stormlib/yaml.py +2 -0
  36. synapse/lib/stormtypes.py +201 -29
  37. synapse/lib/trigger.py +180 -4
  38. synapse/lib/types.py +1 -1
  39. synapse/lib/version.py +2 -2
  40. synapse/lib/view.py +55 -6
  41. synapse/models/inet.py +16 -4
  42. synapse/models/orgs.py +47 -2
  43. synapse/models/risk.py +126 -2
  44. synapse/models/syn.py +6 -0
  45. synapse/tests/files/stormpkg/badapidef.yaml +13 -0
  46. synapse/tests/files/stormpkg/storm/modules/apimod +10 -0
  47. synapse/tests/files/stormpkg/testpkg.yaml +23 -0
  48. synapse/tests/test_cortex.py +50 -34
  49. synapse/tests/test_lib_ast.py +7 -0
  50. synapse/tests/test_lib_autodoc.py +1 -1
  51. synapse/tests/test_lib_modelrev.py +9 -0
  52. synapse/tests/test_lib_node.py +55 -0
  53. synapse/tests/test_lib_storm.py +13 -0
  54. synapse/tests/test_lib_stormlib_storm.py +8 -0
  55. synapse/tests/test_lib_stormsvc.py +24 -1
  56. synapse/tests/test_lib_stormtypes.py +105 -1
  57. synapse/tests/test_lib_trigger.py +315 -0
  58. synapse/tests/test_lib_view.py +1 -2
  59. synapse/tests/test_model_inet.py +22 -0
  60. synapse/tests/test_model_orgs.py +28 -0
  61. synapse/tests/test_model_risk.py +73 -0
  62. synapse/tests/test_tools_autodoc.py +25 -0
  63. synapse/tests/test_tools_genpkg.py +9 -3
  64. synapse/tools/autodoc.py +42 -2
  65. {synapse-2.153.0.dist-info → synapse-2.154.0.dist-info}/METADATA +1 -1
  66. {synapse-2.153.0.dist-info → synapse-2.154.0.dist-info}/RECORD +69 -67
  67. {synapse-2.153.0.dist-info → synapse-2.154.0.dist-info}/WHEEL +1 -1
  68. {synapse-2.153.0.dist-info → synapse-2.154.0.dist-info}/LICENSE +0 -0
  69. {synapse-2.153.0.dist-info → synapse-2.154.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormtypes.py CHANGED
@@ -630,6 +630,7 @@ class LibPkg(Lib):
630
630
  verify = await tobool(verify)
631
631
  await self.runt.snap.core.addStormPkg(pkgdef, verify=verify)
632
632
 
633
+ @stormfunc(readonly=True)
633
634
  async def _libPkgGet(self, name):
634
635
  name = await tostr(name)
635
636
  pkgdef = await self.runt.snap.core.getStormPkg(name)
@@ -638,6 +639,7 @@ class LibPkg(Lib):
638
639
 
639
640
  return Dict(pkgdef)
640
641
 
642
+ @stormfunc(readonly=True)
641
643
  async def _libPkgHas(self, name):
642
644
  name = await tostr(name)
643
645
  pkgdef = await self.runt.snap.core.getStormPkg(name)
@@ -649,10 +651,12 @@ class LibPkg(Lib):
649
651
  self.runt.confirm(('pkg', 'del'), None)
650
652
  await self.runt.snap.core.delStormPkg(name)
651
653
 
654
+ @stormfunc(readonly=True)
652
655
  async def _libPkgList(self):
653
656
  pkgs = await self.runt.snap.core.getStormPkgs()
654
657
  return list(sorted(pkgs, key=lambda x: x.get('name')))
655
658
 
659
+ @stormfunc(readonly=True)
656
660
  async def _libPkgDeps(self, pkgdef):
657
661
  pkgdef = await toprim(pkgdef)
658
662
  return await self.runt.snap.core.verifyStormPkgDeps(pkgdef)
@@ -748,12 +752,15 @@ class LibDmon(Lib):
748
752
 
749
753
  await self.runt.snap.core.delStormDmon(iden)
750
754
 
755
+ @stormfunc(readonly=True)
751
756
  async def _libDmonGet(self, iden):
752
757
  return await self.runt.snap.core.getStormDmon(iden)
753
758
 
759
+ @stormfunc(readonly=True)
754
760
  async def _libDmonList(self):
755
761
  return await self.runt.snap.core.getStormDmons()
756
762
 
763
+ @stormfunc(readonly=True)
757
764
  async def _libDmonLog(self, iden):
758
765
  self.runt.confirm(('dmon', 'log'))
759
766
  return await self.runt.snap.core.getStormDmonLog(iden)
@@ -935,12 +942,14 @@ class LibService(Lib):
935
942
  await self._checkSvcGetPerm(ssvc)
936
943
  return Service(self.runt, ssvc)
937
944
 
945
+ @stormfunc(readonly=True)
938
946
  async def _libSvcHas(self, name):
939
947
  ssvc = self.runt.snap.core.getStormSvc(name)
940
948
  if ssvc is None:
941
949
  return False
942
950
  return True
943
951
 
952
+ @stormfunc(readonly=True)
944
953
  async def _libSvcList(self):
945
954
  self.runt.confirm(('service', 'list'))
946
955
  retn = []
@@ -954,6 +963,7 @@ class LibService(Lib):
954
963
 
955
964
  return retn
956
965
 
966
+ @stormfunc(readonly=True)
957
967
  async def _libSvcWait(self, name, timeout=None):
958
968
  name = await tostr(name)
959
969
  timeout = await toint(timeout, noneok=True)
@@ -1011,6 +1021,7 @@ class LibTags(Lib):
1011
1021
  'prefix': self.prefix,
1012
1022
  }
1013
1023
 
1024
+ @stormfunc(readonly=True)
1014
1025
  async def prefix(self, names, prefix, ispart=False):
1015
1026
 
1016
1027
  prefix = await tostr(prefix)
@@ -1380,6 +1391,7 @@ class LibBase(Lib):
1380
1391
  'trycast': self.trycast,
1381
1392
  }
1382
1393
 
1394
+ @stormfunc(readonly=True)
1383
1395
  async def _libBaseImport(self, name, debug=False, reqvers=None):
1384
1396
 
1385
1397
  name = await tostr(name)
@@ -1517,12 +1529,15 @@ class LibBase(Lib):
1517
1529
  for item in sorted(valu, reverse=reverse):
1518
1530
  yield item
1519
1531
 
1532
+ @stormfunc(readonly=True)
1520
1533
  async def _set(self, *vals):
1521
1534
  return Set(vals)
1522
1535
 
1536
+ @stormfunc(readonly=True)
1523
1537
  async def _list(self, *vals):
1524
1538
  return List(list(vals))
1525
1539
 
1540
+ @stormfunc(readonly=True)
1526
1541
  async def _text(self, *args):
1527
1542
  valu = ''.join(args)
1528
1543
  return Text(valu)
@@ -1712,6 +1727,7 @@ class LibPs(Lib):
1712
1727
  todo = s_common.todo('kill', self.runt.user, idens[0])
1713
1728
  return await self.dyncall('cell', todo)
1714
1729
 
1730
+ @stormfunc(readonly=True)
1715
1731
  async def _list(self):
1716
1732
  todo = s_common.todo('ps', self.runt.user)
1717
1733
  return await self.dyncall('cell', todo)
@@ -1771,15 +1787,18 @@ class LibStr(Lib):
1771
1787
  'format': self.format,
1772
1788
  }
1773
1789
 
1790
+ @stormfunc(readonly=True)
1774
1791
  async def concat(self, *args):
1775
1792
  strs = [await tostr(a) for a in args]
1776
1793
  return ''.join(strs)
1777
1794
 
1795
+ @stormfunc(readonly=True)
1778
1796
  async def format(self, text, **kwargs):
1779
1797
  text = await kwarg_format(text, **kwargs)
1780
1798
 
1781
1799
  return text
1782
1800
 
1801
+ @stormfunc(readonly=True)
1783
1802
  async def join(self, sepr, items):
1784
1803
  strs = [await tostr(item) async for item in toiter(items)]
1785
1804
  return sepr.join(strs)
@@ -2029,6 +2048,7 @@ class LibAxon(Lib):
2029
2048
  return {str(k): str(v) for k, v in item.items()}
2030
2049
  return item
2031
2050
 
2051
+ @stormfunc(readonly=True)
2032
2052
  async def readlines(self, sha256, errors='ignore'):
2033
2053
  if not self.runt.allowed(('axon', 'get')):
2034
2054
  self.runt.confirm(('storm', 'lib', 'axon', 'get'))
@@ -2038,6 +2058,7 @@ class LibAxon(Lib):
2038
2058
  async for line in self.runt.snap.core.axon.readlines(sha256, errors=errors):
2039
2059
  yield line
2040
2060
 
2061
+ @stormfunc(readonly=True)
2041
2062
  async def jsonlines(self, sha256, errors='ignore'):
2042
2063
  if not self.runt.allowed(('axon', 'get')):
2043
2064
  self.runt.confirm(('storm', 'lib', 'axon', 'get'))
@@ -2201,6 +2222,7 @@ class LibAxon(Lib):
2201
2222
 
2202
2223
  return urlfile
2203
2224
 
2225
+ @stormfunc(readonly=True)
2204
2226
  async def list(self, offs=0, wait=False, timeout=None):
2205
2227
  offs = await toint(offs)
2206
2228
  wait = await tobool(wait)
@@ -2215,6 +2237,7 @@ class LibAxon(Lib):
2215
2237
  async for item in axon.hashes(offs, wait=wait, timeout=timeout):
2216
2238
  yield (item[0], s_common.ehex(item[1][0]), item[1][1])
2217
2239
 
2240
+ @stormfunc(readonly=True)
2218
2241
  async def csvrows(self, sha256, dialect='excel', errors='ignore', **fmtparams):
2219
2242
 
2220
2243
  if not self.runt.allowed(('axon', 'get')):
@@ -2230,6 +2253,7 @@ class LibAxon(Lib):
2230
2253
  yield item
2231
2254
  await asyncio.sleep(0)
2232
2255
 
2256
+ @stormfunc(readonly=True)
2233
2257
  async def metrics(self):
2234
2258
  if not self.runt.allowed(('axon', 'has')):
2235
2259
  self.runt.confirm(('storm', 'lib', 'axon', 'has'))
@@ -2337,6 +2361,7 @@ class LibBytes(Lib):
2337
2361
  size, sha256 = await upload.save()
2338
2362
  return size, s_common.ehex(sha256)
2339
2363
 
2364
+ @stormfunc(readonly=True)
2340
2365
  async def _libBytesHas(self, sha256):
2341
2366
  sha256 = await tostr(sha256, noneok=True)
2342
2367
  if sha256 is None:
@@ -2347,6 +2372,7 @@ class LibBytes(Lib):
2347
2372
  ret = await self.dyncall('axon', todo)
2348
2373
  return ret
2349
2374
 
2375
+ @stormfunc(readonly=True)
2350
2376
  async def _libBytesSize(self, sha256):
2351
2377
  sha256 = await tostr(sha256)
2352
2378
  await self.runt.snap.core.getAxon()
@@ -2365,6 +2391,7 @@ class LibBytes(Lib):
2365
2391
 
2366
2392
  return (size, s_common.ehex(sha2))
2367
2393
 
2394
+ @stormfunc(readonly=True)
2368
2395
  async def _libBytesHashset(self, sha256):
2369
2396
  sha256 = await tostr(sha256)
2370
2397
  await self.runt.snap.core.getAxon()
@@ -2394,6 +2421,7 @@ class LibLift(Lib):
2394
2421
  'byNodeData': self._byNodeData,
2395
2422
  }
2396
2423
 
2424
+ @stormfunc(readonly=True)
2397
2425
  async def _byNodeData(self, name):
2398
2426
  async for node in self.runt.snap.nodesByDataName(name):
2399
2427
  yield node
@@ -2610,6 +2638,7 @@ class LibTime(Lib):
2610
2638
  'monthofyear': self.monthofyear,
2611
2639
  }
2612
2640
 
2641
+ @stormfunc(readonly=True)
2613
2642
  async def toUTC(self, tick, timezone):
2614
2643
 
2615
2644
  tick = await toprim(tick)
@@ -2623,69 +2652,81 @@ class LibTime(Lib):
2623
2652
  except s_exc.BadArg as e:
2624
2653
  return (False, s_common.excinfo(e))
2625
2654
 
2655
+ @stormfunc(readonly=True)
2626
2656
  def _now(self):
2627
2657
  return s_common.now()
2628
2658
 
2659
+ @stormfunc(readonly=True)
2629
2660
  async def day(self, tick):
2630
2661
  tick = await toprim(tick)
2631
2662
  timetype = self.runt.snap.core.model.type('time')
2632
2663
  norm, info = timetype.norm(tick)
2633
2664
  return s_time.day(norm)
2634
2665
 
2666
+ @stormfunc(readonly=True)
2635
2667
  async def hour(self, tick):
2636
2668
  tick = await toprim(tick)
2637
2669
  timetype = self.runt.snap.core.model.type('time')
2638
2670
  norm, info = timetype.norm(tick)
2639
2671
  return s_time.hour(norm)
2640
2672
 
2673
+ @stormfunc(readonly=True)
2641
2674
  async def year(self, tick):
2642
2675
  tick = await toprim(tick)
2643
2676
  timetype = self.runt.snap.core.model.type('time')
2644
2677
  norm, info = timetype.norm(tick)
2645
2678
  return s_time.year(norm)
2646
2679
 
2680
+ @stormfunc(readonly=True)
2647
2681
  async def month(self, tick):
2648
2682
  tick = await toprim(tick)
2649
2683
  timetype = self.runt.snap.core.model.type('time')
2650
2684
  norm, info = timetype.norm(tick)
2651
2685
  return s_time.month(norm)
2652
2686
 
2687
+ @stormfunc(readonly=True)
2653
2688
  async def minute(self, tick):
2654
2689
  tick = await toprim(tick)
2655
2690
  timetype = self.runt.snap.core.model.type('time')
2656
2691
  norm, info = timetype.norm(tick)
2657
2692
  return s_time.minute(norm)
2658
2693
 
2694
+ @stormfunc(readonly=True)
2659
2695
  async def second(self, tick):
2660
2696
  tick = await toprim(tick)
2661
2697
  timetype = self.runt.snap.core.model.type('time')
2662
2698
  norm, info = timetype.norm(tick)
2663
2699
  return s_time.second(norm)
2664
2700
 
2701
+ @stormfunc(readonly=True)
2665
2702
  async def dayofweek(self, tick):
2666
2703
  tick = await toprim(tick)
2667
2704
  timetype = self.runt.snap.core.model.type('time')
2668
2705
  norm, info = timetype.norm(tick)
2669
2706
  return s_time.dayofweek(norm)
2670
2707
 
2708
+ @stormfunc(readonly=True)
2671
2709
  async def dayofyear(self, tick):
2672
2710
  tick = await toprim(tick)
2673
2711
  timetype = self.runt.snap.core.model.type('time')
2674
2712
  norm, info = timetype.norm(tick)
2675
2713
  return s_time.dayofyear(norm)
2676
2714
 
2715
+ @stormfunc(readonly=True)
2677
2716
  async def dayofmonth(self, tick):
2678
2717
  tick = await toprim(tick)
2679
2718
  timetype = self.runt.snap.core.model.type('time')
2680
2719
  norm, info = timetype.norm(tick)
2681
2720
  return s_time.dayofmonth(norm)
2682
2721
 
2722
+ @stormfunc(readonly=True)
2683
2723
  async def monthofyear(self, tick):
2684
2724
  tick = await toprim(tick)
2685
2725
  timetype = self.runt.snap.core.model.type('time')
2686
2726
  norm, info = timetype.norm(tick)
2687
2727
  return s_time.month(norm) - 1
2688
2728
 
2729
+ @stormfunc(readonly=True)
2689
2730
  async def _format(self, valu, format):
2690
2731
  timetype = self.runt.snap.core.model.type('time')
2691
2732
  # Give a times string a shot at being normed prior to formatting.
@@ -2709,6 +2750,7 @@ class LibTime(Lib):
2709
2750
  format=format) from None
2710
2751
  return ret
2711
2752
 
2753
+ @stormfunc(readonly=True)
2712
2754
  async def _parse(self, valu, format, errok=False):
2713
2755
  valu = await tostr(valu)
2714
2756
  errok = await tobool(errok)
@@ -2725,6 +2767,7 @@ class LibTime(Lib):
2725
2767
  dt = dt.astimezone(datetime.timezone.utc).replace(tzinfo=None)
2726
2768
  return int((dt - s_time.EPOCH).total_seconds() * 1000)
2727
2769
 
2770
+ @stormfunc(readonly=True)
2728
2771
  async def _sleep(self, valu):
2729
2772
  await self.runt.snap.waitfini(timeout=float(valu))
2730
2773
  await self.runt.snap.clearCache()
@@ -2870,6 +2913,7 @@ class LibRegx(Lib):
2870
2913
  regx = self.compiled[lkey] = regex.compile(pattern, flags=flags)
2871
2914
  return regx
2872
2915
 
2916
+ @stormfunc(readonly=True)
2873
2917
  async def replace(self, pattern, replace, text, flags=0):
2874
2918
  text = await tostr(text)
2875
2919
  flags = await toint(flags)
@@ -2878,6 +2922,7 @@ class LibRegx(Lib):
2878
2922
  regx = await self._getRegx(pattern, flags)
2879
2923
  return regx.sub(replace, text)
2880
2924
 
2925
+ @stormfunc(readonly=True)
2881
2926
  async def matches(self, pattern, text, flags=0):
2882
2927
  text = await tostr(text)
2883
2928
  flags = await toint(flags)
@@ -2885,6 +2930,7 @@ class LibRegx(Lib):
2885
2930
  regx = await self._getRegx(pattern, flags)
2886
2931
  return regx.match(text) is not None
2887
2932
 
2933
+ @stormfunc(readonly=True)
2888
2934
  async def search(self, pattern, text, flags=0):
2889
2935
  text = await tostr(text)
2890
2936
  flags = await toint(flags)
@@ -2897,6 +2943,7 @@ class LibRegx(Lib):
2897
2943
 
2898
2944
  return m.groups()
2899
2945
 
2946
+ @stormfunc(readonly=True)
2900
2947
  async def findall(self, pattern, text, flags=0):
2901
2948
  text = await tostr(text)
2902
2949
  flags = await toint(flags)
@@ -2926,6 +2973,7 @@ class LibCsv(Lib):
2926
2973
  'emit': self._libCsvEmit,
2927
2974
  }
2928
2975
 
2976
+ @stormfunc(readonly=True)
2929
2977
  async def _libCsvEmit(self, *args, table=None):
2930
2978
  row = [await toprim(a) for a in args]
2931
2979
  await self.runt.snap.fire('csv:row', row=row, table=table)
@@ -3052,6 +3100,7 @@ class LibFeed(Lib):
3052
3100
  return
3053
3101
  await self.runt.snap.addFeedData(name, data)
3054
3102
 
3103
+ @stormfunc(readonly=True)
3055
3104
  async def _libList(self):
3056
3105
  todo = ('getFeedFuncs', (), {})
3057
3106
  return await self.runt.dyncall('cortex', todo)
@@ -3106,6 +3155,7 @@ class LibPipe(Lib):
3106
3155
  'gen': self._methPipeGen,
3107
3156
  }
3108
3157
 
3158
+ @stormfunc(readonly=True)
3109
3159
  async def _methPipeGen(self, filler, size=10000):
3110
3160
  size = await toint(size)
3111
3161
  text = await tostr(filler)
@@ -3208,10 +3258,12 @@ class Pipe(StormType):
3208
3258
  'size': self._methPipeSize,
3209
3259
  }
3210
3260
 
3261
+ @stormfunc(readonly=True)
3211
3262
  async def _methPipePuts(self, items):
3212
3263
  items = await toprim(items)
3213
3264
  return await self.queue.puts(items)
3214
3265
 
3266
+ @stormfunc(readonly=True)
3215
3267
  async def _methPipePut(self, item):
3216
3268
  item = await toprim(item)
3217
3269
  return await self.queue.put(item)
@@ -3223,9 +3275,11 @@ class Pipe(StormType):
3223
3275
  '''
3224
3276
  await self.queue.close()
3225
3277
 
3278
+ @stormfunc(readonly=True)
3226
3279
  async def _methPipeSize(self):
3227
3280
  return await self.queue.size()
3228
3281
 
3282
+ @stormfunc(readonly=True)
3229
3283
  async def _methPipeSlice(self, size=1000):
3230
3284
 
3231
3285
  size = await toint(size)
@@ -3239,6 +3293,7 @@ class Pipe(StormType):
3239
3293
 
3240
3294
  return List(items)
3241
3295
 
3296
+ @stormfunc(readonly=True)
3242
3297
  async def _methPipeSlices(self, size=1000):
3243
3298
  size = await toint(size)
3244
3299
  if size < 1 or size > 10000:
@@ -3307,6 +3362,7 @@ class LibQueue(Lib):
3307
3362
 
3308
3363
  return Queue(self.runt, name, info)
3309
3364
 
3365
+ @stormfunc(readonly=True)
3310
3366
  async def _methQueueGet(self, name):
3311
3367
  todo = s_common.todo('getCoreQueue', name)
3312
3368
  gatekeys = ((self.runt.user.iden, ('queue', 'get'), f'queue:{name}'),)
@@ -3325,6 +3381,7 @@ class LibQueue(Lib):
3325
3381
  gatekeys = ((self.runt.user.iden, ('queue', 'del',), f'queue:{name}'), )
3326
3382
  await self.dyncall('cortex', todo, gatekeys=gatekeys)
3327
3383
 
3384
+ @stormfunc(readonly=True)
3328
3385
  async def _methQueueList(self):
3329
3386
  retn = []
3330
3387
 
@@ -3444,6 +3501,7 @@ class Queue(StormType):
3444
3501
  await self.runt.reqGateKeys(gatekeys)
3445
3502
  await self.runt.snap.core.coreQueueCull(self.name, offs)
3446
3503
 
3504
+ @stormfunc(readonly=True)
3447
3505
  async def _methQueueSize(self):
3448
3506
  gatekeys = self._getGateKeys('get')
3449
3507
  await self.runt.reqGateKeys(gatekeys)
@@ -3697,6 +3755,7 @@ class LibBase64(Lib):
3697
3755
  'decode': self._decode
3698
3756
  }
3699
3757
 
3758
+ @stormfunc(readonly=True)
3700
3759
  async def _encode(self, valu, urlsafe=True):
3701
3760
  try:
3702
3761
  if urlsafe:
@@ -3706,6 +3765,7 @@ class LibBase64(Lib):
3706
3765
  mesg = f'Error during base64 encoding - {str(e)}: {repr(valu)[:256]}'
3707
3766
  raise s_exc.StormRuntimeError(mesg=mesg, urlsafe=urlsafe) from None
3708
3767
 
3768
+ @stormfunc(readonly=True)
3709
3769
  async def _decode(self, valu, urlsafe=True):
3710
3770
  try:
3711
3771
  if urlsafe:
@@ -4208,7 +4268,7 @@ class Bytes(Prim):
4208
4268
 
4209
4269
  $subbyts = $byts.slice(3)
4210
4270
  ''',
4211
- 'type': {'type': 'function', '_funcname': 'slice',
4271
+ 'type': {'type': 'function', '_funcname': '_methSlice',
4212
4272
  'args': (
4213
4273
  {'name': 'start', 'type': 'int', 'desc': 'The starting byte index.'},
4214
4274
  {'name': 'end', 'type': 'int', 'default': None,
@@ -4224,7 +4284,7 @@ class Bytes(Prim):
4224
4284
 
4225
4285
  ($x, $y, $z) = $byts.unpack("<HHH")
4226
4286
  ''',
4227
- 'type': {'type': 'function', '_funcname': 'unpack',
4287
+ 'type': {'type': 'function', '_funcname': '_methUnpack',
4228
4288
  'args': (
4229
4289
  {'name': 'fmt', 'type': 'str', 'desc': 'A python struck.pack format string.'},
4230
4290
  {'name': 'offset', 'type': 'int', 'desc': 'An offset to begin unpacking from.', 'default': 0},
@@ -4246,8 +4306,8 @@ class Bytes(Prim):
4246
4306
  'bzip': self._methBzip,
4247
4307
  'gzip': self._methGzip,
4248
4308
  'json': self._methJsonLoad,
4249
- 'slice': self.slice,
4250
- 'unpack': self.unpack,
4309
+ 'slice': self._methSlice,
4310
+ 'unpack': self._methUnpack,
4251
4311
  }
4252
4312
 
4253
4313
  def __len__(self):
@@ -4268,7 +4328,8 @@ class Bytes(Prim):
4268
4328
  item = await s_coro.ornot(self.value)
4269
4329
  return s_msgpack.deepcopy(item, use_list=True)
4270
4330
 
4271
- async def slice(self, start, end=None):
4331
+ @stormfunc(readonly=True)
4332
+ async def _methSlice(self, start, end=None):
4272
4333
  start = await toint(start)
4273
4334
  if end is None:
4274
4335
  return self.valu[start:]
@@ -4276,7 +4337,8 @@ class Bytes(Prim):
4276
4337
  end = await toint(end)
4277
4338
  return self.valu[start:end]
4278
4339
 
4279
- async def unpack(self, fmt, offset=0):
4340
+ @stormfunc(readonly=True)
4341
+ async def _methUnpack(self, fmt, offset=0):
4280
4342
  fmt = await tostr(fmt)
4281
4343
  offset = await toint(offset)
4282
4344
  try:
@@ -4284,6 +4346,7 @@ class Bytes(Prim):
4284
4346
  except struct.error as e:
4285
4347
  raise s_exc.BadArg(mesg=f'unpack() error: {e}')
4286
4348
 
4349
+ @stormfunc(readonly=True)
4287
4350
  async def _methDecode(self, encoding='utf8', errors='surrogatepass'):
4288
4351
  encoding = await tostr(encoding)
4289
4352
  errors = await tostr(errors)
@@ -4295,15 +4358,18 @@ class Bytes(Prim):
4295
4358
  async def _methBunzip(self):
4296
4359
  return bz2.decompress(self.valu)
4297
4360
 
4361
+ @stormfunc(readonly=True)
4298
4362
  async def _methBzip(self):
4299
4363
  return bz2.compress(self.valu)
4300
4364
 
4301
4365
  async def _methGunzip(self):
4302
4366
  return gzip.decompress(self.valu)
4303
4367
 
4368
+ @stormfunc(readonly=True)
4304
4369
  async def _methGzip(self):
4305
4370
  return gzip.compress(self.valu)
4306
4371
 
4372
+ @stormfunc(readonly=True)
4307
4373
  async def _methJsonLoad(self, encoding=None, errors='surrogatepass'):
4308
4374
  try:
4309
4375
  valu = self.valu
@@ -4489,9 +4555,11 @@ class Set(Prim):
4489
4555
  async def _methSetSize(self):
4490
4556
  return len(self)
4491
4557
 
4558
+ @stormfunc(readonly=True)
4492
4559
  async def _methSetHas(self, item):
4493
4560
  return item in self.valu
4494
4561
 
4562
+ @stormfunc(readonly=True)
4495
4563
  async def _methSetAdd(self, *items):
4496
4564
  for i in items:
4497
4565
  if ismutable(i):
@@ -4499,6 +4567,7 @@ class Set(Prim):
4499
4567
  raise s_exc.StormRuntimeError(mesg=mesg)
4500
4568
  self.valu.add(i)
4501
4569
 
4570
+ @stormfunc(readonly=True)
4502
4571
  async def _methSetAdds(self, *items):
4503
4572
  for item in items:
4504
4573
  async for i in toiter(item):
@@ -4507,13 +4576,16 @@ class Set(Prim):
4507
4576
  raise s_exc.StormRuntimeError(mesg=mesg)
4508
4577
  self.valu.add(i)
4509
4578
 
4579
+ @stormfunc(readonly=True)
4510
4580
  async def _methSetRem(self, *items):
4511
4581
  [self.valu.discard(i) for i in items]
4512
4582
 
4583
+ @stormfunc(readonly=True)
4513
4584
  async def _methSetRems(self, *items):
4514
4585
  for item in items:
4515
4586
  [self.valu.discard(i) async for i in toiter(item)]
4516
4587
 
4588
+ @stormfunc(readonly=True)
4517
4589
  async def _methSetList(self):
4518
4590
  return list(self.valu)
4519
4591
 
@@ -4607,6 +4679,9 @@ class List(Prim):
4607
4679
  {'name': 'valu', 'type': 'list', 'desc': 'A list or other iterable.'},
4608
4680
  ),
4609
4681
  'returns': {'type': 'null'}}},
4682
+ {'name': 'unique', 'desc': 'Get a copy of the list containing unique items.',
4683
+ 'type': {'type': 'function', '_funcname': '_methListUnique',
4684
+ 'returns': {'type': 'list'}}},
4610
4685
  )
4611
4686
  _storm_typename = 'list'
4612
4687
  _ismutable = True
@@ -4627,6 +4702,7 @@ class List(Prim):
4627
4702
  'reverse': self._methListReverse,
4628
4703
  'slice': self._methListSlice,
4629
4704
  'extend': self._methListExtend,
4705
+ 'unique': self._methListUnique,
4630
4706
  }
4631
4707
 
4632
4708
  @stormfunc(readonly=True)
@@ -4653,6 +4729,7 @@ class List(Prim):
4653
4729
  def __len__(self):
4654
4730
  return len(self.valu)
4655
4731
 
4732
+ @stormfunc(readonly=True)
4656
4733
  async def _methListHas(self, valu):
4657
4734
  if valu in self.valu:
4658
4735
  return True
@@ -4663,6 +4740,7 @@ class List(Prim):
4663
4740
 
4664
4741
  return prim in self.valu
4665
4742
 
4743
+ @stormfunc(readonly=True)
4666
4744
  async def _methListPop(self):
4667
4745
  try:
4668
4746
  return self.valu.pop()
@@ -4670,11 +4748,13 @@ class List(Prim):
4670
4748
  mesg = 'The list is empty. Nothing to pop.'
4671
4749
  raise s_exc.StormRuntimeError(mesg=mesg)
4672
4750
 
4751
+ @stormfunc(readonly=True)
4673
4752
  async def _methListAppend(self, valu):
4674
4753
  '''
4675
4754
  '''
4676
4755
  self.valu.append(valu)
4677
4756
 
4757
+ @stormfunc(readonly=True)
4678
4758
  async def _methListIndex(self, valu):
4679
4759
  indx = await toint(valu)
4680
4760
  try:
@@ -4683,9 +4763,11 @@ class List(Prim):
4683
4763
  raise s_exc.StormRuntimeError(mesg=str(e), valurepr=await self.stormrepr(),
4684
4764
  len=len(self.valu), indx=indx) from None
4685
4765
 
4766
+ @stormfunc(readonly=True)
4686
4767
  async def _methListReverse(self):
4687
4768
  self.valu.reverse()
4688
4769
 
4770
+ @stormfunc(readonly=True)
4689
4771
  async def _methListLength(self):
4690
4772
  s_common.deprecated('StormType List.length()')
4691
4773
  runt = s_scope.get('runt')
@@ -4693,6 +4775,7 @@ class List(Prim):
4693
4775
  await runt.snap.warnonce('StormType List.length() is deprecated. Use the size() method.')
4694
4776
  return len(self)
4695
4777
 
4778
+ @stormfunc(readonly=True)
4696
4779
  async def _methListSort(self, reverse=False):
4697
4780
  reverse = await tobool(reverse, noneok=True)
4698
4781
  try:
@@ -4701,6 +4784,7 @@ class List(Prim):
4701
4784
  raise s_exc.StormRuntimeError(mesg=f'Error sorting list: {str(e)}',
4702
4785
  valurepr=await self.stormrepr()) from None
4703
4786
 
4787
+ @stormfunc(readonly=True)
4704
4788
  async def _methListSize(self):
4705
4789
  return len(self)
4706
4790
 
@@ -4713,6 +4797,7 @@ class List(Prim):
4713
4797
  end = await toint(end)
4714
4798
  return self.valu[start:end]
4715
4799
 
4800
+ @stormfunc(readonly=True)
4716
4801
  async def _methListExtend(self, valu):
4717
4802
  async for item in toiter(valu):
4718
4803
  self.valu.append(item)
@@ -4724,6 +4809,22 @@ class List(Prim):
4724
4809
  for item in self.valu:
4725
4810
  yield item
4726
4811
 
4812
+ @stormfunc(readonly=True)
4813
+ async def _methListUnique(self):
4814
+ ret = []
4815
+ checkret = []
4816
+
4817
+ for val in self.valu:
4818
+ try:
4819
+ _cval = await toprim(val)
4820
+ except s_exc.NoSuchType:
4821
+ _cval = val
4822
+ if _cval in checkret:
4823
+ continue
4824
+ checkret.append(_cval)
4825
+ ret.append(val)
4826
+ return ret
4827
+
4727
4828
  async def stormrepr(self):
4728
4829
  reprs = [await torepr(k) for k in self.valu]
4729
4830
  rval = ', '.join(reprs)
@@ -4812,10 +4913,12 @@ class Number(Prim):
4812
4913
  'scaleb': self._methScaleb,
4813
4914
  }
4814
4915
 
4916
+ @stormfunc(readonly=True)
4815
4917
  async def _methScaleb(self, other):
4816
4918
  newv = s_common.hugescaleb(self.value(), await toint(other))
4817
4919
  return Number(newv)
4818
4920
 
4921
+ @stormfunc(readonly=True)
4819
4922
  async def _methToInt(self, rounding=None):
4820
4923
  if rounding is None:
4821
4924
  return int(self.valu)
@@ -4826,9 +4929,11 @@ class Number(Prim):
4826
4929
  raise s_exc.StormRuntimeError(mesg=f'Error rounding number: {str(e)}',
4827
4930
  valurepr=await self.stormrepr()) from None
4828
4931
 
4932
+ @stormfunc(readonly=True)
4829
4933
  async def _methToStr(self):
4830
4934
  return str(self.valu)
4831
4935
 
4936
+ @stormfunc(readonly=True)
4832
4937
  async def _methToFloat(self):
4833
4938
  return float(self.valu)
4834
4939
 
@@ -5002,9 +5107,11 @@ class LibUser(Lib):
5002
5107
  'profile': StormHiveDict(self.runt, self.runt.user.profile),
5003
5108
  })
5004
5109
 
5110
+ @stormfunc(readonly=True)
5005
5111
  async def _libUserName(self):
5006
5112
  return self.runt.user.name
5007
5113
 
5114
+ @stormfunc(readonly=True)
5008
5115
  async def _libUserAllowed(self, permname, gateiden=None, default=False):
5009
5116
  permname = await toprim(permname)
5010
5117
  gateiden = await tostr(gateiden, noneok=True)
@@ -5084,6 +5191,7 @@ class LibGlobals(Lib):
5084
5191
  mesg = 'The name of a persistent variable must be a string.'
5085
5192
  raise s_exc.StormRuntimeError(mesg=mesg, name=name)
5086
5193
 
5194
+ @stormfunc(readonly=True)
5087
5195
  async def _methGet(self, name, default=None):
5088
5196
  self._reqStr(name)
5089
5197
 
@@ -5107,6 +5215,7 @@ class LibGlobals(Lib):
5107
5215
  todo = s_common.todo('setStormVar', name, valu)
5108
5216
  return await self.runt.dyncall('cortex', todo, gatekeys=gatekeys)
5109
5217
 
5218
+ @stormfunc(readonly=True)
5110
5219
  async def _methList(self):
5111
5220
  ret = []
5112
5221
 
@@ -5168,6 +5277,7 @@ class StormHiveDict(Prim):
5168
5277
  'list': self._list,
5169
5278
  }
5170
5279
 
5280
+ @stormfunc(readonly=True)
5171
5281
  async def _get(self, name, default=None):
5172
5282
  return self.info.get(name, default)
5173
5283
 
@@ -5183,6 +5293,7 @@ class StormHiveDict(Prim):
5183
5293
 
5184
5294
  return await self.info.set(name, valu)
5185
5295
 
5296
+ @stormfunc(readonly=True)
5186
5297
  def _list(self):
5187
5298
  return list(self.info.items())
5188
5299
 
@@ -5242,18 +5353,23 @@ class LibVars(Lib):
5242
5353
  'type': self._libVarsType,
5243
5354
  }
5244
5355
 
5356
+ @stormfunc(readonly=True)
5245
5357
  async def _libVarsGet(self, name, defv=None):
5246
5358
  return self.runt.getVar(name, defv=defv)
5247
5359
 
5360
+ @stormfunc(readonly=True)
5248
5361
  async def _libVarsSet(self, name, valu):
5249
5362
  await self.runt.setVar(name, valu)
5250
5363
 
5364
+ @stormfunc(readonly=True)
5251
5365
  async def _libVarsDel(self, name):
5252
5366
  await self.runt.popVar(name)
5253
5367
 
5368
+ @stormfunc(readonly=True)
5254
5369
  async def _libVarsList(self):
5255
5370
  return list(self.runt.vars.items())
5256
5371
 
5372
+ @stormfunc(readonly=True)
5257
5373
  async def _libVarsType(self, valu):
5258
5374
  return await totype(valu)
5259
5375
 
@@ -5320,6 +5436,7 @@ class Query(Prim):
5320
5436
  async for node, path in self._getRuntGenr():
5321
5437
  yield Node(node)
5322
5438
 
5439
+ @stormfunc(readonly=True)
5323
5440
  async def _methQueryExec(self):
5324
5441
  logger.info(f'Executing storm query via exec() {{{self.text}}} as [{self.runt.user.name}]')
5325
5442
  try:
@@ -5330,6 +5447,7 @@ class Query(Prim):
5330
5447
  except asyncio.CancelledError: # pragma: no cover
5331
5448
  raise
5332
5449
 
5450
+ @stormfunc(readonly=True)
5333
5451
  async def _methQuerySize(self, limit=1000):
5334
5452
  limit = await toint(limit)
5335
5453
 
@@ -5678,11 +5796,11 @@ class Node(Prim):
5678
5796
  'type': {'type': 'function', '_funcname': '_methNodeValue',
5679
5797
  'returns': {'type': 'prim', 'desc': 'The primary property.', }}},
5680
5798
  {'name': 'getByLayer', 'desc': 'Return a dict you can use to lookup which props/tags came from which layers.',
5681
- 'type': {'type': 'function', '_funcname': 'getByLayer',
5799
+ 'type': {'type': 'function', '_funcname': '_methGetByLayer',
5682
5800
  'returns': {'type': 'dict', 'desc': 'property / tag lookup dictionary.', }}},
5683
5801
  {'name': 'getStorNodes',
5684
5802
  'desc': 'Return a list of "storage nodes" which were fused from the layers to make this node.',
5685
- 'type': {'type': 'function', '_funcname': 'getStorNodes',
5803
+ 'type': {'type': 'function', '_funcname': '_methGetStorNodes',
5686
5804
  'returns': {'type': 'list', 'desc': 'List of storage node objects.', }}},
5687
5805
  )
5688
5806
  _storm_typename = 'node'
@@ -5714,14 +5832,16 @@ class Node(Prim):
5714
5832
  'globtags': self._methNodeGlobTags,
5715
5833
  'difftags': self._methNodeDiffTags,
5716
5834
  'isform': self._methNodeIsForm,
5717
- 'getByLayer': self.getByLayer,
5718
- 'getStorNodes': self.getStorNodes,
5835
+ 'getByLayer': self._methGetByLayer,
5836
+ 'getStorNodes': self._methGetStorNodes,
5719
5837
  }
5720
5838
 
5721
- async def getStorNodes(self):
5839
+ @stormfunc(readonly=True)
5840
+ async def _methGetStorNodes(self):
5722
5841
  return await self.valu.getStorNodes()
5723
5842
 
5724
- def getByLayer(self):
5843
+ @stormfunc(readonly=True)
5844
+ def _methGetByLayer(self):
5725
5845
  return self.valu.getByLayer()
5726
5846
 
5727
5847
  def _ctorNodeData(self, path=None):
@@ -5966,9 +6086,11 @@ class Path(Prim):
5966
6086
  'listvars': self._methPathListVars,
5967
6087
  }
5968
6088
 
6089
+ @stormfunc(readonly=True)
5969
6090
  async def _methPathIdens(self):
5970
6091
  return [n.iden() for n in self.valu.nodes]
5971
6092
 
6093
+ @stormfunc(readonly=True)
5972
6094
  async def _methPathListVars(self):
5973
6095
  return list(self.path.vars.items())
5974
6096
 
@@ -6005,10 +6127,12 @@ class Text(Prim):
6005
6127
  def __len__(self):
6006
6128
  return len(self.valu)
6007
6129
 
6130
+ @stormfunc(readonly=True)
6008
6131
  async def _methTextAdd(self, text, **kwargs):
6009
6132
  text = await kwarg_format(text, **kwargs)
6010
6133
  self.valu += text
6011
6134
 
6135
+ @stormfunc(readonly=True)
6012
6136
  async def _methTextStr(self):
6013
6137
  return self.valu
6014
6138
 
@@ -6084,6 +6208,7 @@ class LibLayer(Lib):
6084
6208
  todo = ('delLayer', (layriden,), {})
6085
6209
  return await self.runt.dyncall('cortex', todo, gatekeys=gatekeys)
6086
6210
 
6211
+ @stormfunc(readonly=True)
6087
6212
  async def _libLayerGet(self, iden=None):
6088
6213
 
6089
6214
  iden = await tostr(iden, noneok=True)
@@ -6097,6 +6222,7 @@ class LibLayer(Lib):
6097
6222
 
6098
6223
  return Layer(self.runt, ldef, path=self.path)
6099
6224
 
6225
+ @stormfunc(readonly=True)
6100
6226
  async def _libLayerList(self):
6101
6227
  todo = s_common.todo('getLayerDefs')
6102
6228
  defs = await self.runt.dyncall('cortex', todo)
@@ -6396,6 +6522,7 @@ class Layer(Prim):
6396
6522
  'getMirrorStatus': self.getMirrorStatus,
6397
6523
  }
6398
6524
 
6525
+ @stormfunc(readonly=True)
6399
6526
  async def liftByTag(self, tagname, formname=None):
6400
6527
  tagname = await tostr(tagname)
6401
6528
  formname = await tostr(formname, noneok=True)
@@ -6410,6 +6537,7 @@ class Layer(Prim):
6410
6537
  async for _, buid, sode in layr.liftByTag(tagname, form=formname):
6411
6538
  yield await self.runt.snap._joinStorNode(buid, {iden: sode})
6412
6539
 
6540
+ @stormfunc(readonly=True)
6413
6541
  async def liftByProp(self, propname, propvalu=None, propcmpr='='):
6414
6542
 
6415
6543
  propname = await tostr(propname)
@@ -6446,6 +6574,7 @@ class Layer(Prim):
6446
6574
  async for _, buid, sode in layr.liftByPropValu(liftform, liftprop, cmprvals):
6447
6575
  yield await self.runt.snap._joinStorNode(buid, {iden: sode})
6448
6576
 
6577
+ @stormfunc(readonly=True)
6449
6578
  async def getMirrorStatus(self):
6450
6579
  iden = self.valu.get('iden')
6451
6580
  layr = self.runt.snap.core.getLayer(iden)
@@ -6539,6 +6668,7 @@ class Layer(Prim):
6539
6668
  layr = self.runt.snap.core.getLayer(layriden)
6540
6669
  return await layr.getFormCounts()
6541
6670
 
6671
+ @stormfunc(readonly=True)
6542
6672
  async def _methGetTagCount(self, tagname, formname=None):
6543
6673
  tagname = await tostr(tagname)
6544
6674
  formname = await tostr(formname, noneok=True)
@@ -6547,6 +6677,7 @@ class Layer(Prim):
6547
6677
  layr = self.runt.snap.core.getLayer(layriden)
6548
6678
  return await layr.getTagCount(tagname, formname=formname)
6549
6679
 
6680
+ @stormfunc(readonly=True)
6550
6681
  async def _methGetPropCount(self, propname, maxsize=None):
6551
6682
  propname = await tostr(propname)
6552
6683
  maxsize = await toint(maxsize, noneok=True)
@@ -6568,6 +6699,7 @@ class Layer(Prim):
6568
6699
 
6569
6700
  return await layr.getPropCount(prop.form.name, prop.name, maxsize=maxsize)
6570
6701
 
6702
+ @stormfunc(readonly=True)
6571
6703
  async def _methLayerEdits(self, offs=0, wait=True, size=None):
6572
6704
  offs = await toint(offs)
6573
6705
  wait = await tobool(wait)
@@ -6584,6 +6716,7 @@ class Layer(Prim):
6584
6716
  if size is not None and size == count:
6585
6717
  break
6586
6718
 
6719
+ @stormfunc(readonly=True)
6587
6720
  async def getStorNode(self, nodeid):
6588
6721
  nodeid = await tostr(nodeid)
6589
6722
  layriden = self.valu.get('iden')
@@ -6591,6 +6724,7 @@ class Layer(Prim):
6591
6724
  layr = self.runt.snap.core.getLayer(layriden)
6592
6725
  return await layr.getStorNode(s_common.uhex(nodeid))
6593
6726
 
6727
+ @stormfunc(readonly=True)
6594
6728
  async def getStorNodes(self):
6595
6729
  layriden = self.valu.get('iden')
6596
6730
  await self.runt.reqUserCanReadLayer(layriden)
@@ -6598,6 +6732,7 @@ class Layer(Prim):
6598
6732
  async for item in layr.getStorNodes():
6599
6733
  yield item
6600
6734
 
6735
+ @stormfunc(readonly=True)
6601
6736
  async def getEdges(self):
6602
6737
  layriden = self.valu.get('iden')
6603
6738
  await self.runt.reqUserCanReadLayer(layriden)
@@ -6605,6 +6740,7 @@ class Layer(Prim):
6605
6740
  async for item in layr.getEdges():
6606
6741
  yield item
6607
6742
 
6743
+ @stormfunc(readonly=True)
6608
6744
  async def getEdgesByN1(self, nodeid):
6609
6745
  nodeid = await tostr(nodeid)
6610
6746
  layriden = self.valu.get('iden')
@@ -6613,6 +6749,7 @@ class Layer(Prim):
6613
6749
  async for item in layr.iterNodeEdgesN1(s_common.uhex(nodeid)):
6614
6750
  yield item
6615
6751
 
6752
+ @stormfunc(readonly=True)
6616
6753
  async def getEdgesByN2(self, nodeid):
6617
6754
  nodeid = await tostr(nodeid)
6618
6755
  layriden = self.valu.get('iden')
@@ -6621,6 +6758,7 @@ class Layer(Prim):
6621
6758
  async for item in layr.iterNodeEdgesN2(s_common.uhex(nodeid)):
6622
6759
  yield item
6623
6760
 
6761
+ @stormfunc(readonly=True)
6624
6762
  async def _methLayerGet(self, name, defv=None):
6625
6763
  return self.valu.get(name, defv)
6626
6764
 
@@ -6647,6 +6785,7 @@ class Layer(Prim):
6647
6785
  valu = await self.runt.dyncall(layriden, todo, gatekeys=gatekeys)
6648
6786
  self.valu[name] = valu
6649
6787
 
6788
+ @stormfunc(readonly=True)
6650
6789
  async def _methLayerPack(self):
6651
6790
  ldef = copy.deepcopy(self.valu)
6652
6791
  pushs = ldef.get('pushs')
@@ -6663,6 +6802,7 @@ class Layer(Prim):
6663
6802
 
6664
6803
  return ldef
6665
6804
 
6805
+ @stormfunc(readonly=True)
6666
6806
  async def _methLayerRepr(self):
6667
6807
  iden = self.valu.get('iden')
6668
6808
  name = self.valu.get('name', 'unnamed')
@@ -7257,6 +7397,14 @@ class LibTrigger(Lib):
7257
7397
  if prop is not None:
7258
7398
  tdef['prop'] = prop
7259
7399
 
7400
+ verb = tdef.pop('verb', None)
7401
+ if verb is not None:
7402
+ tdef['verb'] = verb
7403
+
7404
+ n2form = tdef.pop('n2form', None)
7405
+ if n2form is not None:
7406
+ tdef['n2form'] = n2form
7407
+
7260
7408
  gatekeys = ((useriden, ('trigger', 'add'), viewiden),)
7261
7409
  todo = ('addTrigger', (tdef,), {})
7262
7410
  tdef = await self.dyncall(viewiden, todo, gatekeys=gatekeys)
@@ -7285,6 +7433,7 @@ class LibTrigger(Lib):
7285
7433
 
7286
7434
  return iden
7287
7435
 
7436
+ @stormfunc(readonly=True)
7288
7437
  async def _methTriggerList(self, all=False):
7289
7438
  if all:
7290
7439
  views = self.runt.snap.core.listViews()
@@ -7303,6 +7452,7 @@ class LibTrigger(Lib):
7303
7452
 
7304
7453
  return triggers
7305
7454
 
7455
+ @stormfunc(readonly=True)
7306
7456
  async def _methTriggerGet(self, iden):
7307
7457
  trigger = None
7308
7458
  try:
@@ -7385,6 +7535,7 @@ class Trigger(Prim):
7385
7535
  'pack': self.pack,
7386
7536
  }
7387
7537
 
7538
+ @stormfunc(readonly=True)
7388
7539
  async def pack(self):
7389
7540
  return copy.deepcopy(self.valu)
7390
7541
 
@@ -7887,6 +8038,7 @@ class LibJsonStor(Lib):
7887
8038
  'cachedel': self.cachedel,
7888
8039
  })
7889
8040
 
8041
+ @stormfunc(readonly=True)
7890
8042
  async def has(self, path):
7891
8043
 
7892
8044
  if not self.runt.isAdmin():
@@ -7900,6 +8052,7 @@ class LibJsonStor(Lib):
7900
8052
  fullpath = ('cells', self.runt.snap.core.iden) + path
7901
8053
  return await self.runt.snap.core.hasJsonObj(fullpath)
7902
8054
 
8055
+ @stormfunc(readonly=True)
7903
8056
  async def get(self, path, prop=None):
7904
8057
 
7905
8058
  if not self.runt.isAdmin():
@@ -7960,6 +8113,7 @@ class LibJsonStor(Lib):
7960
8113
 
7961
8114
  return await self.runt.snap.core.delJsonObjProp(fullpath, prop=prop)
7962
8115
 
8116
+ @stormfunc(readonly=True)
7963
8117
  async def iter(self, path=None):
7964
8118
 
7965
8119
  if not self.runt.isAdmin():
@@ -7977,6 +8131,7 @@ class LibJsonStor(Lib):
7977
8131
  async for path, item in self.runt.snap.core.getJsonObjs(fullpath):
7978
8132
  yield path, item
7979
8133
 
8134
+ @stormfunc(readonly=True)
7980
8135
  async def cacheget(self, path, key, asof='now', envl=False):
7981
8136
 
7982
8137
  if not self.runt.isAdmin():
@@ -8144,6 +8299,7 @@ class UserJson(Prim):
8144
8299
  'iter': self.iter,
8145
8300
  })
8146
8301
 
8302
+ @stormfunc(readonly=True)
8147
8303
  async def has(self, path):
8148
8304
 
8149
8305
  path = await toprim(path)
@@ -8156,6 +8312,7 @@ class UserJson(Prim):
8156
8312
 
8157
8313
  return await self.runt.snap.core.hasJsonObj(fullpath)
8158
8314
 
8315
+ @stormfunc(readonly=True)
8159
8316
  async def get(self, path, prop=None):
8160
8317
  path = await toprim(path)
8161
8318
  prop = await toprim(prop)
@@ -8210,6 +8367,7 @@ class UserJson(Prim):
8210
8367
 
8211
8368
  return await self.runt.snap.core.delJsonObjProp(fullpath, prop=prop)
8212
8369
 
8370
+ @stormfunc(readonly=True)
8213
8371
  async def iter(self, path=None):
8214
8372
 
8215
8373
  path = await toprim(path)
@@ -8286,7 +8444,7 @@ class User(Prim):
8286
8444
  ),
8287
8445
  'returns': {'type': 'boolean', 'desc': 'True if the rule is allowed, False otherwise.', }}},
8288
8446
  {'name': 'getAllowedReason', 'desc': 'Return an allowed status and reason for the given perm.',
8289
- 'type': {'type': 'function', '_funcname': 'getAllowedReason',
8447
+ 'type': {'type': 'function', '_funcname': '_methGetAllowedReason',
8290
8448
  'args': (
8291
8449
  {'name': 'permname', 'type': 'str', 'desc': 'The permission string to check.', },
8292
8450
  {'name': 'gateiden', 'type': 'str', 'desc': 'The authgate iden.', 'default': None, },
@@ -8365,7 +8523,7 @@ class User(Prim):
8365
8523
  ),
8366
8524
  'returns': {'type': 'null', }}},
8367
8525
  {'name': 'getRules', 'desc': 'Get the rules for the user and optional auth gate.',
8368
- 'type': {'type': 'function', '_funcname': 'getRules',
8526
+ 'type': {'type': 'function', '_funcname': '_methGetRules',
8369
8527
  'args': (
8370
8528
  {'name': 'gateiden', 'type': 'str',
8371
8529
  'desc': 'The gate iden used for the rules.', 'default': None},
@@ -8400,7 +8558,7 @@ class User(Prim):
8400
8558
  ),
8401
8559
  'returns': {'type': 'null', }}},
8402
8560
  {'name': 'gates', 'desc': 'Return a list of auth gates that the user has rules for.',
8403
- 'type': {'type': 'function', '_funcname': 'gates',
8561
+ 'type': {'type': 'function', '_funcname': '_methGates',
8404
8562
  'args': (),
8405
8563
  'returns': {'type': 'list',
8406
8564
  'desc': 'A list of ``auth:gates`` that the user has rules for.', }}},
@@ -8483,7 +8641,7 @@ class User(Prim):
8483
8641
  'get': self._methUserGet,
8484
8642
  'pack': self._methUserPack,
8485
8643
  'tell': self._methUserTell,
8486
- 'gates': self.gates,
8644
+ 'gates': self._methGates,
8487
8645
  'notify': self._methUserNotify,
8488
8646
  'roles': self._methUserRoles,
8489
8647
  'allowed': self._methUserAllowed,
@@ -8493,15 +8651,16 @@ class User(Prim):
8493
8651
  'delRule': self._methUserDelRule,
8494
8652
  'popRule': self._methUserPopRule,
8495
8653
  'setRoles': self._methUserSetRoles,
8496
- 'getRules': self.getRules,
8654
+ 'getRules': self._methGetRules,
8497
8655
  'setRules': self._methUserSetRules,
8498
8656
  'setAdmin': self._methUserSetAdmin,
8499
8657
  'setEmail': self._methUserSetEmail,
8500
8658
  'setLocked': self._methUserSetLocked,
8501
8659
  'setPasswd': self._methUserSetPasswd,
8502
- 'getAllowedReason': self.getAllowedReason,
8660
+ 'getAllowedReason': self._methGetAllowedReason,
8503
8661
  }
8504
8662
 
8663
+ @stormfunc(readonly=True)
8505
8664
  async def _methUserPack(self):
8506
8665
  return await self.value()
8507
8666
 
@@ -8540,7 +8699,8 @@ class User(Prim):
8540
8699
  udef = await self.runt.snap.core.getUserDef(self.valu)
8541
8700
  return udef.get(name)
8542
8701
 
8543
- async def gates(self):
8702
+ @stormfunc(readonly=True)
8703
+ async def _methGates(self):
8544
8704
  user = self.runt.snap.core.auth.user(self.valu)
8545
8705
  retn = []
8546
8706
  for gateiden in user.authgates.keys():
@@ -8548,10 +8708,12 @@ class User(Prim):
8548
8708
  retn.append(Gate(self.runt, gate))
8549
8709
  return retn
8550
8710
 
8711
+ @stormfunc(readonly=True)
8551
8712
  async def _methUserRoles(self):
8552
8713
  udef = await self.runt.snap.core.getUserDef(self.valu)
8553
8714
  return [Role(self.runt, rdef['iden']) for rdef in udef.get('roles')]
8554
8715
 
8716
+ @stormfunc(readonly=True)
8555
8717
  async def _methUserAllowed(self, permname, gateiden=None, default=False):
8556
8718
  permname = await tostr(permname)
8557
8719
  gateiden = await tostr(gateiden)
@@ -8561,7 +8723,8 @@ class User(Prim):
8561
8723
  user = await self.runt.snap.core.auth.reqUser(self.valu)
8562
8724
  return user.allowed(perm, gateiden=gateiden, default=default)
8563
8725
 
8564
- async def getAllowedReason(self, permname, gateiden=None, default=False):
8726
+ @stormfunc(readonly=True)
8727
+ async def _methGetAllowedReason(self, permname, gateiden=None, default=False):
8565
8728
  permname = await tostr(permname)
8566
8729
  gateiden = await tostr(gateiden)
8567
8730
  default = await tobool(default)
@@ -8591,7 +8754,8 @@ class User(Prim):
8591
8754
  self.runt.confirm(('auth', 'user', 'set', 'rules'), gateiden=gateiden)
8592
8755
  await self.runt.snap.core.setUserRules(self.valu, rules, gateiden=gateiden)
8593
8756
 
8594
- async def getRules(self, gateiden=None):
8757
+ @stormfunc(readonly=True)
8758
+ async def _methGetRules(self, gateiden=None):
8595
8759
  gateiden = await tostr(gateiden, noneok=True)
8596
8760
  user = self.runt.snap.core.auth.user(self.valu)
8597
8761
  return user.getRules(gateiden=gateiden)
@@ -8615,7 +8779,7 @@ class User(Prim):
8615
8779
  self.runt.confirm(('auth', 'user', 'set', 'rules'), gateiden=gateiden)
8616
8780
 
8617
8781
  indx = await toint(indx)
8618
- rules = list(await self.getRules(gateiden=gateiden))
8782
+ rules = list(await self._methGetRules(gateiden=gateiden))
8619
8783
 
8620
8784
  if len(rules) <= indx:
8621
8785
  mesg = f'User {self.valu} only has {len(rules)} rules.'
@@ -8678,7 +8842,7 @@ class Role(Prim):
8678
8842
  'type': {'type': 'function', '_funcname': '_methRolePack', 'args': (),
8679
8843
  'returns': {'type': 'dict', 'desc': 'The packed Role definition.', }}},
8680
8844
  {'name': 'gates', 'desc': 'Return a list of auth gates that the role has rules for.',
8681
- 'type': {'type': 'function', '_funcname': 'gates',
8845
+ 'type': {'type': 'function', '_funcname': '_methGates',
8682
8846
  'args': (),
8683
8847
  'returns': {'type': 'list',
8684
8848
  'desc': 'A list of ``auth:gates`` that the role has rules for.', }}},
@@ -8709,7 +8873,7 @@ class Role(Prim):
8709
8873
  ),
8710
8874
  'returns': {'type': 'list', 'desc': 'The rule which was removed.'}}},
8711
8875
  {'name': 'getRules', 'desc': 'Get the rules for the role and optional auth gate.',
8712
- 'type': {'type': 'function', '_funcname': 'getRules',
8876
+ 'type': {'type': 'function', '_funcname': '_methGetRules',
8713
8877
  'args': (
8714
8878
  {'name': 'gateiden', 'type': 'str',
8715
8879
  'desc': 'The gate iden used for the rules.', 'default': None},
@@ -8754,12 +8918,12 @@ class Role(Prim):
8754
8918
  return {
8755
8919
  'get': self._methRoleGet,
8756
8920
  'pack': self._methRolePack,
8757
- 'gates': self.gates,
8921
+ 'gates': self._methGates,
8758
8922
  'addRule': self._methRoleAddRule,
8759
8923
  'delRule': self._methRoleDelRule,
8760
8924
  'popRule': self._methRolePopRule,
8761
8925
  'setRules': self._methRoleSetRules,
8762
- 'getRules': self.getRules,
8926
+ 'getRules': self._methGetRules,
8763
8927
  }
8764
8928
 
8765
8929
  async def _derefGet(self, name):
@@ -8771,14 +8935,17 @@ class Role(Prim):
8771
8935
  name = await tostr(name)
8772
8936
  await self.runt.snap.core.setRoleName(self.valu, name)
8773
8937
 
8938
+ @stormfunc(readonly=True)
8774
8939
  async def _methRoleGet(self, name):
8775
8940
  rdef = await self.runt.snap.core.getRoleDef(self.valu)
8776
8941
  return rdef.get(name)
8777
8942
 
8943
+ @stormfunc(readonly=True)
8778
8944
  async def _methRolePack(self):
8779
8945
  return await self.value()
8780
8946
 
8781
- async def gates(self):
8947
+ @stormfunc(readonly=True)
8948
+ async def _methGates(self):
8782
8949
  role = self.runt.snap.core.auth.role(self.valu)
8783
8950
  retn = []
8784
8951
  for gateiden in role.authgates.keys():
@@ -8786,7 +8953,8 @@ class Role(Prim):
8786
8953
  retn.append(Gate(self.runt, gate))
8787
8954
  return retn
8788
8955
 
8789
- async def getRules(self, gateiden=None):
8956
+ @stormfunc(readonly=True)
8957
+ async def _methGetRules(self, gateiden=None):
8790
8958
  gateiden = await tostr(gateiden, noneok=True)
8791
8959
  role = self.runt.snap.core.auth.role(self.valu)
8792
8960
  return role.getRules(gateiden=gateiden)
@@ -8817,7 +8985,7 @@ class Role(Prim):
8817
8985
 
8818
8986
  indx = await toint(indx)
8819
8987
 
8820
- rules = list(await self.getRules(gateiden=gateiden))
8988
+ rules = list(await self._methGetRules(gateiden=gateiden))
8821
8989
 
8822
8990
  if len(rules) <= indx:
8823
8991
  mesg = f'Role {self.valu} only has {len(rules)} rules.'
@@ -9310,6 +9478,7 @@ class LibCron(Lib):
9310
9478
  self.runt.confirm(('cron', 'set'), gateiden=iden)
9311
9479
  return await self.runt.snap.core.moveCronJob(self.runt.user.iden, iden, view)
9312
9480
 
9481
+ @stormfunc(readonly=True)
9313
9482
  async def _methCronList(self):
9314
9483
  todo = s_common.todo('listCronJobs')
9315
9484
  gatekeys = ((self.runt.user.iden, ('cron', 'get'), None),)
@@ -9317,6 +9486,7 @@ class LibCron(Lib):
9317
9486
 
9318
9487
  return [CronJob(self.runt, cdef, path=self.path) for cdef in defs]
9319
9488
 
9489
+ @stormfunc(readonly=True)
9320
9490
  async def _methCronGet(self, prefix):
9321
9491
  cdef = await self._matchIdens(prefix, ('cron', 'get'))
9322
9492
 
@@ -9404,6 +9574,7 @@ class CronJob(Prim):
9404
9574
 
9405
9575
  return self
9406
9576
 
9577
+ @stormfunc(readonly=True)
9407
9578
  async def _methCronJobPack(self):
9408
9579
  return copy.deepcopy(self.valu)
9409
9580
 
@@ -9411,6 +9582,7 @@ class CronJob(Prim):
9411
9582
  def _formatTimestamp(ts):
9412
9583
  return datetime.datetime.fromtimestamp(ts, datetime.UTC).strftime('%Y-%m-%dT%H:%M')
9413
9584
 
9585
+ @stormfunc(readonly=True)
9414
9586
  async def _methCronJobPprint(self):
9415
9587
  user = self.valu.get('username')
9416
9588
  view = self.valu.get('view')