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/axon.py
CHANGED
|
@@ -593,7 +593,8 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
593
593
|
await self._reqUserAllowed(('axon', 'del'))
|
|
594
594
|
return await self.cell.dels(sha256s)
|
|
595
595
|
|
|
596
|
-
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
596
|
+
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
597
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
597
598
|
'''
|
|
598
599
|
Stream a file download directly into the Axon.
|
|
599
600
|
|
|
@@ -606,11 +607,20 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
606
607
|
method (str): The HTTP method to use.
|
|
607
608
|
ssl (bool): Perform SSL verification.
|
|
608
609
|
timeout (int): The timeout of the request, in seconds.
|
|
610
|
+
ssl_opts (dict): Additional SSL/TLS options.
|
|
609
611
|
|
|
610
612
|
Notes:
|
|
611
613
|
The response body will be stored, regardless of the response code. The ``ok`` value in the reponse does not
|
|
612
614
|
reflect that a status code, such as a 404, was encountered when retrieving the URL.
|
|
613
615
|
|
|
616
|
+
The ssl_opts dictionary may contain the following values::
|
|
617
|
+
|
|
618
|
+
{
|
|
619
|
+
'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl argument.
|
|
620
|
+
'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
|
|
621
|
+
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
622
|
+
}
|
|
623
|
+
|
|
614
624
|
The dictionary returned by this may contain the following values::
|
|
615
625
|
|
|
616
626
|
{
|
|
@@ -640,18 +650,20 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
640
650
|
dict: An information dictionary containing the results of the request.
|
|
641
651
|
'''
|
|
642
652
|
await self._reqUserAllowed(('axon', 'wget'))
|
|
643
|
-
return await self.cell.wget(url, params=params, headers=headers, json=json, body=body, method=method,
|
|
644
|
-
timeout=timeout, proxy=proxy)
|
|
653
|
+
return await self.cell.wget(url, params=params, headers=headers, json=json, body=body, method=method,
|
|
654
|
+
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
645
655
|
|
|
646
|
-
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
656
|
+
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
657
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
647
658
|
await self._reqUserAllowed(('axon', 'wput'))
|
|
648
|
-
return await self.cell.postfiles(fields, url, params=params, headers=headers,
|
|
649
|
-
|
|
659
|
+
return await self.cell.postfiles(fields, url, params=params, headers=headers, method=method,
|
|
660
|
+
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
650
661
|
|
|
651
|
-
async def wput(self, sha256, url, params=None, headers=None, method='PUT',
|
|
662
|
+
async def wput(self, sha256, url, params=None, headers=None, method='PUT',
|
|
663
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
652
664
|
await self._reqUserAllowed(('axon', 'wput'))
|
|
653
|
-
return await self.cell.wput(sha256, url, params=params, headers=headers, method=method,
|
|
654
|
-
timeout=timeout, proxy=proxy)
|
|
665
|
+
return await self.cell.wput(sha256, url, params=params, headers=headers, method=method,
|
|
666
|
+
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
655
667
|
|
|
656
668
|
async def metrics(self):
|
|
657
669
|
'''
|
|
@@ -1434,7 +1446,8 @@ class Axon(s_cell.Cell):
|
|
|
1434
1446
|
raise s_exc.BadJsonText(mesg=f'Bad json line encountered while processing {sha256}, ({e})',
|
|
1435
1447
|
sha256=sha256) from None
|
|
1436
1448
|
|
|
1437
|
-
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
1449
|
+
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
1450
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
1438
1451
|
'''
|
|
1439
1452
|
Send files from the axon as fields in a multipart/form-data HTTP request.
|
|
1440
1453
|
|
|
@@ -1447,6 +1460,7 @@ class Axon(s_cell.Cell):
|
|
|
1447
1460
|
ssl (bool): Perform SSL verification.
|
|
1448
1461
|
timeout (int): The timeout of the request, in seconds.
|
|
1449
1462
|
proxy (bool|str|null): Use a specific proxy or disable proxy use.
|
|
1463
|
+
ssl_opts (dict): Additional SSL/TLS options.
|
|
1450
1464
|
|
|
1451
1465
|
Notes:
|
|
1452
1466
|
The dictionaries in the fields list may contain the following values::
|
|
@@ -1460,6 +1474,14 @@ class Axon(s_cell.Cell):
|
|
|
1460
1474
|
'content_transfer_encoding': <str> - Optional content-transfer-encoding header for the field.
|
|
1461
1475
|
}
|
|
1462
1476
|
|
|
1477
|
+
The ssl_opts dictionary may contain the following values::
|
|
1478
|
+
|
|
1479
|
+
{
|
|
1480
|
+
'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl argument.
|
|
1481
|
+
'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
|
|
1482
|
+
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1463
1485
|
The dictionary returned by this may contain the following values::
|
|
1464
1486
|
|
|
1465
1487
|
{
|
|
@@ -1478,20 +1500,12 @@ class Axon(s_cell.Cell):
|
|
|
1478
1500
|
if proxy is None:
|
|
1479
1501
|
proxy = self.conf.get('http:proxy')
|
|
1480
1502
|
|
|
1481
|
-
|
|
1503
|
+
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1482
1504
|
|
|
1483
1505
|
connector = None
|
|
1484
1506
|
if proxy:
|
|
1485
1507
|
connector = aiohttp_socks.ProxyConnector.from_url(proxy)
|
|
1486
1508
|
|
|
1487
|
-
if ssl is False:
|
|
1488
|
-
pass
|
|
1489
|
-
elif cadir:
|
|
1490
|
-
ssl = s_common.getSslCtx(cadir)
|
|
1491
|
-
else:
|
|
1492
|
-
# default aiohttp behavior
|
|
1493
|
-
ssl = None
|
|
1494
|
-
|
|
1495
1509
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1496
1510
|
|
|
1497
1511
|
async with aiohttp.ClientSession(connector=connector, timeout=atimeout) as sess:
|
|
@@ -1556,27 +1570,19 @@ class Axon(s_cell.Cell):
|
|
|
1556
1570
|
}
|
|
1557
1571
|
|
|
1558
1572
|
async def wput(self, sha256, url, params=None, headers=None, method='PUT', ssl=True, timeout=None,
|
|
1559
|
-
filename=None, filemime=None, proxy=None):
|
|
1573
|
+
filename=None, filemime=None, proxy=None, ssl_opts=None):
|
|
1560
1574
|
'''
|
|
1561
1575
|
Stream a blob from the axon as the body of an HTTP request.
|
|
1562
1576
|
'''
|
|
1563
1577
|
if proxy is None:
|
|
1564
|
-
|
|
1578
|
+
proxy = self.conf.get('http:proxy')
|
|
1565
1579
|
|
|
1566
|
-
|
|
1580
|
+
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1567
1581
|
|
|
1568
1582
|
connector = None
|
|
1569
1583
|
if proxy:
|
|
1570
1584
|
connector = aiohttp_socks.ProxyConnector.from_url(proxy)
|
|
1571
1585
|
|
|
1572
|
-
if ssl is False:
|
|
1573
|
-
pass
|
|
1574
|
-
elif cadir:
|
|
1575
|
-
ssl = s_common.getSslCtx(cadir)
|
|
1576
|
-
else:
|
|
1577
|
-
# default aiohttp behavior
|
|
1578
|
-
ssl = None
|
|
1579
|
-
|
|
1580
1586
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1581
1587
|
|
|
1582
1588
|
async with aiohttp.ClientSession(connector=connector, timeout=atimeout) as sess:
|
|
@@ -1638,7 +1644,8 @@ class Axon(s_cell.Cell):
|
|
|
1638
1644
|
|
|
1639
1645
|
return info
|
|
1640
1646
|
|
|
1641
|
-
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
1647
|
+
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
1648
|
+
ssl=True, timeout=None, proxy=None, ssl_opts=None):
|
|
1642
1649
|
'''
|
|
1643
1650
|
Stream a file download directly into the Axon.
|
|
1644
1651
|
|
|
@@ -1652,11 +1659,20 @@ class Axon(s_cell.Cell):
|
|
|
1652
1659
|
ssl (bool): Perform SSL verification.
|
|
1653
1660
|
timeout (int): The timeout of the request, in seconds.
|
|
1654
1661
|
proxy (bool|str|null): Use a specific proxy or disable proxy use.
|
|
1662
|
+
ssl_opts (dict): Additional SSL/TLS options.
|
|
1655
1663
|
|
|
1656
1664
|
Notes:
|
|
1657
1665
|
The response body will be stored, regardless of the response code. The ``ok`` value in the reponse does not
|
|
1658
1666
|
reflect that a status code, such as a 404, was encountered when retrieving the URL.
|
|
1659
1667
|
|
|
1668
|
+
The ssl_opts dictionary may contain the following values::
|
|
1669
|
+
|
|
1670
|
+
{
|
|
1671
|
+
'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl argument.
|
|
1672
|
+
'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
|
|
1673
|
+
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1660
1676
|
The dictionary returned by this may contain the following values::
|
|
1661
1677
|
|
|
1662
1678
|
{
|
|
@@ -1690,7 +1706,7 @@ class Axon(s_cell.Cell):
|
|
|
1690
1706
|
if proxy is None:
|
|
1691
1707
|
proxy = self.conf.get('http:proxy')
|
|
1692
1708
|
|
|
1693
|
-
|
|
1709
|
+
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1694
1710
|
|
|
1695
1711
|
connector = None
|
|
1696
1712
|
if proxy:
|
|
@@ -1698,14 +1714,6 @@ class Axon(s_cell.Cell):
|
|
|
1698
1714
|
|
|
1699
1715
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1700
1716
|
|
|
1701
|
-
if ssl is False:
|
|
1702
|
-
pass
|
|
1703
|
-
elif cadir:
|
|
1704
|
-
ssl = s_common.getSslCtx(cadir)
|
|
1705
|
-
else:
|
|
1706
|
-
# default aiohttp behavior
|
|
1707
|
-
ssl = None
|
|
1708
|
-
|
|
1709
1717
|
async with aiohttp.ClientSession(connector=connector, timeout=atimeout) as sess:
|
|
1710
1718
|
|
|
1711
1719
|
try:
|
synapse/cortex.py
CHANGED
|
@@ -3879,6 +3879,10 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
3879
3879
|
if proxyurl is not None:
|
|
3880
3880
|
conf['http:proxy'] = proxyurl
|
|
3881
3881
|
|
|
3882
|
+
cadir = self.conf.get('tls:ca:dir')
|
|
3883
|
+
if cadir is not None:
|
|
3884
|
+
conf['tls:ca:dir'] = cadir
|
|
3885
|
+
|
|
3882
3886
|
self.axon = await s_axon.Axon.anit(path, conf=conf, parent=self)
|
|
3883
3887
|
self.axoninfo = await self.axon.getCellInfo()
|
|
3884
3888
|
self.axon.onfini(self.axready.clear)
|
synapse/daemon.py
CHANGED
|
@@ -218,7 +218,7 @@ async def t2call(link, meth, args, kwargs):
|
|
|
218
218
|
|
|
219
219
|
class Daemon(s_base.Base):
|
|
220
220
|
|
|
221
|
-
async def __anit__(self, certdir=None):
|
|
221
|
+
async def __anit__(self, certdir=None, ahainfo=None):
|
|
222
222
|
|
|
223
223
|
await s_base.Base.__anit__(self)
|
|
224
224
|
|
|
@@ -227,6 +227,8 @@ class Daemon(s_base.Base):
|
|
|
227
227
|
if certdir is None:
|
|
228
228
|
certdir = s_certdir.getCertDir()
|
|
229
229
|
|
|
230
|
+
self.ahainfo = ahainfo
|
|
231
|
+
|
|
230
232
|
self.certdir = certdir
|
|
231
233
|
self.televers = s_telepath.televers
|
|
232
234
|
|
|
@@ -414,13 +416,16 @@ class Daemon(s_base.Base):
|
|
|
414
416
|
async def _getSharedItem(self, name):
|
|
415
417
|
return self.shared.get(name)
|
|
416
418
|
|
|
417
|
-
async def _onTeleSyn(self, link, mesg):
|
|
419
|
+
async def _onTeleSyn(self, link: s_link.Link, mesg):
|
|
418
420
|
|
|
419
421
|
reply = ('tele:syn', {
|
|
420
422
|
'vers': self.televers,
|
|
421
423
|
'retn': (True, None),
|
|
422
424
|
})
|
|
423
425
|
|
|
426
|
+
if self.ahainfo is not None:
|
|
427
|
+
reply[1]['ahainfo'] = self.ahainfo
|
|
428
|
+
|
|
424
429
|
try:
|
|
425
430
|
|
|
426
431
|
vers = mesg[1].get('vers')
|
synapse/lib/cell.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import gc
|
|
2
2
|
import os
|
|
3
|
+
import ssl
|
|
3
4
|
import copy
|
|
4
5
|
import time
|
|
5
6
|
import fcntl
|
|
@@ -12,6 +13,7 @@ import tarfile
|
|
|
12
13
|
import argparse
|
|
13
14
|
import datetime
|
|
14
15
|
import platform
|
|
16
|
+
import tempfile
|
|
15
17
|
import functools
|
|
16
18
|
import contextlib
|
|
17
19
|
import multiprocessing
|
|
@@ -32,6 +34,7 @@ import synapse.lib.boss as s_boss
|
|
|
32
34
|
import synapse.lib.coro as s_coro
|
|
33
35
|
import synapse.lib.hive as s_hive
|
|
34
36
|
import synapse.lib.link as s_link
|
|
37
|
+
import synapse.lib.cache as s_cache
|
|
35
38
|
import synapse.lib.const as s_const
|
|
36
39
|
import synapse.lib.nexus as s_nexus
|
|
37
40
|
import synapse.lib.queue as s_queue
|
|
@@ -58,6 +61,7 @@ import synapse.tools.backup as s_t_backup
|
|
|
58
61
|
logger = logging.getLogger(__name__)
|
|
59
62
|
|
|
60
63
|
SLAB_MAP_SIZE = 128 * s_const.mebibyte
|
|
64
|
+
SSLCTX_CACHE_SIZE = 64
|
|
61
65
|
|
|
62
66
|
'''
|
|
63
67
|
Base classes for the synapse "cell" microservice architecture.
|
|
@@ -1151,6 +1155,8 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
1151
1155
|
self.usermetadb = self.slab.initdb('user:meta') # useriden + <valu> -> dict valu
|
|
1152
1156
|
self.rolemetadb = self.slab.initdb('role:meta') # roleiden + <valu> -> dict valu
|
|
1153
1157
|
|
|
1158
|
+
self._sslctx_cache = s_cache.FixedCache(self._makeCachedSslCtx, size=SSLCTX_CACHE_SIZE)
|
|
1159
|
+
|
|
1154
1160
|
self.hive = await self._initCellHive()
|
|
1155
1161
|
|
|
1156
1162
|
# self.cellinfo, a HiveDict for general purpose persistent storage
|
|
@@ -2647,8 +2653,8 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2647
2653
|
for name, valu in vals.items():
|
|
2648
2654
|
self.sessstor.set(iden, name, valu)
|
|
2649
2655
|
sess = self.sessions.get(iden)
|
|
2650
|
-
|
|
2651
|
-
sess.info
|
|
2656
|
+
if sess is not None:
|
|
2657
|
+
sess.info.update(vals)
|
|
2652
2658
|
|
|
2653
2659
|
@contextlib.contextmanager
|
|
2654
2660
|
def getTempDir(self):
|
|
@@ -2840,7 +2846,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2840
2846
|
|
|
2841
2847
|
async def _initCellDmon(self):
|
|
2842
2848
|
|
|
2843
|
-
|
|
2849
|
+
ahainfo = {
|
|
2850
|
+
'name': self.ahasvcname
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
self.dmon = await s_daemon.Daemon.anit(ahainfo=ahainfo)
|
|
2844
2854
|
self.dmon.share('*', self)
|
|
2845
2855
|
|
|
2846
2856
|
self.onfini(self.dmon.fini)
|
|
@@ -4338,3 +4348,60 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4338
4348
|
self.slab.delete(key_iden, db=self.apikeydb)
|
|
4339
4349
|
self.slab.delete(lkey, db=self.usermetadb)
|
|
4340
4350
|
await asyncio.sleep(0)
|
|
4351
|
+
|
|
4352
|
+
def _makeCachedSslCtx(self, opts):
|
|
4353
|
+
|
|
4354
|
+
opts = dict(opts)
|
|
4355
|
+
|
|
4356
|
+
cadir = self.conf.get('tls:ca:dir')
|
|
4357
|
+
|
|
4358
|
+
if cadir is not None:
|
|
4359
|
+
sslctx = s_common.getSslCtx(cadir, purpose=ssl.Purpose.SERVER_AUTH)
|
|
4360
|
+
else:
|
|
4361
|
+
sslctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
|
|
4362
|
+
|
|
4363
|
+
if not opts['verify']:
|
|
4364
|
+
sslctx.check_hostname = False
|
|
4365
|
+
sslctx.verify_mode = ssl.CERT_NONE
|
|
4366
|
+
|
|
4367
|
+
if not opts['client_cert']:
|
|
4368
|
+
return sslctx
|
|
4369
|
+
|
|
4370
|
+
client_cert = opts['client_cert'].encode()
|
|
4371
|
+
|
|
4372
|
+
if opts['client_key']:
|
|
4373
|
+
client_key = opts['client_key'].encode()
|
|
4374
|
+
else:
|
|
4375
|
+
client_key = None
|
|
4376
|
+
client_key_path = None
|
|
4377
|
+
|
|
4378
|
+
with self.getTempDir() as tmpdir:
|
|
4379
|
+
|
|
4380
|
+
with tempfile.NamedTemporaryFile(dir=tmpdir, mode='wb', delete=False) as fh:
|
|
4381
|
+
fh.write(client_cert)
|
|
4382
|
+
client_cert_path = fh.name
|
|
4383
|
+
|
|
4384
|
+
if client_key:
|
|
4385
|
+
with tempfile.NamedTemporaryFile(dir=tmpdir, mode='wb', delete=False) as fh:
|
|
4386
|
+
fh.write(client_key)
|
|
4387
|
+
client_key_path = fh.name
|
|
4388
|
+
|
|
4389
|
+
try:
|
|
4390
|
+
sslctx.load_cert_chain(client_cert_path, keyfile=client_key_path)
|
|
4391
|
+
except ssl.SSLError as e:
|
|
4392
|
+
raise s_exc.BadArg(mesg=f'Error loading client cert: {str(e)}') from None
|
|
4393
|
+
|
|
4394
|
+
return sslctx
|
|
4395
|
+
|
|
4396
|
+
def getCachedSslCtx(self, opts=None, verify=None):
|
|
4397
|
+
|
|
4398
|
+
if opts is None:
|
|
4399
|
+
opts = {}
|
|
4400
|
+
|
|
4401
|
+
if verify is not None:
|
|
4402
|
+
opts['verify'] = verify
|
|
4403
|
+
|
|
4404
|
+
opts = s_schemas.reqValidSslCtxOpts(opts)
|
|
4405
|
+
|
|
4406
|
+
key = tuple(sorted(opts.items()))
|
|
4407
|
+
return self._sslctx_cache.get(key)
|
synapse/lib/layer.py
CHANGED
|
@@ -1529,12 +1529,14 @@ class Layer(s_nexus.Pusher):
|
|
|
1529
1529
|
|
|
1530
1530
|
mirror = self.layrinfo.get('mirror')
|
|
1531
1531
|
if mirror is not None:
|
|
1532
|
+
s_common.deprecated('mirror layer configuration option', curv='2.162.0')
|
|
1532
1533
|
conf = {'retrysleep': 2}
|
|
1533
1534
|
self.leader = await s_telepath.Client.anit(mirror, conf=conf)
|
|
1534
1535
|
self.leadtask = self.schedCoro(self._runMirrorLoop())
|
|
1535
1536
|
|
|
1536
1537
|
uplayr = self.layrinfo.get('upstream')
|
|
1537
1538
|
if uplayr is not None:
|
|
1539
|
+
s_common.deprecated('upstream layer configuration option', curv='2.162.0')
|
|
1538
1540
|
if isinstance(uplayr, (tuple, list)):
|
|
1539
1541
|
for layr in uplayr:
|
|
1540
1542
|
await self.initUpstreamSync(layr)
|
|
@@ -4382,9 +4384,14 @@ def getNodeEditPerms(nodeedits):
|
|
|
4382
4384
|
'''
|
|
4383
4385
|
Yields (offs, perm) tuples that can be used in user.allowed()
|
|
4384
4386
|
'''
|
|
4387
|
+
tags = []
|
|
4388
|
+
tagadds = []
|
|
4385
4389
|
|
|
4386
4390
|
for nodeoffs, (buid, form, edits) in enumerate(nodeedits):
|
|
4387
4391
|
|
|
4392
|
+
tags.clear()
|
|
4393
|
+
tagadds.clear()
|
|
4394
|
+
|
|
4388
4395
|
for editoffs, (edit, info, _) in enumerate(edits):
|
|
4389
4396
|
|
|
4390
4397
|
permoffs = (nodeoffs, editoffs)
|
|
@@ -4406,7 +4413,11 @@ def getNodeEditPerms(nodeedits):
|
|
|
4406
4413
|
continue
|
|
4407
4414
|
|
|
4408
4415
|
if edit == EDIT_TAG_SET:
|
|
4409
|
-
|
|
4416
|
+
if info[1] != (None, None):
|
|
4417
|
+
tagadds.append(info[0])
|
|
4418
|
+
yield (permoffs, ('node', 'tag', 'add', *info[0].split('.')))
|
|
4419
|
+
else:
|
|
4420
|
+
tags.append((len(info[0]), editoffs, info[0]))
|
|
4410
4421
|
continue
|
|
4411
4422
|
|
|
4412
4423
|
if edit == EDIT_TAG_DEL:
|
|
@@ -4436,3 +4447,11 @@ def getNodeEditPerms(nodeedits):
|
|
|
4436
4447
|
if edit == EDIT_EDGE_DEL:
|
|
4437
4448
|
yield (permoffs, ('node', 'edge', 'del', info[0]))
|
|
4438
4449
|
continue
|
|
4450
|
+
|
|
4451
|
+
for _, editoffs, tag in sorted(tags, reverse=True):
|
|
4452
|
+
look = tag + '.'
|
|
4453
|
+
if any([tagadd.startswith(look) for tagadd in tagadds]):
|
|
4454
|
+
continue
|
|
4455
|
+
|
|
4456
|
+
yield ((nodeoffs, editoffs), ('node', 'tag', 'add', *tag.split('.')))
|
|
4457
|
+
tagadds.append(tag)
|
synapse/lib/oauth.py
CHANGED
|
@@ -230,13 +230,7 @@ class OAuthMixin(s_nexus.Pusher):
|
|
|
230
230
|
|
|
231
231
|
timeout = aiohttp.ClientTimeout(total=DEFAULT_TIMEOUT)
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
if ssl_verify is False:
|
|
235
|
-
ssl = False
|
|
236
|
-
elif cadir:
|
|
237
|
-
ssl = s_common.getSslCtx(cadir)
|
|
238
|
-
else:
|
|
239
|
-
ssl = None
|
|
233
|
+
ssl = self.getCachedSslCtx(verify=ssl_verify)
|
|
240
234
|
|
|
241
235
|
async with aiohttp.ClientSession(timeout=timeout) as sess:
|
|
242
236
|
|
synapse/lib/rstorm.py
CHANGED
|
@@ -29,6 +29,7 @@ re_directive = regex.compile(r'^\.\.\s(storm.*|[^:])::(?:\s(.*)$|$)')
|
|
|
29
29
|
|
|
30
30
|
logger = logging.getLogger(__name__)
|
|
31
31
|
|
|
32
|
+
ONLOAD_TIMEOUT = int(os.getenv('SYNDEV_PKG_LOAD_TIMEOUT', 30)) # seconds
|
|
32
33
|
|
|
33
34
|
class OutPutRst(s_output.OutPutStr):
|
|
34
35
|
'''
|
|
@@ -413,8 +414,17 @@ class StormRst(s_base.Base):
|
|
|
413
414
|
core = self._reqCore()
|
|
414
415
|
|
|
415
416
|
pkg = s_genpkg.loadPkgProto(text)
|
|
417
|
+
|
|
418
|
+
if pkg.get('onload') is not None:
|
|
419
|
+
waiter = core.waiter(1, 'core:pkg:onload:complete')
|
|
420
|
+
else:
|
|
421
|
+
waiter = None
|
|
422
|
+
|
|
416
423
|
await core.addStormPkg(pkg)
|
|
417
424
|
|
|
425
|
+
if waiter is not None and not await waiter.wait(timeout=ONLOAD_TIMEOUT):
|
|
426
|
+
raise s_exc.SynErr(mesg=f'Package onload failed to run for {pkg.get("name")}')
|
|
427
|
+
|
|
418
428
|
async def _handleStormPre(self, text):
|
|
419
429
|
'''
|
|
420
430
|
Run a Storm query to prepare the Cortex without output.
|
|
@@ -453,6 +463,9 @@ class StormRst(s_base.Base):
|
|
|
453
463
|
|
|
454
464
|
svc = await self._getCell(ctor, conf=svcconf)
|
|
455
465
|
|
|
466
|
+
onloadcnt = len([p for p in svc.cellapi._storm_svc_pkgs if p.get('onload') is not None])
|
|
467
|
+
waiter = core.waiter(onloadcnt, 'core:pkg:onload:complete') if onloadcnt else None
|
|
468
|
+
|
|
456
469
|
svc.dmon.share('svc', svc)
|
|
457
470
|
root = await svc.auth.getUserByName('root')
|
|
458
471
|
await root.setPasswd('root')
|
|
@@ -463,6 +476,9 @@ class StormRst(s_base.Base):
|
|
|
463
476
|
await core.nodes(f'service.add {svcname} {surl}')
|
|
464
477
|
await core.nodes(f'$lib.service.wait({svcname})')
|
|
465
478
|
|
|
479
|
+
if waiter is not None and not await waiter.wait(timeout=ONLOAD_TIMEOUT):
|
|
480
|
+
raise s_exc.SynErr(mesg=f'Package onload failed to run for service {svcname}')
|
|
481
|
+
|
|
466
482
|
async def _handleStormFail(self, text):
|
|
467
483
|
valu = json.loads(text)
|
|
468
484
|
assert valu in (True, False), f'storm-fail must be a boolean: {text}'
|
synapse/lib/schemas.py
CHANGED
|
@@ -263,3 +263,13 @@ _cellUserApiKeySchema = {
|
|
|
263
263
|
],
|
|
264
264
|
}
|
|
265
265
|
reqValidUserApiKeyDef = s_config.getJsValidator(_cellUserApiKeySchema)
|
|
266
|
+
|
|
267
|
+
reqValidSslCtxOpts = s_config.getJsValidator({
|
|
268
|
+
'type': 'object',
|
|
269
|
+
'properties': {
|
|
270
|
+
'verify': {'type': 'boolean', 'default': True},
|
|
271
|
+
'client_cert': {'type': ['string', 'null'], 'default': None},
|
|
272
|
+
'client_key': {'type': ['string', 'null'], 'default': None},
|
|
273
|
+
},
|
|
274
|
+
'additionalProperties': False,
|
|
275
|
+
})
|
synapse/lib/storm.py
CHANGED
|
@@ -181,7 +181,7 @@ wgetdescr = '''Retrieve bytes from a URL and store them in the axon. Yields inet
|
|
|
181
181
|
Examples:
|
|
182
182
|
|
|
183
183
|
# Specify custom headers and parameters
|
|
184
|
-
inet:url=https://vertex.link/foo.bar.txt | wget --headers
|
|
184
|
+
inet:url=https://vertex.link/foo.bar.txt | wget --headers ({"User-Agent": "Foo/Bar"}) --params ({"clientid": "42"})
|
|
185
185
|
|
|
186
186
|
# Download multiple URL targets without inbound nodes
|
|
187
187
|
wget https://vertex.link https://vtx.lk
|
|
@@ -3787,7 +3787,23 @@ class MergeCmd(Cmd):
|
|
|
3787
3787
|
runt.confirmPropDel(prop, layriden=layr0)
|
|
3788
3788
|
runt.confirmPropSet(prop, layriden=layr1)
|
|
3789
3789
|
|
|
3790
|
+
tags = []
|
|
3791
|
+
tagadds = []
|
|
3790
3792
|
for tag, valu in sode.get('tags', {}).items():
|
|
3793
|
+
if valu != (None, None):
|
|
3794
|
+
tagadds.append(tag)
|
|
3795
|
+
tagperm = tuple(tag.split('.'))
|
|
3796
|
+
runt.confirm(('node', 'tag', 'del') + tagperm, gateiden=layr0)
|
|
3797
|
+
runt.confirm(('node', 'tag', 'add') + tagperm, gateiden=layr1)
|
|
3798
|
+
else:
|
|
3799
|
+
tags.append((len(tag), tag))
|
|
3800
|
+
|
|
3801
|
+
for _, tag in sorted(tags, reverse=True):
|
|
3802
|
+
look = tag + '.'
|
|
3803
|
+
if any([tagadd.startswith(look) for tagadd in tagadds]):
|
|
3804
|
+
continue
|
|
3805
|
+
|
|
3806
|
+
tagadds.append(tag)
|
|
3791
3807
|
tagperm = tuple(tag.split('.'))
|
|
3792
3808
|
runt.confirm(('node', 'tag', 'del') + tagperm, gateiden=layr0)
|
|
3793
3809
|
runt.confirm(('node', 'tag', 'add') + tagperm, gateiden=layr1)
|