synapse 2.211.0__py311-none-any.whl → 2.213.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/lib/cell.py +6 -3
- synapse/lib/node.py +7 -2
- synapse/lib/scrape.py +3 -1
- synapse/lib/snap.py +21 -17
- synapse/lib/stormlib/json.py +1 -1
- synapse/lib/stormlib/spooled.py +3 -0
- synapse/lib/stormtypes.py +18 -0
- synapse/lib/types.py +36 -8
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +66 -3
- synapse/telepath.py +4 -2
- synapse/tests/test_lib_cell.py +15 -3
- synapse/tests/test_lib_config.py +8 -2
- synapse/tests/test_lib_layer.py +2 -2
- synapse/tests/test_lib_scrape.py +6 -0
- synapse/tests/test_lib_storm.py +13 -2
- synapse/tests/test_lib_stormhttp.py +6 -6
- synapse/tests/test_lib_stormlib_json.py +4 -1
- synapse/tests/test_lib_stormlib_spooled.py +11 -0
- synapse/tests/test_lib_stormtypes.py +11 -0
- synapse/tests/test_lib_types.py +136 -44
- synapse/tests/test_model_crypto.py +8 -0
- synapse/tests/test_model_inet.py +42 -4
- synapse/tests/test_telepath.py +18 -0
- synapse/tests/utils.py +4 -0
- {synapse-2.211.0.dist-info → synapse-2.213.0.dist-info}/METADATA +1 -1
- {synapse-2.211.0.dist-info → synapse-2.213.0.dist-info}/RECORD +30 -30
- {synapse-2.211.0.dist-info → synapse-2.213.0.dist-info}/WHEEL +1 -1
- {synapse-2.211.0.dist-info → synapse-2.213.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.211.0.dist-info → synapse-2.213.0.dist-info}/top_level.txt +0 -0
synapse/lib/cell.py
CHANGED
|
@@ -3495,13 +3495,16 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
3495
3495
|
await user.addRule(rule)
|
|
3496
3496
|
|
|
3497
3497
|
@contextlib.asynccontextmanager
|
|
3498
|
-
async def getLocalProxy(self, share=
|
|
3498
|
+
async def getLocalProxy(self, share=None, user='root'):
|
|
3499
3499
|
url = self.getLocalUrl(share=share, user=user)
|
|
3500
3500
|
prox = await s_telepath.openurl(url)
|
|
3501
3501
|
yield prox
|
|
3502
3502
|
|
|
3503
|
-
def getLocalUrl(self, share=
|
|
3504
|
-
|
|
3503
|
+
def getLocalUrl(self, share=None, user='root'):
|
|
3504
|
+
url = f'cell://{user}@{self.dirn}'
|
|
3505
|
+
if share is not None:
|
|
3506
|
+
url = f'{url}:{share}'
|
|
3507
|
+
return url
|
|
3505
3508
|
|
|
3506
3509
|
def _initCellConf(self, conf):
|
|
3507
3510
|
'''
|
synapse/lib/node.py
CHANGED
|
@@ -207,8 +207,13 @@ class Node:
|
|
|
207
207
|
|
|
208
208
|
embdnode = retn.get(nodepath)
|
|
209
209
|
if embdnode is None:
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
iden = node.iden()
|
|
211
|
+
# TODO deprecate / remove use of * once we can minver optic
|
|
212
|
+
embdnode = retn[nodepath] = {
|
|
213
|
+
'*': iden,
|
|
214
|
+
'$iden': iden,
|
|
215
|
+
'$form': node.form.name,
|
|
216
|
+
}
|
|
212
217
|
|
|
213
218
|
for relp in relprops:
|
|
214
219
|
embdnode[relp] = node.props.get(relp)
|
synapse/lib/scrape.py
CHANGED
|
@@ -65,6 +65,8 @@ inverse_prefixs = {
|
|
|
65
65
|
'<': '>',
|
|
66
66
|
'{': '}',
|
|
67
67
|
'(': ')',
|
|
68
|
+
'\u2018': '\u2019', # Unicode Left Single Quotation Mark and Right Single Quotation Mark
|
|
69
|
+
'\u201c': '\u201d', # Unicode Left Double Quotation Mark and Right Double Quotation Mark
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
cve_dashes = ''.join(('-',) + s_chop.unicode_dashes)
|
|
@@ -287,7 +289,7 @@ def url_scheme_check(match: regex.Match):
|
|
|
287
289
|
scrape_types = [ # type: ignore
|
|
288
290
|
('file:path', linux_path_regex, {'callback': linux_path_check, 'flags': regex.VERBOSE}),
|
|
289
291
|
('file:path', windows_path_regex, {'callback': windows_path_check, 'flags': regex.VERBOSE}),
|
|
290
|
-
('inet:url', r'(?P<prefix>[
|
|
292
|
+
('inet:url', r'(?P<prefix>[‘“\\{<\(\[]?)(?P<valu>[a-zA-Z][a-zA-Z0-9]*://(?(?=[,.]+[ \'\"\t\n\r\f\v])|[^ \'\"\t\n\r\f\v])+)',
|
|
291
293
|
{'callback': url_scheme_check}),
|
|
292
294
|
('inet:url', r'(["\'])?(?P<valu>\\[^\n]+?)(?(1)\1|\s)', {'callback': unc_path_check}),
|
|
293
295
|
('inet:email', r'(?=(?:[^a-z0-9_.+-]|^)(?P<valu>[a-z0-9_\.\-+]{1,256}@(?:[a-z0-9_-]{1,63}\.){1,10}(?:%s))(?:[^a-z0-9_.-]|[.\s]|$))' % tldcat, {}),
|
synapse/lib/snap.py
CHANGED
|
@@ -746,19 +746,25 @@ class Snap(s_base.Base):
|
|
|
746
746
|
|
|
747
747
|
async def _joinEmbedStor(self, storage, embeds):
|
|
748
748
|
for nodePath, relProps in embeds.items():
|
|
749
|
+
|
|
749
750
|
await asyncio.sleep(0)
|
|
750
|
-
|
|
751
|
+
|
|
752
|
+
iden = relProps.get('$iden')
|
|
751
753
|
if not iden:
|
|
752
754
|
continue
|
|
753
755
|
|
|
754
756
|
stor = await self.view.getStorNodes(s_common.uhex(iden))
|
|
755
757
|
for relProp in relProps.keys():
|
|
758
|
+
|
|
756
759
|
await asyncio.sleep(0)
|
|
757
|
-
|
|
760
|
+
|
|
761
|
+
if relProp[0] in ('*', '$'):
|
|
758
762
|
continue
|
|
759
763
|
|
|
760
764
|
for idx, layrstor in enumerate(stor):
|
|
765
|
+
|
|
761
766
|
await asyncio.sleep(0)
|
|
767
|
+
|
|
762
768
|
props = layrstor.get('props')
|
|
763
769
|
if not props:
|
|
764
770
|
continue
|
|
@@ -1319,13 +1325,13 @@ class Snap(s_base.Base):
|
|
|
1319
1325
|
|
|
1320
1326
|
if etyp == s_layer.EDIT_NODE_ADD:
|
|
1321
1327
|
node.bylayer['ndef'] = wlyr.iden
|
|
1322
|
-
callbacks.append((node.form.wasAdded, (node,)
|
|
1323
|
-
callbacks.append((self.view.runNodeAdd, (node,)
|
|
1328
|
+
callbacks.append((node.form.wasAdded, (node,)))
|
|
1329
|
+
callbacks.append((self.view.runNodeAdd, (node,)))
|
|
1324
1330
|
continue
|
|
1325
1331
|
|
|
1326
1332
|
if etyp == s_layer.EDIT_NODE_DEL:
|
|
1327
|
-
callbacks.append((node.form.wasDeleted, (node,)
|
|
1328
|
-
callbacks.append((self.view.runNodeDel, (node,)
|
|
1333
|
+
callbacks.append((node.form.wasDeleted, (node,)))
|
|
1334
|
+
callbacks.append((self.view.runNodeDel, (node,)))
|
|
1329
1335
|
continue
|
|
1330
1336
|
|
|
1331
1337
|
if etyp == s_layer.EDIT_PROP_SET:
|
|
@@ -1340,8 +1346,8 @@ class Snap(s_base.Base):
|
|
|
1340
1346
|
node.props[name] = valu
|
|
1341
1347
|
node.bylayer['props'][name] = wlyr.iden
|
|
1342
1348
|
|
|
1343
|
-
callbacks.append((prop.wasSet, (node, oldv)
|
|
1344
|
-
callbacks.append((self.view.runPropSet, (node, prop, oldv)
|
|
1349
|
+
callbacks.append((prop.wasSet, (node, oldv)))
|
|
1350
|
+
callbacks.append((self.view.runPropSet, (node, prop, oldv)))
|
|
1345
1351
|
continue
|
|
1346
1352
|
|
|
1347
1353
|
if etyp == s_layer.EDIT_PROP_DEL:
|
|
@@ -1356,8 +1362,8 @@ class Snap(s_base.Base):
|
|
|
1356
1362
|
node.props.pop(name, None)
|
|
1357
1363
|
node.bylayer['props'].pop(name, None)
|
|
1358
1364
|
|
|
1359
|
-
callbacks.append((prop.wasDel, (node, oldv)
|
|
1360
|
-
callbacks.append((self.view.runPropSet, (node, prop, oldv)
|
|
1365
|
+
callbacks.append((prop.wasDel, (node, oldv)))
|
|
1366
|
+
callbacks.append((self.view.runPropSet, (node, prop, oldv)))
|
|
1361
1367
|
continue
|
|
1362
1368
|
|
|
1363
1369
|
if etyp == s_layer.EDIT_TAG_SET:
|
|
@@ -1367,8 +1373,7 @@ class Snap(s_base.Base):
|
|
|
1367
1373
|
node.tags[tag] = valu
|
|
1368
1374
|
node.bylayer['tags'][tag] = wlyr.iden
|
|
1369
1375
|
|
|
1370
|
-
callbacks.append((self.view.runTagAdd, (node, tag, valu)
|
|
1371
|
-
callbacks.append((self.wlyr.fire, ('tag:add', ), {'tag': tag, 'node': node.iden()}))
|
|
1376
|
+
callbacks.append((self.view.runTagAdd, (node, tag, valu)))
|
|
1372
1377
|
continue
|
|
1373
1378
|
|
|
1374
1379
|
if etyp == s_layer.EDIT_TAG_DEL:
|
|
@@ -1378,8 +1383,7 @@ class Snap(s_base.Base):
|
|
|
1378
1383
|
node.tags.pop(tag, None)
|
|
1379
1384
|
node.bylayer['tags'].pop(tag, None)
|
|
1380
1385
|
|
|
1381
|
-
callbacks.append((self.view.runTagDel, (node, tag, oldv)
|
|
1382
|
-
callbacks.append((self.wlyr.fire, ('tag:del', ), {'tag': tag, 'node': node.iden()}))
|
|
1386
|
+
callbacks.append((self.view.runTagDel, (node, tag, oldv)))
|
|
1383
1387
|
continue
|
|
1384
1388
|
|
|
1385
1389
|
if etyp == s_layer.EDIT_TAGPROP_SET:
|
|
@@ -1414,14 +1418,14 @@ class Snap(s_base.Base):
|
|
|
1414
1418
|
if etyp == s_layer.EDIT_EDGE_ADD:
|
|
1415
1419
|
verb, n2iden = parms
|
|
1416
1420
|
n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
|
|
1417
|
-
callbacks.append((self.view.runEdgeAdd, (node, verb, n2)
|
|
1421
|
+
callbacks.append((self.view.runEdgeAdd, (node, verb, n2)))
|
|
1418
1422
|
|
|
1419
1423
|
if etyp == s_layer.EDIT_EDGE_DEL:
|
|
1420
1424
|
verb, n2iden = parms
|
|
1421
1425
|
n2 = await self.getNodeByBuid(s_common.uhex(n2iden))
|
|
1422
|
-
callbacks.append((self.view.runEdgeDel, (node, verb, n2)
|
|
1426
|
+
callbacks.append((self.view.runEdgeDel, (node, verb, n2)))
|
|
1423
1427
|
|
|
1424
|
-
[await func(*args
|
|
1428
|
+
[await func(*args) for (func, args) in callbacks]
|
|
1425
1429
|
|
|
1426
1430
|
if actualedits:
|
|
1427
1431
|
await self.fire('node:edits', edits=actualedits)
|
synapse/lib/stormlib/json.py
CHANGED
|
@@ -134,7 +134,7 @@ class JsonLib(s_stormtypes.Lib):
|
|
|
134
134
|
|
|
135
135
|
@s_stormtypes.stormfunc(readonly=True)
|
|
136
136
|
async def _jsonSchema(self, schema, use_default=True):
|
|
137
|
-
schema = await s_stormtypes.toprim(schema)
|
|
137
|
+
schema = await s_stormtypes.toprim(schema, use_list=True)
|
|
138
138
|
use_default = await s_stormtypes.tobool(use_default)
|
|
139
139
|
# We have to ensure that we have a valid schema for making the object.
|
|
140
140
|
try:
|
synapse/lib/stormlib/spooled.py
CHANGED
synapse/lib/stormtypes.py
CHANGED
|
@@ -4731,6 +4731,9 @@ class Str(Prim):
|
|
|
4731
4731
|
return str(self) == str(othr)
|
|
4732
4732
|
return False
|
|
4733
4733
|
|
|
4734
|
+
async def bool(self):
|
|
4735
|
+
return bool(self.valu)
|
|
4736
|
+
|
|
4734
4737
|
@stormfunc(readonly=True)
|
|
4735
4738
|
async def _methStrFind(self, valu):
|
|
4736
4739
|
text = await tostr(valu)
|
|
@@ -4970,6 +4973,9 @@ class Bytes(Prim):
|
|
|
4970
4973
|
return self.valu == othr.valu
|
|
4971
4974
|
return False
|
|
4972
4975
|
|
|
4976
|
+
async def bool(self):
|
|
4977
|
+
return bool(self.valu)
|
|
4978
|
+
|
|
4973
4979
|
async def _storm_copy(self):
|
|
4974
4980
|
item = await s_coro.ornot(self.value)
|
|
4975
4981
|
return s_msgpack.deepcopy(item, use_list=True)
|
|
@@ -5042,6 +5048,9 @@ class Dict(Prim):
|
|
|
5042
5048
|
def __len__(self):
|
|
5043
5049
|
return len(self.valu)
|
|
5044
5050
|
|
|
5051
|
+
async def bool(self):
|
|
5052
|
+
return bool(self.valu)
|
|
5053
|
+
|
|
5045
5054
|
async def _storm_copy(self):
|
|
5046
5055
|
item = await s_coro.ornot(self.value)
|
|
5047
5056
|
return s_msgpack.deepcopy(item, use_list=True)
|
|
@@ -5194,6 +5203,9 @@ class Set(Prim):
|
|
|
5194
5203
|
def __len__(self):
|
|
5195
5204
|
return len(self.valu)
|
|
5196
5205
|
|
|
5206
|
+
async def bool(self):
|
|
5207
|
+
return bool(self.valu)
|
|
5208
|
+
|
|
5197
5209
|
async def _methSetSize(self):
|
|
5198
5210
|
return len(self)
|
|
5199
5211
|
|
|
@@ -5384,6 +5396,9 @@ class List(Prim):
|
|
|
5384
5396
|
def __len__(self):
|
|
5385
5397
|
return len(self.valu)
|
|
5386
5398
|
|
|
5399
|
+
async def bool(self):
|
|
5400
|
+
return bool(self.valu)
|
|
5401
|
+
|
|
5387
5402
|
@stormfunc(readonly=True)
|
|
5388
5403
|
async def _methListHas(self, valu):
|
|
5389
5404
|
if valu in self.valu:
|
|
@@ -5519,6 +5534,9 @@ class Bool(Prim):
|
|
|
5519
5534
|
def __hash__(self):
|
|
5520
5535
|
return hash((self._storm_typename, self.value()))
|
|
5521
5536
|
|
|
5537
|
+
async def bool(self):
|
|
5538
|
+
return bool(self.valu)
|
|
5539
|
+
|
|
5522
5540
|
@registry.registerType
|
|
5523
5541
|
class Number(Prim):
|
|
5524
5542
|
'''
|
synapse/lib/types.py
CHANGED
|
@@ -651,9 +651,10 @@ class Hex(Type):
|
|
|
651
651
|
|
|
652
652
|
def postTypeInit(self):
|
|
653
653
|
self._size = self.opts.get('size')
|
|
654
|
+
self._zeropad = self.opts.get('zeropad')
|
|
654
655
|
|
|
655
656
|
# This is for backward compat with v2.142.x where zeropad was a bool
|
|
656
|
-
|
|
657
|
+
# TODO: Remove this compat check in 3xx
|
|
657
658
|
if isinstance(self._zeropad, bool):
|
|
658
659
|
if self._zeropad:
|
|
659
660
|
self._zeropad = self._size
|
|
@@ -678,6 +679,7 @@ class Hex(Type):
|
|
|
678
679
|
if self._size:
|
|
679
680
|
self._zeropad = min(self._zeropad, self._size)
|
|
680
681
|
|
|
682
|
+
self.setNormFunc(int, self._normPyInt)
|
|
681
683
|
self.setNormFunc(str, self._normPyStr)
|
|
682
684
|
self.setNormFunc(bytes, self._normPyBytes)
|
|
683
685
|
self.storlifts.update({
|
|
@@ -703,21 +705,47 @@ class Hex(Type):
|
|
|
703
705
|
return self._storLiftNorm(cmpr, valu)
|
|
704
706
|
|
|
705
707
|
def _storLiftPref(self, cmpr, valu):
|
|
708
|
+
if not isinstance(valu, str):
|
|
709
|
+
vtyp = type(valu).__name__
|
|
710
|
+
mesg = f'Hex prefix lift values must be str, not {vtyp}.'
|
|
711
|
+
raise s_exc.BadTypeValu(mesg=mesg, type=vtyp, name=self.name)
|
|
712
|
+
|
|
706
713
|
valu = self._preNormHex(valu)
|
|
707
714
|
return (
|
|
708
715
|
('^=', valu, self.stortype),
|
|
709
716
|
)
|
|
710
717
|
|
|
718
|
+
def _normPyInt(self, valu):
|
|
719
|
+
extra = 7
|
|
720
|
+
if valu < 0:
|
|
721
|
+
# Negative values need a little more space to store the sign
|
|
722
|
+
extra = 8
|
|
723
|
+
|
|
724
|
+
bytelen = max((valu.bit_length() + extra) // 8, self._zeropad // 2)
|
|
725
|
+
|
|
726
|
+
try:
|
|
727
|
+
byts = valu.to_bytes(bytelen, 'big', signed=(valu < 0))
|
|
728
|
+
hexval = s_common.ehex(byts)
|
|
729
|
+
|
|
730
|
+
except OverflowError as e: # pragma: no cover
|
|
731
|
+
mesg = f'Invalid width for {valu}.'
|
|
732
|
+
raise s_exc.BadTypeValu(mesg=mesg, name=self.name)
|
|
733
|
+
|
|
734
|
+
if self._size and len(hexval) != self._size:
|
|
735
|
+
raise s_exc.BadTypeValu(valu=valu, reqwidth=self._size, name=self.name,
|
|
736
|
+
mesg='Invalid width.')
|
|
737
|
+
|
|
738
|
+
return hexval, {}
|
|
739
|
+
|
|
711
740
|
def _normPyStr(self, valu):
|
|
712
|
-
valu =
|
|
713
|
-
if valu.startswith('0x'):
|
|
714
|
-
valu = valu[2:]
|
|
741
|
+
valu = self._preNormHex(valu)
|
|
715
742
|
|
|
716
|
-
valu
|
|
743
|
+
if len(valu) % 2 != 0:
|
|
744
|
+
valu = f'0{valu}'
|
|
717
745
|
|
|
718
746
|
if not valu:
|
|
719
|
-
raise s_exc.BadTypeValu(valu=valu, name=
|
|
720
|
-
mesg='No string left after stripping')
|
|
747
|
+
raise s_exc.BadTypeValu(valu=valu, name=self.name,
|
|
748
|
+
mesg='No string left after stripping.')
|
|
721
749
|
|
|
722
750
|
if self._zeropad and len(valu) < self._zeropad:
|
|
723
751
|
padlen = self._zeropad - len(valu)
|
|
@@ -732,7 +760,7 @@ class Hex(Type):
|
|
|
732
760
|
|
|
733
761
|
if self._size and len(valu) != self._size:
|
|
734
762
|
raise s_exc.BadTypeValu(valu=valu, reqwidth=self._size, name=self.name,
|
|
735
|
-
mesg='
|
|
763
|
+
mesg='Invalid width.')
|
|
736
764
|
return valu, {}
|
|
737
765
|
|
|
738
766
|
def _normPyBytes(self, valu):
|
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, 213, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = 'e3d843a470b137e9d2094b69a7878101afb4f8b1'
|
synapse/models/inet.py
CHANGED
|
@@ -35,6 +35,10 @@ ipv4max = 2 ** 32 - 1
|
|
|
35
35
|
|
|
36
36
|
rfc6598 = ipaddress.IPv4Network('100.64.0.0/10')
|
|
37
37
|
|
|
38
|
+
# defined from https://x.com/4A4133/status/1887269972545839559
|
|
39
|
+
ja4_regex = r'^([tqd])([sd\d]\d)([di])(\d{2})(\d{2})([a-zA-Z0-9]{2})_([0-9a-f]{12})_([0-9a-f]{12})$'
|
|
40
|
+
ja4s_regex = r'^([tq])([sd\d]\d)(\d{2})([a-zA-Z0-9]{2})_([0-9a-f]{4})_([0-9a-f]{12})$'
|
|
41
|
+
|
|
38
42
|
def getAddrType(ip):
|
|
39
43
|
|
|
40
44
|
if ip.is_multicast:
|
|
@@ -1678,6 +1682,18 @@ class InetModule(s_module.CoreModule):
|
|
|
1678
1682
|
('inet:tls:handshake', ('guid', {}), {
|
|
1679
1683
|
'doc': 'An instance of a TLS handshake between a server and client.'}),
|
|
1680
1684
|
|
|
1685
|
+
('inet:tls:ja4', ('str', {'strip': True, 'regex': ja4_regex}), {
|
|
1686
|
+
'doc': 'A JA4 TLS client fingerprint.'}),
|
|
1687
|
+
|
|
1688
|
+
('inet:tls:ja4s', ('str', {'strip': True, 'regex': ja4s_regex}), {
|
|
1689
|
+
'doc': 'A JA4S TLS server fingerprint.'}),
|
|
1690
|
+
|
|
1691
|
+
('inet:tls:ja4:sample', ('comp', {'fields': (('client', 'inet:client'), ('ja4', 'inet:tls:ja4'))}), {
|
|
1692
|
+
'doc': 'A JA4 TLS client fingerprint used by a client.'}),
|
|
1693
|
+
|
|
1694
|
+
('inet:tls:ja4s:sample', ('comp', {'fields': (('server', 'inet:server'), ('ja4s', 'inet:tls:ja4s'))}), {
|
|
1695
|
+
'doc': 'A JA4S TLS server fingerprint used by a server.'}),
|
|
1696
|
+
|
|
1681
1697
|
('inet:tls:ja3s:sample', ('comp', {'fields': (('server', 'inet:server'), ('ja3s', 'hash:md5'))}), {
|
|
1682
1698
|
'doc': 'A JA3 sample taken from a server.'}),
|
|
1683
1699
|
|
|
@@ -3565,23 +3581,70 @@ class InetModule(s_module.CoreModule):
|
|
|
3565
3581
|
'doc': 'The server that was sampled to compute the JARM hash.'}),
|
|
3566
3582
|
)),
|
|
3567
3583
|
|
|
3584
|
+
('inet:tls:ja4', {}, ()),
|
|
3585
|
+
('inet:tls:ja4s', {}, ()),
|
|
3586
|
+
|
|
3587
|
+
('inet:tls:ja4:sample', {}, (
|
|
3588
|
+
|
|
3589
|
+
('ja4', ('inet:tls:ja4', {}), {
|
|
3590
|
+
'ro': True,
|
|
3591
|
+
'doc': 'The JA4 TLS client fingerprint.'}),
|
|
3592
|
+
|
|
3593
|
+
('client', ('inet:client', {}), {
|
|
3594
|
+
'ro': True,
|
|
3595
|
+
'doc': 'The client which initiated the TLS handshake with a JA4 fingerprint.'}),
|
|
3596
|
+
)),
|
|
3597
|
+
|
|
3598
|
+
('inet:tls:ja4s:sample', {}, (
|
|
3599
|
+
|
|
3600
|
+
('ja4s', ('inet:tls:ja4s', {}), {
|
|
3601
|
+
'ro': True,
|
|
3602
|
+
'doc': 'The JA4S TLS server fingerprint.'}),
|
|
3603
|
+
|
|
3604
|
+
('server', ('inet:server', {}), {
|
|
3605
|
+
'ro': True,
|
|
3606
|
+
'doc': 'The server which responded to the TLS handshake with a JA4S fingerprint.'}),
|
|
3607
|
+
)),
|
|
3608
|
+
|
|
3568
3609
|
('inet:tls:handshake', {}, (
|
|
3610
|
+
|
|
3569
3611
|
('time', ('time', {}), {
|
|
3570
3612
|
'doc': 'The time the handshake was initiated.'}),
|
|
3613
|
+
|
|
3571
3614
|
('flow', ('inet:flow', {}), {
|
|
3572
3615
|
'doc': 'The raw inet:flow associated with the handshake.'}),
|
|
3616
|
+
|
|
3573
3617
|
('server', ('inet:server', {}), {
|
|
3574
3618
|
'doc': 'The TLS server during the handshake.'}),
|
|
3619
|
+
|
|
3575
3620
|
('server:cert', ('crypto:x509:cert', {}), {
|
|
3576
3621
|
'doc': 'The x509 certificate sent by the server during the handshake.'}),
|
|
3577
|
-
|
|
3578
|
-
|
|
3622
|
+
|
|
3623
|
+
('server:ja3s', ('hash:md5', {}), {
|
|
3624
|
+
'doc': 'The JA3S fingerprint of the server response.'}),
|
|
3625
|
+
|
|
3626
|
+
('server:ja4s', ('inet:tls:ja4s', {}), {
|
|
3627
|
+
'doc': 'The JA4S fingerprint of the server response.'}),
|
|
3628
|
+
|
|
3579
3629
|
('client', ('inet:client', {}), {
|
|
3580
3630
|
'doc': 'The TLS client during the handshake.'}),
|
|
3631
|
+
|
|
3581
3632
|
('client:cert', ('crypto:x509:cert', {}), {
|
|
3582
3633
|
'doc': 'The x509 certificate sent by the client during the handshake.'}),
|
|
3634
|
+
|
|
3635
|
+
('client:ja3', ('hash:md5', {}), {
|
|
3636
|
+
'doc': 'The JA3 fingerprint of the client request.'}),
|
|
3637
|
+
|
|
3638
|
+
('client:ja4', ('inet:tls:ja4', {}), {
|
|
3639
|
+
'doc': 'The JA4 fingerprint of the client request.'}),
|
|
3640
|
+
|
|
3583
3641
|
('client:fingerprint:ja3', ('hash:md5', {}), {
|
|
3584
|
-
'
|
|
3642
|
+
'deprecated': True,
|
|
3643
|
+
'doc': 'Deprecated. Please use :client:ja3.'}),
|
|
3644
|
+
|
|
3645
|
+
('server:fingerprint:ja3', ('hash:md5', {}), {
|
|
3646
|
+
'deprecated': True,
|
|
3647
|
+
'doc': 'Deprecated. Please use :server:ja3s.'}),
|
|
3585
3648
|
)),
|
|
3586
3649
|
|
|
3587
3650
|
('inet:tls:ja3s:sample', {}, (
|
synapse/telepath.py
CHANGED
|
@@ -1605,8 +1605,6 @@ async def openinfo(info):
|
|
|
1605
1605
|
# cell://rel/path/to/celldir:share
|
|
1606
1606
|
path = info.get('path')
|
|
1607
1607
|
|
|
1608
|
-
name = info.get('name', '*')
|
|
1609
|
-
|
|
1610
1608
|
# support cell://<relpath>/<to>/<cell>
|
|
1611
1609
|
# by detecting host...
|
|
1612
1610
|
host = info.get('host')
|
|
@@ -1614,9 +1612,12 @@ async def openinfo(info):
|
|
|
1614
1612
|
path = path.strip('/')
|
|
1615
1613
|
path = os.path.join(host, path)
|
|
1616
1614
|
|
|
1615
|
+
name = '*'
|
|
1617
1616
|
if ':' in path:
|
|
1618
1617
|
path, name = path.split(':')
|
|
1619
1618
|
|
|
1619
|
+
name = info.get('name', name)
|
|
1620
|
+
|
|
1620
1621
|
full = os.path.join(path, 'sock')
|
|
1621
1622
|
link = await s_link.unixconnect(full)
|
|
1622
1623
|
|
|
@@ -1626,6 +1627,7 @@ async def openinfo(info):
|
|
|
1626
1627
|
path = info.get('path')
|
|
1627
1628
|
if ':' in path:
|
|
1628
1629
|
path, name = path.split(':')
|
|
1630
|
+
name = info.get('name', name)
|
|
1629
1631
|
link = await s_link.unixconnect(path)
|
|
1630
1632
|
|
|
1631
1633
|
elif scheme in ('tcp', 'ssl'):
|
synapse/tests/test_lib_cell.py
CHANGED
|
@@ -194,6 +194,18 @@ testDataSchema_v1 = {
|
|
|
194
194
|
|
|
195
195
|
class CellTest(s_t_utils.SynTest):
|
|
196
196
|
|
|
197
|
+
async def test_cell_getLocalUrl(self):
|
|
198
|
+
with self.getTestDir() as dirn:
|
|
199
|
+
async with self.getTestCell(dirn=dirn) as cell:
|
|
200
|
+
url = cell.getLocalUrl()
|
|
201
|
+
self.eq(url, f'cell://root@{dirn}')
|
|
202
|
+
|
|
203
|
+
url = cell.getLocalUrl(share='*/layer')
|
|
204
|
+
self.eq(url, f'cell://root@{dirn}:*/layer')
|
|
205
|
+
|
|
206
|
+
url = cell.getLocalUrl(user='lowuser', share='*/view')
|
|
207
|
+
self.eq(url, f'cell://lowuser@{dirn}:*/view')
|
|
208
|
+
|
|
197
209
|
async def test_cell_drive(self):
|
|
198
210
|
|
|
199
211
|
with self.getTestDir() as dirn:
|
|
@@ -2580,10 +2592,10 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2580
2592
|
viewiden = view.get('iden')
|
|
2581
2593
|
|
|
2582
2594
|
opts = {'view': viewiden}
|
|
2583
|
-
with self.
|
|
2595
|
+
with self.getAsyncLoggerStream('synapse.lib.lmdbslab',
|
|
2584
2596
|
'Error during slab resize callback - foo') as stream:
|
|
2585
|
-
|
|
2586
|
-
self.true(stream.wait(
|
|
2597
|
+
msgs = await core.stormlist('for $x in $lib.range(200) {[test:int=$x]}', opts=opts)
|
|
2598
|
+
self.true(await stream.wait(timeout=30))
|
|
2587
2599
|
|
|
2588
2600
|
async with self.getTestCore() as core:
|
|
2589
2601
|
|
synapse/tests/test_lib_config.py
CHANGED
|
@@ -164,8 +164,8 @@ class ConfTest(s_test.SynTest):
|
|
|
164
164
|
# We can ensure that certain vars are loaded
|
|
165
165
|
self.eq('Funky string time!', conf.req('key:string'))
|
|
166
166
|
# And throw if they are not, or if the requested key isn't even schema valid
|
|
167
|
-
self.raises(s_exc.NeedConfValu, conf.
|
|
168
|
-
self.raises(s_exc.BadArg, conf.
|
|
167
|
+
self.raises(s_exc.NeedConfValu, conf.req, 'key:bool:nodefval')
|
|
168
|
+
self.raises(s_exc.BadArg, conf.req, 'key:newp')
|
|
169
169
|
|
|
170
170
|
# Since we're an Mutable mapping, we have some dict methods available to us
|
|
171
171
|
self.len(8, conf) # __len__
|
|
@@ -380,6 +380,12 @@ class ConfTest(s_test.SynTest):
|
|
|
380
380
|
self.eq(item['key:number'], 123)
|
|
381
381
|
self.notin('key:string', item)
|
|
382
382
|
|
|
383
|
+
item = validator({'key:multi': 123})
|
|
384
|
+
self.eq(item['key:multi'], 123)
|
|
385
|
+
|
|
386
|
+
item = validator({'key:multi': '123'})
|
|
387
|
+
self.eq(item['key:multi'], '123')
|
|
388
|
+
|
|
383
389
|
async def test_config_ref_handler(self):
|
|
384
390
|
|
|
385
391
|
filename = pathlib.Path(s_data.path(
|
synapse/tests/test_lib_layer.py
CHANGED
|
@@ -1399,8 +1399,8 @@ class LayerTest(s_t_utils.SynTest):
|
|
|
1399
1399
|
self.len(1, nodes)
|
|
1400
1400
|
self.eq(nodes[0].ndef, ('inet:ipv4', 0x01020304))
|
|
1401
1401
|
self.eq(nodes[0].get('asn'), 33)
|
|
1402
|
-
self.
|
|
1403
|
-
self.
|
|
1402
|
+
self.eq(nodes[0].getTag('foo.bar'), (None, None))
|
|
1403
|
+
self.eq(nodes[0].getTagProp('foo.bar', 'confidence'), 100)
|
|
1404
1404
|
|
|
1405
1405
|
self.eq(10004, await core.count('.created'))
|
|
1406
1406
|
self.len(2, await core.nodes('syn:tag~=foo'))
|
synapse/tests/test_lib_scrape.py
CHANGED
|
@@ -203,6 +203,10 @@ A bunch of prefixed urls
|
|
|
203
203
|
|
|
204
204
|
https://c2server.com/evil/malware/doesnot[care+]aboutstandards{at-all}
|
|
205
205
|
|
|
206
|
+
beep “https://unicode.doublequote.org/test.php” boop
|
|
207
|
+
|
|
208
|
+
x ‘https://unicode.singlequote.org/test.php’ z
|
|
209
|
+
|
|
206
210
|
'''
|
|
207
211
|
|
|
208
212
|
data3 = '''
|
|
@@ -725,6 +729,8 @@ class ScrapeTest(s_t_utils.SynTest):
|
|
|
725
729
|
nodes.remove(('inet:url', 'https://www.thingspace.com/blog/giggles.html'))
|
|
726
730
|
nodes.remove(('inet:url', 'https://testme.org/test.php'))
|
|
727
731
|
nodes.remove(('inet:url', 'https://c2server.com/evil/malware/doesnot[care+]aboutstandards{at-all}'))
|
|
732
|
+
nodes.remove(('inet:url', 'https://unicode.doublequote.org/test.php'))
|
|
733
|
+
nodes.remove(('inet:url', 'https://unicode.singlequote.org/test.php'))
|
|
728
734
|
|
|
729
735
|
nodes = list(s_scrape.scrape(btc_addresses))
|
|
730
736
|
self.len(11, nodes)
|
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -1736,6 +1736,8 @@ class StormTest(s_t_utils.SynTest):
|
|
|
1736
1736
|
self.stormHasNoErr(await core.stormlist('merge --diff', opts=altview))
|
|
1737
1737
|
|
|
1738
1738
|
oldn = await core.nodes('[ ou:name=readonly ]', opts=altview)
|
|
1739
|
+
# need to pause a moment so the created times differ
|
|
1740
|
+
await asyncio.sleep(0.01)
|
|
1739
1741
|
newn = await core.nodes('[ ou:name=readonly ]')
|
|
1740
1742
|
self.ne(oldn[0].props['.created'], newn[0].props['.created'])
|
|
1741
1743
|
|
|
@@ -2251,16 +2253,18 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2251
2253
|
nodes = [m[1] for m in msgs if m[0] == 'node']
|
|
2252
2254
|
|
|
2253
2255
|
node = nodes[0]
|
|
2256
|
+
self.eq('inet:asn', node[1]['embeds']['asn']['$form'])
|
|
2254
2257
|
self.eq('hehe', node[1]['embeds']['asn']['name'])
|
|
2255
|
-
self.eq('796d67b92a6ffe9b88fa19d115b46ab6712d673a06ae602d41de84b1464782f2', node[1]['embeds']['asn']['
|
|
2258
|
+
self.eq('796d67b92a6ffe9b88fa19d115b46ab6712d673a06ae602d41de84b1464782f2', node[1]['embeds']['asn']['$iden'])
|
|
2256
2259
|
|
|
2257
2260
|
opts = {'embeds': {'ou:org': {'hq::email': ('user',)}}}
|
|
2258
2261
|
msgs = await core.stormlist('[ ou:org=* :country=* :hq=* ] { -> ps:contact [ :email=visi@vertex.link ] }', opts=opts)
|
|
2259
2262
|
nodes = [m[1] for m in msgs if m[0] == 'node']
|
|
2260
2263
|
node = nodes[0]
|
|
2261
2264
|
|
|
2265
|
+
self.eq('inet:email', node[1]['embeds']['hq::email']['$form'])
|
|
2262
2266
|
self.eq('visi', node[1]['embeds']['hq::email']['user'])
|
|
2263
|
-
self.eq('2346d7bed4b0fae05e00a413bbf8716c9e08857eb71a1ecf303b8972823f2899', node[1]['embeds']['hq::email']['
|
|
2267
|
+
self.eq('2346d7bed4b0fae05e00a413bbf8716c9e08857eb71a1ecf303b8972823f2899', node[1]['embeds']['hq::email']['$iden'])
|
|
2264
2268
|
|
|
2265
2269
|
fork = await core.callStorm('return($lib.view.get().fork().iden)')
|
|
2266
2270
|
|
|
@@ -2373,10 +2377,17 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2373
2377
|
self.eq(['inet:service:rule', 'risk:vulnerable'], [n[0][0] for n in nodes])
|
|
2374
2378
|
|
|
2375
2379
|
embeds = nodes[0][1]['embeds']
|
|
2380
|
+
|
|
2381
|
+
self.nn(embeds['object']['$iden'])
|
|
2382
|
+
self.eq('risk:vulnerable', embeds['object']['$form'])
|
|
2376
2383
|
self.eq(1, embeds['object']['mitigated'])
|
|
2377
2384
|
self.eq(None, embeds['object']['newp'])
|
|
2385
|
+
|
|
2386
|
+
self.nn(embeds['object::node']['$iden'])
|
|
2387
|
+
self.eq('it:prod:hardware', embeds['object::node']['$form'])
|
|
2378
2388
|
self.eq('foohw', embeds['object::node']['name'])
|
|
2379
2389
|
self.eq(None, embeds['object::node']['newp'])
|
|
2390
|
+
self.eq('inet:service:account', embeds['grantee']['$form'])
|
|
2380
2391
|
self.eq('foocon', embeds['grantee']['id'])
|
|
2381
2392
|
self.eq(None, embeds['grantee']['newp'])
|
|
2382
2393
|
|
|
@@ -642,9 +642,9 @@ class StormHttpTest(s_test.SynTest):
|
|
|
642
642
|
self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
|
|
643
643
|
|
|
644
644
|
q = '$resp=$lib.inet.http.get("http://vertex.link") return(($resp.code, $resp.err))'
|
|
645
|
-
code, (errname,
|
|
645
|
+
code, (errname, errinfo) = await core.callStorm(q)
|
|
646
646
|
self.eq(code, -1)
|
|
647
|
-
self.
|
|
647
|
+
self.isin("connect to proxy 127.0.0.1:1", errinfo.get('mesg'))
|
|
648
648
|
|
|
649
649
|
msgs = await core.stormlist('$resp=$lib.inet.http.get("http://vertex.link", proxy=(null)) $lib.print($resp.err)')
|
|
650
650
|
self.stormIsInWarn('HTTP proxy argument to $lib.null is deprecated', msgs)
|
|
@@ -669,7 +669,7 @@ class StormHttpTest(s_test.SynTest):
|
|
|
669
669
|
self.stormIsInErr(errmsg.format(perm='storm.lib.inet.http.proxy'), msgs)
|
|
670
670
|
|
|
671
671
|
resp = await core.callStorm('return($lib.inet.http.get(http://vertex.link, proxy=socks5://user:pass@127.0.0.1:1))')
|
|
672
|
-
self.
|
|
672
|
+
self.isin("connect to proxy 127.0.0.1:1", resp['err'][1].get('mesg'))
|
|
673
673
|
|
|
674
674
|
# test $lib.axon proxy API
|
|
675
675
|
asvisi = {'user': visi.iden}
|
|
@@ -748,13 +748,13 @@ class StormHttpTest(s_test.SynTest):
|
|
|
748
748
|
opts = {'vars': {'proxy': 'socks5://user:pass@127.0.0.1:1'}, 'user': visi.iden}
|
|
749
749
|
|
|
750
750
|
resp = await core.callStorm(q1, opts=opts)
|
|
751
|
-
self.
|
|
751
|
+
self.isin("connect to proxy 127.0.0.1:1", resp['err'][1].get('mesg'))
|
|
752
752
|
|
|
753
753
|
resp = await core.callStorm(q2, opts=opts)
|
|
754
|
-
self.
|
|
754
|
+
self.isin("connect to proxy 127.0.0.1:1", resp['err'][1].get('mesg'))
|
|
755
755
|
|
|
756
756
|
resp = await core.callStorm(q3, opts=opts)
|
|
757
|
-
self.
|
|
757
|
+
self.isin("connect to proxy 127.0.0.1:1", resp['err'][1].get('mesg'))
|
|
758
758
|
|
|
759
759
|
opts = {'vars': {'proxy': False}, 'user': visi.iden}
|
|
760
760
|
|