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

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

Potentially problematic release.


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

Files changed (87) hide show
  1. synapse/axon.py +19 -16
  2. synapse/cortex.py +203 -15
  3. synapse/exc.py +0 -2
  4. synapse/lib/ast.py +42 -23
  5. synapse/lib/autodoc.py +2 -2
  6. synapse/lib/cache.py +16 -1
  7. synapse/lib/cell.py +5 -5
  8. synapse/lib/httpapi.py +198 -2
  9. synapse/lib/layer.py +5 -2
  10. synapse/lib/modelrev.py +36 -3
  11. synapse/lib/node.py +2 -5
  12. synapse/lib/parser.py +1 -1
  13. synapse/lib/schemas.py +51 -0
  14. synapse/lib/snap.py +10 -0
  15. synapse/lib/storm.lark +24 -4
  16. synapse/lib/storm.py +98 -19
  17. synapse/lib/storm_format.py +1 -1
  18. synapse/lib/stormhttp.py +11 -4
  19. synapse/lib/stormlib/auth.py +16 -2
  20. synapse/lib/stormlib/backup.py +1 -0
  21. synapse/lib/stormlib/basex.py +2 -0
  22. synapse/lib/stormlib/cell.py +7 -0
  23. synapse/lib/stormlib/compression.py +3 -0
  24. synapse/lib/stormlib/cortex.py +1168 -0
  25. synapse/lib/stormlib/ethereum.py +1 -0
  26. synapse/lib/stormlib/graph.py +2 -0
  27. synapse/lib/stormlib/hashes.py +5 -0
  28. synapse/lib/stormlib/hex.py +6 -0
  29. synapse/lib/stormlib/infosec.py +6 -1
  30. synapse/lib/stormlib/ipv6.py +1 -0
  31. synapse/lib/stormlib/iters.py +58 -1
  32. synapse/lib/stormlib/json.py +5 -0
  33. synapse/lib/stormlib/mime.py +1 -0
  34. synapse/lib/stormlib/model.py +19 -3
  35. synapse/lib/stormlib/modelext.py +1 -0
  36. synapse/lib/stormlib/notifications.py +2 -0
  37. synapse/lib/stormlib/pack.py +2 -0
  38. synapse/lib/stormlib/random.py +1 -0
  39. synapse/lib/stormlib/smtp.py +0 -7
  40. synapse/lib/stormlib/stats.py +223 -0
  41. synapse/lib/stormlib/stix.py +8 -0
  42. synapse/lib/stormlib/storm.py +1 -0
  43. synapse/lib/stormlib/version.py +3 -0
  44. synapse/lib/stormlib/xml.py +3 -0
  45. synapse/lib/stormlib/yaml.py +2 -0
  46. synapse/lib/stormtypes.py +250 -170
  47. synapse/lib/trigger.py +180 -4
  48. synapse/lib/types.py +1 -1
  49. synapse/lib/version.py +2 -2
  50. synapse/lib/view.py +55 -6
  51. synapse/models/inet.py +21 -6
  52. synapse/models/orgs.py +48 -2
  53. synapse/models/risk.py +126 -2
  54. synapse/models/syn.py +6 -0
  55. synapse/tests/files/stormpkg/badapidef.yaml +13 -0
  56. synapse/tests/files/stormpkg/storm/modules/apimod +10 -0
  57. synapse/tests/files/stormpkg/testpkg.yaml +23 -0
  58. synapse/tests/test_axon.py +7 -2
  59. synapse/tests/test_cortex.py +231 -35
  60. synapse/tests/test_lib_ast.py +138 -43
  61. synapse/tests/test_lib_autodoc.py +1 -1
  62. synapse/tests/test_lib_modelrev.py +9 -0
  63. synapse/tests/test_lib_node.py +55 -0
  64. synapse/tests/test_lib_storm.py +14 -1
  65. synapse/tests/test_lib_stormhttp.py +65 -6
  66. synapse/tests/test_lib_stormlib_auth.py +12 -3
  67. synapse/tests/test_lib_stormlib_cortex.py +1327 -0
  68. synapse/tests/test_lib_stormlib_iters.py +116 -0
  69. synapse/tests/test_lib_stormlib_stats.py +187 -0
  70. synapse/tests/test_lib_stormlib_storm.py +8 -0
  71. synapse/tests/test_lib_stormsvc.py +24 -1
  72. synapse/tests/test_lib_stormtypes.py +124 -69
  73. synapse/tests/test_lib_trigger.py +315 -0
  74. synapse/tests/test_lib_view.py +1 -2
  75. synapse/tests/test_model_base.py +26 -0
  76. synapse/tests/test_model_inet.py +22 -0
  77. synapse/tests/test_model_orgs.py +28 -0
  78. synapse/tests/test_model_risk.py +73 -0
  79. synapse/tests/test_tools_autodoc.py +25 -0
  80. synapse/tests/test_tools_genpkg.py +9 -3
  81. synapse/tests/utils.py +39 -0
  82. synapse/tools/autodoc.py +42 -2
  83. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/METADATA +2 -2
  84. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/RECORD +87 -79
  85. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/WHEEL +1 -1
  86. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/LICENSE +0 -0
  87. {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,223 @@
1
+ import collections
2
+
3
+ import synapse.exc as s_exc
4
+ import synapse.common as s_common
5
+
6
+ import synapse.lib.storm as s_storm
7
+ import synapse.lib.stormtypes as s_stormtypes
8
+
9
+ class StatsCountByCmd(s_storm.Cmd):
10
+ '''
11
+ Tally occurrences of values and display a bar chart of the results.
12
+
13
+ Examples:
14
+
15
+ // Show counts of geo:name values referenced by media:news nodes.
16
+ media:news -(refs)> geo:name | stats.countby
17
+
18
+ // Show counts of ASN values in a set of IPs.
19
+ inet:ipv4#myips | stats.countby :asn
20
+
21
+ // Show counts of attacker names for risk:compromise nodes.
22
+ risk:compromise | stats.countby :attacker::name
23
+ '''
24
+
25
+ name = 'stats.countby'
26
+ readonly = True
27
+
28
+ def getArgParser(self):
29
+ pars = s_storm.Cmd.getArgParser(self)
30
+ pars.add_argument('valu', nargs='?', default=s_common.novalu,
31
+ help='A relative property or variable to tally.')
32
+ pars.add_argument('--reverse', default=False, action='store_true',
33
+ help='Display results in ascending instead of descending order.')
34
+ pars.add_argument('--size', type='int', default=None,
35
+ help='Maximum number of bars to display.')
36
+ pars.add_argument('--char', type='str', default='#',
37
+ help='Character to use for bars.')
38
+ pars.add_argument('--bar-width', type='int', default=50,
39
+ help='Width of the bars to display.')
40
+ pars.add_argument('--label-max-width', type='int', default=None,
41
+ help='Maximum width of the labels to display.')
42
+ pars.add_argument('--yield', default=False, action='store_true',
43
+ dest='yieldnodes', help='Yield inbound nodes.')
44
+ return pars
45
+
46
+ async def execStormCmd(self, runt, genr):
47
+
48
+ labelwidth = await s_stormtypes.toint(self.opts.label_max_width, noneok=True)
49
+ if labelwidth is not None and labelwidth < 0:
50
+ mesg = f'Value for --label-max-width must be >= 0, got: {labelwidth}'
51
+ raise s_exc.BadArg(mesg=mesg)
52
+
53
+ barwidth = await s_stormtypes.toint(self.opts.bar_width)
54
+ if barwidth < 0:
55
+ mesg = f'Value for --bar-width must be >= 0, got: {barwidth}'
56
+ raise s_exc.BadArg(mesg=mesg)
57
+
58
+ counts = collections.defaultdict(int)
59
+
60
+ usenode = self.opts.valu is s_common.novalu
61
+
62
+ async for node, path in genr:
63
+ if self.opts.yieldnodes:
64
+ yield node, path
65
+
66
+ if usenode:
67
+ valu = node.repr()
68
+ else:
69
+ valu = self.opts.valu
70
+ if s_stormtypes.ismutable(valu):
71
+ raise s_exc.BadArg(mesg='Mutable values cannot be used for counting.')
72
+
73
+ valu = await s_stormtypes.tostr(await s_stormtypes.toprim(valu))
74
+
75
+ counts[valu] += 1
76
+
77
+ if len(counts) == 0:
78
+ await runt.printf('No values to display!')
79
+ return
80
+
81
+ values = list(sorted(counts.items(), key=lambda x: x[1]))
82
+
83
+ maxv = values[-1][1]
84
+ size = await s_stormtypes.toint(self.opts.size, noneok=True)
85
+ char = (await s_stormtypes.tostr(self.opts.char))[0]
86
+ reverse = self.opts.reverse
87
+
88
+ if reverse:
89
+ order = 1
90
+ if size:
91
+ values = values[:size]
92
+ else:
93
+ order = -1
94
+ if size:
95
+ values = values[len(values) - size:]
96
+
97
+ namewidth = 0
98
+ countwidth = 0
99
+ for (name, count) in values:
100
+ if (namelen := len(str(name))) > namewidth:
101
+ namewidth = namelen
102
+
103
+ if (countlen := len(str(count))) > countwidth:
104
+ countwidth = countlen
105
+
106
+ if labelwidth is not None:
107
+ namewidth = min(labelwidth, namewidth)
108
+
109
+ for (name, count) in values[::order]:
110
+
111
+ barsize = int((count / maxv) * barwidth)
112
+ bar = ''.ljust(barsize, char)
113
+ line = f'{name[0:namewidth].rjust(namewidth)} | {count:>{countwidth}} | {bar}'
114
+
115
+ await runt.printf(line)
116
+
117
+ @s_stormtypes.registry.registerLib
118
+ class LibStats(s_stormtypes.Lib):
119
+ '''
120
+ A Storm Library for statistics related functionality.
121
+ '''
122
+ _storm_locals = (
123
+ {'name': 'tally', 'desc': 'Get a Tally object.',
124
+ 'type': {'type': 'function', '_funcname': 'tally',
125
+ 'returns': {'type': 'stat:tally', 'desc': 'A new tally object.', }}},
126
+ )
127
+ _storm_lib_path = ('stats',)
128
+
129
+ def getObjLocals(self):
130
+ return {
131
+ 'tally': self.tally,
132
+ }
133
+
134
+ @s_stormtypes.stormfunc(readonly=True)
135
+ async def tally(self):
136
+ return StatTally(path=self.path)
137
+
138
+ @s_stormtypes.registry.registerType
139
+ class StatTally(s_stormtypes.Prim):
140
+ '''
141
+ A tally object.
142
+
143
+ An example of using it::
144
+
145
+ $tally = $lib.stats.tally()
146
+
147
+ $tally.inc(foo)
148
+
149
+ for $name, $total in $tally {
150
+ $doStuff($name, $total)
151
+ }
152
+
153
+ '''
154
+ _storm_typename = 'stat:tally'
155
+ _storm_locals = (
156
+ {'name': 'inc', 'desc': 'Increment a given counter.',
157
+ 'type': {'type': 'function', '_funcname': 'inc',
158
+ 'args': (
159
+ {'name': 'name', 'desc': 'The name of the counter to increment.', 'type': 'str', },
160
+ {'name': 'valu', 'desc': 'The value to increment the counter by.', 'type': 'int', 'default': 1, },
161
+ ),
162
+ 'returns': {'type': 'null', }}},
163
+ {'name': 'get', 'desc': 'Get the value of a given counter.',
164
+ 'type': {'type': 'function', '_funcname': 'get',
165
+ 'args': (
166
+ {'name': 'name', 'type': 'str', 'desc': 'The name of the counter to get.', },
167
+ ),
168
+ 'returns': {'type': 'int',
169
+ 'desc': 'The value of the counter, or 0 if the counter does not exist.', }}},
170
+ {'name': 'sorted', 'desc': 'Get a list of (counter, value) tuples in sorted order.',
171
+ 'type': {'type': 'function', '_funcname': 'sorted',
172
+ 'args': (
173
+ {'name': 'byname', 'desc': 'Sort by counter name instead of value.',
174
+ 'type': 'bool', 'default': False},
175
+ {'name': 'reverse', 'desc': 'Sort in descending order instead of ascending order.',
176
+ 'type': 'bool', 'default': False},
177
+ ),
178
+ 'returns': {'type': 'list',
179
+ 'desc': 'List of (counter, value) tuples in sorted order.'}}},
180
+ )
181
+ _ismutable = True
182
+
183
+ def __init__(self, path=None):
184
+ s_stormtypes.Prim.__init__(self, {}, path=path)
185
+ self.counters = collections.defaultdict(int)
186
+ self.locls.update(self.getObjLocals())
187
+
188
+ def getObjLocals(self):
189
+ return {
190
+ 'inc': self.inc,
191
+ 'get': self.get,
192
+ 'sorted': self.sorted,
193
+ }
194
+
195
+ async def __aiter__(self):
196
+ for name, valu in self.counters.items():
197
+ yield name, valu
198
+
199
+ def __len__(self):
200
+ return len(self.counters)
201
+
202
+ @s_stormtypes.stormfunc(readonly=True)
203
+ async def inc(self, name, valu=1):
204
+ valu = await s_stormtypes.toint(valu)
205
+ self.counters[name] += valu
206
+
207
+ @s_stormtypes.stormfunc(readonly=True)
208
+ async def get(self, name):
209
+ return self.counters.get(name, 0)
210
+
211
+ def value(self):
212
+ return dict(self.counters)
213
+
214
+ async def iter(self):
215
+ for item in tuple(self.counters.items()):
216
+ yield item
217
+
218
+ @s_stormtypes.stormfunc(readonly=True)
219
+ async def sorted(self, byname=False, reverse=False):
220
+ if byname:
221
+ return list(sorted(self.counters.items(), reverse=reverse))
222
+ else:
223
+ return list(sorted(self.counters.items(), key=lambda x: x[1], reverse=reverse))
@@ -653,10 +653,12 @@ class LibStix(s_stormtypes.Lib):
653
653
  'validate': self.validateBundle,
654
654
  }
655
655
 
656
+ @s_stormtypes.stormfunc(readonly=True)
656
657
  async def validateBundle(self, bundle):
657
658
  bundle = await s_stormtypes.toprim(bundle)
658
659
  return await s_coro.semafork(validateStix, bundle)
659
660
 
661
+ @s_stormtypes.stormfunc(readonly=True)
660
662
  async def liftBundle(self, bundle):
661
663
  bundle = await s_stormtypes.toprim(bundle)
662
664
 
@@ -861,6 +863,7 @@ class LibStixImport(s_stormtypes.Lib):
861
863
  'ingest': self.ingest,
862
864
  }
863
865
 
866
+ @s_stormtypes.stormfunc(readonly=True)
864
867
  async def config(self):
865
868
  return s_msgpack.deepcopy(stixingest, use_list=True)
866
869
 
@@ -1129,10 +1132,12 @@ class LibStixExport(s_stormtypes.Lib):
1129
1132
  'timestamp': self.timestamp,
1130
1133
  }
1131
1134
 
1135
+ @s_stormtypes.stormfunc(readonly=True)
1132
1136
  async def config(self):
1133
1137
  # make a new mutable config
1134
1138
  return json.loads(json.dumps(_DefaultConfig))
1135
1139
 
1140
+ @s_stormtypes.stormfunc(readonly=True)
1136
1141
  async def bundle(self, config=None):
1137
1142
 
1138
1143
  if config is None:
@@ -1265,6 +1270,7 @@ class StixBundle(s_stormtypes.Prim):
1265
1270
  # async def addPropMap(self, formname, stixtype, propname, stormtext):
1266
1271
  # async def addRelsMap(self, formname, stixtype, relname, targtype, stormtext):
1267
1272
 
1273
+ @s_stormtypes.stormfunc(readonly=True)
1268
1274
  async def add(self, node, stixtype=None):
1269
1275
 
1270
1276
  if len(self.objs) >= self.maxsize:
@@ -1380,6 +1386,7 @@ class StixBundle(s_stormtypes.Prim):
1380
1386
  }
1381
1387
  return ret
1382
1388
 
1389
+ @s_stormtypes.stormfunc(readonly=True)
1383
1390
  def pack(self):
1384
1391
  objects = list(self.objs.values())
1385
1392
  if self.synextension:
@@ -1391,6 +1398,7 @@ class StixBundle(s_stormtypes.Prim):
1391
1398
  }
1392
1399
  return bundle
1393
1400
 
1401
+ @s_stormtypes.stormfunc(readonly=True)
1394
1402
  def size(self):
1395
1403
  return len(self.objs)
1396
1404
 
@@ -23,6 +23,7 @@ class LibStorm(s_stormtypes.Lib):
23
23
  'eval': self._evalStorm,
24
24
  }
25
25
 
26
+ @s_stormtypes.stormfunc(readonly=True)
26
27
  async def _evalStorm(self, text, cast=None):
27
28
 
28
29
  text = await s_stormtypes.tostr(text)
@@ -45,12 +45,15 @@ class VersionLib(s_stormtypes.Lib):
45
45
  'synapse': self._getSynVersion,
46
46
  }
47
47
 
48
+ @s_stormtypes.stormfunc(readonly=True)
48
49
  async def _getSynVersion(self):
49
50
  return s_version.version
50
51
 
52
+ @s_stormtypes.stormfunc(readonly=True)
51
53
  async def _getSynCommit(self):
52
54
  return s_version.commit
53
55
 
56
+ @s_stormtypes.stormfunc(readonly=True)
54
57
  async def matches(self, vertup, reqstr):
55
58
  reqstr = await s_stormtypes.tostr(reqstr)
56
59
  vertup = tuple(await s_stormtypes.toprim(vertup))
@@ -49,6 +49,7 @@ class XmlElement(s_stormtypes.Prim):
49
49
  for elem in self.elem:
50
50
  yield XmlElement(self.runt, elem)
51
51
 
52
+ @s_stormtypes.stormfunc(readonly=True)
52
53
  async def find(self, name, nested=True):
53
54
  name = await s_stormtypes.tostr(name)
54
55
  nested = await s_stormtypes.tobool(nested)
@@ -60,6 +61,7 @@ class XmlElement(s_stormtypes.Prim):
60
61
  for elem in self.elem.findall(name):
61
62
  yield XmlElement(self.runt, elem)
62
63
 
64
+ @s_stormtypes.stormfunc(readonly=True)
63
65
  async def get(self, name):
64
66
  name = await s_stormtypes.tostr(name)
65
67
  elem = self.elem.find(name)
@@ -87,6 +89,7 @@ class LibXml(s_stormtypes.Lib):
87
89
  'parse': self.parse,
88
90
  }
89
91
 
92
+ @s_stormtypes.stormfunc(readonly=True)
90
93
  async def parse(self, valu):
91
94
  valu = await s_stormtypes.tostr(valu)
92
95
  try:
@@ -34,11 +34,13 @@ class LibYaml(s_stormtypes.Lib):
34
34
  'load': self.load,
35
35
  }
36
36
 
37
+ @s_stormtypes.stormfunc(readonly=True)
37
38
  async def save(self, valu, sort_keys=True):
38
39
  valu = await s_stormtypes.toprim(valu)
39
40
  sort_keys = await s_stormtypes.tobool(sort_keys)
40
41
  return yaml.dump(valu, sort_keys=sort_keys, Dumper=s_common.Dumper)
41
42
 
43
+ @s_stormtypes.stormfunc(readonly=True)
42
44
  async def load(self, valu):
43
45
  valu = await s_stormtypes.tostr(valu)
44
46
  try: