synapse 2.176.0__py311-none-any.whl → 2.178.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 +24 -9
- synapse/cortex.py +337 -172
- synapse/cryotank.py +46 -37
- synapse/datamodel.py +17 -4
- synapse/exc.py +19 -0
- synapse/lib/agenda.py +7 -13
- synapse/lib/aha.py +361 -88
- synapse/lib/auth.py +1520 -0
- synapse/lib/base.py +27 -9
- synapse/lib/cell.py +422 -163
- synapse/lib/config.py +15 -11
- synapse/lib/coro.py +13 -0
- synapse/lib/grammar.py +5 -0
- synapse/lib/hive.py +24 -3
- synapse/lib/hiveauth.py +6 -32
- synapse/lib/layer.py +7 -9
- synapse/lib/link.py +22 -18
- synapse/lib/lmdbslab.py +152 -3
- synapse/lib/modelrev.py +1 -1
- synapse/lib/nexus.py +24 -12
- synapse/lib/schemas.py +136 -0
- synapse/lib/storm.py +61 -29
- synapse/lib/stormlib/aha.py +1 -1
- synapse/lib/stormlib/auth.py +185 -10
- synapse/lib/stormlib/cortex.py +16 -5
- synapse/lib/stormlib/gen.py +80 -0
- synapse/lib/stormlib/imap.py +6 -2
- synapse/lib/stormlib/model.py +55 -0
- synapse/lib/stormlib/modelext.py +60 -0
- synapse/lib/stormlib/smtp.py +12 -2
- synapse/lib/stormlib/tabular.py +212 -0
- synapse/lib/stormtypes.py +14 -1
- synapse/lib/trigger.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -28
- synapse/models/base.py +7 -0
- synapse/models/biz.py +4 -0
- synapse/models/files.py +8 -1
- synapse/models/inet.py +8 -0
- synapse/telepath.py +32 -17
- synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
- synapse/tests/files/aha/certs/cas/synapse.key +51 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
- synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
- synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
- synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
- synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
- synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
- synapse/tests/files/rstorm/testsvc.py +1 -1
- synapse/tests/test_axon.py +8 -5
- synapse/tests/test_cortex.py +149 -141
- synapse/tests/test_cryotank.py +4 -4
- synapse/tests/test_datamodel.py +7 -0
- synapse/tests/test_lib_agenda.py +10 -3
- synapse/tests/test_lib_aha.py +336 -490
- synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
- synapse/tests/test_lib_base.py +20 -0
- synapse/tests/test_lib_cell.py +210 -30
- synapse/tests/test_lib_config.py +4 -3
- synapse/tests/test_lib_httpapi.py +18 -14
- synapse/tests/test_lib_layer.py +33 -33
- synapse/tests/test_lib_link.py +42 -1
- synapse/tests/test_lib_lmdbslab.py +68 -0
- synapse/tests/test_lib_nexus.py +12 -4
- synapse/tests/test_lib_node.py +0 -7
- synapse/tests/test_lib_storm.py +45 -0
- synapse/tests/test_lib_stormlib_aha.py +35 -36
- synapse/tests/test_lib_stormlib_auth.py +21 -0
- synapse/tests/test_lib_stormlib_cell.py +4 -15
- synapse/tests/test_lib_stormlib_cortex.py +12 -12
- synapse/tests/test_lib_stormlib_gen.py +99 -0
- synapse/tests/test_lib_stormlib_imap.py +14 -3
- synapse/tests/test_lib_stormlib_model.py +108 -0
- synapse/tests/test_lib_stormlib_modelext.py +64 -0
- synapse/tests/test_lib_stormlib_smtp.py +51 -0
- synapse/tests/test_lib_stormlib_tabular.py +226 -0
- synapse/tests/test_lib_stormsvc.py +4 -1
- synapse/tests/test_lib_stormtypes.py +10 -0
- synapse/tests/test_model_base.py +3 -0
- synapse/tests/test_model_biz.py +3 -0
- synapse/tests/test_model_files.py +12 -2
- synapse/tests/test_model_inet.py +24 -0
- synapse/tests/test_tools_aha.py +78 -101
- synapse/tests/test_tools_changelog.py +196 -0
- synapse/tests/test_tools_healthcheck.py +4 -3
- synapse/tests/utils.py +87 -121
- synapse/tools/aha/clone.py +50 -0
- synapse/tools/aha/enroll.py +2 -1
- synapse/tools/backup.py +2 -2
- synapse/tools/changelog.py +776 -15
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/METADATA +48 -48
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/RECORD +95 -82
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/WHEEL +1 -1
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/LICENSE +0 -0
- {synapse-2.176.0.dist-info → synapse-2.178.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormlib/auth.py
CHANGED
|
@@ -633,7 +633,7 @@ class UserProfile(s_stormtypes.Prim):
|
|
|
633
633
|
async def deref(self, name):
|
|
634
634
|
name = await s_stormtypes.tostr(name)
|
|
635
635
|
self.runt.confirm(('auth', 'user', 'get', 'profile', name))
|
|
636
|
-
return
|
|
636
|
+
return await self.runt.snap.core.getUserProfInfo(self.valu, name)
|
|
637
637
|
|
|
638
638
|
async def setitem(self, name, valu):
|
|
639
639
|
name = await s_stormtypes.tostr(name)
|
|
@@ -654,7 +654,7 @@ class UserProfile(s_stormtypes.Prim):
|
|
|
654
654
|
|
|
655
655
|
async def value(self):
|
|
656
656
|
self.runt.confirm(('auth', 'user', 'get', 'profile'))
|
|
657
|
-
return
|
|
657
|
+
return await self.runt.snap.core.getUserProfile(self.valu)
|
|
658
658
|
|
|
659
659
|
@s_stormtypes.registry.registerType
|
|
660
660
|
class UserJson(s_stormtypes.Prim):
|
|
@@ -807,7 +807,7 @@ class UserVars(s_stormtypes.Prim):
|
|
|
807
807
|
|
|
808
808
|
async def deref(self, name):
|
|
809
809
|
name = await s_stormtypes.tostr(name)
|
|
810
|
-
return
|
|
810
|
+
return await self.runt.snap.core.getUserVarValu(self.valu, name)
|
|
811
811
|
|
|
812
812
|
async def setitem(self, name, valu):
|
|
813
813
|
name = await s_stormtypes.tostr(name)
|
|
@@ -821,7 +821,7 @@ class UserVars(s_stormtypes.Prim):
|
|
|
821
821
|
|
|
822
822
|
async def iter(self):
|
|
823
823
|
async for name, valu in self.runt.snap.core.iterUserVars(self.valu):
|
|
824
|
-
yield name,
|
|
824
|
+
yield name, valu
|
|
825
825
|
await asyncio.sleep(0)
|
|
826
826
|
|
|
827
827
|
@s_stormtypes.registry.registerType
|
|
@@ -1596,6 +1596,181 @@ class LibAuth(s_stormtypes.Lib):
|
|
|
1596
1596
|
perm = await s_stormtypes.toprim(perm)
|
|
1597
1597
|
return self.runt.snap.core.getPermDef(perm)
|
|
1598
1598
|
|
|
1599
|
+
@s_stormtypes.registry.registerType
|
|
1600
|
+
class StormUserVarsDict(s_stormtypes.Prim):
|
|
1601
|
+
'''
|
|
1602
|
+
A Storm Primitive that maps the HiveDict interface to a user vars dictionary.
|
|
1603
|
+
'''
|
|
1604
|
+
_storm_locals = (
|
|
1605
|
+
{'name': 'get', 'desc': 'Get the value for a user var.',
|
|
1606
|
+
'type': {'type': 'function', '_funcname': '_get',
|
|
1607
|
+
'args': (
|
|
1608
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the var.', },
|
|
1609
|
+
{'name': 'default', 'type': 'prim', 'default': None,
|
|
1610
|
+
'desc': 'The default value to return if not set.', },
|
|
1611
|
+
),
|
|
1612
|
+
'returns': {'type': 'prim', 'desc': 'The requested value.', }}},
|
|
1613
|
+
{'name': 'pop', 'desc': 'Remove a user var value.',
|
|
1614
|
+
'type': {'type': 'function', '_funcname': '_pop',
|
|
1615
|
+
'args': (
|
|
1616
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the var.', },
|
|
1617
|
+
{'name': 'default', 'type': 'prim', 'default': None,
|
|
1618
|
+
'desc': 'The default value to return if not set.', },
|
|
1619
|
+
),
|
|
1620
|
+
'returns': {'type': 'prim', 'desc': 'The requested value.', }}},
|
|
1621
|
+
{'name': 'set', 'desc': 'Set a user var value.',
|
|
1622
|
+
'type': {'type': 'function', '_funcname': '_set',
|
|
1623
|
+
'args': (
|
|
1624
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the var to set.', },
|
|
1625
|
+
{'name': 'valu', 'type': 'prim', 'desc': 'The value to store.', },
|
|
1626
|
+
),
|
|
1627
|
+
'returns': {'type': ['null', 'prim'],
|
|
1628
|
+
'desc': 'Old value of the var if it was previously set, or none.', }}},
|
|
1629
|
+
{'name': 'list', 'desc': 'List the vars and their values.',
|
|
1630
|
+
'type': {'type': 'function', '_funcname': '_list',
|
|
1631
|
+
'returns': {'type': 'list', 'desc': 'A list of tuples containing var, value pairs.', }}},
|
|
1632
|
+
)
|
|
1633
|
+
_storm_typename = 'user:vars:dict'
|
|
1634
|
+
_ismutable = True
|
|
1635
|
+
|
|
1636
|
+
def __init__(self, runt, valu, path=None):
|
|
1637
|
+
s_stormtypes.Prim.__init__(self, valu, path=path)
|
|
1638
|
+
self.runt = runt
|
|
1639
|
+
self.locls.update(self.getObjLocals())
|
|
1640
|
+
|
|
1641
|
+
def getObjLocals(self):
|
|
1642
|
+
return {
|
|
1643
|
+
'get': self._get,
|
|
1644
|
+
'pop': self._pop,
|
|
1645
|
+
'set': self._set,
|
|
1646
|
+
'list': self._list,
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
1650
|
+
async def _get(self, name, default=None):
|
|
1651
|
+
name = await s_stormtypes.tostr(name)
|
|
1652
|
+
return await self.runt.snap.core.getUserVarValu(self.valu, name, default=default)
|
|
1653
|
+
|
|
1654
|
+
async def _pop(self, name, default=None):
|
|
1655
|
+
name = await s_stormtypes.tostr(name)
|
|
1656
|
+
return await self.runt.snap.core.popUserVarValu(self.valu, name, default=default)
|
|
1657
|
+
|
|
1658
|
+
async def _set(self, name, valu):
|
|
1659
|
+
if not isinstance(name, str):
|
|
1660
|
+
mesg = 'The name of a variable must be a string.'
|
|
1661
|
+
raise s_exc.StormRuntimeError(mesg=mesg, name=name)
|
|
1662
|
+
|
|
1663
|
+
name = await s_stormtypes.tostr(name)
|
|
1664
|
+
oldv = await self.runt.snap.core.getUserVarValu(self.valu, name)
|
|
1665
|
+
|
|
1666
|
+
valu = await s_stormtypes.toprim(valu)
|
|
1667
|
+
|
|
1668
|
+
await self.runt.snap.core.setUserVarValu(self.valu, name, valu)
|
|
1669
|
+
return oldv
|
|
1670
|
+
|
|
1671
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
1672
|
+
async def _list(self):
|
|
1673
|
+
valu = await self.value()
|
|
1674
|
+
return list(valu.items())
|
|
1675
|
+
|
|
1676
|
+
async def iter(self):
|
|
1677
|
+
async for name, valu in self.runt.snap.core.iterUserVars(self.valu):
|
|
1678
|
+
yield name, valu
|
|
1679
|
+
await asyncio.sleep(0)
|
|
1680
|
+
|
|
1681
|
+
async def value(self):
|
|
1682
|
+
varz = {}
|
|
1683
|
+
async for key, valu in self.runt.snap.core.iterUserVars(self.valu):
|
|
1684
|
+
varz[key] = valu
|
|
1685
|
+
await asyncio.sleep(0)
|
|
1686
|
+
|
|
1687
|
+
return varz
|
|
1688
|
+
|
|
1689
|
+
@s_stormtypes.registry.registerType
|
|
1690
|
+
class StormUserProfileDict(s_stormtypes.Prim):
|
|
1691
|
+
'''
|
|
1692
|
+
A Storm Primitive that maps the HiveDict interface to a user profile dictionary.
|
|
1693
|
+
'''
|
|
1694
|
+
_storm_locals = (
|
|
1695
|
+
{'name': 'get', 'desc': 'Get a user profile value.',
|
|
1696
|
+
'type': {'type': 'function', '_funcname': '_get',
|
|
1697
|
+
'args': (
|
|
1698
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the user profile value.', },
|
|
1699
|
+
{'name': 'default', 'type': 'prim', 'default': None,
|
|
1700
|
+
'desc': 'The default value to return if not set.', },
|
|
1701
|
+
),
|
|
1702
|
+
'returns': {'type': 'prim', 'desc': 'The requested value.', }}},
|
|
1703
|
+
{'name': 'pop', 'desc': 'Remove a user profile value.',
|
|
1704
|
+
'type': {'type': 'function', '_funcname': '_pop',
|
|
1705
|
+
'args': (
|
|
1706
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the user profile value.', },
|
|
1707
|
+
{'name': 'default', 'type': 'prim', 'default': None,
|
|
1708
|
+
'desc': 'The default value to return if not set.', },
|
|
1709
|
+
),
|
|
1710
|
+
'returns': {'type': 'prim', 'desc': 'The requested value.', }}},
|
|
1711
|
+
{'name': 'set', 'desc': 'Set a user profile value.',
|
|
1712
|
+
'type': {'type': 'function', '_funcname': '_set',
|
|
1713
|
+
'args': (
|
|
1714
|
+
{'name': 'name', 'type': 'str', 'desc': 'The name of the user profile value to set.', },
|
|
1715
|
+
{'name': 'valu', 'type': 'prim', 'desc': 'The value to store.', },
|
|
1716
|
+
),
|
|
1717
|
+
'returns': {'type': ['null', 'prim'],
|
|
1718
|
+
'desc': 'Old value if it was previously set, or none.', }}},
|
|
1719
|
+
{'name': 'list', 'desc': 'List the user profile vars and their values.',
|
|
1720
|
+
'type': {'type': 'function', '_funcname': '_list',
|
|
1721
|
+
'returns': {'type': 'list', 'desc': 'A list of tuples containing var, value pairs.', }}},
|
|
1722
|
+
)
|
|
1723
|
+
_storm_typename = 'user:profile:dict'
|
|
1724
|
+
_ismutable = True
|
|
1725
|
+
|
|
1726
|
+
def __init__(self, runt, valu, path=None):
|
|
1727
|
+
s_stormtypes.Prim.__init__(self, valu, path=path)
|
|
1728
|
+
self.runt = runt
|
|
1729
|
+
self.locls.update(self.getObjLocals())
|
|
1730
|
+
|
|
1731
|
+
def getObjLocals(self):
|
|
1732
|
+
return {
|
|
1733
|
+
'get': self._get,
|
|
1734
|
+
'pop': self._pop,
|
|
1735
|
+
'set': self._set,
|
|
1736
|
+
'list': self._list,
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
1740
|
+
async def _get(self, name, default=None):
|
|
1741
|
+
name = await s_stormtypes.tostr(name)
|
|
1742
|
+
return await self.runt.snap.core.getUserProfInfo(self.valu, name, default=default)
|
|
1743
|
+
|
|
1744
|
+
async def _pop(self, name, default=None):
|
|
1745
|
+
name = await s_stormtypes.tostr(name)
|
|
1746
|
+
return await self.runt.snap.core.popUserProfInfo(self.valu, name, default=default)
|
|
1747
|
+
|
|
1748
|
+
async def _set(self, name, valu):
|
|
1749
|
+
if not isinstance(name, str):
|
|
1750
|
+
mesg = 'The name of a variable must be a string.'
|
|
1751
|
+
raise s_exc.StormRuntimeError(mesg=mesg, name=name)
|
|
1752
|
+
|
|
1753
|
+
name = await s_stormtypes.tostr(name)
|
|
1754
|
+
oldv = await self.runt.snap.core.getUserProfInfo(self.valu, name)
|
|
1755
|
+
|
|
1756
|
+
valu = await s_stormtypes.toprim(valu)
|
|
1757
|
+
|
|
1758
|
+
await self.runt.snap.core.setUserProfInfo(self.valu, name, valu)
|
|
1759
|
+
return oldv
|
|
1760
|
+
|
|
1761
|
+
@s_stormtypes.stormfunc(readonly=True)
|
|
1762
|
+
async def _list(self):
|
|
1763
|
+
valu = await self.value()
|
|
1764
|
+
return list(valu.items())
|
|
1765
|
+
|
|
1766
|
+
async def iter(self):
|
|
1767
|
+
async for name, valu in self.runt.snap.core.iterUserProfInfo(self.valu):
|
|
1768
|
+
yield name, valu
|
|
1769
|
+
await asyncio.sleep(0)
|
|
1770
|
+
|
|
1771
|
+
async def value(self):
|
|
1772
|
+
return await self.runt.snap.core.getUserProfile(self.valu)
|
|
1773
|
+
|
|
1599
1774
|
@s_stormtypes.registry.registerLib
|
|
1600
1775
|
class LibUser(s_stormtypes.Lib):
|
|
1601
1776
|
'''
|
|
@@ -1614,10 +1789,10 @@ class LibUser(s_stormtypes.Lib):
|
|
|
1614
1789
|
),
|
|
1615
1790
|
'returns': {'type': 'boolean',
|
|
1616
1791
|
'desc': 'True if the user has the requested permission, false otherwise.', }}},
|
|
1617
|
-
{'name': 'vars', 'desc': "Get a
|
|
1618
|
-
'type': '
|
|
1619
|
-
{'name': 'profile', 'desc': "Get a
|
|
1620
|
-
'type': '
|
|
1792
|
+
{'name': 'vars', 'desc': "Get a dictionary representing the current user's persistent variables.",
|
|
1793
|
+
'type': 'auth:user:vars', },
|
|
1794
|
+
{'name': 'profile', 'desc': "Get a dictionary representing the current user's profile information.",
|
|
1795
|
+
'type': 'auth:user:profile', },
|
|
1621
1796
|
{'name': 'iden', 'desc': 'The user GUID for the current storm user.', 'type': 'str'},
|
|
1622
1797
|
)
|
|
1623
1798
|
_storm_lib_path = ('user', )
|
|
@@ -1632,9 +1807,9 @@ class LibUser(s_stormtypes.Lib):
|
|
|
1632
1807
|
def addLibFuncs(self):
|
|
1633
1808
|
super().addLibFuncs()
|
|
1634
1809
|
self.locls.update({
|
|
1635
|
-
'vars':
|
|
1810
|
+
'vars': StormUserVarsDict(self.runt, self.runt.user.iden),
|
|
1636
1811
|
'json': UserJson(self.runt, self.runt.user.iden),
|
|
1637
|
-
'profile':
|
|
1812
|
+
'profile': StormUserProfileDict(self.runt, self.runt.user.iden),
|
|
1638
1813
|
})
|
|
1639
1814
|
|
|
1640
1815
|
@s_stormtypes.stormfunc(readonly=True)
|
synapse/lib/stormlib/cortex.py
CHANGED
|
@@ -20,8 +20,21 @@ stormcmds = [
|
|
|
20
20
|
'storm': '''
|
|
21
21
|
$apis = $lib.cortex.httpapi.list()
|
|
22
22
|
if $apis {
|
|
23
|
-
$
|
|
24
|
-
|
|
23
|
+
$config = (({
|
|
24
|
+
"separators": {
|
|
25
|
+
'data:row': ''
|
|
26
|
+
},
|
|
27
|
+
"columns": [
|
|
28
|
+
{'name': 'order', 'width': 5},
|
|
29
|
+
{'name': 'iden', 'width': 32},
|
|
30
|
+
{'name': 'owner', 'width': 20},
|
|
31
|
+
{'name': 'auth', 'width': 5},
|
|
32
|
+
{'name': 'runas', 'width': 6},
|
|
33
|
+
{'name': 'path'},
|
|
34
|
+
]
|
|
35
|
+
}))
|
|
36
|
+
$printer = $lib.tabular.printer($config)
|
|
37
|
+
$lib.print($printer.header())
|
|
25
38
|
for ($n, $api) in $lib.iters.enum($apis) {
|
|
26
39
|
try {
|
|
27
40
|
$user = $api.owner.name
|
|
@@ -29,9 +42,7 @@ stormcmds = [
|
|
|
29
42
|
$user = `No user found ({$err.info.user})`
|
|
30
43
|
}
|
|
31
44
|
$auth = `{$api.authenticated}`
|
|
32
|
-
$
|
|
33
|
-
$mesg=`{$order.ljust(5)} {$api.iden} {$user.ljust(20)} {$auth.ljust(5)} {$api.runas.ljust(6)} {$api.path}`
|
|
34
|
-
$lib.print($mesg)
|
|
45
|
+
$lib.print($printer.row(($n, $api.iden, $user, $auth, $api.runas, $api.path)))
|
|
35
46
|
}
|
|
36
47
|
} else {
|
|
37
48
|
$lib.print('No Extended HTTP API endpoints are registered.')
|
synapse/lib/stormlib/gen.py
CHANGED
|
@@ -136,6 +136,34 @@ class LibGen(s_stormtypes.Lib):
|
|
|
136
136
|
{'name': 'name', 'type': 'str', 'desc': 'The name of the place.'},
|
|
137
137
|
),
|
|
138
138
|
'returns': {'type': 'node', 'desc': 'A geo:place node with the given name.'}}},
|
|
139
|
+
{'name': 'fileBytesBySha256',
|
|
140
|
+
'desc': 'Returns a file:bytes node by SHA256, adding the node if it does not exist.',
|
|
141
|
+
'type': {'type': 'function', '_funcname': '_storm_query',
|
|
142
|
+
'args': (
|
|
143
|
+
{'name': 'sha256', 'type': ['str', 'hash:sha256'], 'desc': 'The SHA256 fingerprint for the file:bytes node.'},
|
|
144
|
+
{'name': 'try', 'type': 'boolean', 'default': False,
|
|
145
|
+
'desc': 'Type normalization will fail silently instead of raising an exception.'},
|
|
146
|
+
),
|
|
147
|
+
'returns': {'type': 'node', 'desc': 'A file:bytes node with the given SHA256.'}}},
|
|
148
|
+
{'name': 'cryptoX509CertBySha256',
|
|
149
|
+
'desc': 'Returns a crypto:x509:cert node by SHA256, adding the node if it does not exist.',
|
|
150
|
+
'type': {'type': 'function', '_funcname': '_storm_query',
|
|
151
|
+
'args': (
|
|
152
|
+
{'name': 'sha256', 'type': ['str', 'hash:sha256'], 'desc': 'The SHA256 fingerprint for the certificate.'},
|
|
153
|
+
{'name': 'try', 'type': 'boolean', 'default': False,
|
|
154
|
+
'desc': 'Type normalization will fail silently instead of raising an exception.'},
|
|
155
|
+
),
|
|
156
|
+
'returns': {'type': 'node', 'desc': 'A crypto:x509:cert node with the given SHA256.'}}},
|
|
157
|
+
{'name': 'inetTlsServerCertByServerAndSha256',
|
|
158
|
+
'desc': 'Returns an inet:tls:servercert node by server and SHA256, adding the node if it does not exist.',
|
|
159
|
+
'type': {'type': 'function', '_funcname': '_storm_query',
|
|
160
|
+
'args': (
|
|
161
|
+
{'name': 'server', 'type': ['str', 'inet:server'], 'desc': 'The server associated with the x509 certificate.'},
|
|
162
|
+
{'name': 'sha256', 'type': ['str', 'hash:sha256'], 'desc': 'The SHA256 fingerprint for the certificate.'},
|
|
163
|
+
{'name': 'try', 'type': 'boolean', 'default': False,
|
|
164
|
+
'desc': 'Type normalization will fail silently instead of raising an exception.'},
|
|
165
|
+
),
|
|
166
|
+
'returns': {'type': 'node', 'desc': 'An inet:tls:servercert node with the given server and SHA256.'}}},
|
|
139
167
|
)
|
|
140
168
|
_storm_lib_path = ('gen',)
|
|
141
169
|
|
|
@@ -425,6 +453,58 @@ class LibGen(s_stormtypes.Lib):
|
|
|
425
453
|
[ geo:place=(gen, name, $geoname) :name=$geoname ]
|
|
426
454
|
return($node)
|
|
427
455
|
}
|
|
456
|
+
|
|
457
|
+
function fileBytesBySha256(sha256, try=$lib.false) {
|
|
458
|
+
($ok, $sha256) = $__maybeCast($try, hash:sha256, $sha256)
|
|
459
|
+
if (not $ok) { return() }
|
|
460
|
+
|
|
461
|
+
file:bytes=$sha256
|
|
462
|
+
return($node)
|
|
463
|
+
|
|
464
|
+
file:bytes:sha256=$sha256
|
|
465
|
+
return($node)
|
|
466
|
+
|
|
467
|
+
[ file:bytes=$sha256 ]
|
|
468
|
+
return($node)
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function cryptoX509CertBySha256(sha256, try=$lib.false) {
|
|
472
|
+
($ok, $sha256) = $__maybeCast($try, hash:sha256, $sha256)
|
|
473
|
+
if (not $ok) { return() }
|
|
474
|
+
|
|
475
|
+
$guid = $lib.guid(valu=$sha256)
|
|
476
|
+
|
|
477
|
+
// Try to lift crypto:x509:cert by guid
|
|
478
|
+
crypto:x509:cert=$guid
|
|
479
|
+
return($node)
|
|
480
|
+
|
|
481
|
+
// Try to lift crypto:x509:cert by sha256
|
|
482
|
+
crypto:x509:cert:sha256=$sha256
|
|
483
|
+
return($node)
|
|
484
|
+
|
|
485
|
+
// Try to lift crypto:x509:cert by file
|
|
486
|
+
file:bytes:sha256=$sha256 -> crypto:x509:cert:file
|
|
487
|
+
{ -:sha256 [ :sha256 = $sha256 ] }
|
|
488
|
+
return($node)
|
|
489
|
+
|
|
490
|
+
// Create a new crypto:x509:cert with file and sha256
|
|
491
|
+
[ crypto:x509:cert=$guid
|
|
492
|
+
:file = $fileBytesBySha256($sha256)
|
|
493
|
+
:sha256 = $sha256
|
|
494
|
+
]
|
|
495
|
+
return($node)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function inetTlsServerCertByServerAndSha256(server, sha256, try=$lib.false) {
|
|
499
|
+
($ok, $server) = $__maybeCast($try, inet:server, $server)
|
|
500
|
+
if (not $ok) { return() }
|
|
501
|
+
|
|
502
|
+
$crypto = $cryptoX509CertBySha256($sha256, try=$try)
|
|
503
|
+
if (not $crypto) { return() }
|
|
504
|
+
|
|
505
|
+
[ inet:tls:servercert=($server, $crypto) ]
|
|
506
|
+
return($node)
|
|
507
|
+
}
|
|
428
508
|
'''
|
|
429
509
|
|
|
430
510
|
stormcmds = (
|
synapse/lib/stormlib/imap.py
CHANGED
|
@@ -50,6 +50,8 @@ class ImapLib(s_stormtypes.Lib):
|
|
|
50
50
|
'desc': 'The time to wait for all commands on the server to execute.'},
|
|
51
51
|
{'type': 'bool', 'name': 'ssl', 'default': True,
|
|
52
52
|
'desc': 'Use SSL to connect to the IMAP server.'},
|
|
53
|
+
{'type': 'bool', 'name': 'ssl_verify', 'default': True,
|
|
54
|
+
'desc': 'Perform SSL/TLS verification.'},
|
|
53
55
|
),
|
|
54
56
|
'returns': {
|
|
55
57
|
'type': 'inet:imap:server',
|
|
@@ -69,17 +71,19 @@ class ImapLib(s_stormtypes.Lib):
|
|
|
69
71
|
'connect': self.connect,
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
async def connect(self, host, port=993, timeout=30, ssl=True):
|
|
74
|
+
async def connect(self, host, port=993, timeout=30, ssl=True, ssl_verify=True):
|
|
73
75
|
|
|
74
76
|
self.runt.confirm(('storm', 'inet', 'imap', 'connect'))
|
|
75
77
|
|
|
76
78
|
ssl = await s_stormtypes.tobool(ssl)
|
|
77
79
|
host = await s_stormtypes.tostr(host)
|
|
78
80
|
port = await s_stormtypes.toint(port)
|
|
81
|
+
ssl_verify = await s_stormtypes.tobool(ssl_verify)
|
|
79
82
|
timeout = await s_stormtypes.toint(timeout, noneok=True)
|
|
80
83
|
|
|
81
84
|
if ssl:
|
|
82
|
-
|
|
85
|
+
ctx = self.runt.snap.core.getCachedSslCtx(opts=None, verify=ssl_verify)
|
|
86
|
+
imap_cli = aioimaplib.IMAP4_SSL(host=host, port=port, timeout=timeout, ssl_context=ctx)
|
|
83
87
|
else:
|
|
84
88
|
imap_cli = aioimaplib.IMAP4(host=host, port=port, timeout=timeout)
|
|
85
89
|
|
synapse/lib/stormlib/model.py
CHANGED
|
@@ -919,8 +919,63 @@ class LibModelMigrations(s_stormtypes.Lib, MigrationEditorMixin):
|
|
|
919
919
|
'desc': 'Do not copy nodedata to the risk:vulnerable node.'},
|
|
920
920
|
),
|
|
921
921
|
'returns': {'type': 'list', 'desc': 'A list of idens for the risk:vulnerable nodes.'}}},
|
|
922
|
+
{'name': 'inetSslCertToTlsServerCert', 'desc': '''
|
|
923
|
+
Create a inet:tls:servercert node from the provided inet:ssl:cert node.
|
|
924
|
+
|
|
925
|
+
Edits will be made to the inet:tls:servercert node in the current write layer.
|
|
926
|
+
|
|
927
|
+
Tags, tag properties, edges, and node data will be copied
|
|
928
|
+
to the inet:tls:servercert node. However, existing tag properties and
|
|
929
|
+
node data will not be overwritten.
|
|
930
|
+
''',
|
|
931
|
+
'type': {'type': 'function', '_funcname': '_storm_query',
|
|
932
|
+
'args': (
|
|
933
|
+
{'name': 'n', 'type': 'node', 'desc': 'The inet:ssl:cert node to migrate.'},
|
|
934
|
+
{'name': 'nodata', 'type': 'bool', 'default': False,
|
|
935
|
+
'desc': 'Do not copy nodedata to the inet:tls:servercert node.'},
|
|
936
|
+
),
|
|
937
|
+
'returns': {'type': 'node', 'desc': 'The newly created inet:tls:servercert node.'}}},
|
|
938
|
+
|
|
922
939
|
)
|
|
923
940
|
_storm_lib_path = ('model', 'migration', 's')
|
|
941
|
+
_storm_query = '''
|
|
942
|
+
function inetSslCertToTlsServerCert(n, nodata=$lib.false) {
|
|
943
|
+
$form = $n.form()
|
|
944
|
+
if ($form != 'inet:ssl:cert') {
|
|
945
|
+
$mesg = `$lib.model.migration.s.inetSslCertToTlsServerCert() only accepts inet:ssl:cert nodes, not {$form}`
|
|
946
|
+
$lib.raise(BadArg, $mesg)
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
$server = $n.props.server
|
|
950
|
+
$sha256 = { yield $n -> file:bytes -> hash:sha256 }
|
|
951
|
+
|
|
952
|
+
if $sha256 {
|
|
953
|
+
|
|
954
|
+
yield $lib.gen.inetTlsServerCertByServerAndSha256($server, $sha256)
|
|
955
|
+
|
|
956
|
+
} else {
|
|
957
|
+
|
|
958
|
+
// File doesn't have a :sha256, try to lift/create a crypto:x509:node based on the file link
|
|
959
|
+
$crypto = { yield $n -> file:bytes -> crypto:x509:cert:file }
|
|
960
|
+
if (not $crypto) {
|
|
961
|
+
$crypto = {[ crypto:x509:cert=($n.props.file,) :file=$n.props.file ]}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
[ inet:tls:servercert=($server, $crypto) ]
|
|
965
|
+
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
[ .seen ?= $n.props.".seen" ]
|
|
969
|
+
|
|
970
|
+
$lib.model.migration.copyTags($n, $node, overwrite=$lib.false)
|
|
971
|
+
$lib.model.migration.copyEdges($n, $node)
|
|
972
|
+
if (not $nodata) {
|
|
973
|
+
$lib.model.migration.copyData($n, $node, overwrite=$lib.false)
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
return($node)
|
|
977
|
+
}
|
|
978
|
+
'''
|
|
924
979
|
|
|
925
980
|
def getObjLocals(self):
|
|
926
981
|
return {
|
synapse/lib/stormlib/modelext.py
CHANGED
|
@@ -77,6 +77,27 @@ class LibModelExt(s_stormtypes.Lib):
|
|
|
77
77
|
{'name': 'model', 'type': 'dict', 'desc': 'A model dictionary from getExtModel().', },
|
|
78
78
|
),
|
|
79
79
|
'returns': {'type': 'boolean'}}},
|
|
80
|
+
{'name': 'addEdge', 'desc': 'Add an extended edge definition to the data model.',
|
|
81
|
+
'type': {'type': 'function', '_funcname': 'addEdge',
|
|
82
|
+
'args': (
|
|
83
|
+
{'name': 'n1form', 'type': 'str',
|
|
84
|
+
'desc': 'The form of the n1 node. May be "*" or null to specify "any".'},
|
|
85
|
+
{'name': 'verb', 'type': 'str', 'desc': 'The edge verb, which must begin with "_".'},
|
|
86
|
+
{'name': 'n2form', 'type': 'str',
|
|
87
|
+
'desc': 'The form of the n2 node. May be "*" or null to specify "any".'},
|
|
88
|
+
{'name': 'edgeinfo', 'type': 'dict', 'desc': 'A Synapse edge info dictionary.'},
|
|
89
|
+
),
|
|
90
|
+
'returns': {'type': 'null'}}},
|
|
91
|
+
{'name': 'delEdge', 'desc': 'Remove an extended edge definition from the data model.',
|
|
92
|
+
'type': {'type': 'function', '_funcname': 'delEdge',
|
|
93
|
+
'args': (
|
|
94
|
+
{'name': 'n1form', 'type': 'str',
|
|
95
|
+
'desc': 'The form of the n1 node. May be "*" or null to specify "any".'},
|
|
96
|
+
{'name': 'verb', 'type': 'str', 'desc': 'The edge verb, which must begin with "_".'},
|
|
97
|
+
{'name': 'n2form', 'type': 'str',
|
|
98
|
+
'desc': 'The form of the n2 node. May be "*" or null to specify "any".'},
|
|
99
|
+
),
|
|
100
|
+
'returns': {'type': 'null'}}},
|
|
80
101
|
)
|
|
81
102
|
_storm_lib_path = ('model', 'ext')
|
|
82
103
|
|
|
@@ -92,6 +113,8 @@ class LibModelExt(s_stormtypes.Lib):
|
|
|
92
113
|
'delTagProp': self.delTagProp,
|
|
93
114
|
'getExtModel': self.getExtModel,
|
|
94
115
|
'addExtModel': self.addExtModel,
|
|
116
|
+
'addEdge': self.addEdge,
|
|
117
|
+
'delEdge': self.delEdge,
|
|
95
118
|
}
|
|
96
119
|
|
|
97
120
|
# TODO type docs in the new convention
|
|
@@ -163,3 +186,40 @@ class LibModelExt(s_stormtypes.Lib):
|
|
|
163
186
|
async def addExtModel(self, model):
|
|
164
187
|
model = await s_stormtypes.toprim(model)
|
|
165
188
|
return await self.runt.snap.core.addExtModel(model)
|
|
189
|
+
|
|
190
|
+
async def addEdge(self, n1form, verb, n2form, edgeinfo):
|
|
191
|
+
verb = await s_stormtypes.tostr(verb)
|
|
192
|
+
n1form = await s_stormtypes.tostr(n1form, noneok=True)
|
|
193
|
+
n2form = await s_stormtypes.tostr(n2form, noneok=True)
|
|
194
|
+
edgeinfo = await s_stormtypes.toprim(edgeinfo)
|
|
195
|
+
|
|
196
|
+
if not (s_grammar.isEdgeVerb(verb) and verb.islower()):
|
|
197
|
+
mesg = f'Invalid edge verb {verb}'
|
|
198
|
+
raise s_exc.BadEdgeDef(mesg=mesg, n1form=n1form, verb=verb, n2form=n2form)
|
|
199
|
+
|
|
200
|
+
if n1form == '*':
|
|
201
|
+
n1form = None
|
|
202
|
+
|
|
203
|
+
if n2form == '*':
|
|
204
|
+
n2form = None
|
|
205
|
+
|
|
206
|
+
s_stormtypes.confirm(('model', 'edge', 'add'))
|
|
207
|
+
await self.runt.snap.core.addEdge((n1form, verb, n2form), edgeinfo)
|
|
208
|
+
|
|
209
|
+
async def delEdge(self, n1form, verb, n2form):
|
|
210
|
+
verb = await s_stormtypes.tostr(verb)
|
|
211
|
+
n1form = await s_stormtypes.tostr(n1form, noneok=True)
|
|
212
|
+
n2form = await s_stormtypes.tostr(n2form, noneok=True)
|
|
213
|
+
|
|
214
|
+
if not (s_grammar.isEdgeVerb(verb) and verb.islower()):
|
|
215
|
+
mesg = f'Invalid edge verb {verb}'
|
|
216
|
+
raise s_exc.BadEdgeDef(mesg=mesg, n1form=n1form, verb=verb, n2form=n2form)
|
|
217
|
+
|
|
218
|
+
if n1form == '*':
|
|
219
|
+
n1form = None
|
|
220
|
+
|
|
221
|
+
if n2form == '*':
|
|
222
|
+
n2form = None
|
|
223
|
+
|
|
224
|
+
s_stormtypes.confirm(('model', 'edge', 'del'))
|
|
225
|
+
await self.runt.snap.core.delEdge((n1form, verb, n2form))
|
synapse/lib/stormlib/smtp.py
CHANGED
|
@@ -96,6 +96,8 @@ class SmtpMessage(s_stormtypes.StormType):
|
|
|
96
96
|
'desc': 'Use the STARTTLS directive with the SMTP server.'},
|
|
97
97
|
{'name': 'timeout', 'type': 'int', 'default': 60,
|
|
98
98
|
'desc': 'The timeout (in seconds) to wait for message delivery.'},
|
|
99
|
+
{'type': 'bool', 'name': 'ssl_verify', 'default': True,
|
|
100
|
+
'desc': 'Perform SSL/TLS verification.'},
|
|
99
101
|
),
|
|
100
102
|
'returns': {'type': 'list', 'desc': 'An ($ok, $valu) tuple.'}}},
|
|
101
103
|
|
|
@@ -148,7 +150,8 @@ class SmtpMessage(s_stormtypes.StormType):
|
|
|
148
150
|
async def _getEmailHtml(self):
|
|
149
151
|
return self.bodyhtml
|
|
150
152
|
|
|
151
|
-
async def send(self, host, port=25, user=None, passwd=None, usetls=False, starttls=False, timeout=60
|
|
153
|
+
async def send(self, host, port=25, user=None, passwd=None, usetls=False, starttls=False, timeout=60,
|
|
154
|
+
ssl_verify=True):
|
|
152
155
|
|
|
153
156
|
self.runt.confirm(('storm', 'inet', 'smtp', 'send'))
|
|
154
157
|
|
|
@@ -161,6 +164,7 @@ class SmtpMessage(s_stormtypes.StormType):
|
|
|
161
164
|
port = await s_stormtypes.toint(port)
|
|
162
165
|
usetls = await s_stormtypes.tobool(usetls)
|
|
163
166
|
starttls = await s_stormtypes.tobool(starttls)
|
|
167
|
+
ssl_verify = await s_stormtypes.tobool(ssl_verify)
|
|
164
168
|
|
|
165
169
|
if usetls and starttls:
|
|
166
170
|
raise s_exc.BadArg(mesg='usetls and starttls are mutually exclusive arguments.')
|
|
@@ -183,6 +187,10 @@ class SmtpMessage(s_stormtypes.StormType):
|
|
|
183
187
|
|
|
184
188
|
recipients = [await s_stormtypes.tostr(e) for e in self.recipients]
|
|
185
189
|
|
|
190
|
+
ctx = None
|
|
191
|
+
if usetls or starttls:
|
|
192
|
+
ctx = self.runt.snap.core.getCachedSslCtx(opts=None, verify=ssl_verify)
|
|
193
|
+
|
|
186
194
|
futu = aiosmtplib.send(message,
|
|
187
195
|
port=port,
|
|
188
196
|
hostname=host,
|
|
@@ -191,7 +199,9 @@ class SmtpMessage(s_stormtypes.StormType):
|
|
|
191
199
|
use_tls=usetls,
|
|
192
200
|
start_tls=starttls,
|
|
193
201
|
username=user,
|
|
194
|
-
password=passwd
|
|
202
|
+
password=passwd,
|
|
203
|
+
tls_context=ctx,
|
|
204
|
+
)
|
|
195
205
|
|
|
196
206
|
await s_common.wait_for(futu, timeout=timeout)
|
|
197
207
|
|