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/stormlib/stix.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import uuid
|
|
3
2
|
import asyncio
|
|
4
3
|
import logging
|
|
@@ -589,7 +588,7 @@ def validateStix(bundle, version='2.1'):
|
|
|
589
588
|
'mesg': '',
|
|
590
589
|
'result': {},
|
|
591
590
|
}
|
|
592
|
-
bundle =
|
|
591
|
+
bundle = s_msgpack.deepcopy(bundle, use_list=True)
|
|
593
592
|
opts = stix2validator.ValidationOptions(strict=True, version=version)
|
|
594
593
|
try:
|
|
595
594
|
results = stix2validator.validate_parsed_json(bundle, options=opts)
|
|
@@ -1172,7 +1171,7 @@ class LibStixExport(s_stormtypes.Lib):
|
|
|
1172
1171
|
@s_stormtypes.stormfunc(readonly=True)
|
|
1173
1172
|
async def config(self):
|
|
1174
1173
|
# make a new mutable config
|
|
1175
|
-
return
|
|
1174
|
+
return s_msgpack.deepcopy(_DefaultConfig, use_list=True)
|
|
1176
1175
|
|
|
1177
1176
|
@s_stormtypes.stormfunc(readonly=True)
|
|
1178
1177
|
async def bundle(self, config=None):
|
|
@@ -1372,7 +1371,7 @@ class StixBundle(s_stormtypes.Prim):
|
|
|
1372
1371
|
return stixid
|
|
1373
1372
|
|
|
1374
1373
|
def _initStixItem(self, stixid, stixtype, node):
|
|
1375
|
-
ndef =
|
|
1374
|
+
ndef = s_msgpack.deepcopy(node.ndef, use_list=True)
|
|
1376
1375
|
retn = {
|
|
1377
1376
|
'id': stixid,
|
|
1378
1377
|
'type': stixtype,
|
synapse/lib/stormlib/vault.py
CHANGED
|
@@ -321,7 +321,7 @@ class LibVault(s_stormtypes.Lib):
|
|
|
321
321
|
{'name': 'vtype', 'type': 'str',
|
|
322
322
|
'desc': 'The type of this vault.'},
|
|
323
323
|
{'name': 'scope', 'type': 'str',
|
|
324
|
-
'desc': 'Scope for this vault. One of "user", "role", "global", or
|
|
324
|
+
'desc': 'Scope for this vault. One of "user", "role", "global", or ``(null)`` for unscoped vaults.'},
|
|
325
325
|
{'name': 'owner', 'type': 'str',
|
|
326
326
|
'desc': 'User/role iden for this vault if scope is "user" or "role". None for "global" scope vaults.'},
|
|
327
327
|
{'name': 'secrets', 'type': 'dict',
|
|
@@ -359,9 +359,9 @@ class LibVault(s_stormtypes.Lib):
|
|
|
359
359
|
'args': (
|
|
360
360
|
{'name': 'vtype', 'type': 'str', 'desc': 'The vault type to retrieved.'},
|
|
361
361
|
{'name': 'scope', 'type': 'str', 'default': None,
|
|
362
|
-
'desc': 'The scope for the specified type. If
|
|
362
|
+
'desc': 'The scope for the specified type. If ``(null)``, then getByType will search.'},
|
|
363
363
|
),
|
|
364
|
-
'returns': {'type': 'vault', 'desc': 'Vault or
|
|
364
|
+
'returns': {'type': 'vault', 'desc': 'Vault or ``(null)`` if the vault could not be retrieved.'}}},
|
|
365
365
|
{'name': 'list', 'desc': 'List vaults accessible to the current user.',
|
|
366
366
|
'type': {'type': 'function', '_funcname': '_listVaults',
|
|
367
367
|
'args': (),
|
|
@@ -649,14 +649,14 @@ class Vault(s_stormtypes.Prim):
|
|
|
649
649
|
'type': {'type': 'function', '_funcname': '_methSetPerm',
|
|
650
650
|
'args': (
|
|
651
651
|
{'name': 'iden', 'type': 'str', 'desc': 'The user or role to modify.'},
|
|
652
|
-
{'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden.
|
|
652
|
+
{'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden. ``(null)`` to remove an existing permission.'},
|
|
653
653
|
),
|
|
654
|
-
'returns': {'type': 'boolean', 'desc': '
|
|
654
|
+
'returns': {'type': 'boolean', 'desc': '``(true)`` if the permission was set, ``(false)`` otherwise.', }}},
|
|
655
655
|
|
|
656
656
|
{'name': 'delete', 'desc': 'Delete the Vault.',
|
|
657
657
|
'type': {'type': 'function', '_funcname': '_methDelete',
|
|
658
658
|
'args': (),
|
|
659
|
-
'returns': {'type': 'boolean', 'desc': '
|
|
659
|
+
'returns': {'type': 'boolean', 'desc': '``(true)`` if the vault was deleted, ``(false)`` otherwise.', }}},
|
|
660
660
|
)
|
|
661
661
|
_storm_typename = 'vault'
|
|
662
662
|
_ismutable = False
|
synapse/lib/stormlib/xml.py
CHANGED
|
@@ -21,7 +21,7 @@ class XmlElement(s_stormtypes.Prim):
|
|
|
21
21
|
'args': (
|
|
22
22
|
{'name': 'name', 'type': 'str', 'desc': 'The name of the XML tag.'},
|
|
23
23
|
{'name': 'nested', 'type': 'bool', 'default': True,
|
|
24
|
-
'desc': 'Set to
|
|
24
|
+
'desc': 'Set to ``(false)`` to only find direct children.'},
|
|
25
25
|
),
|
|
26
26
|
'returns': {'type': 'generator', 'desc': 'A generator which yields xml:elements.'}}},
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ class XmlElement(s_stormtypes.Prim):
|
|
|
30
30
|
'args': (
|
|
31
31
|
{'name': 'name', 'type': 'str', 'desc': 'The name of the child XML element tag.'},
|
|
32
32
|
),
|
|
33
|
-
'returns': {'type': 'xml:element', 'desc': 'The child XML element or
|
|
33
|
+
'returns': {'type': 'xml:element', 'desc': 'The child XML element or ``(null)``.'}}},
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
def __init__(self, runt, elem):
|
synapse/lib/stormtypes.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import bz2
|
|
2
2
|
import copy
|
|
3
3
|
import gzip
|
|
4
|
-
import json
|
|
5
4
|
import time
|
|
6
5
|
|
|
7
6
|
import regex
|
|
@@ -25,6 +24,7 @@ import synapse.common as s_common
|
|
|
25
24
|
import synapse.telepath as s_telepath
|
|
26
25
|
|
|
27
26
|
import synapse.lib.coro as s_coro
|
|
27
|
+
import synapse.lib.json as s_json
|
|
28
28
|
import synapse.lib.node as s_node
|
|
29
29
|
import synapse.lib.time as s_time
|
|
30
30
|
import synapse.lib.cache as s_cache
|
|
@@ -837,14 +837,14 @@ class LibDmon(Lib):
|
|
|
837
837
|
{'name': 'iden', 'type': 'str', 'desc': 'The GUID of the Dmon to stop.'},
|
|
838
838
|
),
|
|
839
839
|
'returns': {'type': 'boolean',
|
|
840
|
-
'desc': '
|
|
840
|
+
'desc': '``(true)`` unless the dmon does not exist or was already stopped.'}}},
|
|
841
841
|
{'name': 'start', 'desc': 'Start a storm dmon.',
|
|
842
842
|
'type': {'type': 'function', '_funcname': '_libDmonStart',
|
|
843
843
|
'args': (
|
|
844
844
|
{'name': 'iden', 'type': 'str', 'desc': 'The GUID of the dmon to start.'},
|
|
845
845
|
),
|
|
846
846
|
'returns': {'type': 'boolean',
|
|
847
|
-
'desc': '
|
|
847
|
+
'desc': '``(true)`` unless the dmon does not exist or was already started.'}}},
|
|
848
848
|
)
|
|
849
849
|
_storm_lib_path = ('dmon',)
|
|
850
850
|
|
|
@@ -1469,7 +1469,7 @@ class LibBase(Lib):
|
|
|
1469
1469
|
|
|
1470
1470
|
Update the current runtime to enable debugging::
|
|
1471
1471
|
|
|
1472
|
-
$lib.debug =
|
|
1472
|
+
$lib.debug = (true)''',
|
|
1473
1473
|
'type': {
|
|
1474
1474
|
'type': ['gtor', 'stor'],
|
|
1475
1475
|
'_storfunc': '_setRuntDebug',
|
|
@@ -1782,7 +1782,7 @@ class LibBase(Lib):
|
|
|
1782
1782
|
name = await tostr(name)
|
|
1783
1783
|
mesg = await tostr(mesg)
|
|
1784
1784
|
info = await toprim(info)
|
|
1785
|
-
|
|
1785
|
+
s_json.reqjsonsafe(info)
|
|
1786
1786
|
|
|
1787
1787
|
ctor = getattr(s_exc, name, None)
|
|
1788
1788
|
if ctor is not None:
|
|
@@ -1841,7 +1841,7 @@ class LibBase(Lib):
|
|
|
1841
1841
|
@stormfunc(readonly=True)
|
|
1842
1842
|
async def _fire(self, name, **info):
|
|
1843
1843
|
info = await toprim(info)
|
|
1844
|
-
|
|
1844
|
+
s_json.reqjsonsafe(info)
|
|
1845
1845
|
await self.runt.snap.fire('storm:fire', type=name, data=info)
|
|
1846
1846
|
|
|
1847
1847
|
@registry.registerLib
|
|
@@ -2103,9 +2103,9 @@ class LibAxon(Lib):
|
|
|
2103
2103
|
|
|
2104
2104
|
For APIs that accept a proxy argument, the following values are supported::
|
|
2105
2105
|
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2106
|
+
``(null)``: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
|
|
2107
|
+
``(true)``: Use the proxy defined by the http:proxy configuration option if set.
|
|
2108
|
+
``(false)``: Do not use the proxy defined by the http:proxy configuration option if set.
|
|
2109
2109
|
<str>: A proxy URL string.
|
|
2110
2110
|
'''
|
|
2111
2111
|
_storm_locals = (
|
|
@@ -3025,7 +3025,7 @@ class LibTime(Lib):
|
|
|
3025
3025
|
{'name': 'valu', 'type': 'str', 'desc': 'The timestamp string to parse.', },
|
|
3026
3026
|
{'name': 'format', 'type': 'str', 'desc': 'The format string to use for parsing.', },
|
|
3027
3027
|
{'name': 'errok', 'type': 'boolean', 'default': False,
|
|
3028
|
-
'desc': 'If set, parsing errors will return
|
|
3028
|
+
'desc': 'If set, parsing errors will return ``(null)`` instead of raising an exception.'}
|
|
3029
3029
|
),
|
|
3030
3030
|
'returns': {'type': 'int', 'desc': 'The epoch timestamp for the string.', }}},
|
|
3031
3031
|
{'name': 'format', 'desc': '''
|
|
@@ -3365,7 +3365,7 @@ class LibRegx(Lib):
|
|
|
3365
3365
|
In order to get the matching groups, patterns must use parentheses
|
|
3366
3366
|
to indicate the start and stop of the regex to return portions of.
|
|
3367
3367
|
If groups are not used, a successful match will return a empty list
|
|
3368
|
-
and a unsuccessful match will return
|
|
3368
|
+
and a unsuccessful match will return ``(null)``.
|
|
3369
3369
|
|
|
3370
3370
|
Example:
|
|
3371
3371
|
Extract the matching groups from a piece of text::
|
|
@@ -3407,7 +3407,6 @@ class LibRegx(Lib):
|
|
|
3407
3407
|
'returns': {'type': 'list', 'desc': 'A list of lists of strings for the matching groups in the pattern.', }}},
|
|
3408
3408
|
{'name': 'matches', 'desc': '''
|
|
3409
3409
|
Check if text matches a pattern.
|
|
3410
|
-
Returns $lib.true if the text matches the pattern, otherwise $lib.false.
|
|
3411
3410
|
|
|
3412
3411
|
Notes:
|
|
3413
3412
|
This API requires the pattern to match at the start of the string.
|
|
@@ -4797,11 +4796,7 @@ class Str(Prim):
|
|
|
4797
4796
|
|
|
4798
4797
|
@stormfunc(readonly=True)
|
|
4799
4798
|
async def _methStrJson(self):
|
|
4800
|
-
|
|
4801
|
-
return json.loads(self.valu, strict=True)
|
|
4802
|
-
except Exception as e:
|
|
4803
|
-
mesg = f'Text is not valid JSON: {self.valu}'
|
|
4804
|
-
raise s_exc.BadJsonText(mesg=mesg)
|
|
4799
|
+
return s_json.loads(self.valu)
|
|
4805
4800
|
|
|
4806
4801
|
@registry.registerType
|
|
4807
4802
|
class Bytes(Prim):
|
|
@@ -4990,19 +4985,15 @@ class Bytes(Prim):
|
|
|
4990
4985
|
errors = await tostr(errors)
|
|
4991
4986
|
|
|
4992
4987
|
if encoding is None:
|
|
4993
|
-
encoding =
|
|
4988
|
+
encoding = s_json.detect_encoding(valu)
|
|
4994
4989
|
else:
|
|
4995
4990
|
encoding = await tostr(encoding)
|
|
4996
4991
|
|
|
4997
|
-
return
|
|
4992
|
+
return s_json.loads(valu.decode(encoding, errors))
|
|
4998
4993
|
|
|
4999
4994
|
except UnicodeDecodeError as e:
|
|
5000
4995
|
raise s_exc.StormRuntimeError(mesg=f'{e}: {s_common.trimText(repr(valu))}') from None
|
|
5001
4996
|
|
|
5002
|
-
except json.JSONDecodeError as e:
|
|
5003
|
-
mesg = f'Unable to decode bytes as json: {e.args[0]}'
|
|
5004
|
-
raise s_exc.BadJsonText(mesg=mesg)
|
|
5005
|
-
|
|
5006
4997
|
@registry.registerType
|
|
5007
4998
|
class Dict(Prim):
|
|
5008
4999
|
'''
|
|
@@ -6262,7 +6253,7 @@ class NodeData(Prim):
|
|
|
6262
6253
|
gateiden = self.valu.snap.wlyr.iden
|
|
6263
6254
|
confirm(('node', 'data', 'set', name), gateiden=gateiden)
|
|
6264
6255
|
valu = await toprim(valu)
|
|
6265
|
-
|
|
6256
|
+
s_json.reqjsonsafe(valu)
|
|
6266
6257
|
return await self.valu.setData(name, valu)
|
|
6267
6258
|
|
|
6268
6259
|
async def _popNodeData(self, name):
|
|
@@ -7790,7 +7781,7 @@ class View(Prim):
|
|
|
7790
7781
|
_storm_locals = (
|
|
7791
7782
|
{'name': 'iden', 'desc': 'The iden of the View.', 'type': 'str', },
|
|
7792
7783
|
{'name': 'layers', 'desc': 'The ``layer`` objects associated with the ``view``.', 'type': 'list', },
|
|
7793
|
-
{'name': 'parent', 'desc': 'The parent View. Will be
|
|
7784
|
+
{'name': 'parent', 'desc': 'The parent View. Will be ``(null)`` if the view is not a fork.', 'type': 'str'},
|
|
7794
7785
|
{'name': 'triggers', 'desc': 'The ``trigger`` objects associated with the ``view``.',
|
|
7795
7786
|
'type': 'list', },
|
|
7796
7787
|
{'name': 'children', 'desc': 'Yield Views which are children of this View.',
|
|
@@ -7815,7 +7806,7 @@ class View(Prim):
|
|
|
7815
7806
|
the protected option (below) until this option is removed.
|
|
7816
7807
|
|
|
7817
7808
|
protected (bool)
|
|
7818
|
-
Setting to
|
|
7809
|
+
Setting to ``(true)`` will prevent the layer from being merged or deleted.
|
|
7819
7810
|
|
|
7820
7811
|
layers (list(str))
|
|
7821
7812
|
Set the list of layer idens for a non-forked view. Layers are specified
|
|
@@ -8752,7 +8743,7 @@ class LibTrigger(Lib):
|
|
|
8752
8743
|
pass
|
|
8753
8744
|
|
|
8754
8745
|
if trigger is None:
|
|
8755
|
-
raise s_exc.NoSuchIden('Trigger not found')
|
|
8746
|
+
raise s_exc.NoSuchIden(mesg='Trigger not found', iden=iden)
|
|
8756
8747
|
|
|
8757
8748
|
self.runt.confirm(('trigger', 'get'), gateiden=iden)
|
|
8758
8749
|
|
|
@@ -8906,7 +8897,7 @@ class LibJsonStor(Lib):
|
|
|
8906
8897
|
{'name': 'path', 'type': 'str|list', 'desc': 'A path string or list of path parts.'},
|
|
8907
8898
|
{'name': 'prop', 'type': 'str|list', 'desc': 'A property name or list of name parts.', 'default': None},
|
|
8908
8899
|
),
|
|
8909
|
-
'returns': {'type': 'prim', 'desc': 'The previously stored value or
|
|
8900
|
+
'returns': {'type': 'prim', 'desc': 'The previously stored value or ``(null)``.'}}},
|
|
8910
8901
|
|
|
8911
8902
|
{'name': 'set', 'desc': 'Set a JSON object or object property.',
|
|
8912
8903
|
'type': {'type': 'function', '_funcname': 'set',
|
synapse/lib/structlog.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import json
|
|
2
|
-
|
|
3
1
|
import logging
|
|
4
2
|
|
|
5
3
|
import synapse.common as s_common
|
|
6
4
|
|
|
5
|
+
import synapse.lib.json as s_json
|
|
6
|
+
|
|
7
7
|
class JsonFormatter(logging.Formatter):
|
|
8
8
|
def __init__(self, *args, **kwargs):
|
|
9
9
|
super().__init__(*args, **kwargs)
|
|
@@ -37,4 +37,4 @@ class JsonFormatter(logging.Formatter):
|
|
|
37
37
|
if extras:
|
|
38
38
|
ret.update({k: v for k, v in extras.items() if k not in ret})
|
|
39
39
|
|
|
40
|
-
return
|
|
40
|
+
return s_json.dumps(ret, default=str).decode()
|
synapse/lib/types.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.chop as s_chop
|
|
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
|
|
@@ -1601,7 +1602,7 @@ class Data(Type):
|
|
|
1601
1602
|
|
|
1602
1603
|
def norm(self, valu):
|
|
1603
1604
|
try:
|
|
1604
|
-
|
|
1605
|
+
s_json.reqjsonsafe(valu)
|
|
1605
1606
|
if self.validator is not None:
|
|
1606
1607
|
self.validator(valu)
|
|
1607
1608
|
except (s_exc.MustBeJsonSafe, s_exc.SchemaViolation) as e:
|
synapse/lib/version.py
CHANGED
|
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
|
|
|
223
223
|
##############################################################################
|
|
224
224
|
# The following are touched during the release process by bumpversion.
|
|
225
225
|
# Do not modify these directly.
|
|
226
|
-
version = (2,
|
|
226
|
+
version = (2, 203, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = '809ecdca2e2b05f1cd111bb23c237127b2b9c177'
|
synapse/lib/view.py
CHANGED
|
@@ -1360,17 +1360,21 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
1360
1360
|
'readonly': False
|
|
1361
1361
|
}
|
|
1362
1362
|
|
|
1363
|
+
if name is None:
|
|
1364
|
+
if (pname := self.parent.info.get('name')) is not None:
|
|
1365
|
+
name = f'inserted fork of {pname}'
|
|
1366
|
+
else:
|
|
1367
|
+
name = f'inserted fork of {self.parent.iden}'
|
|
1368
|
+
|
|
1363
1369
|
vdef = {
|
|
1364
1370
|
'iden': s_common.guid(),
|
|
1371
|
+
'name': name,
|
|
1365
1372
|
'created': ctime,
|
|
1366
1373
|
'creator': useriden,
|
|
1367
1374
|
'parent': self.parent.iden,
|
|
1368
1375
|
'layers': [layriden] + [lyr.iden for lyr in self.parent.layers]
|
|
1369
1376
|
}
|
|
1370
1377
|
|
|
1371
|
-
if name is not None:
|
|
1372
|
-
vdef['name'] = name
|
|
1373
|
-
|
|
1374
1378
|
s_layer.reqValidLdef(ldef)
|
|
1375
1379
|
s_schemas.reqValidView(vdef)
|
|
1376
1380
|
|
synapse/models/base.py
CHANGED
|
@@ -29,10 +29,18 @@ class BaseModule(s_module.CoreModule):
|
|
|
29
29
|
|
|
30
30
|
'types': (
|
|
31
31
|
|
|
32
|
+
('meta:feed', ('guid', {}), {
|
|
33
|
+
'doc': 'A data feed provided by a specific source.'}),
|
|
34
|
+
|
|
35
|
+
('meta:feed:type:taxonomy', ('taxonomy', {}), {
|
|
36
|
+
'interfaces': ('meta:taxonomy',),
|
|
37
|
+
'doc': 'A data feed type taxonomy.'}),
|
|
38
|
+
|
|
32
39
|
('meta:source', ('guid', {}), {
|
|
33
40
|
'doc': 'A data source unique identifier.'}),
|
|
34
41
|
|
|
35
42
|
('meta:seen', ('comp', {'fields': (('source', 'meta:source'), ('node', 'ndef'))}), {
|
|
43
|
+
'deprecated': True,
|
|
36
44
|
'doc': 'Annotates that the data in a node was obtained from or observed by a given source.'}),
|
|
37
45
|
|
|
38
46
|
('meta:note', ('guid', {}), {
|
|
@@ -167,15 +175,22 @@ class BaseModule(s_module.CoreModule):
|
|
|
167
175
|
'edges': (
|
|
168
176
|
((None, 'refs', None), {
|
|
169
177
|
'doc': 'The source node contains a reference to the target node.'}),
|
|
178
|
+
|
|
170
179
|
(('meta:source', 'seen', None), {
|
|
171
180
|
'doc': 'The meta:source observed the target node.'}),
|
|
181
|
+
|
|
182
|
+
(('meta:feed', 'found', None), {
|
|
183
|
+
'doc': 'The meta:feed produced the target node.'}),
|
|
184
|
+
|
|
172
185
|
(('meta:note', 'about', None), {
|
|
173
|
-
'doc': 'The meta:note is about the target node.'
|
|
174
|
-
|
|
186
|
+
'doc': 'The meta:note is about the target node.'}),
|
|
187
|
+
|
|
175
188
|
(('meta:ruleset', 'has', 'meta:rule'), {
|
|
176
189
|
'doc': 'The meta:ruleset includes the meta:rule.'}),
|
|
190
|
+
|
|
177
191
|
(('meta:rule', 'matches', None), {
|
|
178
192
|
'doc': 'The meta:rule has matched on target node.'}),
|
|
193
|
+
|
|
179
194
|
(('meta:rule', 'detects', None), {
|
|
180
195
|
'doc': 'The meta:rule is designed to detect instances of the target node.'}),
|
|
181
196
|
),
|
|
@@ -213,6 +228,40 @@ class BaseModule(s_module.CoreModule):
|
|
|
213
228
|
|
|
214
229
|
)),
|
|
215
230
|
|
|
231
|
+
('meta:feed:type:taxonomy', {}, ()),
|
|
232
|
+
('meta:feed', {}, (
|
|
233
|
+
|
|
234
|
+
('name', ('str', {'lower': True, 'onespace': True}), {
|
|
235
|
+
'doc': 'A name for the feed.'}),
|
|
236
|
+
|
|
237
|
+
('type', ('meta:feed:type:taxonomy', {}), {
|
|
238
|
+
'doc': 'The type of data feed.'}),
|
|
239
|
+
|
|
240
|
+
('source', ('meta:source', {}), {
|
|
241
|
+
'doc': 'The meta:source which provides the feed.'}),
|
|
242
|
+
|
|
243
|
+
('url', ('inet:url', {}), {
|
|
244
|
+
'doc': 'The URL of the feed API endpoint.'}),
|
|
245
|
+
|
|
246
|
+
('query', ('str', {}), {
|
|
247
|
+
'doc': 'The query logic associated with generating the feed output.'}),
|
|
248
|
+
|
|
249
|
+
('opts', ('data', {}), {
|
|
250
|
+
'doc': 'An opaque JSON object containing feed parameters and options.'}),
|
|
251
|
+
|
|
252
|
+
('period', ('ival', {}), {
|
|
253
|
+
'doc': 'The time window over which results have been ingested.'}),
|
|
254
|
+
|
|
255
|
+
('latest', ('time', {}), {
|
|
256
|
+
'doc': 'The time of the last record consumed from the feed.'}),
|
|
257
|
+
|
|
258
|
+
('offset', ('int', {}), {
|
|
259
|
+
'doc': 'The offset of the last record consumed from the feed.'}),
|
|
260
|
+
|
|
261
|
+
('cursor', ('str', {'strip': True}), {
|
|
262
|
+
'doc': 'A cursor used to track ingest offset within the feed.'}),
|
|
263
|
+
)),
|
|
264
|
+
|
|
216
265
|
('meta:note:type:taxonomy', {}, ()),
|
|
217
266
|
('meta:note', {}, (
|
|
218
267
|
|
synapse/telepath.py
CHANGED
|
@@ -394,7 +394,7 @@ class Share(s_base.Base):
|
|
|
394
394
|
This should never be used by synapse core code. This is for sync client code convenience only.
|
|
395
395
|
'''
|
|
396
396
|
if s_threads.iden() == self.tid:
|
|
397
|
-
raise s_exc.SynErr('Use of synchronous context manager in async code')
|
|
397
|
+
raise s_exc.SynErr(mesg='Use of synchronous context manager in async code')
|
|
398
398
|
|
|
399
399
|
self._ctxobj = self.schedCoroSafePend(self.__aenter__())
|
|
400
400
|
return self
|
|
@@ -593,7 +593,7 @@ class Proxy(s_base.Base):
|
|
|
593
593
|
|
|
594
594
|
'''
|
|
595
595
|
_link_task = None
|
|
596
|
-
_link_event =
|
|
596
|
+
_link_event = None
|
|
597
597
|
_all_proxies = set()
|
|
598
598
|
|
|
599
599
|
async def __anit__(self, link, name):
|
|
@@ -650,6 +650,7 @@ class Proxy(s_base.Base):
|
|
|
650
650
|
if not Proxy._all_proxies and Proxy._link_task is not None:
|
|
651
651
|
Proxy._link_task.cancel()
|
|
652
652
|
Proxy._link_task = None
|
|
653
|
+
Proxy._link_event = None
|
|
653
654
|
|
|
654
655
|
Proxy._all_proxies.add(self)
|
|
655
656
|
|
|
@@ -657,6 +658,7 @@ class Proxy(s_base.Base):
|
|
|
657
658
|
self.link.onfini(self.fini)
|
|
658
659
|
|
|
659
660
|
if Proxy._link_task is None:
|
|
661
|
+
Proxy._link_event = asyncio.Event()
|
|
660
662
|
Proxy._link_task = s_coro.create_task(Proxy._linkLoopTask())
|
|
661
663
|
|
|
662
664
|
@classmethod
|
|
@@ -821,7 +823,7 @@ class Proxy(s_base.Base):
|
|
|
821
823
|
This must not be used from async code, and it should never be used in core synapse code.
|
|
822
824
|
'''
|
|
823
825
|
if s_threads.iden() == self.tid:
|
|
824
|
-
raise s_exc.SynErr('Use of synchronous context manager in async code')
|
|
826
|
+
raise s_exc.SynErr(mesg='Use of synchronous context manager in async code')
|
|
825
827
|
self._ctxobj = self.schedCoroSafePend(self.__aenter__())
|
|
826
828
|
return self
|
|
827
829
|
|
synapse/tests/files/__init__.py
CHANGED
synapse/tests/test_axon.py
CHANGED
|
@@ -103,7 +103,7 @@ class HttpPushFile(s_httpapi.StreamHandler):
|
|
|
103
103
|
assert item['filename'] == 'bytes'
|
|
104
104
|
|
|
105
105
|
assert args.get('zip_password') == [b'test']
|
|
106
|
-
assert args.get('dict') == [b'{"foo":
|
|
106
|
+
assert args.get('dict') == [b'{"foo":"bar"}']
|
|
107
107
|
self.sendRestRetn(self.gotsize)
|
|
108
108
|
|
|
109
109
|
class AxonTest(s_t_utils.SynTest):
|
|
@@ -4,6 +4,7 @@ import asyncio
|
|
|
4
4
|
import synapse.common as s_common
|
|
5
5
|
|
|
6
6
|
import synapse.lib.cmdr as s_cmdr
|
|
7
|
+
import synapse.lib.json as s_json
|
|
7
8
|
import synapse.lib.encoding as s_encoding
|
|
8
9
|
import synapse.lib.lmdbslab as s_lmdbslab
|
|
9
10
|
|
|
@@ -352,7 +353,7 @@ class CmdCoreTest(s_t_utils.SynTest):
|
|
|
352
353
|
await cmdr.runCmdLine(f'storm --save-nodes {path} test:int')
|
|
353
354
|
outp.expect('2 nodes')
|
|
354
355
|
|
|
355
|
-
jsdata = [item for item in
|
|
356
|
+
jsdata = [item for item in s_json.jslines(path)]
|
|
356
357
|
self.len(2, jsdata)
|
|
357
358
|
self.eq({tuple(n[0]) for n in jsdata},
|
|
358
359
|
{('test:int', 20), ('test:int', 30)})
|
|
@@ -371,7 +372,7 @@ class CmdCoreTest(s_t_utils.SynTest):
|
|
|
371
372
|
with s_common.genfile(stormfile) as fd:
|
|
372
373
|
fd.write(b'[ inet:fqdn=$hehe ]')
|
|
373
374
|
|
|
374
|
-
|
|
375
|
+
s_json.jssave(test_opts, optsfile)
|
|
375
376
|
s_common.yamlsave(test_opts, optsfile_yaml)
|
|
376
377
|
|
|
377
378
|
outp = self.getTestOutp()
|
synapse/tests/test_cmds_hive.py
CHANGED
synapse/tests/test_common.py
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import http
|
|
2
3
|
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
import subprocess
|
|
5
6
|
|
|
6
7
|
import yaml
|
|
8
|
+
import aiohttp
|
|
7
9
|
|
|
8
10
|
import synapse.exc as s_exc
|
|
9
11
|
import synapse.common as s_common
|
|
12
|
+
|
|
13
|
+
import synapse.lib.httpapi as s_httpapi
|
|
14
|
+
|
|
10
15
|
import synapse.tests.utils as s_t_utils
|
|
11
16
|
|
|
12
17
|
logger = logging.getLogger(__name__)
|
|
@@ -426,25 +431,6 @@ class CommonTest(s_t_utils.SynTest):
|
|
|
426
431
|
retn = s_common.merggenr2([asyncl(lt) for lt in (l3, l2, l1)], reverse=True)
|
|
427
432
|
self.eq((9, 8, 7, 6, 5, 4, 3, 2, 1), await alist(retn))
|
|
428
433
|
|
|
429
|
-
def test_jsonsafe(self):
|
|
430
|
-
items = (
|
|
431
|
-
(None, None),
|
|
432
|
-
(1234, None),
|
|
433
|
-
('1234', None),
|
|
434
|
-
({'asdf': 'haha'}, None),
|
|
435
|
-
({'a': (1,), 'b': [{'': 4}, 56, None, {'t': True, 'f': False}, 'oh my']}, None),
|
|
436
|
-
(b'1234', s_exc.BadArg),
|
|
437
|
-
({'a': 'a', 2: 2}, s_exc.BadArg),
|
|
438
|
-
({'a', 'b', 'c'}, s_exc.BadArg),
|
|
439
|
-
(s_common.novalu, s_exc.BadArg),
|
|
440
|
-
)
|
|
441
|
-
for (item, eret) in items:
|
|
442
|
-
if eret is None:
|
|
443
|
-
self.none(s_common.reqJsonSafeStrict(item))
|
|
444
|
-
else:
|
|
445
|
-
with self.raises(eret):
|
|
446
|
-
s_common.reqJsonSafeStrict(item)
|
|
447
|
-
|
|
448
434
|
def test_sslctx(self):
|
|
449
435
|
with self.getTestDir(mirror='certdir') as dirn:
|
|
450
436
|
cadir = s_common.genpath(dirn, 'cas')
|
|
@@ -481,3 +467,27 @@ class CommonTest(s_t_utils.SynTest):
|
|
|
481
467
|
v = s_common.trimText(iv, n=n)
|
|
482
468
|
self.le(len(v), n)
|
|
483
469
|
self.eq(v, ev)
|
|
470
|
+
|
|
471
|
+
async def test_tornado_monkeypatch(self):
|
|
472
|
+
class JsonHandler(s_httpapi.Handler):
|
|
473
|
+
async def get(self):
|
|
474
|
+
resp = {
|
|
475
|
+
'foo': 'bar',
|
|
476
|
+
'html': '<html></html>'
|
|
477
|
+
}
|
|
478
|
+
self.write(resp)
|
|
479
|
+
|
|
480
|
+
async with self.getTestCore() as core:
|
|
481
|
+
core.addHttpApi('/api/v1/test_tornado/', JsonHandler, {'cell': core})
|
|
482
|
+
_, port = await core.addHttpsPort(0)
|
|
483
|
+
url = f'https://127.0.0.1:{port}/api/v1/test_tornado/'
|
|
484
|
+
|
|
485
|
+
async with aiohttp.ClientSession() as session:
|
|
486
|
+
async with session.get(url, ssl=False) as resp:
|
|
487
|
+
self.eq(resp.status, http.HTTPStatus.OK)
|
|
488
|
+
|
|
489
|
+
text = await resp.text()
|
|
490
|
+
self.eq(text, '{"foo":"bar","html":"<html><\\/html>"}')
|
|
491
|
+
|
|
492
|
+
json = await resp.json()
|
|
493
|
+
self.eq(json, {'foo': 'bar', 'html': '<html></html>'})
|
synapse/tests/test_cortex.py
CHANGED
|
@@ -1559,8 +1559,8 @@ class CortexTest(s_t_utils.SynTest):
|
|
|
1559
1559
|
self.eq(refs.get('fqdn'), ('inet:fqdn', 'woot.com'))
|
|
1560
1560
|
self.eq(refs.get('ipv4'), ('inet:ipv4', 0x01020304))
|
|
1561
1561
|
|
|
1562
|
-
self.len(1, await core.nodes('[
|
|
1563
|
-
opts={'vars': {'
|
|
1562
|
+
self.len(1, await core.nodes('[test:str=testndef :somestr=$somestr :bar=$valu]',
|
|
1563
|
+
opts={'vars': {'somestr': sorc, 'valu': node.ndef}}))
|
|
1564
1564
|
|
|
1565
1565
|
# test un-populated properties
|
|
1566
1566
|
nodes = await core.nodes('[ps:contact="*"]')
|
|
@@ -1592,13 +1592,13 @@ class CortexTest(s_t_utils.SynTest):
|
|
|
1592
1592
|
self.eq(ints, (('test:int', 1), ('test:int', 2), ('test:int', 3)))
|
|
1593
1593
|
|
|
1594
1594
|
opts = {'vars': {'sorc': sorc}}
|
|
1595
|
-
nodes = await core.nodes('
|
|
1595
|
+
nodes = await core.nodes('test:str:somestr=$sorc -> *', opts=opts)
|
|
1596
1596
|
|
|
1597
1597
|
self.len(2, nodes)
|
|
1598
1598
|
self.isin('inet:dns:a', {n.ndef[0] for n in nodes})
|
|
1599
1599
|
|
|
1600
1600
|
opts = {'vars': {'sorc': sorc}}
|
|
1601
|
-
nodes = await core.nodes('
|
|
1601
|
+
nodes = await core.nodes('test:str:somestr=$sorc :bar -> *', opts=opts)
|
|
1602
1602
|
|
|
1603
1603
|
self.len(1, nodes)
|
|
1604
1604
|
self.eq('inet:dns:a', nodes[0].ndef[0])
|
|
@@ -3955,7 +3955,7 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
3955
3955
|
'refs': True,
|
|
3956
3956
|
'edges': False,
|
|
3957
3957
|
'forms': {},
|
|
3958
|
-
'pivots': ['
|
|
3958
|
+
'pivots': ['<(seen)- meta:source'],
|
|
3959
3959
|
'degrees': 3,
|
|
3960
3960
|
'filters': ['+#nope'],
|
|
3961
3961
|
'filterinput': False,
|