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/cortex.py CHANGED
@@ -1271,10 +1271,14 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1271
1271
 
1272
1272
  await self._initOAuthManager()
1273
1273
 
1274
+ stormdmonhive = await self.hive.open(('cortex', 'storm', 'dmons'))
1275
+ self.stormdmonhive = await stormdmonhive.dict()
1274
1276
  self.stormdmons = await s_storm.DmonManager.anit(self)
1275
1277
  self.onfini(self.stormdmons)
1278
+
1276
1279
  self.agenda = await s_agenda.Agenda.anit(self)
1277
1280
  self.onfini(self.agenda)
1281
+
1278
1282
  await self._initStormGraphs()
1279
1283
 
1280
1284
  self.trigson = self.conf.get('trigger:enable')
@@ -2233,10 +2237,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
2233
2237
 
2234
2238
  async def _initStormDmons(self):
2235
2239
 
2236
- node = await self.hive.open(('cortex', 'storm', 'dmons'))
2237
-
2238
- self.stormdmonhive = await node.dict()
2239
-
2240
2240
  for iden, ddef in self.stormdmonhive.items():
2241
2241
  try:
2242
2242
  await self.runStormDmon(iden, ddef)
synapse/lib/ast.py CHANGED
@@ -593,10 +593,15 @@ class SubQuery(Oper):
593
593
  async for item in self.kids[0].run(runt, genr):
594
594
  yield item
595
595
 
596
- async def _compute(self, runt, limit):
596
+ async def _compute(self, runt, path, limit):
597
+
597
598
  retn = []
598
599
 
599
- async with runt.getSubRuntime(self.kids[0]) as runt:
600
+ opts = {}
601
+ if path is not None:
602
+ opts['vars'] = path.vars.copy()
603
+
604
+ async with runt.getSubRuntime(self.kids[0], opts=opts) as runt:
600
605
  async for valunode, valupath in runt.execute():
601
606
 
602
607
  retn.append(valunode.ndef[1])
@@ -615,7 +620,7 @@ class SubQuery(Oper):
615
620
  Its value is the primary property of the node yielded, or the returned value.
616
621
  '''
617
622
  try:
618
- retn = await self._compute(runt, 1)
623
+ retn = await self._compute(runt, path, 1)
619
624
 
620
625
  except s_stormctrl.StormReturn as e:
621
626
  # a subquery assignment with a return; just use the returned value
@@ -631,7 +636,7 @@ class SubQuery(Oper):
631
636
  Use subquery as an array.
632
637
  '''
633
638
  try:
634
- return await self._compute(runt, 128)
639
+ return await self._compute(runt, path, 128)
635
640
  except s_stormctrl.StormReturn as e:
636
641
  # a subquery assignment with a return; just use the returned value
637
642
  return e.item
@@ -3105,7 +3110,7 @@ async def expr_prefix(x, y):
3105
3110
  return x.startswith(y)
3106
3111
 
3107
3112
  async def expr_re(x, y):
3108
- if regex.search(await tostr(y), await tostr(x)):
3113
+ if regex.search(await tostr(y), await tostr(x), flags=regex.I):
3109
3114
  return True
3110
3115
  return False
3111
3116
 
synapse/lib/autodoc.py CHANGED
@@ -173,7 +173,7 @@ def getArgLines(rtype):
173
173
  for obj in atyp:
174
174
  assert isinstance(obj, str)
175
175
  tdata = ', '.join([f'``{obj}``' for obj in atyp])
176
- rline = f'The input type may one one of the following: {tdata}.'
176
+ rline = f'The input type may be one of the following: {tdata}.'
177
177
  line = f' {name}: {desc} {rline}'
178
178
  elif isinstance(atyp, dict):
179
179
  logger.warning('Fully declarative input types are not yet supported.')
