synapse 2.161.0__py311-none-any.whl → 2.163.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 +48 -40
- synapse/cortex.py +4 -0
- synapse/daemon.py +7 -2
- synapse/lib/cell.py +70 -3
- synapse/lib/layer.py +20 -1
- synapse/lib/oauth.py +1 -7
- synapse/lib/rstorm.py +16 -0
- synapse/lib/schemas.py +10 -0
- synapse/lib/storm.py +17 -1
- synapse/lib/stormhttp.py +52 -28
- synapse/lib/stormlib/stix.py +6 -3
- synapse/lib/stormtypes.py +336 -26
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +15 -2
- synapse/models/inet.py +9 -0
- synapse/models/infotech.py +28 -26
- synapse/models/orgs.py +3 -0
- synapse/models/proj.py +9 -2
- synapse/models/risk.py +32 -0
- synapse/telepath.py +2 -0
- synapse/tests/files/rstorm/testsvc.py +8 -1
- synapse/tests/files/stormpkg/testpkg.yaml +4 -0
- synapse/tests/test_axon.py +4 -4
- synapse/tests/test_cortex.py +8 -8
- synapse/tests/test_daemon.py +19 -0
- synapse/tests/test_lib_ast.py +17 -17
- synapse/tests/test_lib_grammar.py +4 -4
- synapse/tests/test_lib_rstorm.py +38 -2
- synapse/tests/test_lib_storm.py +15 -15
- synapse/tests/test_lib_stormhttp.py +182 -19
- synapse/tests/test_lib_stormlib_auth.py +3 -3
- synapse/tests/test_lib_stormlib_cell.py +1 -1
- synapse/tests/test_lib_stormlib_cortex.py +50 -2
- synapse/tests/test_lib_stormlib_json.py +2 -2
- synapse/tests/test_lib_stormlib_macro.py +1 -1
- synapse/tests/test_lib_stormlib_modelext.py +37 -37
- synapse/tests/test_lib_stormlib_oauth.py +20 -20
- synapse/tests/test_lib_stormlib_stix.py +3 -1
- synapse/tests/test_lib_stormtypes.py +159 -52
- synapse/tests/test_lib_stormwhois.py +1 -1
- synapse/tests/test_lib_trigger.py +11 -11
- synapse/tests/test_lib_view.py +23 -1
- synapse/tests/test_model_crypto.py +1 -1
- synapse/tests/test_model_inet.py +6 -0
- synapse/tests/test_model_orgs.py +2 -1
- synapse/tests/test_model_proj.py +6 -0
- synapse/tests/test_model_risk.py +10 -0
- synapse/tests/test_tools_storm.py +1 -1
- {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/METADATA +3 -1
- {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/RECORD +53 -53
- {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/LICENSE +0 -0
- {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/WHEEL +0 -0
- {synapse-2.161.0.dist-info → synapse-2.163.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormtypes.py
CHANGED
|
@@ -34,12 +34,17 @@ import synapse.lib.scope as s_scope
|
|
|
34
34
|
import synapse.lib.msgpack as s_msgpack
|
|
35
35
|
import synapse.lib.trigger as s_trigger
|
|
36
36
|
import synapse.lib.urlhelp as s_urlhelp
|
|
37
|
+
import synapse.lib.version as s_version
|
|
37
38
|
import synapse.lib.stormctrl as s_stormctrl
|
|
38
39
|
import synapse.lib.provenance as s_provenance
|
|
39
40
|
|
|
40
41
|
logger = logging.getLogger(__name__)
|
|
41
42
|
|
|
43
|
+
AXON_MINVERS_PROXY = (2, 97, 0)
|
|
44
|
+
AXON_MINVERS_SSLOPTS = '>=2.162.0'
|
|
45
|
+
|
|
42
46
|
class Undef:
|
|
47
|
+
_storm_typename = 'undef'
|
|
43
48
|
async def stormrepr(self):
|
|
44
49
|
return '$lib.undef'
|
|
45
50
|
|
|
@@ -1085,13 +1090,6 @@ class LibBase(Lib):
|
|
|
1085
1090
|
{'name': '*vals', 'type': 'any', 'desc': 'Initial values to place in the set.', },
|
|
1086
1091
|
),
|
|
1087
1092
|
'returns': {'type': 'set', 'desc': 'The new set.', }}},
|
|
1088
|
-
{'name': 'dict', 'desc': 'Get a Storm Dict object.',
|
|
1089
|
-
'type': {'type': 'function', '_funcname': '_dict',
|
|
1090
|
-
'args': (
|
|
1091
|
-
{'name': '**kwargs', 'type': 'any',
|
|
1092
|
-
'desc': 'Initial set of keyword argumetns to place into the dict.', },
|
|
1093
|
-
),
|
|
1094
|
-
'returns': {'type': 'dict', 'desc': 'A dictionary object.', }}},
|
|
1095
1093
|
{'name': 'exit', 'desc': 'Cause a Storm Runtime to stop running.',
|
|
1096
1094
|
'type': {'type': 'function', '_funcname': '_exit',
|
|
1097
1095
|
'args': (
|
|
@@ -1103,6 +1101,8 @@ class LibBase(Lib):
|
|
|
1103
1101
|
'type': {'type': 'function', '_funcname': '_guid',
|
|
1104
1102
|
'args': (
|
|
1105
1103
|
{'name': '*args', 'type': 'prim', 'desc': 'Arguments which are hashed to create a guid.', },
|
|
1104
|
+
{'name': 'valu', 'type': 'prim', 'default': '$lib.undef',
|
|
1105
|
+
'desc': 'Create a guid from a single value (no positional arguments can be specified).', },
|
|
1106
1106
|
),
|
|
1107
1107
|
'returns': {'type': 'str', 'desc': 'A guid.', }}},
|
|
1108
1108
|
{'name': 'fire', 'desc': '''
|
|
@@ -1147,7 +1147,7 @@ class LibBase(Lib):
|
|
|
1147
1147
|
Examples:
|
|
1148
1148
|
Create a dictionary object with a key whose value is null, and call ``$lib.fire()`` with it::
|
|
1149
1149
|
|
|
1150
|
-
cli> storm $d
|
|
1150
|
+
cli> storm $d=({"key": $lib.null}) $lib.fire('demo', d=$d)
|
|
1151
1151
|
('storm:fire', {'type': 'demo', 'data': {'d': {'key': None}}})
|
|
1152
1152
|
''',
|
|
1153
1153
|
'type': 'null', },
|
|
@@ -1227,7 +1227,7 @@ class LibBase(Lib):
|
|
|
1227
1227
|
|
|
1228
1228
|
Format and print string based on variables::
|
|
1229
1229
|
|
|
1230
|
-
cli> storm $d
|
|
1230
|
+
cli> storm $d=({"key1": (1), "key2": "two"})
|
|
1231
1231
|
for ($key, $value) in $d { $lib.print('{k} => {v}', k=$key, v=$value) }
|
|
1232
1232
|
key1 => 1
|
|
1233
1233
|
key2 => two
|
|
@@ -1377,7 +1377,6 @@ class LibBase(Lib):
|
|
|
1377
1377
|
'max': self._max,
|
|
1378
1378
|
'set': self._set,
|
|
1379
1379
|
'copy': self._copy,
|
|
1380
|
-
'dict': self._dict,
|
|
1381
1380
|
'exit': self._exit,
|
|
1382
1381
|
'guid': self._guid,
|
|
1383
1382
|
'fire': self._fire,
|
|
@@ -1550,10 +1549,17 @@ class LibBase(Lib):
|
|
|
1550
1549
|
return Text(valu)
|
|
1551
1550
|
|
|
1552
1551
|
@stormfunc(readonly=True)
|
|
1553
|
-
async def _guid(self, *args):
|
|
1552
|
+
async def _guid(self, *args, valu=undef):
|
|
1554
1553
|
if args:
|
|
1554
|
+
if valu is not undef:
|
|
1555
|
+
raise s_exc.BadArg(mesg='Valu cannot be specified if positional arguments are provided')
|
|
1555
1556
|
args = await toprim(args)
|
|
1556
1557
|
return s_common.guid(args)
|
|
1558
|
+
|
|
1559
|
+
if valu is not undef:
|
|
1560
|
+
valu = await toprim(valu)
|
|
1561
|
+
return s_common.guid(valu)
|
|
1562
|
+
|
|
1557
1563
|
return s_common.guid()
|
|
1558
1564
|
|
|
1559
1565
|
@stormfunc(readonly=True)
|
|
@@ -1677,16 +1683,125 @@ class LibBase(Lib):
|
|
|
1677
1683
|
mesg = await self._get_mesg(mesg, **kwargs)
|
|
1678
1684
|
await self.runt.warn(mesg, log=False)
|
|
1679
1685
|
|
|
1680
|
-
@stormfunc(readonly=True)
|
|
1681
|
-
async def _dict(self, **kwargs):
|
|
1682
|
-
return Dict(kwargs)
|
|
1683
|
-
|
|
1684
1686
|
@stormfunc(readonly=True)
|
|
1685
1687
|
async def _fire(self, name, **info):
|
|
1686
1688
|
info = await toprim(info)
|
|
1687
1689
|
s_common.reqjsonsafe(info)
|
|
1688
1690
|
await self.runt.snap.fire('storm:fire', type=name, data=info)
|
|
1689
1691
|
|
|
1692
|
+
@registry.registerLib
|
|
1693
|
+
class LibDict(Lib):
|
|
1694
|
+
'''
|
|
1695
|
+
A Storm Library for interacting with dictionaries.
|
|
1696
|
+
'''
|
|
1697
|
+
_storm_locals = (
|
|
1698
|
+
{'name': 'keys', 'desc': 'Retrieve a list of keys in the specified dictionary.',
|
|
1699
|
+
'type': {'type': 'function', '_funcname': '_keys',
|
|
1700
|
+
'args': (
|
|
1701
|
+
{'name': 'valu', 'type': 'dict', 'desc': 'The dictionary to operate on.'},
|
|
1702
|
+
),
|
|
1703
|
+
'returns': {'type': 'list', 'desc': 'List of keys in the specified dictionary.', }}},
|
|
1704
|
+
{'name': 'pop', 'desc': 'Remove specified key and return the corresponding value.',
|
|
1705
|
+
'type': {'type': 'function', '_funcname': '_pop',
|
|
1706
|
+
'args': (
|
|
1707
|
+
{'name': 'valu', 'type': 'dict', 'desc': 'The dictionary to operate on.'},
|
|
1708
|
+
{'name': 'key', 'type': 'str', 'desc': 'The key name of the value to pop.'},
|
|
1709
|
+
{'name': 'default', 'type': 'any', 'default': '$lib.undef',
|
|
1710
|
+
'desc': 'Optional default value to return if the key does not exist in the dictionary.'},
|
|
1711
|
+
),
|
|
1712
|
+
'returns': {'type': 'any', 'desc': 'The popped value.', }}},
|
|
1713
|
+
{'name': 'update', 'desc': 'Update the specified dictionary with keys/values from another dictionary.',
|
|
1714
|
+
'type': {'type': 'function', '_funcname': '_update',
|
|
1715
|
+
'args': (
|
|
1716
|
+
{'name': 'valu', 'type': 'dict', 'desc': 'The target dictionary (update to).'},
|
|
1717
|
+
{'name': 'other', 'type': 'dict', 'desc': 'The source dictionary (update from).'},
|
|
1718
|
+
),
|
|
1719
|
+
'returns': {'type': 'null'}}},
|
|
1720
|
+
{'name': 'values', 'desc': 'Retrieve a list of values in the specified dictionary.',
|
|
1721
|
+
'type': {'type': 'function', '_funcname': '_values',
|
|
1722
|
+
'args': (
|
|
1723
|
+
{'name': 'valu', 'type': 'dict', 'desc': 'The dictionary to operate on.'},
|
|
1724
|
+
),
|
|
1725
|
+
'returns': {'type': 'list', 'desc': 'List of values in the specified dictionary.', }}},
|
|
1726
|
+
)
|
|
1727
|
+
_storm_lib_path = ('dict',)
|
|
1728
|
+
|
|
1729
|
+
def getObjLocals(self):
|
|
1730
|
+
return {
|
|
1731
|
+
'has': self._has,
|
|
1732
|
+
'keys': self._keys,
|
|
1733
|
+
'pop': self._pop,
|
|
1734
|
+
'update': self._update,
|
|
1735
|
+
'values': self._values,
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
async def _check_type(self, valu, name='valu'):
|
|
1739
|
+
if isinstance(valu, (dict, Dict)):
|
|
1740
|
+
return
|
|
1741
|
+
|
|
1742
|
+
typ = getattr(valu, '_storm_typename', None)
|
|
1743
|
+
if typ is None:
|
|
1744
|
+
prim = await toprim(valu)
|
|
1745
|
+
typ = type(prim).__name__
|
|
1746
|
+
|
|
1747
|
+
mesg = f'{name} argument must be a dict, not {typ}.'
|
|
1748
|
+
raise s_exc.BadArg(mesg=mesg)
|
|
1749
|
+
|
|
1750
|
+
@stormfunc(readonly=True)
|
|
1751
|
+
async def _has(self, valu, name):
|
|
1752
|
+
await self._check_type(valu)
|
|
1753
|
+
valu = await toprim(valu)
|
|
1754
|
+
return name in valu
|
|
1755
|
+
|
|
1756
|
+
@stormfunc(readonly=True)
|
|
1757
|
+
async def _keys(self, valu):
|
|
1758
|
+
await self._check_type(valu)
|
|
1759
|
+
valu = await toprim(valu)
|
|
1760
|
+
return list(valu.keys())
|
|
1761
|
+
|
|
1762
|
+
@stormfunc(readonly=True)
|
|
1763
|
+
async def _pop(self, valu, key, default=undef):
|
|
1764
|
+
await self._check_type(valu)
|
|
1765
|
+
|
|
1766
|
+
real = await toprim(valu)
|
|
1767
|
+
key = await tostr(key)
|
|
1768
|
+
|
|
1769
|
+
if key not in real:
|
|
1770
|
+
if default == undef:
|
|
1771
|
+
mesg = f'Key {key} does not exist in dictionary.'
|
|
1772
|
+
raise s_exc.BadArg(mesg=mesg)
|
|
1773
|
+
return await toprim(default)
|
|
1774
|
+
|
|
1775
|
+
# Make sure we have a storm Dict
|
|
1776
|
+
valu = fromprim(valu)
|
|
1777
|
+
|
|
1778
|
+
ret = await valu.deref(key)
|
|
1779
|
+
await valu.setitem(key, undef)
|
|
1780
|
+
return ret
|
|
1781
|
+
|
|
1782
|
+
@stormfunc(readonly=True)
|
|
1783
|
+
async def _update(self, valu, other):
|
|
1784
|
+
await self._check_type(valu)
|
|
1785
|
+
await self._check_type(other, name='other')
|
|
1786
|
+
|
|
1787
|
+
valu = fromprim(valu)
|
|
1788
|
+
other = await toprim(other)
|
|
1789
|
+
|
|
1790
|
+
for k, v in other.items():
|
|
1791
|
+
await valu.setitem(k, v)
|
|
1792
|
+
|
|
1793
|
+
@stormfunc(readonly=True)
|
|
1794
|
+
async def _values(self, valu):
|
|
1795
|
+
await self._check_type(valu)
|
|
1796
|
+
|
|
1797
|
+
valu = await toprim(valu)
|
|
1798
|
+
return list(valu.values())
|
|
1799
|
+
|
|
1800
|
+
async def __call__(self, **kwargs):
|
|
1801
|
+
s_common.deprecated('$lib.dict()', curv='2.161.0')
|
|
1802
|
+
await self.runt.snap.warnonce('$lib.dict() is deprecated. Use ({}) instead.')
|
|
1803
|
+
return Dict(kwargs)
|
|
1804
|
+
|
|
1690
1805
|
@registry.registerLib
|
|
1691
1806
|
class LibPs(Lib):
|
|
1692
1807
|
'''
|
|
@@ -1700,7 +1815,7 @@ class LibPs(Lib):
|
|
|
1700
1815
|
'desc': 'The prefix of the task to stop. '
|
|
1701
1816
|
'Tasks will only be stopped if there is a single prefix match.'},
|
|
1702
1817
|
),
|
|
1703
|
-
'returns': {'type': 'boolean', 'desc': '
|
|
1818
|
+
'returns': {'type': 'boolean', 'desc': 'True if the task was cancelled, False otherwise.', }}},
|
|
1704
1819
|
{'name': 'list', 'desc': 'List tasks the current user can access.',
|
|
1705
1820
|
'type': {'type': 'function', '_funcname': '_list',
|
|
1706
1821
|
'returns': {'type': 'list', 'desc': 'A list of task definitions.', }}},
|
|
@@ -1814,6 +1929,14 @@ class LibStr(Lib):
|
|
|
1814
1929
|
class LibAxon(Lib):
|
|
1815
1930
|
'''
|
|
1816
1931
|
A Storm library for interacting with the Cortex's Axon.
|
|
1932
|
+
|
|
1933
|
+
For APIs that accept an ssl_opts argument, the dictionary may contain the following values::
|
|
1934
|
+
|
|
1935
|
+
{
|
|
1936
|
+
'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl argument.
|
|
1937
|
+
'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
|
|
1938
|
+
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
1939
|
+
}
|
|
1817
1940
|
'''
|
|
1818
1941
|
_storm_locals = (
|
|
1819
1942
|
{'name': 'wget', 'desc': """
|
|
@@ -1826,7 +1949,7 @@ class LibAxon(Lib):
|
|
|
1826
1949
|
Example:
|
|
1827
1950
|
Get the Vertex Project website::
|
|
1828
1951
|
|
|
1829
|
-
$headers =
|
|
1952
|
+
$headers = ({})
|
|
1830
1953
|
$headers."User-Agent" = Foo/Bar
|
|
1831
1954
|
|
|
1832
1955
|
$resp = $lib.axon.wget("http://vertex.link", method=GET, headers=$headers)
|
|
@@ -1849,6 +1972,9 @@ class LibAxon(Lib):
|
|
|
1849
1972
|
'default': None},
|
|
1850
1973
|
{'name': 'proxy', 'type': ['bool', 'null', 'str'],
|
|
1851
1974
|
'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
|
|
1975
|
+
{'name': 'ssl_opts', 'type': 'dict',
|
|
1976
|
+
'desc': 'Optional SSL/TLS options. See $lib.axon help for additional details.',
|
|
1977
|
+
'default': None},
|
|
1852
1978
|
),
|
|
1853
1979
|
'returns': {'type': 'dict', 'desc': 'A status dictionary of metadata.'}}},
|
|
1854
1980
|
{'name': 'wput', 'desc': """
|
|
@@ -1869,10 +1995,13 @@ class LibAxon(Lib):
|
|
|
1869
1995
|
'default': None},
|
|
1870
1996
|
{'name': 'proxy', 'type': ['bool', 'null', 'str'],
|
|
1871
1997
|
'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
|
|
1998
|
+
{'name': 'ssl_opts', 'type': 'dict',
|
|
1999
|
+
'desc': 'Optional SSL/TLS options. See $lib.axon help for additional details.',
|
|
2000
|
+
'default': None},
|
|
1872
2001
|
),
|
|
1873
2002
|
'returns': {'type': 'dict', 'desc': 'A status dictionary of metadata.'}}},
|
|
1874
2003
|
{'name': 'urlfile', 'desc': '''
|
|
1875
|
-
|
|
2004
|
+
Retrieve the target URL using the wget() function and construct an inet:urlfile node from the response.
|
|
1876
2005
|
|
|
1877
2006
|
Notes:
|
|
1878
2007
|
This accepts the same arguments as ``$lib.axon.wget()``.
|
|
@@ -2019,6 +2148,82 @@ class LibAxon(Lib):
|
|
|
2019
2148
|
''',
|
|
2020
2149
|
'type': {'type': 'function', '_funcname': 'metrics',
|
|
2021
2150
|
'returns': {'type': 'dict', 'desc': 'A dictionary containing runtime data about the Axon.'}}},
|
|
2151
|
+
{'name': 'put', 'desc': '''
|
|
2152
|
+
Save the given bytes variable to the Axon the Cortex is configured to use.
|
|
2153
|
+
|
|
2154
|
+
Examples:
|
|
2155
|
+
Save a base64 encoded buffer to the Axon::
|
|
2156
|
+
|
|
2157
|
+
cli> storm $s='dGVzdA==' $buf=$lib.base64.decode($s) ($size, $sha256)=$lib.axon.put($buf)
|
|
2158
|
+
$lib.print('size={size} sha256={sha256}', size=$size, sha256=$sha256)
|
|
2159
|
+
|
|
2160
|
+
size=4 sha256=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08''',
|
|
2161
|
+
'type': {'type': 'function', '_funcname': 'put',
|
|
2162
|
+
'args': (
|
|
2163
|
+
{'name': 'byts', 'type': 'bytes', 'desc': 'The bytes to save.', },
|
|
2164
|
+
),
|
|
2165
|
+
'returns': {'type': 'list', 'desc': 'A tuple of the file size and sha256 value.', }}},
|
|
2166
|
+
{'name': 'has', 'desc': '''
|
|
2167
|
+
Check if the Axon the Cortex is configured to use has a given sha256 value.
|
|
2168
|
+
|
|
2169
|
+
Examples:
|
|
2170
|
+
Check if the Axon has a given file::
|
|
2171
|
+
|
|
2172
|
+
# This example assumes the Axon does have the bytes
|
|
2173
|
+
cli> storm if $lib.axon.has(9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08) {
|
|
2174
|
+
$lib.print("Has bytes")
|
|
2175
|
+
} else {
|
|
2176
|
+
$lib.print("Does not have bytes")
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
Has bytes
|
|
2180
|
+
''',
|
|
2181
|
+
'type': {'type': 'function', '_funcname': 'has',
|
|
2182
|
+
'args': (
|
|
2183
|
+
{'name': 'sha256', 'type': 'str', 'desc': 'The sha256 value to check.', },
|
|
2184
|
+
),
|
|
2185
|
+
'returns': {'type': 'boolean', 'desc': 'True if the Axon has the file, false if it does not.', }}},
|
|
2186
|
+
{'name': 'size', 'desc': '''
|
|
2187
|
+
Return the size of the bytes stored in the Axon for the given sha256.
|
|
2188
|
+
|
|
2189
|
+
Examples:
|
|
2190
|
+
Get the size for a file given a variable named ``$sha256``::
|
|
2191
|
+
|
|
2192
|
+
$size = $lib.axon.size($sha256)
|
|
2193
|
+
''',
|
|
2194
|
+
'type': {'type': 'function', '_funcname': 'size',
|
|
2195
|
+
'args': (
|
|
2196
|
+
{'name': 'sha256', 'type': 'str', 'desc': 'The sha256 value to check.', },
|
|
2197
|
+
),
|
|
2198
|
+
'returns': {'type': ['int', 'null'],
|
|
2199
|
+
'desc': 'The size of the file or ``null`` if the file is not found.', }}},
|
|
2200
|
+
{'name': 'hashset', 'desc': '''
|
|
2201
|
+
Return additional hashes of the bytes stored in the Axon for the given sha256.
|
|
2202
|
+
|
|
2203
|
+
Examples:
|
|
2204
|
+
Get the md5 hash for a file given a variable named ``$sha256``::
|
|
2205
|
+
|
|
2206
|
+
$hashset = $lib.axon.hashset($sha256)
|
|
2207
|
+
$md5 = $hashset.md5
|
|
2208
|
+
''',
|
|
2209
|
+
'type': {'type': 'function', '_funcname': 'hashset',
|
|
2210
|
+
'args': (
|
|
2211
|
+
{'name': 'sha256', 'type': 'str', 'desc': 'The sha256 value to calculate hashes for.', },
|
|
2212
|
+
),
|
|
2213
|
+
'returns': {'type': 'dict', 'desc': 'A dictionary of additional hashes.', }}},
|
|
2214
|
+
{'name': 'upload', 'desc': '''
|
|
2215
|
+
Upload a stream of bytes to the Axon as a file.
|
|
2216
|
+
|
|
2217
|
+
Examples:
|
|
2218
|
+
Upload bytes from a generator::
|
|
2219
|
+
|
|
2220
|
+
($size, $sha256) = $lib.axon.upload($getBytesChunks())
|
|
2221
|
+
''',
|
|
2222
|
+
'type': {'type': 'function', '_funcname': 'upload',
|
|
2223
|
+
'args': (
|
|
2224
|
+
{'name': 'genr', 'type': 'generator', 'desc': 'A generator which yields bytes.', },
|
|
2225
|
+
),
|
|
2226
|
+
'returns': {'type': 'list', 'desc': 'A tuple of the file size and sha256 value.', }}},
|
|
2022
2227
|
)
|
|
2023
2228
|
_storm_lib_path = ('axon',)
|
|
2024
2229
|
_storm_lib_perms = (
|
|
@@ -2046,6 +2251,11 @@ class LibAxon(Lib):
|
|
|
2046
2251
|
'jsonlines': self.jsonlines,
|
|
2047
2252
|
'csvrows': self.csvrows,
|
|
2048
2253
|
'metrics': self.metrics,
|
|
2254
|
+
'put': self.put,
|
|
2255
|
+
'has': self.has,
|
|
2256
|
+
'size': self.size,
|
|
2257
|
+
'upload': self.upload,
|
|
2258
|
+
'hashset': self.hashset,
|
|
2049
2259
|
}
|
|
2050
2260
|
|
|
2051
2261
|
def strify(self, item):
|
|
@@ -2105,7 +2315,8 @@ class LibAxon(Lib):
|
|
|
2105
2315
|
axon = self.runt.snap.core.axon
|
|
2106
2316
|
return await axon.del_(sha256b)
|
|
2107
2317
|
|
|
2108
|
-
async def wget(self, url, headers=None, params=None, method='GET', json=None, body=None,
|
|
2318
|
+
async def wget(self, url, headers=None, params=None, method='GET', json=None, body=None,
|
|
2319
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
2109
2320
|
|
|
2110
2321
|
if not self.runt.allowed(('axon', 'wget')):
|
|
2111
2322
|
self.runt.confirm(('storm', 'lib', 'axon', 'wget'))
|
|
@@ -2120,6 +2331,7 @@ class LibAxon(Lib):
|
|
|
2120
2331
|
headers = await toprim(headers)
|
|
2121
2332
|
timeout = await toprim(timeout)
|
|
2122
2333
|
proxy = await toprim(proxy)
|
|
2334
|
+
ssl_opts = await toprim(ssl_opts)
|
|
2123
2335
|
|
|
2124
2336
|
if proxy is not None:
|
|
2125
2337
|
self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
|
|
@@ -2131,16 +2343,23 @@ class LibAxon(Lib):
|
|
|
2131
2343
|
|
|
2132
2344
|
kwargs = {}
|
|
2133
2345
|
axonvers = self.runt.snap.core.axoninfo['synapse']['version']
|
|
2134
|
-
if axonvers >=
|
|
2346
|
+
if axonvers >= AXON_MINVERS_PROXY:
|
|
2135
2347
|
kwargs['proxy'] = proxy
|
|
2136
2348
|
|
|
2349
|
+
if ssl_opts is not None:
|
|
2350
|
+
mesg = f'The ssl_opts argument requires an Axon Synapse version {AXON_MINVERS_SSLOPTS}, ' \
|
|
2351
|
+
f'but the Axon is running {axonvers}'
|
|
2352
|
+
s_version.reqVersion(axonvers, AXON_MINVERS_SSLOPTS, mesg=mesg)
|
|
2353
|
+
kwargs['ssl_opts'] = ssl_opts
|
|
2354
|
+
|
|
2137
2355
|
axon = self.runt.snap.core.axon
|
|
2138
2356
|
resp = await axon.wget(url, headers=headers, params=params, method=method, ssl=ssl, body=body, json=json,
|
|
2139
2357
|
timeout=timeout, **kwargs)
|
|
2140
2358
|
resp['original_url'] = url
|
|
2141
2359
|
return resp
|
|
2142
2360
|
|
|
2143
|
-
async def wput(self, sha256, url, headers=None, params=None, method='PUT',
|
|
2361
|
+
async def wput(self, sha256, url, headers=None, params=None, method='PUT',
|
|
2362
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
2144
2363
|
|
|
2145
2364
|
if not self.runt.allowed(('axon', 'wput')):
|
|
2146
2365
|
self.runt.confirm(('storm', 'lib', 'axon', 'wput'))
|
|
@@ -2154,6 +2373,7 @@ class LibAxon(Lib):
|
|
|
2154
2373
|
params = await toprim(params)
|
|
2155
2374
|
headers = await toprim(headers)
|
|
2156
2375
|
timeout = await toprim(timeout)
|
|
2376
|
+
ssl_opts = await toprim(ssl_opts)
|
|
2157
2377
|
|
|
2158
2378
|
params = self.strify(params)
|
|
2159
2379
|
headers = self.strify(headers)
|
|
@@ -2166,10 +2386,17 @@ class LibAxon(Lib):
|
|
|
2166
2386
|
|
|
2167
2387
|
kwargs = {}
|
|
2168
2388
|
axonvers = self.runt.snap.core.axoninfo['synapse']['version']
|
|
2169
|
-
if axonvers >=
|
|
2389
|
+
if axonvers >= AXON_MINVERS_PROXY:
|
|
2170
2390
|
kwargs['proxy'] = proxy
|
|
2171
2391
|
|
|
2172
|
-
|
|
2392
|
+
if ssl_opts is not None:
|
|
2393
|
+
mesg = f'The ssl_opts argument requires an Axon Synapse version {AXON_MINVERS_SSLOPTS}, ' \
|
|
2394
|
+
f'but the Axon is running {axonvers}'
|
|
2395
|
+
s_version.reqVersion(axonvers, AXON_MINVERS_SSLOPTS, mesg=mesg)
|
|
2396
|
+
kwargs['ssl_opts'] = ssl_opts
|
|
2397
|
+
|
|
2398
|
+
return await axon.wput(sha256byts, url, headers=headers, params=params, method=method,
|
|
2399
|
+
ssl=ssl, timeout=timeout, **kwargs)
|
|
2173
2400
|
|
|
2174
2401
|
async def urlfile(self, *args, **kwargs):
|
|
2175
2402
|
gateiden = self.runt.snap.wlyr.iden
|
|
@@ -2270,10 +2497,62 @@ class LibAxon(Lib):
|
|
|
2270
2497
|
self.runt.confirm(('storm', 'lib', 'axon', 'has'))
|
|
2271
2498
|
return await self.runt.snap.core.axon.metrics()
|
|
2272
2499
|
|
|
2500
|
+
async def upload(self, genr):
|
|
2501
|
+
|
|
2502
|
+
self.runt.confirm(('axon', 'upload'))
|
|
2503
|
+
|
|
2504
|
+
await self.runt.snap.core.getAxon()
|
|
2505
|
+
async with await self.runt.snap.core.axon.upload() as upload:
|
|
2506
|
+
async for byts in s_coro.agen(genr):
|
|
2507
|
+
await upload.write(byts)
|
|
2508
|
+
size, sha256 = await upload.save()
|
|
2509
|
+
return size, s_common.ehex(sha256)
|
|
2510
|
+
|
|
2511
|
+
@stormfunc(readonly=True)
|
|
2512
|
+
async def has(self, sha256):
|
|
2513
|
+
sha256 = await tostr(sha256, noneok=True)
|
|
2514
|
+
if sha256 is None:
|
|
2515
|
+
return None
|
|
2516
|
+
|
|
2517
|
+
self.runt.confirm(('axon', 'has'))
|
|
2518
|
+
|
|
2519
|
+
await self.runt.snap.core.getAxon()
|
|
2520
|
+
return await self.runt.snap.core.axon.has(s_common.uhex(sha256))
|
|
2521
|
+
|
|
2522
|
+
@stormfunc(readonly=True)
|
|
2523
|
+
async def size(self, sha256):
|
|
2524
|
+
sha256 = await tostr(sha256)
|
|
2525
|
+
|
|
2526
|
+
self.runt.confirm(('axon', 'has'))
|
|
2527
|
+
|
|
2528
|
+
await self.runt.snap.core.getAxon()
|
|
2529
|
+
return await self.runt.snap.core.axon.size(s_common.uhex(sha256))
|
|
2530
|
+
|
|
2531
|
+
async def put(self, byts):
|
|
2532
|
+
if not isinstance(byts, bytes):
|
|
2533
|
+
mesg = '$lib.axon.put() requires a bytes argument'
|
|
2534
|
+
raise s_exc.BadArg(mesg=mesg)
|
|
2535
|
+
|
|
2536
|
+
self.runt.confirm(('axon', 'upload'))
|
|
2537
|
+
|
|
2538
|
+
await self.runt.snap.core.getAxon()
|
|
2539
|
+
size, sha256 = await self.runt.snap.core.axon.put(byts)
|
|
2540
|
+
|
|
2541
|
+
return (size, s_common.ehex(sha256))
|
|
2542
|
+
|
|
2543
|
+
@stormfunc(readonly=True)
|
|
2544
|
+
async def hashset(self, sha256):
|
|
2545
|
+
sha256 = await tostr(sha256)
|
|
2546
|
+
|
|
2547
|
+
self.runt.confirm(('axon', 'has'))
|
|
2548
|
+
|
|
2549
|
+
await self.runt.snap.core.getAxon()
|
|
2550
|
+
return await self.runt.snap.core.axon.hashset(s_common.uhex(sha256))
|
|
2551
|
+
|
|
2273
2552
|
@registry.registerLib
|
|
2274
2553
|
class LibBytes(Lib):
|
|
2275
2554
|
'''
|
|
2276
|
-
A Storm Library for interacting with bytes storage.
|
|
2555
|
+
A Storm Library for interacting with bytes storage. This Library is deprecated; use ``$lib.axon.*`` instead.
|
|
2277
2556
|
'''
|
|
2278
2557
|
_storm_locals = (
|
|
2279
2558
|
{'name': 'put', 'desc': '''
|
|
@@ -2365,6 +2644,9 @@ class LibBytes(Lib):
|
|
|
2365
2644
|
}
|
|
2366
2645
|
|
|
2367
2646
|
async def _libBytesUpload(self, genr):
|
|
2647
|
+
|
|
2648
|
+
self.runt.confirm(('axon', 'upload'), default=True)
|
|
2649
|
+
|
|
2368
2650
|
await self.runt.snap.core.getAxon()
|
|
2369
2651
|
async with await self.runt.snap.core.axon.upload() as upload:
|
|
2370
2652
|
async for byts in s_coro.agen(genr):
|
|
@@ -2374,10 +2656,13 @@ class LibBytes(Lib):
|
|
|
2374
2656
|
|
|
2375
2657
|
@stormfunc(readonly=True)
|
|
2376
2658
|
async def _libBytesHas(self, sha256):
|
|
2659
|
+
|
|
2377
2660
|
sha256 = await tostr(sha256, noneok=True)
|
|
2378
2661
|
if sha256 is None:
|
|
2379
2662
|
return None
|
|
2380
2663
|
|
|
2664
|
+
self.runt.confirm(('axon', 'has'), default=True)
|
|
2665
|
+
|
|
2381
2666
|
await self.runt.snap.core.getAxon()
|
|
2382
2667
|
todo = s_common.todo('has', s_common.uhex(sha256))
|
|
2383
2668
|
ret = await self.dyncall('axon', todo)
|
|
@@ -2385,17 +2670,24 @@ class LibBytes(Lib):
|
|
|
2385
2670
|
|
|
2386
2671
|
@stormfunc(readonly=True)
|
|
2387
2672
|
async def _libBytesSize(self, sha256):
|
|
2673
|
+
|
|
2388
2674
|
sha256 = await tostr(sha256)
|
|
2675
|
+
|
|
2676
|
+
self.runt.confirm(('axon', 'has'), default=True)
|
|
2677
|
+
|
|
2389
2678
|
await self.runt.snap.core.getAxon()
|
|
2390
2679
|
todo = s_common.todo('size', s_common.uhex(sha256))
|
|
2391
2680
|
ret = await self.dyncall('axon', todo)
|
|
2392
2681
|
return ret
|
|
2393
2682
|
|
|
2394
2683
|
async def _libBytesPut(self, byts):
|
|
2684
|
+
|
|
2395
2685
|
if not isinstance(byts, bytes):
|
|
2396
2686
|
mesg = '$lib.bytes.put() requires a bytes argument'
|
|
2397
2687
|
raise s_exc.BadArg(mesg=mesg)
|
|
2398
2688
|
|
|
2689
|
+
self.runt.confirm(('axon', 'upload'), default=True)
|
|
2690
|
+
|
|
2399
2691
|
await self.runt.snap.core.getAxon()
|
|
2400
2692
|
todo = s_common.todo('put', byts)
|
|
2401
2693
|
size, sha2 = await self.dyncall('axon', todo)
|
|
@@ -2404,7 +2696,11 @@ class LibBytes(Lib):
|
|
|
2404
2696
|
|
|
2405
2697
|
@stormfunc(readonly=True)
|
|
2406
2698
|
async def _libBytesHashset(self, sha256):
|
|
2699
|
+
|
|
2407
2700
|
sha256 = await tostr(sha256)
|
|
2701
|
+
|
|
2702
|
+
self.runt.confirm(('axon', 'has'), default=True)
|
|
2703
|
+
|
|
2408
2704
|
await self.runt.snap.core.getAxon()
|
|
2409
2705
|
todo = s_common.todo('hashset', s_common.uhex(sha256))
|
|
2410
2706
|
ret = await self.dyncall('axon', todo)
|
|
@@ -3207,7 +3503,7 @@ class Pipe(StormType):
|
|
|
3207
3503
|
{'name': 'put', 'desc': 'Add a single item to the Pipe.',
|
|
3208
3504
|
'type': {'type': 'function', '_funcname': '_methPipePut',
|
|
3209
3505
|
'args': (
|
|
3210
|
-
{'name': 'item', 'type': 'any', 'desc': '
|
|
3506
|
+
{'name': 'item', 'type': 'any', 'desc': 'An object to add to the Pipe.', },
|
|
3211
3507
|
),
|
|
3212
3508
|
'returns': {'type': 'null', }}},
|
|
3213
3509
|
{'name': 'puts', 'desc': 'Add a list of items to the Pipe.',
|
|
@@ -4056,6 +4352,9 @@ class Str(Prim):
|
|
|
4056
4352
|
'desc': 'Keyword values which are substituted into the string.', },
|
|
4057
4353
|
),
|
|
4058
4354
|
'returns': {'type': 'str', 'desc': 'The new string.', }}},
|
|
4355
|
+
{'name': 'json', 'desc': 'Parse a JSON string and return the deserialized data.',
|
|
4356
|
+
'type': {'type': 'function', '_funcname': '_methStrJson', 'args': (),
|
|
4357
|
+
'returns': {'type': 'prim', 'desc': 'The JSON deserialized object.', }}},
|
|
4059
4358
|
)
|
|
4060
4359
|
_storm_typename = 'str'
|
|
4061
4360
|
_ismutable = False
|
|
@@ -4085,6 +4384,7 @@ class Str(Prim):
|
|
|
4085
4384
|
'slice': self._methStrSlice,
|
|
4086
4385
|
'reverse': self._methStrReverse,
|
|
4087
4386
|
'format': self._methStrFormat,
|
|
4387
|
+
'json': self._methStrJson,
|
|
4088
4388
|
}
|
|
4089
4389
|
|
|
4090
4390
|
def __int__(self):
|
|
@@ -4200,6 +4500,14 @@ class Str(Prim):
|
|
|
4200
4500
|
async def _methStrReverse(self):
|
|
4201
4501
|
return self.valu[::-1]
|
|
4202
4502
|
|
|
4503
|
+
@stormfunc(readonly=True)
|
|
4504
|
+
async def _methStrJson(self):
|
|
4505
|
+
try:
|
|
4506
|
+
return json.loads(self.valu, strict=True)
|
|
4507
|
+
except Exception as e:
|
|
4508
|
+
mesg = f'Text is not valid JSON: {self.valu}'
|
|
4509
|
+
raise s_exc.BadJsonText(mesg=mesg)
|
|
4510
|
+
|
|
4203
4511
|
@registry.registerType
|
|
4204
4512
|
class Bytes(Prim):
|
|
4205
4513
|
'''
|
|
@@ -5536,7 +5844,7 @@ class NodeData(Prim):
|
|
|
5536
5844
|
{'name': 'name', 'type': 'str', 'desc': 'Name of the data to get.', },
|
|
5537
5845
|
),
|
|
5538
5846
|
'returns': {'type': 'prim', 'desc': 'The stored node data.', }}},
|
|
5539
|
-
{'name': 'pop', 'desc': '
|
|
5847
|
+
{'name': 'pop', 'desc': 'Pop (remove) a the Node data from the Node.',
|
|
5540
5848
|
'type': {'type': 'function', '_funcname': '_popNodeData',
|
|
5541
5849
|
'args': (
|
|
5542
5850
|
{'name': 'name', 'type': 'str', 'desc': 'The name of the data to remove from the node.', },
|
|
@@ -7591,6 +7899,8 @@ class View(Prim):
|
|
|
7591
7899
|
mesg = 'You are not a member of a role with voting privileges for this merge request.'
|
|
7592
7900
|
raise s_exc.AuthDeny(mesg=mesg)
|
|
7593
7901
|
|
|
7902
|
+
view.reqValidVoter(self.runt.user.iden)
|
|
7903
|
+
|
|
7594
7904
|
vote = {'user': self.runt.user.iden, 'approved': await tobool(approved)}
|
|
7595
7905
|
|
|
7596
7906
|
if comment is not None:
|
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, 163, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = '72acabe1afe8661274c9e09284ab1726994fa41b'
|
synapse/lib/view.py
CHANGED
|
@@ -268,15 +268,28 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
268
268
|
vote['offset'] = await self.layers[0].getEditIndx()
|
|
269
269
|
return await self._push('merge:vote:set', vote)
|
|
270
270
|
|
|
271
|
+
def reqValidVoter(self, useriden):
|
|
272
|
+
|
|
273
|
+
merge = self.getMergeRequest()
|
|
274
|
+
if merge is None:
|
|
275
|
+
raise s_exc.BadState(mesg=f'View ({self.iden}) does not have a merge request.')
|
|
276
|
+
|
|
277
|
+
if merge.get('creator') == useriden:
|
|
278
|
+
raise s_exc.AuthDeny(mesg='A user may not vote for their own merge request.')
|
|
279
|
+
|
|
271
280
|
@s_nexus.Pusher.onPush('merge:vote:set')
|
|
272
281
|
async def _setMergeVote(self, vote):
|
|
273
282
|
|
|
274
283
|
self.reqParentQuorum()
|
|
275
284
|
s_schemas.reqValidVote(vote)
|
|
276
285
|
|
|
277
|
-
|
|
286
|
+
useriden = vote.get('user')
|
|
287
|
+
|
|
288
|
+
self.reqValidVoter(useriden)
|
|
289
|
+
|
|
290
|
+
bidn = s_common.uhex(useriden)
|
|
278
291
|
|
|
279
|
-
self.core.slab.put(self.bidn + b'merge:vote' +
|
|
292
|
+
self.core.slab.put(self.bidn + b'merge:vote' + bidn, s_msgpack.en(vote), db='view:meta')
|
|
280
293
|
|
|
281
294
|
await self.core.feedBeholder('view:merge:vote:set', {'view': self.iden, 'vote': vote})
|
|
282
295
|
|
synapse/models/inet.py
CHANGED
|
@@ -1560,6 +1560,15 @@ class InetModule(s_module.CoreModule):
|
|
|
1560
1560
|
('headers', ('array', {'type': 'inet:email:header'}), {
|
|
1561
1561
|
'doc': 'An array of email headers from the message.'}),
|
|
1562
1562
|
|
|
1563
|
+
('received:from:ipv4', ('inet:ipv4', {}), {
|
|
1564
|
+
'doc': 'The sending SMTP server IPv4, potentially from the Received: header.'}),
|
|
1565
|
+
|
|
1566
|
+
('received:from:ipv6', ('inet:ipv6', {}), {
|
|
1567
|
+
'doc': 'The sending SMTP server IPv6, potentially from the Received: header.'}),
|
|
1568
|
+
|
|
1569
|
+
('received:from:fqdn', ('inet:fqdn', {}), {
|
|
1570
|
+
'doc': 'The sending server FQDN, potentially from the Received: header.'}),
|
|
1571
|
+
|
|
1563
1572
|
)),
|
|
1564
1573
|
|
|
1565
1574
|
('inet:email:header', {}, (
|