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.
- synapse/axon.py +19 -16
- synapse/cortex.py +203 -15
- synapse/exc.py +0 -2
- synapse/lib/ast.py +42 -23
- synapse/lib/autodoc.py +2 -2
- synapse/lib/cache.py +16 -1
- synapse/lib/cell.py +5 -5
- synapse/lib/httpapi.py +198 -2
- synapse/lib/layer.py +5 -2
- synapse/lib/modelrev.py +36 -3
- synapse/lib/node.py +2 -5
- synapse/lib/parser.py +1 -1
- synapse/lib/schemas.py +51 -0
- synapse/lib/snap.py +10 -0
- synapse/lib/storm.lark +24 -4
- synapse/lib/storm.py +98 -19
- synapse/lib/storm_format.py +1 -1
- synapse/lib/stormhttp.py +11 -4
- synapse/lib/stormlib/auth.py +16 -2
- synapse/lib/stormlib/backup.py +1 -0
- synapse/lib/stormlib/basex.py +2 -0
- synapse/lib/stormlib/cell.py +7 -0
- synapse/lib/stormlib/compression.py +3 -0
- synapse/lib/stormlib/cortex.py +1168 -0
- synapse/lib/stormlib/ethereum.py +1 -0
- synapse/lib/stormlib/graph.py +2 -0
- synapse/lib/stormlib/hashes.py +5 -0
- synapse/lib/stormlib/hex.py +6 -0
- synapse/lib/stormlib/infosec.py +6 -1
- synapse/lib/stormlib/ipv6.py +1 -0
- synapse/lib/stormlib/iters.py +58 -1
- synapse/lib/stormlib/json.py +5 -0
- synapse/lib/stormlib/mime.py +1 -0
- synapse/lib/stormlib/model.py +19 -3
- synapse/lib/stormlib/modelext.py +1 -0
- synapse/lib/stormlib/notifications.py +2 -0
- synapse/lib/stormlib/pack.py +2 -0
- synapse/lib/stormlib/random.py +1 -0
- synapse/lib/stormlib/smtp.py +0 -7
- synapse/lib/stormlib/stats.py +223 -0
- synapse/lib/stormlib/stix.py +8 -0
- synapse/lib/stormlib/storm.py +1 -0
- synapse/lib/stormlib/version.py +3 -0
- synapse/lib/stormlib/xml.py +3 -0
- synapse/lib/stormlib/yaml.py +2 -0
- synapse/lib/stormtypes.py +250 -170
- synapse/lib/trigger.py +180 -4
- synapse/lib/types.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -6
- synapse/models/inet.py +21 -6
- synapse/models/orgs.py +48 -2
- synapse/models/risk.py +126 -2
- synapse/models/syn.py +6 -0
- synapse/tests/files/stormpkg/badapidef.yaml +13 -0
- synapse/tests/files/stormpkg/storm/modules/apimod +10 -0
- synapse/tests/files/stormpkg/testpkg.yaml +23 -0
- synapse/tests/test_axon.py +7 -2
- synapse/tests/test_cortex.py +231 -35
- synapse/tests/test_lib_ast.py +138 -43
- synapse/tests/test_lib_autodoc.py +1 -1
- synapse/tests/test_lib_modelrev.py +9 -0
- synapse/tests/test_lib_node.py +55 -0
- synapse/tests/test_lib_storm.py +14 -1
- synapse/tests/test_lib_stormhttp.py +65 -6
- synapse/tests/test_lib_stormlib_auth.py +12 -3
- synapse/tests/test_lib_stormlib_cortex.py +1327 -0
- synapse/tests/test_lib_stormlib_iters.py +116 -0
- synapse/tests/test_lib_stormlib_stats.py +187 -0
- synapse/tests/test_lib_stormlib_storm.py +8 -0
- synapse/tests/test_lib_stormsvc.py +24 -1
- synapse/tests/test_lib_stormtypes.py +124 -69
- synapse/tests/test_lib_trigger.py +315 -0
- synapse/tests/test_lib_view.py +1 -2
- synapse/tests/test_model_base.py +26 -0
- synapse/tests/test_model_inet.py +22 -0
- synapse/tests/test_model_orgs.py +28 -0
- synapse/tests/test_model_risk.py +73 -0
- synapse/tests/test_tools_autodoc.py +25 -0
- synapse/tests/test_tools_genpkg.py +9 -3
- synapse/tests/utils.py +39 -0
- synapse/tools/autodoc.py +42 -2
- {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/METADATA +2 -2
- {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/RECORD +87 -79
- {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/WHEEL +1 -1
- {synapse-2.152.0.dist-info → synapse-2.154.0.dist-info}/LICENSE +0 -0
- {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))
|
synapse/lib/stormlib/stix.py
CHANGED
|
@@ -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
|
|
synapse/lib/stormlib/storm.py
CHANGED
synapse/lib/stormlib/version.py
CHANGED
|
@@ -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))
|
synapse/lib/stormlib/xml.py
CHANGED
|
@@ -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:
|
synapse/lib/stormlib/yaml.py
CHANGED
|
@@ -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:
|