@@ -287,7 +287,7 @@ def getReturnLines(rtype, known_types=None, types_prefix=None, suffix=None, isst
287
287
  elif isinstance(rtype, dict):
288
288
  returns = rtype.get('returns')
289
289
  assert returns is not None, f'Invalid returns for {rtype}'
290
- name = returns.get('name', 'Returns')
290
+ name = returns.get('name', 'Returns').title()
291
291
 
292
292
  desc = returns.get('desc')
293
293
  rettype = returns.get('type')
synapse/lib/cache.py CHANGED
@@ -179,6 +179,14 @@ def getTagGlobRegx(name):
179
179
  regq = regexizeTagGlob(name)
180
180
  return regex.compile(regq)
181
181
 
182
+ def regexizeEdgeGlob(edge):
183
+ return ReRegex.sub(r'(.+)', regex.escape(edge))
184
+
185
+ @memoize()
186
+ def getEdgeGlobRegx(name):
187
+ regq = regexizeEdgeGlob(name)
188
+ return regex.compile(regq)
189
+
182
190
  class TagGlobs:
183
191
  '''
184
192
  An object that manages multiple tag globs and values for caching.
@@ -191,7 +199,7 @@ class TagGlobs:
191
199
 
192
200
  self.cache.clear()
193
201
 
194
- regx = getTagGlobRegx(name)
202
+ regx = self._getGlobRegex(name)
195
203
 
196
204
  glob = (regx, (name, valu))
197
205
 
@@ -213,5 +221,12 @@ class TagGlobs:
213
221
  def get(self, name):
214
222
  return self.cache.get(name)
215
223
 
224
+ def _getGlobRegex(self, name):
225
+ return getTagGlobRegx(name)
226
+
216
227
  def _getGlobMatches(self, name):
217
228
  return [g[1] for g in self.globs if g[0].fullmatch(name) is not None]
229
+
230
+ class EdgeGlobs(TagGlobs):
231
+ def _getGlobRegex(self, name):
232
+ return getEdgeGlobRegx(name)
synapse/lib/layer.py CHANGED
@@ -125,6 +125,7 @@ class LayerApi(s_cell.CellApi):
125
125
  await self._reqUserAllowed(self.liftperm)
126
126
  async for item in self.layr.iterLayerNodeEdits():
127
127
  yield item
128
+ await asyncio.sleep(0)
128
129
 
129
130
  @s_cell.adminapi()
130
131
  async def saveNodeEdits(self, edits, meta):
@@ -511,7 +512,7 @@ class StorType:
511
512
 
512
513
  async def _liftRegx(self, liftby, valu, reverse=False):
513
514
 
514
- regx = regex.compile(valu)
515
+ regx = regex.compile(valu, flags=regex.I)
515
516
 
516
517
  abrvlen = liftby.abrvlen
517
518
  isarray = isinstance(liftby, IndxByPropArray)
synapse/lib/modelrev.py CHANGED
@@ -8,7 +8,7 @@ import synapse.lib.layer as s_layer
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
 
11
- maxvers = (0, 2, 21)
11
+ maxvers = (0, 2, 22)
12
12
 
13
13
  class ModelRev:
14
14
 
@@ -35,6 +35,7 @@ class ModelRev:
35
35
  ((0, 2, 19), self.revModel_0_2_19),
36
36
  ((0, 2, 20), self.revModel_0_2_20),
37
37
  ((0, 2, 21), self.revModel_0_2_21),
38
+ ((0, 2, 22), self.revModel_0_2_22),
38
39
  )
39
40
 
40
41
  async def _uniqSortArray(self, todoprops, layers):
@@ -725,6 +726,9 @@ class ModelRev:
725
726
  await self._normPropValu(layers, 'risk:vuln:name')
726
727
  await self._propToForm(layers, 'risk:vuln:name', 'risk:vulnname')
727
728
 
729
+ async def revModel_0_2_22(self, layers):
730
+ await self._normFormSubs(layers, 'inet:ipv4', cmprvalu='100.64.0.0/10')
731
+
728
732
  async def runStorm(self, text, opts=None):
729
733
  '''
730
734
  Run storm code in a schedcoro and log the output messages.
@@ -880,7 +884,7 @@ class ModelRev:
880
884
  if nodeedits:
881
885
  await save()
882
886
 
883
- async def _normFormSubs(self, layers, formname, liftprop=None):
887
+ async def _normFormSubs(self, layers, formname, liftprop=None, cmprvalu=s_common.novalu, cmpr='='):
884
888
 
885
889
  # NOTE: this API may be used to re-normalize subs but *not* to change their storage types
886
890
  # and will *not* auto-populate linked forms from subs which are form types.
@@ -898,7 +902,36 @@ class ModelRev:
898
902
  await layr.storNodeEdits(nodeedits, meta)
899
903
  nodeedits.clear()
900
904
 
901
- async for lkey, buid, sode in layr.liftByProp(form.name, liftprop):
905
+ if cmprvalu is s_common.novalu:
906
+ # This is for lifts such as:
907
+ # <formname>
908
+ # <formname>:<liftprop>
909
+ # E.g.:
910
+ # inet:ipv4
911
+ # inet:ipv4:type
912
+ genr = layr.liftByProp(form.name, liftprop)
913
+
914
+ elif liftprop is None:
915
+ # This is for lifts such as:
916
+ # <formname><cmpr><cmprvalu>
917
+ # E.g.:
918
+ # inet:ipv4=1.2.3.4
919
+
920
+ # Don't norm cmprvalu first because it may not be normable
921
+ cmprvals = form.type.getStorCmprs(cmpr, cmprvalu)
922
+ genr = layr.liftByFormValu(form.name, cmprvals)
923
+
924
+ else: # liftprop is not None # pragma: no cover
925
+ # This is for lifts such as:
926
+ # <formname>:<liftprop><cmpr><cmprvalu>
927
+ # E.g.:
928
+ # inet:ipv4:type=private
929
+
930
+ # Don't norm cmprvalu first because it may not be normable
931
+ cmprvals = form.type.getStorCmprs(cmpr, cmprvalu)
932
+ genr = layr.liftByPropValu(form.name, liftprop, cmprvals)
933
+
934
+ async for _, buid, sode in genr:
902
935
 
903
936
  sodevalu = sode.get('valu')
904
937
  if sodevalu is None: # pragma: no cover
synapse/lib/node.py CHANGED
@@ -485,10 +485,6 @@ class Node:
485
485
  raise s_exc.IsRuntForm(mesg='Cannot delete tags from runt nodes.',
486
486
  form=self.form.full, tag=tag)
487
487
 
488
- curv = self.tags.get(name, s_common.novalu)
489
- if curv is s_common.novalu:
490
- return ()
491
-
492
488
  pref = name + '.'
493
489
 
494
490
  todel = [(len(t), t) for t in self.tags.keys() if t.startswith(pref)]
@@ -529,7 +525,8 @@ class Node:
529
525
  edits.append((s_layer.EDIT_TAG_DEL, (subtag, None), ()))
530
526
 
531
527
  edits.extend(self._getTagPropDel(name))
532
- edits.append((s_layer.EDIT_TAG_DEL, (name, None), ()))
528
+ if self.getTag(name, defval=s_common.novalu) is not s_common.novalu:
529
+ edits.append((s_layer.EDIT_TAG_DEL, (name, None), ()))
533
530
 
534
531
  return edits
535
532
 
synapse/lib/snap.py CHANGED
@@ -1147,6 +1147,16 @@ class Snap(s_base.Base):
1147
1147
  node.nodedata.pop(name, None)
1148
1148
  continue
1149
1149
 
1150
+ if etyp == s_layer.EDIT_EDGE_ADD:
1151
+ verb, n2iden = parms
1152
+ n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
1153
+ callbacks.append((self.view.runEdgeAdd, (node, verb, n2), {}))
1154
+
1155
+ if etyp == s_layer.EDIT_EDGE_DEL:
1156
+ verb, n2iden = parms
1157
+ n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
1158
+ callbacks.append((self.view.runEdgeDel, (node, verb, n2), {}))
1159
+
1150
1160
  [await func(*args, **kwargs) for (func, args, kwargs) in callbacks]
1151
1161
 
1152
1162
  if actualedits:
synapse/lib/storm.py CHANGED
@@ -45,6 +45,8 @@ Notes:
45
45
  * node:add
46
46
  * node:del
47
47
  * prop:set
48
+ * edge:add
49
+ * edge:del
48
50
 
49
51
  When condition is tag:add or tag:del, you may optionally provide a form name
50
52
  to restrict the trigger to fire only on tags added or deleted from nodes of
@@ -56,6 +58,10 @@ Simple one level tag globbing is supported, only at the end after a period,
56
58
  that is aka.* matches aka.foo and aka.bar but not aka.foo.bar. aka* is not
57
59
  supported.
58
60
 
61
+ When the condition is edge:add or edge:del, you may optionally provide a
62
+ form name or a destination form name to only fire on edges added or deleted
63
+ from nodes of those forms.
64
+
59
65
  Examples:
60
66
  # Adds a tag to every inet:ipv4 added
61
67
  trigger.add node:add --form inet:ipv4 --query {[ +#mytag ]}
@@ -65,6 +71,13 @@ Examples:
65
71
 
66
72
  # Adds a tag #todo to every inet:ipv4 as it is tagged #aka
67
73
  trigger.add tag:add --form inet:ipv4 --tag aka --query {[ +#todo ]}
74
+
75
+ # Adds a tag #todo to the N1 node of every refs edge add
76
+ trigger.add edge:add --verb refs --query {[ +#todo ]}
77
+
78
+ # Adds a tag #todo to the N1 node of every seen edge delete, provided that
79
+ # both nodes are of form file:bytes
80
+ trigger.add edge:del --verb seen --form file:bytes --n2form file:bytes --query {[ +#todo ]}
68
81
  '''
69
82
 
70
83
  addcrondescr = '''
@@ -307,6 +320,10 @@ reqValidPkgdef = s_config.getJsValidator({
307
320
  'name': {'type': 'string'},
308
321
  'storm': {'type': 'string'},
309
322
  'modconf': {'type': 'object'},
323
+ 'apidefs': {
324
+ 'type': ['array', 'null'],
325
+ 'items': {'$ref': '#/definitions/apidef'},
326
+ },
310
327
  'asroot': {'type': 'boolean'},
311
328
  'asroot:perms': {'type': 'array',
312
329
  'items': {'type': 'array',
@@ -316,6 +333,67 @@ reqValidPkgdef = s_config.getJsValidator({
316
333
  'additionalProperties': True,
317
334
  'required': ['name', 'storm']
318
335
  },
336
+ 'apidef': {
337
+ 'type': 'object',
338
+ 'properties': {
339
+ 'name': {'type': 'string'},
340
+ 'desc': {'type': 'string'},
341
+ 'type': {
342
+ 'type': 'object',
343
+ 'properties': {
344
+ 'type': {
345
+ 'type': 'string',
346
+ 'enum': ['function']
347
+ },
348
+ 'args': {
349
+ 'type': 'array',
350
+ 'items': {'$ref': '#/definitions/apiarg'},
351
+ },
352
+ 'returns': {
353
+ 'type': 'object',
354
+ 'properties': {
355
+ 'name': {
356
+ 'type': 'string',
357
+ 'enum': ['yields'],
358
+ },
359
+ 'desc': {'type': 'string'},
360
+ 'type': {
361
+ 'oneOf': [
362
+ {'$ref': '#/definitions/apitype'},
363
+ {'type': 'array', 'items': {'$ref': '#/definitions/apitype'}},
364
+ ],
365
+ },
366
+ },
367
+ 'additionalProperties': False,
368
+ 'required': ['type', 'desc']
369
+ },
370
+ },
371
+ 'additionalProperties': False,
372
+ 'required': ['type', 'returns'],
373
+ },
374
+ },
375
+ 'additionalProperties': False,
376
+ 'required': ['name', 'desc', 'type']
377
+ },
378
+ 'apiarg': {
379
+ 'type': 'object',
380
+ 'properties': {
381
+ 'name': {'type': 'string'},
382
+ 'desc': {'type': 'string'},
383
+ 'type': {
384
+ 'oneOf': [
385
+ {'$ref': '#/definitions/apitype'},
386
+ {'type': 'array', 'items': {'$ref': '#/definitions/apitype'}},
387
+ ],
388
+ },
389
+ 'default': {'type': ['boolean', 'integer', 'string', 'null']},
390
+ },
391
+ 'additionalProperties': False,
392
+ 'required': ['name', 'desc', 'type']
393
+ },
394
+ 'apitype': {
395
+ 'type': 'string',
396
+ },
319
397
  'command': {
320
398
  'type': 'object',
321
399
  'properties': {
@@ -999,6 +1077,8 @@ stormcmds = (
999
1077
  ('--form', {'help': 'Form to fire on.'}),
1000
1078
  ('--tag', {'help': 'Tag to fire on.'}),
1001
1079
  ('--prop', {'help': 'Property to fire on.'}),
1080
+ ('--verb', {'help': 'Edge verb to fire on.'}),
1081
+ ('--n2form', {'help': 'The form of the n2 node to fire on.'}),
1002
1082
  ('--query', {'help': 'Query for the trigger to execute.', 'required': True,
1003
1083
  'dest': 'storm', }),
1004
1084
  ('--async', {'default': False, 'action': 'store_true',
synapse/lib/stormhttp.py CHANGED
@@ -274,14 +274,17 @@ class LibHttp(s_stormtypes.Lib):
274
274
  return {str(k): str(v) for k, v in item.items()}
275
275
  return item
276
276
 
277
+ @s_stormtypes.stormfunc(readonly=True)
277
278
  async def urlencode(self, text):
278
279
  text = await s_stormtypes.tostr(text)
279
280
  return urllib.parse.quote_plus(text)
280
281
 
282
+ @s_stormtypes.stormfunc(readonly=True)
281
283
  async def urldecode(self, text):
282
284
  text = await s_stormtypes.tostr(text)
283
285
  return urllib.parse.unquote_plus(text)
284
286
 
287
+ @s_stormtypes.stormfunc(readonly=True)
285
288
  async def codereason(self, code):
286
289
  code = await s_stormtypes.toint(code)
287
290
  return s_common.httpcodereason(code)
@@ -50,6 +50,7 @@ class BackupLib(s_stormtypes.Lib):
50
50
  gatekeys = ((self.runt.user.iden, ('backup', 'run'), None),)
51
51
  return await self.dyncall('cortex', todo, gatekeys=gatekeys)
52
52
 
53
+ @s_stormtypes.stormfunc(readonly=True)
53
54
  async def _listBackups(self):
54
55
  todo = s_common.todo('getBackups')
55
56
  gatekeys = ((self.runt.user.iden, ('backup', 'list'), None),)
@@ -35,6 +35,7 @@ class BaseXLib(s_stormtypes.Lib):
35
35
  'decode': self.decode,
36
36
  }
37
37
 
38
+ @s_stormtypes.stormfunc(readonly=True)
38
39
  async def encode(self, byts, charset):
39
40
  if not isinstance(byts, bytes):
40
41
  raise s_exc.BadArg(mesg='$lib.basex.encode() requires a bytes argument.')
@@ -54,6 +55,7 @@ class BaseXLib(s_stormtypes.Lib):
54
55
 
55
56
  return ''.join(retn[::-1])
56
57
 
58
+ @s_stormtypes.stormfunc(readonly=True)
57
59
  async def decode(self, text, charset):
58
60
  text = await s_stormtypes.tostr(text)
59
61
  charset = await s_stormtypes.tostr(charset)
@@ -192,6 +192,7 @@ class CellLib(s_stormtypes.Lib):
192
192
 
193
193
  return curv
194
194
 
195
+ @s_stormtypes.stormfunc(readonly=True)
195
196
  async def _hotFixesCheck(self):
196
197
  if not self.runt.isAdmin():
197
198
  mesg = '$lib.cell.stormFixesCheck() requires admin privs.'
@@ -210,30 +211,35 @@ class CellLib(s_stormtypes.Lib):
210
211
 
211
212
  return dowork
212
213
 
214
+ @s_stormtypes.stormfunc(readonly=True)
213
215
  async def _getCellInfo(self):
214
216
  if not self.runt.isAdmin():
215
217
  mesg = '$lib.cell.getCellInfo() requires admin privs.'
216
218
  raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
217
219
  return await self.runt.snap.core.getCellInfo()
218
220
 
221
+ @s_stormtypes.stormfunc(readonly=True)
219
222
  async def _getSystemInfo(self):
220
223
  if not self.runt.isAdmin():
221
224
  mesg = '$lib.cell.getSystemInfo() requires admin privs.'
222
225
  raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
223
226
  return await self.runt.snap.core.getSystemInfo()
224
227
 
228
+ @s_stormtypes.stormfunc(readonly=True)
225
229
  async def _getBackupInfo(self):
226
230
  if not self.runt.isAdmin():
227
231
  mesg = '$lib.cell.getBackupInfo() requires admin privs.'
228
232
  raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
229
233
  return await self.runt.snap.core.getBackupInfo()
230
234
 
235
+ @s_stormtypes.stormfunc(readonly=True)
231
236
  async def _getHealthCheck(self):
232
237
  if not self.runt.isAdmin():
233
238
  mesg = '$lib.cell.getHealthCheck() requires admin privs.'
234
239
  raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
235
240
  return await self.runt.snap.core.getHealthCheck()
236
241
 
242
+ @s_stormtypes.stormfunc(readonly=True)
237
243
  async def _getMirrorUrls(self, name=None):
238
244
 
239
245
  if not self.runt.isAdmin():
@@ -265,6 +271,7 @@ class CellLib(s_stormtypes.Lib):
265
271
 
266
272
  return await self.runt.snap.core.trimNexsLog(consumers=consumers, timeout=timeout)
267
273
 
274
+ @s_stormtypes.stormfunc(readonly=True)
268
275
  async def _uptime(self, name=None):
269
276
 
270
277
  name = await s_stormtypes.tostr(name, noneok=True)
@@ -47,6 +47,7 @@ class Bzip2Lib(s_stormtypes.Lib):
47
47
  'un': self.un,
48
48
  }
49
49
 
50
+ @s_stormtypes.stormfunc(readonly=True)
50
51
  async def en(self, valu):
51
52
  valu = await s_stormtypes.toprim(valu)
52
53
  try:
@@ -103,6 +104,7 @@ class GzipLib(s_stormtypes.Lib):
103
104
  'un': self.un,
104
105
  }
105
106
 
107
+ @s_stormtypes.stormfunc(readonly=True)
106
108
  async def en(self, valu):
107
109
  valu = await s_stormtypes.toprim(valu)
108
110
  try:
@@ -159,6 +161,7 @@ class ZlibLib(s_stormtypes.Lib):
159
161
  'un': self.un,
160
162
  }
161
163
 
164
+ @s_stormtypes.stormfunc(readonly=True)
162
165
  async def en(self, valu):
163
166
  valu = await s_stormtypes.toprim(valu)
164
167
  try:
@@ -24,6 +24,7 @@ class EthereumLib(s_stormtypes.Lib):
24
24
  'eip55': self.eip55,
25
25
  }
26
26
 
27
+ @s_stormtypes.stormfunc(readonly=True)
27
28
  async def eip55(self, addr):
28
29
  addr = await s_stormtypes.tostr(addr)
29
30
  addr = addr.lower()
@@ -180,6 +180,7 @@ class GraphLib(s_stormtypes.Lib):
180
180
  gdef = await s_stormtypes.toprim(gdef)
181
181
  return await self.runt.snap.core.addStormGraph(gdef, user=self.runt.user)
182
182
 
183
+ @s_stormtypes.stormfunc(readonly=True)
183
184
  async def _methGraphGet(self, iden=None):
184
185
  iden = await s_stormtypes.tostr(iden, noneok=True)
185
186
  if iden is None:
@@ -201,6 +202,7 @@ class GraphLib(s_stormtypes.Lib):
201
202
 
202
203
  await self.runt.snap.core.modStormGraph(iden, info, user=self.runt.user)
203
204
 
205
+ @s_stormtypes.stormfunc(readonly=True)
204
206
  async def _methGraphList(self):
205
207
  projs = []
206
208
  async for proj in self.runt.snap.core.getStormGraphs(user=self.runt.user):
@@ -46,15 +46,19 @@ class LibHashes(s_stormtypes.Lib):
46
46
  'sha512': self._sha512,
47
47
  }
48
48
 
49
+ @s_stormtypes.stormfunc(readonly=True)
49
50
  async def _md5(self, byts):
50
51
  return hashlib.md5(byts, usedforsecurity=False).hexdigest()
51
52
 
53
+ @s_stormtypes.stormfunc(readonly=True)
52
54
  async def _sha1(self, byts):
53
55
  return hashlib.sha1(byts, usedforsecurity=False).hexdigest()
54
56
 
57
+ @s_stormtypes.stormfunc(readonly=True)
55
58
  async def _sha256(self, byts):
56
59
  return hashlib.sha256(byts).hexdigest()
57
60
 
61
+ @s_stormtypes.stormfunc(readonly=True)
58
62
  async def _sha512(self, byts):
59
63
  return hashlib.sha512(byts).hexdigest()
60
64
 
@@ -88,6 +92,7 @@ class LibHmac(s_stormtypes.Lib):
88
92
  'digest': self._digest,
89
93
  }
90
94
 
95
+ @s_stormtypes.stormfunc(readonly=True)
91
96
  async def _digest(self, key, mesg, alg='sha256') -> bytes:
92
97
  key = await s_stormtypes.toprim(key)
93
98
  if not isinstance(key, bytes):
@@ -74,11 +74,13 @@ class HexLib(s_stormtypes.Lib):
74
74
  'signext': self.signext,
75
75
  }
76
76
 
77
+ @s_stormtypes.stormfunc(readonly=True)
77
78
  async def encode(self, valu):
78
79
  if not isinstance(valu, bytes):
79
80
  raise s_exc.BadArg(mesg='$lib.hex.encode() requires a bytes argument.')
80
81
  return s_common.ehex(valu)
81
82
 
83
+ @s_stormtypes.stormfunc(readonly=True)
82
84
  async def decode(self, valu):
83
85
  valu = await s_stormtypes.tostr(valu)
84
86
  try:
@@ -86,6 +88,7 @@ class HexLib(s_stormtypes.Lib):
86
88
  except binascii.Error as e:
87
89
  raise s_exc.BadArg(mesg=f'$lib.hex.decode(): {e}')
88
90
 
91
+ @s_stormtypes.stormfunc(readonly=True)
89
92
  async def toint(self, valu, signed=False):
90
93
  valu = await s_stormtypes.tostr(valu)
91
94
  signed = await s_stormtypes.tobool(signed)
@@ -97,6 +100,7 @@ class HexLib(s_stormtypes.Lib):
97
100
 
98
101
  return int.from_bytes(byts, 'big', signed=signed)
99
102
 
103
+ @s_stormtypes.stormfunc(readonly=True)
100
104
  async def fromint(self, valu, length, signed=False):
101
105
  valu = await s_stormtypes.toint(valu)
102
106
  length = await s_stormtypes.toint(length)
@@ -108,6 +112,7 @@ class HexLib(s_stormtypes.Lib):
108
112
  except OverflowError as e:
109
113
  raise s_exc.BadArg(mesg=f'$lib.hex.fromint(): {e}')
110
114
 
115
+ @s_stormtypes.stormfunc(readonly=True)
111
116
  async def trimext(self, valu):
112
117
  valu = await s_stormtypes.tostr(valu)
113
118
 
@@ -124,6 +129,7 @@ class HexLib(s_stormtypes.Lib):
124
129
  break
125
130
  return valu
126
131
 
132
+ @s_stormtypes.stormfunc(readonly=True)
127
133
  async def signext(self, valu, length):
128
134
  valu = await s_stormtypes.tostr(valu)
129
135
  length = await s_stormtypes.toint(length)
@@ -494,6 +494,7 @@ class MitreAttackFlowLib(s_stormtypes.Lib):
494
494
  'norm': self._norm,
495
495
  }
496
496
 
497
+ @s_stormtypes.stormfunc(readonly=True)
497
498
  async def _norm(self, flow):
498
499
  flow = await s_stormtypes.toprim(flow)
499
500
 
@@ -619,6 +620,7 @@ class CvssLib(s_stormtypes.Lib):
619
620
  'calculateFromProps': self.calculateFromProps,
620
621
  }
621
622
 
623
+ @s_stormtypes.stormfunc(readonly=True)
622
624
  async def vectToProps(self, text):
623
625
  s_common.deprecated('$lib.infosec.cvss.vectToProps()', '2.137.0', '3.0.0')
624
626
  await self.runt.snap.warnonce('$lib.infosec.cvss.vectToProps() is deprecated.')
@@ -690,6 +692,7 @@ class CvssLib(s_stormtypes.Lib):
690
692
 
691
693
  return rval
692
694
 
695
+ @s_stormtypes.stormfunc(readonly=True)
693
696
  async def calculateFromProps(self, props, vers='3.1'):
694
697
 
695
698
  vers = await s_stormtypes.tostr(vers)
@@ -815,6 +818,7 @@ class CvssLib(s_stormtypes.Lib):
815
818
 
816
819
  return rval
817
820
 
821
+ @s_stormtypes.stormfunc(readonly=True)
818
822
  async def vectToScore(self, vect, vers=None):
819
823
  vers = await s_stormtypes.tostr(vers, noneok=True)
820
824
 
@@ -39,6 +39,7 @@ class LibIpv6(s_stormtypes.Lib):
39
39
  'expand': self._expand,
40
40
  }
41
41
 
42
+ @s_stormtypes.stormfunc(readonly=True)
42
43
  async def _expand(self, valu):
43
44
  valu = await s_stormtypes.tostr(valu)
44
45
  valu = valu.strip()
@@ -47,12 +47,14 @@ class LibIters(s_stormtypes.Lib):
47
47
  'zip': self._zip,
48
48
  }
49
49
 
50
+ @s_stormtypes.stormfunc(readonly=True)
50
51
  async def enum(self, genr):
51
52
  indx = 0
52
53
  async for item in s_stormtypes.toiter(genr):
53
54
  yield (indx, item)
54
55
  indx += 1
55
56
 
57
+ @s_stormtypes.stormfunc(readonly=True)
56
58
  async def _zip(self, *args):
57
59
 
58
60
  async with contextlib.AsyncExitStack() as stack: