synapse 2.202.0__py311-none-any.whl → 2.203.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 +4 -4
- synapse/cmds/cortex.py +4 -6
- synapse/cmds/hive.py +10 -10
- synapse/common.py +17 -58
- synapse/cortex.py +6 -6
- synapse/data/__init__.py +3 -2
- synapse/data/iana.uris.mpk +1 -0
- synapse/lib/autodoc.py +3 -3
- synapse/lib/cli.py +2 -2
- synapse/lib/config.py +2 -2
- synapse/lib/encoding.py +4 -3
- synapse/lib/httpapi.py +7 -11
- synapse/lib/json.py +224 -0
- synapse/lib/lmdbslab.py +1 -1
- synapse/lib/oauth.py +176 -54
- synapse/lib/rstorm.py +18 -14
- synapse/lib/schemas.py +87 -1
- synapse/lib/scrape.py +35 -13
- synapse/lib/snap.py +2 -1
- synapse/lib/storm.py +2 -2
- synapse/lib/stormhttp.py +11 -13
- synapse/lib/stormlib/aha.py +4 -4
- synapse/lib/stormlib/auth.py +1 -1
- synapse/lib/stormlib/cache.py +2 -2
- synapse/lib/stormlib/cortex.py +5 -5
- synapse/lib/stormlib/graph.py +1 -1
- synapse/lib/stormlib/imap.py +1 -1
- synapse/lib/stormlib/json.py +8 -11
- synapse/lib/stormlib/model.py +1 -1
- synapse/lib/stormlib/notifications.py +2 -2
- synapse/lib/stormlib/oauth.py +105 -2
- synapse/lib/stormlib/stats.py +4 -0
- synapse/lib/stormlib/stix.py +3 -4
- synapse/lib/stormlib/vault.py +6 -6
- synapse/lib/stormlib/xml.py +2 -2
- synapse/lib/stormtypes.py +19 -28
- synapse/lib/structlog.py +3 -3
- synapse/lib/types.py +2 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +7 -3
- synapse/models/base.py +51 -2
- synapse/telepath.py +5 -3
- synapse/tests/files/__init__.py +0 -1
- synapse/tests/test_axon.py +1 -1
- synapse/tests/test_cmds_cortex.py +3 -2
- synapse/tests/test_cmds_hive.py +4 -4
- synapse/tests/test_common.py +29 -19
- synapse/tests/test_cortex.py +5 -5
- synapse/tests/test_lib_ast.py +3 -3
- synapse/tests/test_lib_autodoc.py +5 -5
- synapse/tests/test_lib_base.py +1 -1
- synapse/tests/test_lib_cell.py +16 -10
- synapse/tests/test_lib_config.py +2 -2
- synapse/tests/test_lib_encoding.py +2 -2
- synapse/tests/test_lib_grammar.py +64 -64
- synapse/tests/test_lib_httpapi.py +13 -13
- synapse/tests/test_lib_json.py +219 -0
- synapse/tests/test_lib_multislabseqn.py +2 -1
- synapse/tests/test_lib_node.py +2 -2
- synapse/tests/test_lib_scrape.py +50 -0
- synapse/tests/test_lib_storm.py +6 -6
- synapse/tests/test_lib_stormhttp.py +4 -4
- synapse/tests/test_lib_stormlib_auth.py +3 -2
- synapse/tests/test_lib_stormlib_cortex.py +10 -12
- synapse/tests/test_lib_stormlib_infosec.py +2 -3
- synapse/tests/test_lib_stormlib_json.py +18 -21
- synapse/tests/test_lib_stormlib_log.py +1 -1
- synapse/tests/test_lib_stormlib_oauth.py +603 -1
- synapse/tests/test_lib_stormlib_stats.py +13 -3
- synapse/tests/test_lib_stormlib_stix.py +5 -5
- synapse/tests/test_lib_stormtypes.py +4 -4
- synapse/tests/test_lib_structlog.py +5 -6
- synapse/tests/test_lib_view.py +8 -0
- synapse/tests/test_model_base.py +32 -0
- synapse/tests/test_model_infotech.py +2 -2
- synapse/tests/test_telepath.py +0 -1
- synapse/tests/test_tools_cryo_cat.py +4 -3
- synapse/tests/test_tools_docker_validate.py +4 -2
- synapse/tests/test_tools_feed.py +30 -2
- synapse/tests/test_tools_genpkg.py +1 -1
- synapse/tests/test_tools_healthcheck.py +8 -7
- synapse/tests/test_utils.py +2 -2
- synapse/tests/utils.py +3 -3
- synapse/tools/autodoc.py +3 -3
- synapse/tools/changelog.py +2 -2
- synapse/tools/cryo/cat.py +3 -3
- synapse/tools/csvtool.py +2 -3
- synapse/tools/docker/validate.py +5 -5
- synapse/tools/feed.py +2 -1
- synapse/tools/genpkg.py +3 -2
- synapse/tools/healthcheck.py +2 -3
- synapse/tools/json2mpk.py +2 -2
- synapse/utils/getrefs.py +6 -6
- synapse/vendor/cpython/lib/json.py +35 -0
- synapse/vendor/cpython/lib/test/test_json.py +22 -0
- {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/METADATA +2 -1
- {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/RECORD +100 -95
- {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/WHEEL +1 -1
- {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/LICENSE +0 -0
- {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/top_level.txt +0 -0
synapse/lib/schemas.py
CHANGED
|
@@ -383,6 +383,7 @@ _changelogTypes = {'migration': 'Automatic Migrations',
|
|
|
383
383
|
'model': 'Model Changes',
|
|
384
384
|
'feat': 'Features and Enhancements',
|
|
385
385
|
'bug': 'Bugfixes',
|
|
386
|
+
'note': 'Notes',
|
|
386
387
|
'doc': 'Improved documentation',
|
|
387
388
|
'deprecation': 'Deprecations'}
|
|
388
389
|
|
|
@@ -407,7 +408,7 @@ _changelogSchema = {
|
|
|
407
408
|
'additionalProperties': False,
|
|
408
409
|
'required': ['type', 'desc']
|
|
409
410
|
}
|
|
410
|
-
|
|
411
|
+
_reqChangelogSchema = s_config.getJsValidator(_changelogSchema)
|
|
411
412
|
|
|
412
413
|
tabularConfSchema = {
|
|
413
414
|
'type': 'object',
|
|
@@ -1042,3 +1043,88 @@ _reqValidDdefSchema = {
|
|
|
1042
1043
|
}
|
|
1043
1044
|
}
|
|
1044
1045
|
reqValidDdef = s_config.getJsValidator(_reqValidDdefSchema)
|
|
1046
|
+
|
|
1047
|
+
_client_assertion_schema = {
|
|
1048
|
+
'type': 'object',
|
|
1049
|
+
'oneOf': [
|
|
1050
|
+
{
|
|
1051
|
+
'required': ['cortex:callstorm'],
|
|
1052
|
+
'properties': {
|
|
1053
|
+
'cortex:callstorm': {
|
|
1054
|
+
'type': 'object',
|
|
1055
|
+
'properties': {
|
|
1056
|
+
'query': {'type': 'string'},
|
|
1057
|
+
'vars': {'type': 'object'},
|
|
1058
|
+
'view': {'type': 'string', 'pattern': s_config.re_iden},
|
|
1059
|
+
},
|
|
1060
|
+
'required': ['query', 'view'],
|
|
1061
|
+
'additionalProperties': False,
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
'additionalProperties': False,
|
|
1065
|
+
'not': {
|
|
1066
|
+
'required': ['msft:azure:workloadidentity'],
|
|
1067
|
+
}
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
'required': ['msft:azure:workloadidentity'],
|
|
1071
|
+
'properties': {
|
|
1072
|
+
'msft:azure:workloadidentity': {
|
|
1073
|
+
'type': 'object',
|
|
1074
|
+
'properties': {
|
|
1075
|
+
'token': {'type': 'boolean'},
|
|
1076
|
+
'client_id': {'type': 'boolean'},
|
|
1077
|
+
},
|
|
1078
|
+
'required': ['token'],
|
|
1079
|
+
'additionalProperties': False,
|
|
1080
|
+
}
|
|
1081
|
+
},
|
|
1082
|
+
'additionalProperties': False,
|
|
1083
|
+
'not': {
|
|
1084
|
+
'required': ['cortex:callstorm'],
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
]
|
|
1088
|
+
}
|
|
1089
|
+
_reqValidOauth2ProviderSchema = {
|
|
1090
|
+
'type': 'object',
|
|
1091
|
+
'properties': {
|
|
1092
|
+
'iden': {'type': 'string', 'pattern': s_config.re_iden},
|
|
1093
|
+
'name': {'type': 'string'},
|
|
1094
|
+
'flow_type': {'type': 'string', 'default': 'authorization_code', 'enum': ['authorization_code']},
|
|
1095
|
+
'auth_scheme': {'type': 'string', 'default': 'basic', 'enum': ['basic', 'client_assertion']},
|
|
1096
|
+
'client_id': {'type': 'string'},
|
|
1097
|
+
'client_secret': {'type': 'string'},
|
|
1098
|
+
'client_assertion': _client_assertion_schema,
|
|
1099
|
+
'scope': {'type': 'string'},
|
|
1100
|
+
'ssl_verify': {'type': 'boolean', 'default': True},
|
|
1101
|
+
'auth_uri': {'type': 'string'},
|
|
1102
|
+
'token_uri': {'type': 'string'},
|
|
1103
|
+
'redirect_uri': {'type': 'string'},
|
|
1104
|
+
'extensions': {
|
|
1105
|
+
'type': 'object',
|
|
1106
|
+
'properties': {
|
|
1107
|
+
'pkce': {'type': 'boolean'},
|
|
1108
|
+
},
|
|
1109
|
+
'additionalProperties': False,
|
|
1110
|
+
},
|
|
1111
|
+
'extra_auth_params': {
|
|
1112
|
+
'type': 'object',
|
|
1113
|
+
'additionalProperties': {'type': 'string'},
|
|
1114
|
+
},
|
|
1115
|
+
},
|
|
1116
|
+
'additionalProperties': False,
|
|
1117
|
+
'required': ['iden', 'name', 'scope', 'auth_uri', 'token_uri', 'redirect_uri'],
|
|
1118
|
+
}
|
|
1119
|
+
reqValidOauth2Provider = s_config.getJsValidator(_reqValidOauth2ProviderSchema)
|
|
1120
|
+
|
|
1121
|
+
_reqValidOauth2TokenResponseSchema = {
|
|
1122
|
+
'type': 'object',
|
|
1123
|
+
'properties': {
|
|
1124
|
+
'access_token': {'type': 'string'},
|
|
1125
|
+
'expires_in': {'type': 'number', 'exclusiveMinimum': 0},
|
|
1126
|
+
},
|
|
1127
|
+
'additionalProperties': True,
|
|
1128
|
+
'required': ['access_token', 'expires_in'],
|
|
1129
|
+
}
|
|
1130
|
+
reqValidOauth2TokenResponse = s_config.getJsValidator(_reqValidOauth2TokenResponseSchema)
|
synapse/lib/scrape.py
CHANGED
|
@@ -24,6 +24,22 @@ ipaddress = s_common.ipaddress
|
|
|
24
24
|
|
|
25
25
|
logger = logging.getLogger(__name__)
|
|
26
26
|
|
|
27
|
+
urilist = set(s_data.get('iana.uris'))
|
|
28
|
+
urilist.update([
|
|
29
|
+
'aha',
|
|
30
|
+
'ftps',
|
|
31
|
+
'mysql',
|
|
32
|
+
'postgresql',
|
|
33
|
+
'slack',
|
|
34
|
+
'socks4',
|
|
35
|
+
'socks4a',
|
|
36
|
+
'socks5',
|
|
37
|
+
'socks5h',
|
|
38
|
+
'tcp',
|
|
39
|
+
'unk',
|
|
40
|
+
'webpack'
|
|
41
|
+
])
|
|
42
|
+
|
|
27
43
|
tldlist = list(s_data.get('iana.tlds'))
|
|
28
44
|
tldlist.extend([
|
|
29
45
|
'bit',
|
|
@@ -53,18 +69,6 @@ inverse_prefixs = {
|
|
|
53
69
|
|
|
54
70
|
cve_dashes = ''.join(('-',) + s_chop.unicode_dashes)
|
|
55
71
|
|
|
56
|
-
def fqdn_prefix_check(match: regex.Match):
|
|
57
|
-
mnfo = match.groupdict()
|
|
58
|
-
valu = mnfo.get('valu')
|
|
59
|
-
prefix = mnfo.get('prefix')
|
|
60
|
-
cbfo = {}
|
|
61
|
-
if prefix is not None:
|
|
62
|
-
new_valu = valu.rstrip(inverse_prefixs.get(prefix))
|
|
63
|
-
if new_valu != valu:
|
|
64
|
-
valu = new_valu
|
|
65
|
-
cbfo['match'] = valu
|
|
66
|
-
return valu, cbfo
|
|
67
|
-
|
|
68
72
|
def fqdn_check(match: regex.Match):
|
|
69
73
|
mnfo = match.groupdict()
|
|
70
74
|
valu = mnfo.get('valu')
|
|
@@ -261,12 +265,30 @@ def unc_path_check(match: regex.Match):
|
|
|
261
265
|
|
|
262
266
|
return valu, {}
|
|
263
267
|
|
|
268
|
+
def url_scheme_check(match: regex.Match):
|
|
269
|
+
mnfo = match.groupdict()
|
|
270
|
+
valu = mnfo.get('valu')
|
|
271
|
+
prefix = mnfo.get('prefix')
|
|
272
|
+
|
|
273
|
+
cbfo = {}
|
|
274
|
+
if prefix is not None:
|
|
275
|
+
new_valu = valu.rstrip(inverse_prefixs.get(prefix))
|
|
276
|
+
if new_valu != valu:
|
|
277
|
+
valu = new_valu
|
|
278
|
+
cbfo['match'] = valu
|
|
279
|
+
|
|
280
|
+
scheme = valu.split('://')[0].lower()
|
|
281
|
+
if scheme not in urilist:
|
|
282
|
+
return None, {}
|
|
283
|
+
|
|
284
|
+
return valu, cbfo
|
|
285
|
+
|
|
264
286
|
# these must be ordered from most specific to least specific to allow first=True to work
|
|
265
287
|
scrape_types = [ # type: ignore
|
|
266
288
|
('file:path', linux_path_regex, {'callback': linux_path_check, 'flags': regex.VERBOSE}),
|
|
267
289
|
('file:path', windows_path_regex, {'callback': windows_path_check, 'flags': regex.VERBOSE}),
|
|
268
290
|
('inet:url', r'(?P<prefix>[\\{<\(\[]?)(?P<valu>[a-zA-Z][a-zA-Z0-9]*://(?(?=[,.]+[ \'\"\t\n\r\f\v])|[^ \'\"\t\n\r\f\v])+)',
|
|
269
|
-
{'callback':
|
|
291
|
+
{'callback': url_scheme_check}),
|
|
270
292
|
('inet:url', r'(["\'])?(?P<valu>\\[^\n]+?)(?(1)\1|\s)', {'callback': unc_path_check}),
|
|
271
293
|
('inet:email', r'(?=(?:[^a-z0-9_.+-]|^)(?P<valu>[a-z0-9_\.\-+]{1,256}@(?:[a-z0-9_-]{1,63}\.){1,10}(?:%s))(?:[^a-z0-9_.-]|[.\s]|$))' % tldcat, {}),
|
|
272
294
|
('inet:server', fr'(?P<valu>(?:(?<!\d|\d\.|[0-9a-f:]:)((?P<addr>{ipv4_match})|\[(?P<v6addr>{ipv6_match})\]):(?P<port>\d{{1,5}})(?!\d|\.\d)))',
|
synapse/lib/snap.py
CHANGED
|
@@ -11,6 +11,7 @@ import synapse.exc as s_exc
|
|
|
11
11
|
import synapse.common as s_common
|
|
12
12
|
|
|
13
13
|
import synapse.lib.base as s_base
|
|
14
|
+
import synapse.lib.json as s_json
|
|
14
15
|
import synapse.lib.node as s_node
|
|
15
16
|
import synapse.lib.time as s_time
|
|
16
17
|
import synapse.lib.cache as s_cache
|
|
@@ -218,7 +219,7 @@ class ProtoNode:
|
|
|
218
219
|
return
|
|
219
220
|
|
|
220
221
|
try:
|
|
221
|
-
|
|
222
|
+
s_json.reqjsonsafe(valu)
|
|
222
223
|
except s_exc.MustBeJsonSafe as e:
|
|
223
224
|
if self.ctx.snap.strict:
|
|
224
225
|
raise e
|
synapse/lib/storm.py
CHANGED
|
@@ -2592,7 +2592,7 @@ class Cmd:
|
|
|
2592
2592
|
|
|
2593
2593
|
async def execStormCmd(self, runt, genr): # pragma: no cover
|
|
2594
2594
|
''' Abstract base method '''
|
|
2595
|
-
raise s_exc.NoSuchImpl('Subclass must implement execStormCmd')
|
|
2595
|
+
raise s_exc.NoSuchImpl(mesg='Subclass must implement execStormCmd')
|
|
2596
2596
|
for item in genr:
|
|
2597
2597
|
yield item
|
|
2598
2598
|
|
|
@@ -4768,7 +4768,7 @@ class GraphCmd(Cmd):
|
|
|
4768
4768
|
inet:fqdn | graph
|
|
4769
4769
|
--degrees 2
|
|
4770
4770
|
--filter { -#nope }
|
|
4771
|
-
--pivot {
|
|
4771
|
+
--pivot { <(seen)- meta:source }
|
|
4772
4772
|
--form-pivot inet:fqdn {<- * | limit 20}
|
|
4773
4773
|
--form-pivot inet:fqdn {-> * | limit 20}
|
|
4774
4774
|
--form-filter inet:fqdn {-inet:fqdn:issuffix=1}
|
synapse/lib/stormhttp.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import asyncio
|
|
3
2
|
import logging
|
|
4
3
|
import urllib.parse
|
|
@@ -12,6 +11,7 @@ import synapse.exc as s_exc
|
|
|
12
11
|
import synapse.common as s_common
|
|
13
12
|
|
|
14
13
|
import synapse.lib.base as s_base
|
|
14
|
+
import synapse.lib.json as s_json
|
|
15
15
|
import synapse.lib.msgpack as s_msgpack
|
|
16
16
|
import synapse.lib.version as s_version
|
|
17
17
|
import synapse.lib.stormtypes as s_stormtypes
|
|
@@ -56,7 +56,7 @@ class WebSocket(s_base.Base, s_stormtypes.StormType):
|
|
|
56
56
|
try:
|
|
57
57
|
|
|
58
58
|
mesg = await s_stormtypes.toprim(mesg)
|
|
59
|
-
await self.resp.send_bytes(
|
|
59
|
+
await self.resp.send_bytes(s_json.dumps(mesg))
|
|
60
60
|
return (True, None)
|
|
61
61
|
|
|
62
62
|
except asyncio.CancelledError: # pragma: no cover
|
|
@@ -69,10 +69,8 @@ class WebSocket(s_base.Base, s_stormtypes.StormType):
|
|
|
69
69
|
|
|
70
70
|
try:
|
|
71
71
|
_type, data, extra = await s_common.wait_for(self.resp.receive(), timeout=timeout)
|
|
72
|
-
if _type
|
|
73
|
-
return (True,
|
|
74
|
-
if _type == aiohttp.WSMsgType.TEXT:
|
|
75
|
-
return (True, json.loads(data.encode()))
|
|
72
|
+
if _type in (aiohttp.WSMsgType.BINARY, aiohttp.WSMsgType.TEXT):
|
|
73
|
+
return (True, s_json.loads(data))
|
|
76
74
|
if _type == aiohttp.WSMsgType.CLOSED: # pragma: no cover
|
|
77
75
|
return (True, None)
|
|
78
76
|
return (False, ('BadMesgFormat', {'mesg': f'WebSocket RX unhandled type: {_type.name}'})) # pragma: no cover
|
|
@@ -100,9 +98,9 @@ class LibHttp(s_stormtypes.Lib):
|
|
|
100
98
|
|
|
101
99
|
For APIs that accept a proxy argument, the following values are supported::
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
(null): Deprecated - Use the proxy defined by the http:proxy configuration option if set.
|
|
102
|
+
(true): Use the proxy defined by the http:proxy configuration option if set.
|
|
103
|
+
(false): Do not use the proxy defined by the http:proxy configuration option if set.
|
|
106
104
|
<str>: A proxy URL string.
|
|
107
105
|
'''
|
|
108
106
|
_storm_locals = (
|
|
@@ -563,17 +561,17 @@ class HttpResp(s_stormtypes.Prim):
|
|
|
563
561
|
errors = await s_stormtypes.tostr(errors)
|
|
564
562
|
|
|
565
563
|
if encoding is None:
|
|
566
|
-
encoding =
|
|
564
|
+
encoding = s_json.detect_encoding(valu)
|
|
567
565
|
else:
|
|
568
566
|
encoding = await s_stormtypes.tostr(encoding)
|
|
569
567
|
|
|
570
|
-
return
|
|
568
|
+
return s_json.loads(valu.decode(encoding, errors))
|
|
571
569
|
|
|
572
570
|
except UnicodeDecodeError as e:
|
|
573
571
|
raise s_exc.StormRuntimeError(mesg=f'{e}: {s_common.trimText(repr(valu))}') from None
|
|
574
572
|
|
|
575
|
-
except
|
|
576
|
-
mesg = f'Unable to decode HTTP response as json: {e.
|
|
573
|
+
except s_exc.BadJsonText as e:
|
|
574
|
+
mesg = f'Unable to decode HTTP response as json: {e.get("mesg")}'
|
|
577
575
|
raise s_exc.BadJsonText(mesg=mesg)
|
|
578
576
|
|
|
579
577
|
async def _httpRespMsgpack(self):
|
synapse/lib/stormlib/aha.py
CHANGED
|
@@ -47,7 +47,7 @@ class AhaLib(s_stormtypes.Lib):
|
|
|
47
47
|
'desc': 'An optional dictionary of filters to use when resolving the AHA service.'}
|
|
48
48
|
),
|
|
49
49
|
'returns': {'type': ('null', 'dict'),
|
|
50
|
-
'desc': 'The AHA service information dictionary, or
|
|
50
|
+
'desc': 'The AHA service information dictionary, or ``(null))``.', }}},
|
|
51
51
|
{'name': 'list', 'desc': 'Enumerate all of the AHA services.',
|
|
52
52
|
'type': {'type': 'function', '_funcname': '_methAhaList', 'args': (),
|
|
53
53
|
'returns': {'name': 'Yields', 'type': 'list',
|
|
@@ -97,14 +97,14 @@ class AhaLib(s_stormtypes.Lib):
|
|
|
97
97
|
Examples:
|
|
98
98
|
Call getNexusChanges on an AHA service::
|
|
99
99
|
|
|
100
|
-
$todo = $lib.utils.todo('getNexusChanges', (0), wait
|
|
100
|
+
$todo = $lib.utils.todo('getNexusChanges', (0), wait=(false))
|
|
101
101
|
for $info in $lib.aha.callPeerGenr(cortex..., $todo) {
|
|
102
102
|
$lib.print($info)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
Call getNexusChanges on an AHA service, skipping the invoking service::
|
|
106
106
|
|
|
107
|
-
$todo = $lib.utils.todo('getNexusChanges', (0), wait
|
|
107
|
+
$todo = $lib.utils.todo('getNexusChanges', (0), wait=(false))
|
|
108
108
|
for $info in $lib.aha.callPeerGenr(cortex..., $todo, skiprun=$lib.cell.getCellInfo().cell.run) {
|
|
109
109
|
$lib.print($info)
|
|
110
110
|
}
|
|
@@ -259,7 +259,7 @@ class AhaPoolLib(s_stormtypes.Lib):
|
|
|
259
259
|
{'name': 'name', 'type': 'str',
|
|
260
260
|
'desc': 'The name of the pool to get. It is easiest to use the relative name of a pool, ending with "...".', },
|
|
261
261
|
),
|
|
262
|
-
'returns': {'type': ['null', 'aha:pool'], 'desc': 'The pool if it exists, or
|
|
262
|
+
'returns': {'type': ['null', 'aha:pool'], 'desc': 'The pool if it exists, or ``(null)``.'}}},
|
|
263
263
|
{'name': 'list', 'desc': 'Enumerate all of the AHA service pools.',
|
|
264
264
|
'type': {'type': 'function', '_funcname': '_methPoolList',
|
|
265
265
|
'returns': {'name': 'yields', 'type': 'aha:pool'}}},
|
synapse/lib/stormlib/auth.py
CHANGED
|
@@ -684,7 +684,7 @@ class UserJson(s_stormtypes.Prim):
|
|
|
684
684
|
{'name': 'path', 'type': 'str|list', 'desc': 'A path string or list of path parts.'},
|
|
685
685
|
{'name': 'prop', 'type': 'str|list', 'desc': 'A property name or list of name parts.', 'default': None},
|
|
686
686
|
),
|
|
687
|
-
'returns': {'type': 'prim', 'desc': 'The previously stored value or
|
|
687
|
+
'returns': {'type': 'prim', 'desc': 'The previously stored value or ``(null)``.'}}},
|
|
688
688
|
|
|
689
689
|
{'name': 'set', 'desc': 'Set a JSON object or object property for the user.',
|
|
690
690
|
'type': {'type': 'function', '_funcname': 'set',
|
synapse/lib/stormlib/cache.py
CHANGED
|
@@ -24,7 +24,7 @@ class LibCache(s_stormtypes.Lib):
|
|
|
24
24
|
to the key argument provided to .get().
|
|
25
25
|
|
|
26
26
|
The callback Storm query must contain a return statement, and if it does not return a value
|
|
27
|
-
when executed with the input,
|
|
27
|
+
when executed with the input, ``(null)`` will be set as the value.
|
|
28
28
|
|
|
29
29
|
The fixed cache uses FIFO to evict items once the maximum size is reached.
|
|
30
30
|
|
|
@@ -114,7 +114,7 @@ class FixedCache(s_stormtypes.StormType):
|
|
|
114
114
|
{'name': 'key', 'type': 'any', 'desc': 'The key to pop.'},
|
|
115
115
|
),
|
|
116
116
|
'returns': {'type': 'any',
|
|
117
|
-
'desc': 'The value from the cache, or
|
|
117
|
+
'desc': 'The value from the cache, or ``(null)`` if it does not exist', }}},
|
|
118
118
|
{'name': 'put', 'desc': 'Put an item into the cache.',
|
|
119
119
|
'type': {'type': 'function', '_funcname': '_methPut',
|
|
120
120
|
'args': (
|
synapse/lib/stormlib/cortex.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
import json
|
|
3
2
|
import logging
|
|
4
3
|
|
|
5
4
|
import synapse.exc as s_exc
|
|
6
5
|
import synapse.telepath as s_telepath
|
|
7
6
|
|
|
7
|
+
import synapse.lib.json as s_json
|
|
8
8
|
import synapse.lib.storm as s_storm
|
|
9
9
|
import synapse.lib.stormtypes as s_stormtypes
|
|
10
10
|
import synapse.lib.stormlib.auth as slib_auth
|
|
@@ -990,8 +990,8 @@ class HttpReq(s_stormtypes.StormType):
|
|
|
990
990
|
@s_stormtypes.stormfunc(readonly=True)
|
|
991
991
|
def _ctorJson(self, path=None):
|
|
992
992
|
try:
|
|
993
|
-
return
|
|
994
|
-
except (UnicodeDecodeError,
|
|
993
|
+
return s_json.loads(self.rnfo.get('body'))
|
|
994
|
+
except (UnicodeDecodeError, s_exc.BadJsonText) as e:
|
|
995
995
|
raise s_exc.StormRuntimeError(mesg=f'Failed to decode request body as JSON: {e}') from None
|
|
996
996
|
|
|
997
997
|
@s_stormtypes.stormfunc(readonly=True)
|
|
@@ -1028,7 +1028,7 @@ class HttpReq(s_stormtypes.StormType):
|
|
|
1028
1028
|
if body is not s_stormtypes.undef:
|
|
1029
1029
|
if not isinstance(body, bytes):
|
|
1030
1030
|
body = await s_stormtypes.toprim(body)
|
|
1031
|
-
body =
|
|
1031
|
+
body = s_json.dumps(body)
|
|
1032
1032
|
headers['Content-Type'] = 'application/json; charset=utf8"'
|
|
1033
1033
|
headers['Content-Length'] = len(body)
|
|
1034
1034
|
|
|
@@ -1126,7 +1126,7 @@ class CortexHttpApi(s_stormtypes.Lib):
|
|
|
1126
1126
|
{'name': 'path', 'type': 'string',
|
|
1127
1127
|
'desc': 'Path to use to retrieve an object.'},
|
|
1128
1128
|
),
|
|
1129
|
-
'returns': {'type': ['http:api', 'null'], 'desc': 'The ``http:api`` object or
|
|
1129
|
+
'returns': {'type': ['http:api', 'null'], 'desc': 'The ``http:api`` object or ``(null)`` if there is no match.'}}},
|
|
1130
1130
|
{'name': 'list', 'desc': 'Get all the Extended HTTP APIs on the Cortex',
|
|
1131
1131
|
'type': {'type': 'function', '_funcname': 'listHttpApis', 'args': (),
|
|
1132
1132
|
'returns': {'type': 'list', 'desc': 'A list of ``http:api`` objects'}}},
|
synapse/lib/stormlib/graph.py
CHANGED
synapse/lib/stormlib/imap.py
CHANGED
|
@@ -193,7 +193,7 @@ class ImapServer(s_stormtypes.StormType):
|
|
|
193
193
|
{'type': 'str', 'name': '*args',
|
|
194
194
|
'desc': 'A set of search criteria to use.'},
|
|
195
195
|
{'type': ['str', 'null'], 'name': 'charset', 'default': 'utf-8',
|
|
196
|
-
'desc': 'The CHARSET used for the search. May be set to
|
|
196
|
+
'desc': 'The CHARSET used for the search. May be set to ``(null)`` to disable CHARSET.'},
|
|
197
197
|
),
|
|
198
198
|
'returns': {
|
|
199
199
|
'type': 'list',
|
synapse/lib/stormlib/json.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import copy
|
|
2
|
-
import json
|
|
3
2
|
import asyncio
|
|
4
3
|
import logging
|
|
5
4
|
|
|
6
5
|
import synapse.exc as s_exc
|
|
7
6
|
|
|
8
7
|
import synapse.lib.coro as s_coro
|
|
8
|
+
import synapse.lib.json as s_json
|
|
9
9
|
import synapse.lib.config as s_config
|
|
10
10
|
import synapse.lib.stormtypes as s_stormtypes
|
|
11
11
|
|
|
@@ -93,7 +93,7 @@ class JsonLib(s_stormtypes.Lib):
|
|
|
93
93
|
'type': {'type': 'function', '_funcname': '_jsonSave',
|
|
94
94
|
'args': (
|
|
95
95
|
{'name': 'item', 'type': 'any', 'desc': 'The item to be serialized as a JSON string.', },
|
|
96
|
-
{'name': 'indent', 'type': '
|
|
96
|
+
{'name': 'indent', 'type': 'boolean', 'desc': 'Indent serialized data with two spaces.', 'default': False},
|
|
97
97
|
),
|
|
98
98
|
'returns': {'type': 'str', 'desc': 'The JSON serialized object.', }}},
|
|
99
99
|
{'name': 'schema', 'desc': 'Get a JS schema validation object.',
|
|
@@ -116,24 +116,21 @@ class JsonLib(s_stormtypes.Lib):
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
@s_stormtypes.stormfunc(readonly=True)
|
|
119
|
-
async def _jsonSave(self, item, indent=
|
|
120
|
-
indent = await s_stormtypes.
|
|
119
|
+
async def _jsonSave(self, item, indent=False):
|
|
120
|
+
indent = await s_stormtypes.tobool(indent)
|
|
121
121
|
|
|
122
122
|
try:
|
|
123
123
|
item = await s_stormtypes.toprim(item)
|
|
124
|
-
|
|
125
|
-
except Exception as e:
|
|
124
|
+
except Exception:
|
|
126
125
|
mesg = f'Argument is not JSON compatible: {item}'
|
|
127
126
|
raise s_exc.MustBeJsonSafe(mesg=mesg)
|
|
128
127
|
|
|
128
|
+
return s_json.dumps(item, indent=indent).decode()
|
|
129
|
+
|
|
129
130
|
@s_stormtypes.stormfunc(readonly=True)
|
|
130
131
|
async def _jsonLoad(self, text):
|
|
131
132
|
text = await s_stormtypes.tostr(text)
|
|
132
|
-
|
|
133
|
-
return json.loads(text, strict=True)
|
|
134
|
-
except Exception as e:
|
|
135
|
-
mesg = f'Text is not valid JSON: {text}'
|
|
136
|
-
raise s_exc.BadJsonText(mesg=mesg)
|
|
133
|
+
return s_json.loads(text)
|
|
137
134
|
|
|
138
135
|
@s_stormtypes.stormfunc(readonly=True)
|
|
139
136
|
async def _jsonSchema(self, schema, use_default=True):
|
synapse/lib/stormlib/model.py
CHANGED
|
@@ -200,7 +200,7 @@ class LibModelTags(s_stormtypes.Lib):
|
|
|
200
200
|
Examples:
|
|
201
201
|
Create a tag model for the ``cno.cve`` tag::
|
|
202
202
|
|
|
203
|
-
$regx = (
|
|
203
|
+
$regx = ([null, null, "[0-9]{4}", "[0-9]{5}"])
|
|
204
204
|
$lib.model.tags.set(cno.cve, regex, $regx)''',
|
|
205
205
|
'type': {'type': 'function', '_funcname': '_setTagModel',
|
|
206
206
|
'args': (
|
|
@@ -41,7 +41,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
41
41
|
{
|
|
42
42
|
'name': 'get',
|
|
43
43
|
'desc': '''
|
|
44
|
-
Return a notification by ID (or
|
|
44
|
+
Return a notification by ID (or ``(null)`` ).
|
|
45
45
|
|
|
46
46
|
''',
|
|
47
47
|
'type': {
|
|
@@ -51,7 +51,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
51
51
|
),
|
|
52
52
|
'returns': {
|
|
53
53
|
'name': 'retn', 'type': 'dict',
|
|
54
|
-
'desc': 'The requested notification or
|
|
54
|
+
'desc': 'The requested notification or ``(null)``.'},
|
|
55
55
|
},
|
|
56
56
|
},
|
|
57
57
|
)
|
synapse/lib/stormlib/oauth.py
CHANGED
|
@@ -145,15 +145,118 @@ class OAuthV2Lib(s_stormtypes.Lib):
|
|
|
145
145
|
})
|
|
146
146
|
|
|
147
147
|
// Optionally enable PKCE
|
|
148
|
-
$conf.extensions = ({"pkce":
|
|
148
|
+
$conf.extensions = ({"pkce": true})
|
|
149
149
|
|
|
150
150
|
// Optionally disable SSL verification
|
|
151
|
-
$conf.ssl_verify =
|
|
151
|
+
$conf.ssl_verify = (false)
|
|
152
152
|
|
|
153
153
|
// Optionally provide additional key-val parameters
|
|
154
154
|
// to include when calling the auth URI
|
|
155
155
|
$conf.extra_auth_params = ({"customparam": "foo"})
|
|
156
156
|
|
|
157
|
+
$lib.inet.http.oauth.v2.addProvider($conf)
|
|
158
|
+
|
|
159
|
+
Add a new provider which uses the Microsoft Azure Federated Workflow Identify token credentials.
|
|
160
|
+
This resolves the client_assertion from the AZURE_FEDERATED_TOKEN_FILE environment variable::
|
|
161
|
+
|
|
162
|
+
$iden = $lib.guid(azureexample, provider, oauth)
|
|
163
|
+
$authority_id = '4b70ee6f-d47b-3262-baa1-41cd7faed71b'
|
|
164
|
+
$conf = ({
|
|
165
|
+
"iden": $iden,
|
|
166
|
+
"name": "example_provider",
|
|
167
|
+
"auth_scheme": "client_assertion",
|
|
168
|
+
"client_id": "yourclientid",
|
|
169
|
+
"client_assertion": {
|
|
170
|
+
"msft:azure:workloadidentity": {
|
|
171
|
+
"token": true,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
"scope": "first_scope second_scope",
|
|
175
|
+
"auth_uri": `https://login.microsoftonline.com/{$authority_id}/oauth2/v2.0/authorize`,
|
|
176
|
+
"token_uri": `https://login.microsoftonline.com/{$authority_id}/oauth2/v2.0/token`,
|
|
177
|
+
"redirect_uri": "https://local.redirect.com/oauth",
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Optionally enable PKCE
|
|
181
|
+
$conf.extensions = ({"pkce": true})
|
|
182
|
+
|
|
183
|
+
// Optionally disable SSL verification
|
|
184
|
+
$conf.ssl_verify = (false)
|
|
185
|
+
|
|
186
|
+
// Optionally provide additional key-val parameters
|
|
187
|
+
// to include when calling the auth URI
|
|
188
|
+
$conf.extra_auth_params = ({"customparam": "foo"})
|
|
189
|
+
|
|
190
|
+
$lib.inet.http.oauth.v2.addProvider($conf)
|
|
191
|
+
|
|
192
|
+
If the ``client_id`` value should come from the AZURE_CLIENT_ID environment variable, use the
|
|
193
|
+
following configuration::
|
|
194
|
+
|
|
195
|
+
$conf = ({
|
|
196
|
+
"iden": $iden,
|
|
197
|
+
"name": "example_provider",
|
|
198
|
+
"auth_scheme": "client_assertion",
|
|
199
|
+
"client_assertion": {
|
|
200
|
+
"msft:azure:workloadidentity": {
|
|
201
|
+
"token": true,
|
|
202
|
+
"client_id": true,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
"scope": "first_scope second_scope",
|
|
206
|
+
"auth_uri": `https://login.microsoftonline.com/{$authority_id}/oauth2/v2.0/authorize`,
|
|
207
|
+
"token_uri": `https://login.microsoftonline.com/{$authority_id}/oauth2/v2.0/token`,
|
|
208
|
+
"redirect_uri": "https://local.redirect.com/oauth",
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
Add a new provider which uses a custom Storm callback to obtain the client_assertion data. These
|
|
212
|
+
callbacks are executed as the user who is performing the authorization_code workflow. The Storm
|
|
213
|
+
callback must return data in a tuple of ``bool`` and a dictionary containing the assertion in the
|
|
214
|
+
key ``token``. Error messages should be in the key ``error``::
|
|
215
|
+
|
|
216
|
+
$iden = $lib.guid(callstormexample, provider, oauth)
|
|
217
|
+
|
|
218
|
+
// Example callback
|
|
219
|
+
$callbackQuery = ${
|
|
220
|
+
$url = `{$baseurl}/api/oauth/getAssertion`
|
|
221
|
+
$resp = $lib.inet.http.get($url, ssl_verify=$ssl_verify)
|
|
222
|
+
if ($resp.code = 200) {
|
|
223
|
+
$resp = ([true, {'token': $resp.json().assertion}])
|
|
224
|
+
} else {
|
|
225
|
+
$resp = ([false, {"error": `Failed to get assertion from {$url}`}])
|
|
226
|
+
}
|
|
227
|
+
return ( $resp )
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Specify any variables that need to be provided to $callbackQuery
|
|
231
|
+
$myCallbackVars = ({
|
|
232
|
+
'baseurl': 'https://local.assertion.provider.corp',
|
|
233
|
+
'ssl_verify': true,
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// Specify the view the callback is run in.
|
|
237
|
+
$view = $lib.view.get().iden
|
|
238
|
+
|
|
239
|
+
$conf = ({
|
|
240
|
+
"iden": $iden,
|
|
241
|
+
"name": "example_provider",
|
|
242
|
+
"auth_scheme": "client_assertion",
|
|
243
|
+
"client_id": "yourclientid",
|
|
244
|
+
"client_assertion": {
|
|
245
|
+
"cortex:callstorm": {
|
|
246
|
+
"query": $callbackQuery,
|
|
247
|
+
"view": $view,
|
|
248
|
+
"vars": $myCallbackVars,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
"scope": "first_scope second_scope",
|
|
252
|
+
"auth_uri": "https://provider.com/auth",
|
|
253
|
+
"token_uri": "https://provider.com/token",
|
|
254
|
+
"redirect_uri": "https://local.redirect.com/oauth",
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Optionally enable PKCE
|
|
258
|
+
$conf.extensions = ({"pkce": true})
|
|
259
|
+
|
|
157
260
|
$lib.inet.http.oauth.v2.addProvider($conf)
|
|
158
261
|
''',
|
|
159
262
|
'type': {
|
synapse/lib/stormlib/stats.py
CHANGED
|
@@ -220,11 +220,13 @@ class StatTally(s_stormtypes.Prim):
|
|
|
220
220
|
|
|
221
221
|
@s_stormtypes.stormfunc(readonly=True)
|
|
222
222
|
async def inc(self, name, valu=1):
|
|
223
|
+
name = await s_stormtypes.tostr(name)
|
|
223
224
|
valu = await s_stormtypes.toint(valu)
|
|
224
225
|
self.counters[name] += valu
|
|
225
226
|
|
|
226
227
|
@s_stormtypes.stormfunc(readonly=True)
|
|
227
228
|
async def get(self, name):
|
|
229
|
+
name = await s_stormtypes.tostr(name)
|
|
228
230
|
return self.counters.get(name, 0)
|
|
229
231
|
|
|
230
232
|
def value(self):
|
|
@@ -236,6 +238,8 @@ class StatTally(s_stormtypes.Prim):
|
|
|
236
238
|
|
|
237
239
|
@s_stormtypes.stormfunc(readonly=True)
|
|
238
240
|
async def sorted(self, byname=False, reverse=False):
|
|
241
|
+
byname = await s_stormtypes.tobool(byname)
|
|
242
|
+
reverse = await s_stormtypes.tobool(reverse)
|
|
239
243
|
if byname:
|
|
240
244
|
return list(sorted(self.counters.items(), reverse=reverse))
|
|
241
245
|
else:
|