synapse 2.177.0__py311-none-any.whl → 2.179.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.

Files changed (73) hide show
  1. synapse/cortex.py +170 -31
  2. synapse/datamodel.py +47 -1
  3. synapse/exc.py +1 -0
  4. synapse/lib/aha.py +362 -88
  5. synapse/lib/ast.py +26 -22
  6. synapse/lib/base.py +39 -12
  7. synapse/lib/cell.py +315 -119
  8. synapse/lib/config.py +15 -11
  9. synapse/lib/coro.py +27 -0
  10. synapse/lib/drive.py +551 -0
  11. synapse/lib/layer.py +0 -5
  12. synapse/lib/link.py +1 -1
  13. synapse/lib/lmdbslab.py +3 -3
  14. synapse/lib/nexus.py +24 -12
  15. synapse/lib/schemas.py +39 -0
  16. synapse/lib/snap.py +17 -7
  17. synapse/lib/storm.py +3 -1
  18. synapse/lib/stormhttp.py +1 -0
  19. synapse/lib/stormlib/imap.py +6 -2
  20. synapse/lib/stormlib/modelext.py +29 -3
  21. synapse/lib/stormlib/smtp.py +12 -2
  22. synapse/lib/stormlib/stix.py +40 -17
  23. synapse/lib/stormlib/vault.py +2 -2
  24. synapse/lib/stormtypes.py +1 -1
  25. synapse/lib/types.py +9 -0
  26. synapse/lib/version.py +2 -2
  27. synapse/lookup/pe.py +303 -38
  28. synapse/models/dns.py +24 -1
  29. synapse/models/geospace.py +4 -1
  30. synapse/models/infotech.py +26 -1
  31. synapse/telepath.py +32 -17
  32. synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
  33. synapse/tests/files/aha/certs/cas/synapse.key +51 -0
  34. synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
  35. synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
  36. synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
  37. synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
  38. synapse/tests/files/rstorm/testsvc.py +1 -1
  39. synapse/tests/test_axon.py +1 -1
  40. synapse/tests/test_cortex.py +67 -60
  41. synapse/tests/test_lib_agenda.py +3 -3
  42. synapse/tests/test_lib_aha.py +353 -490
  43. synapse/tests/test_lib_base.py +20 -0
  44. synapse/tests/test_lib_cell.py +273 -22
  45. synapse/tests/test_lib_config.py +4 -3
  46. synapse/tests/test_lib_coro.py +12 -0
  47. synapse/tests/test_lib_nexus.py +8 -0
  48. synapse/tests/test_lib_stormhttp.py +40 -0
  49. synapse/tests/test_lib_stormlib_aha.py +35 -35
  50. synapse/tests/test_lib_stormlib_cell.py +4 -15
  51. synapse/tests/test_lib_stormlib_imap.py +14 -3
  52. synapse/tests/test_lib_stormlib_modelext.py +55 -3
  53. synapse/tests/test_lib_stormlib_smtp.py +51 -0
  54. synapse/tests/test_lib_stormlib_stix.py +15 -0
  55. synapse/tests/test_lib_stormlib_vault.py +11 -1
  56. synapse/tests/test_lib_stormtypes.py +5 -0
  57. synapse/tests/test_lib_types.py +9 -0
  58. synapse/tests/test_model_dns.py +8 -0
  59. synapse/tests/test_model_geospace.py +3 -1
  60. synapse/tests/test_model_infotech.py +47 -0
  61. synapse/tests/test_model_syn.py +11 -0
  62. synapse/tests/test_tools_aha.py +78 -101
  63. synapse/tests/test_utils_stormcov.py +1 -1
  64. synapse/tests/utils.py +86 -120
  65. synapse/tools/aha/clone.py +50 -0
  66. synapse/tools/aha/enroll.py +2 -1
  67. synapse/tools/backup.py +2 -2
  68. synapse/tools/changelog.py +31 -1
  69. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/METADATA +48 -48
  70. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/RECORD +73 -65
  71. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/WHEEL +1 -1
  72. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/LICENSE +0 -0
  73. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/top_level.txt +0 -0
synapse/lib/nexus.py CHANGED
@@ -91,7 +91,6 @@ class NexsRoot(s_base.Base):
91
91
  self.writeholds = set()
92
92
 
93
93
  self.applytask = None
94
- self.applylock = asyncio.Lock()
95
94
 
96
95
  self.ready = asyncio.Event()
97
96
  self.donexslog = self.cell.conf.get('nexslog:en')
@@ -110,9 +109,7 @@ class NexsRoot(s_base.Base):
110
109
 
111
110
  logpath = s_common.genpath(self.dirn, 'slabs', 'nexuslog')
112
111
 
113
- self.map_async = self.cell.conf.get('nexslog:async')
114
- self.nexsslab = await s_lmdbslab.Slab.anit(path, map_async=self.map_async)
115
- self.nexsslab.addResizeCallback(cell.checkFreeSpace)
112
+ self.nexsslab = await cell._initSlabFile(path)
116
113
 
117
114
  self.nexshot = await self.nexsslab.getHotCount('nexs:indx')
118
115
 
@@ -126,8 +123,7 @@ class NexsRoot(s_base.Base):
126
123
  elif vers != 2:
127
124
  raise s_exc.BadStorageVersion(mesg=f'Got nexus log version {vers}. Expected 2. Accidental downgrade?')
128
125
 
129
- slabopts = {'map_async': self.map_async}
130
- self.nexslog = await s_multislabseqn.MultiSlabSeqn.anit(logpath, slabopts=slabopts, cell=cell)
126
+ self.nexslog = await s_multislabseqn.MultiSlabSeqn.anit(logpath, cell=cell)
131
127
 
132
128
  # just in case were previously configured differently
133
129
  logindx = self.nexslog.index()
@@ -147,6 +143,9 @@ class NexsRoot(s_base.Base):
147
143
 
148
144
  self.onfini(fini)
149
145
 
146
+ def getNexsKids(self):
147
+ return list(self._nexskids.values())
148
+
150
149
  async def _migrateV1toV2(self, nexspath, logpath):
151
150
  '''
152
151
  Close the slab, move it to the new multislab location, then copy out the nexshot
@@ -195,8 +194,7 @@ class NexsRoot(s_base.Base):
195
194
 
196
195
  # Open a fresh slab where the old one used to be
197
196
  logger.warning(f'Re-opening fresh nexslog slab at {nexspath} for nexshot')
198
- self.nexsslab = await s_lmdbslab.Slab.anit(nexspath, map_async=self.map_async)
199
- self.nexsslab.addResizeCallback(self.cell.checkFreeSpace)
197
+ self.nexsslab = await self.cell._initSlabFile(nexspath)
200
198
 
201
199
  self.nexshot = await self.nexsslab.getHotCount('nexs:indx')
202
200
 
@@ -230,7 +228,7 @@ class NexsRoot(s_base.Base):
230
228
 
231
229
  async def enNexsLog(self):
232
230
 
233
- async with self.applylock:
231
+ async with self.cell.nexslock:
234
232
 
235
233
  if self.donexslog:
236
234
  return
@@ -309,7 +307,6 @@ class NexsRoot(s_base.Base):
309
307
  If I'm not a follower, mutate, otherwise, ask the leader to make the change and wait for the follower loop
310
308
  to hand me the result through a future.
311
309
  '''
312
-
313
310
  # pick up a reference to avoid race when we eventually can promote
314
311
  client = self.client
315
312
 
@@ -344,7 +341,7 @@ class NexsRoot(s_base.Base):
344
341
  if meta is None:
345
342
  meta = {}
346
343
 
347
- async with self.applylock:
344
+ async with self.cell.nexslock:
348
345
  self.reqNotReadOnly()
349
346
  # Keep a reference to the shielded task to ensure it isn't GC'd
350
347
  self.applytask = asyncio.create_task(self._eat((nexsiden, event, args, kwargs, meta)))
@@ -577,6 +574,9 @@ class NexsRoot(s_base.Base):
577
574
  if respfutu is not None:
578
575
  respfutu.set_result(retn)
579
576
 
577
+ except s_exc.LinkShutDown:
578
+ logger.warning(f'mirror loop: leader closed the connection.')
579
+
580
580
  except Exception as exc: # pragma: no cover
581
581
  logger.exception(f'error in mirror loop: {exc}')
582
582
 
@@ -634,9 +634,21 @@ class Pusher(s_base.Base, metaclass=RegMethType):
634
634
  assert prev is not None, f'Failed removing {self.nexsiden}'
635
635
 
636
636
  self.onfini(onfini)
637
-
638
637
  self.nexsroot = nexsroot
639
638
 
639
+ async def modNexsRoot(self, ctor):
640
+
641
+ kids = [self]
642
+ if self.nexsroot is not None:
643
+ kids = self.nexsroot.getNexsKids()
644
+ await self.nexsroot.fini()
645
+
646
+ nexsroot = await ctor()
647
+
648
+ [kid.setNexsRoot(nexsroot) for kid in kids]
649
+
650
+ await nexsroot.startup()
651
+
640
652
  @classmethod
641
653
  def onPush(cls, event: str, passitem=False) -> Callable:
642
654
  '''
synapse/lib/schemas.py CHANGED
@@ -274,6 +274,7 @@ reqValidSslCtxOpts = s_config.getJsValidator({
274
274
  'verify': {'type': 'boolean', 'default': True},
275
275
  'client_cert': {'type': ['string', 'null'], 'default': None},
276
276
  'client_key': {'type': ['string', 'null'], 'default': None},
277
+ 'ca_cert': {'type': ['string', 'null'], 'default': None},
277
278
  },
278
279
  'additionalProperties': False,
279
280
  })
@@ -454,3 +455,41 @@ tabularConfSchema = {
454
455
  }
455
456
 
456
457
  reqValidTabularConf = s_config.getJsValidator(tabularConfSchema)
458
+
459
+ emptySchema = {'object': {}, 'additionalProperties': False}
460
+ re_drivename = r'^[\w_.-]{1,128}$'
461
+
462
+ driveInfoSchema = {
463
+ 'type': 'object',
464
+ 'properties': {
465
+ 'iden': {'type': 'string', 'pattern': s_config.re_iden},
466
+ 'parent': {'type': 'string', 'pattern': s_config.re_iden},
467
+ 'type': {'type': 'string', 'pattern': re_drivename},
468
+ 'name': {'type': 'string', 'pattern': re_drivename},
469
+ 'perm': s_msgpack.deepcopy(easyPermSchema),
470
+ 'kids': {'type': 'number', 'minimum': 0},
471
+ 'created': {'type': 'number'},
472
+ 'creator': {'type': 'string', 'pattern': s_config.re_iden},
473
+ # these are also data version info...
474
+ 'size': {'type': 'number', 'minimum': 0},
475
+ 'updated': {'type': 'number'},
476
+ 'updater': {'type': 'string', 'pattern': s_config.re_iden},
477
+ 'version': {'type': 'array', 'items': {'type': 'number', 'minItems': 3, 'maxItems': 3}},
478
+ },
479
+ 'required': ('iden', 'parent', 'name', 'created', 'creator', 'kids'),
480
+ 'additionalProperties': False,
481
+ }
482
+ reqValidDriveInfo = s_config.getJsValidator(driveInfoSchema)
483
+
484
+ driveDataVersSchema = {
485
+ 'type': 'object',
486
+ 'properties': {
487
+ 'size': {'type': 'number', 'minimum': 0},
488
+ 'updated': {'type': 'number'},
489
+ 'updater': {'type': 'string', 'pattern': s_config.re_iden},
490
+ 'version': {'type': 'array', 'items': {'type': 'number', 'minItems': 3, 'maxItems': 3}},
491
+ },
492
+ 'required': ('size', 'version', 'updated', 'updater'),
493
+ 'additionalProperties': False,
494
+ }
495
+ reqValidDriveDataVers = s_config.getJsValidator(driveDataVersSchema)
synapse/lib/snap.py CHANGED
@@ -316,6 +316,10 @@ class ProtoNode:
316
316
  mesg = f'Tagprop {name} does not exist in this Cortex.'
317
317
  return await self.ctx.snap._raiseOnStrict(s_exc.NoSuchTagProp, mesg)
318
318
 
319
+ if prop.locked:
320
+ mesg = f'Tagprop {name} is locked.'
321
+ return await self.ctx.snap._raiseOnStrict(s_exc.IsDeprLocked, mesg)
322
+
319
323
  try:
320
324
  norm, info = prop.type.norm(valu)
321
325
  except s_exc.BadTypeValu as e:
@@ -1029,7 +1033,7 @@ class Snap(s_base.Base):
1029
1033
  if node is not None:
1030
1034
  yield node
1031
1035
 
1032
- async def nodesByPropValu(self, full, cmpr, valu, reverse=False):
1036
+ async def nodesByPropValu(self, full, cmpr, valu, reverse=False, norm=True):
1033
1037
  if cmpr == 'type=':
1034
1038
  if reverse:
1035
1039
  async for node in self.nodesByPropTypeValu(full, valu, reverse=reverse):
@@ -1050,10 +1054,13 @@ class Snap(s_base.Base):
1050
1054
  mesg = f'No property named "{full}".'
1051
1055
  raise s_exc.NoSuchProp(mesg=mesg)
1052
1056
 
1053
- cmprvals = prop.type.getStorCmprs(cmpr, valu)
1054
- # an empty return probably means ?= with invalid value
1055
- if not cmprvals:
1056
- return
1057
+ if norm:
1058
+ cmprvals = prop.type.getStorCmprs(cmpr, valu)
1059
+ # an empty return probably means ?= with invalid value
1060
+ if not cmprvals:
1061
+ return
1062
+ else:
1063
+ cmprvals = ((cmpr, valu, prop.type.stortype),)
1057
1064
 
1058
1065
  if prop.isrunt:
1059
1066
  for storcmpr, storvalu, _ in cmprvals:
@@ -1108,7 +1115,7 @@ class Snap(s_base.Base):
1108
1115
  async for node in self.nodesByPropArray(prop.full, '=', valu, reverse=reverse):
1109
1116
  yield node
1110
1117
 
1111
- async def nodesByPropArray(self, full, cmpr, valu, reverse=False):
1118
+ async def nodesByPropArray(self, full, cmpr, valu, reverse=False, norm=True):
1112
1119
 
1113
1120
  prop = self.core.model.prop(full)
1114
1121
  if prop is None:
@@ -1119,7 +1126,10 @@ class Snap(s_base.Base):
1119
1126
  mesg = f'Array syntax is invalid on non array type: {prop.type.name}.'
1120
1127
  raise s_exc.BadTypeValu(mesg=mesg)
1121
1128
 
1122
- cmprvals = prop.type.arraytype.getStorCmprs(cmpr, valu)
1129
+ if norm:
1130
+ cmprvals = prop.type.arraytype.getStorCmprs(cmpr, valu)
1131
+ else:
1132
+ cmprvals = ((cmpr, valu, prop.type.arraytype.stortype),)
1123
1133
 
1124
1134
  if prop.isform:
1125
1135
  async for (buid, sodes) in self.core._liftByPropArray(prop.name, None, cmprvals, self.layers, reverse=reverse):
synapse/lib/storm.py CHANGED
@@ -53,7 +53,9 @@ When condition is tag:add or tag:del, you may optionally provide a form name
53
53
  to restrict the trigger to fire only on tags added or deleted from nodes of
54
54
  those forms.
55
55
 
56
- The added tag is provided to the query as an embedded variable '$tag'.
56
+ The added tag is provided to the query in the ``$auto`` dictionary variable under
57
+ ``$auto.opts.tag``. Usage of the ``$tag`` variable is deprecated and it will no longer
58
+ be populated in Synapse v3.0.0.
57
59
 
58
60
  Simple one level tag globbing is supported, only at the end after a period,
59
61
  that is aka.* matches aka.foo and aka.bar but not aka.foo.bar. aka* is not
synapse/lib/stormhttp.py CHANGED
@@ -95,6 +95,7 @@ class LibHttp(s_stormtypes.Lib):
95
95
  'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl_verify argument.
96
96
  'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
97
97
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
98
+ 'ca_cert': <str> - A PEM encoded full chain CA certificate for use when verifying the request.
98
99
  }
99
100
  '''
100
101
  _storm_locals = (
@@ -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
- imap_cli = aioimaplib.IMAP4_SSL(host=host, port=port, timeout=timeout)
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
 
@@ -1,4 +1,5 @@
1
1
  import synapse.exc as s_exc
2
+ import synapse.common as s_common
2
3
  import synapse.lib.grammar as s_grammar
3
4
 
4
5
  import synapse.lib.stormtypes as s_stormtypes
@@ -54,6 +55,8 @@ class LibModelExt(s_stormtypes.Lib):
54
55
  'args': (
55
56
  {'name': 'formname', 'type': 'str', 'desc': 'The form with the extended property.', },
56
57
  {'name': 'propname', 'type': 'str', 'desc': 'The extended property to remove.', },
58
+ {'name': 'force', 'type': 'boolean', 'default': False,
59
+ 'desc': 'Delete the property from all nodes before removing the definition.', },
57
60
  ),
58
61
  'returns': {'type': 'null', }}},
59
62
  {'name': 'delUnivProp',
@@ -61,12 +64,16 @@ class LibModelExt(s_stormtypes.Lib):
61
64
  'type': {'type': 'function', '_funcname': 'delUnivProp',
62
65
  'args': (
63
66
  {'name': 'propname', 'type': 'str', 'desc': 'Name of the universal property to remove.', },
67
+ {'name': 'force', 'type': 'boolean', 'default': False,
68
+ 'desc': 'Delete the property from all nodes before removing the definition.', },
64
69
  ),
65
70
  'returns': {'type': 'null', }}},
66
71
  {'name': 'delTagProp', 'desc': 'Remove an extended tag property definition from the model.',
67
72
  'type': {'type': 'function', '_funcname': 'delTagProp',
68
73
  'args': (
69
74
  {'name': 'propname', 'type': 'str', 'desc': 'Name of the tag property to remove.', },
75
+ {'name': 'force', 'type': 'boolean', 'default': False,
76
+ 'desc': 'Delete the tag property from all nodes before removing the definition.', },
70
77
  ),
71
78
  'returns': {'type': 'null', }}},
72
79
  {'name': 'getExtModel', 'desc': 'Get all extended model elements.',
@@ -163,20 +170,39 @@ class LibModelExt(s_stormtypes.Lib):
163
170
  s_stormtypes.confirm(('model', 'form', 'del', formname))
164
171
  await self.runt.snap.core.delForm(formname)
165
172
 
166
- async def delFormProp(self, formname, propname):
173
+ async def delFormProp(self, formname, propname, force=False):
167
174
  formname = await s_stormtypes.tostr(formname)
168
175
  propname = await s_stormtypes.tostr(propname)
176
+ force = await s_stormtypes.tobool(force)
169
177
  s_stormtypes.confirm(('model', 'prop', 'del', formname))
178
+
179
+ if force is True:
180
+ meta = {'user': self.runt.snap.user.iden, 'time': s_common.now()}
181
+ await self.runt.snap.core._delAllFormProp(formname, propname, meta)
182
+
170
183
  await self.runt.snap.core.delFormProp(formname, propname)
171
184
 
172
- async def delUnivProp(self, propname):
185
+ async def delUnivProp(self, propname, force=False):
173
186
  propname = await s_stormtypes.tostr(propname)
187
+ force = await s_stormtypes.tobool(force)
174
188
  s_stormtypes.confirm(('model', 'univ', 'del'))
189
+
190
+ if force:
191
+ meta = {'user': self.runt.snap.user.iden, 'time': s_common.now()}
192
+ await self.runt.snap.core._delAllUnivProp(propname, meta)
193
+
175
194
  await self.runt.snap.core.delUnivProp(propname)
176
195
 
177
- async def delTagProp(self, propname):
196
+ async def delTagProp(self, propname, force=False):
178
197
  propname = await s_stormtypes.tostr(propname)
198
+ force = await s_stormtypes.tobool(force)
199
+
179
200
  s_stormtypes.confirm(('model', 'tagprop', 'del'))
201
+
202
+ if force:
203
+ meta = {'user': self.runt.snap.user.iden, 'time': s_common.now()}
204
+ await self.runt.snap.core._delAllTagProp(propname, meta)
205
+
180
206
  await self.runt.snap.core.delTagProp(propname)
181
207
 
182
208
  @s_stormtypes.stormfunc(readonly=True)
@@ -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
 
@@ -875,14 +875,19 @@ class LibStixImport(s_stormtypes.Lib):
875
875
  bundle = await s_stormtypes.toprim(bundle)
876
876
  config = await s_stormtypes.toprim(config)
877
877
 
878
+ if not isinstance(config, dict):
879
+ mesg = 'STIX ingest config must be a dictionary.'
880
+ raise s_exc.BadArg(mesg=mesg)
881
+
878
882
  config.setdefault('bundle', {})
879
883
  config.setdefault('objects', {})
880
884
  config.setdefault('relationships', [])
881
885
 
882
- rellook = {r['type']: r for r in config.get('relationships', ())}
883
-
884
- nodesbyid = {}
885
- relationships = []
886
+ try:
887
+ rellook = {r['type']: r for r in config.get('relationships', ())}
888
+ except Exception as e:
889
+ mesg = f'Error processing relationships in STIX bundle ingest config: {e}.'
890
+ raise s_exc.BadArg(mesg=mesg)
886
891
 
887
892
  bundlenode = None
888
893
 
@@ -890,13 +895,41 @@ class LibStixImport(s_stormtypes.Lib):
890
895
  if bundleconf is None:
891
896
  bundleconf = {}
892
897
 
898
+ if not isinstance(bundleconf, dict):
899
+ mesg = 'STIX ingest config bundle value must be a dictionary.'
900
+ raise s_exc.BadArg(mesg=mesg)
901
+
893
902
  bundlestorm = bundleconf.get('storm')
894
903
  if bundlestorm:
904
+ if not isinstance(bundlestorm, str):
905
+ mesg = 'STIX ingest config storm query must be a string.'
906
+ raise s_exc.BadArg(mesg=mesg)
907
+
895
908
  bundlenode = await self._callStorm(bundlestorm, {'bundle': bundle})
896
909
 
897
910
  self.runt.layerConfirm(('node', 'edge', 'add', 'refs'))
898
911
 
899
- for obj in bundle.get('objects'):
912
+ try:
913
+ nodesbyid = await self._ingestObjects(bundle, config, rellook)
914
+ except Exception as e:
915
+ mesg = f'Error processing objects in STIX bundle ingest: {e}.'
916
+ raise s_exc.BadArg(mesg=mesg)
917
+
918
+ if bundlenode is not None:
919
+ for node in nodesbyid.values():
920
+ await bundlenode.addEdge('refs', node.iden())
921
+ await asyncio.sleep(0)
922
+ yield bundlenode
923
+
924
+ for node in nodesbyid.values():
925
+ yield node
926
+
927
+ async def _ingestObjects(self, bundle, config, rellook):
928
+
929
+ nodesbyid = {}
930
+ relationships = []
931
+
932
+ for obj in bundle.get('objects', ()):
900
933
 
901
934
  objtype = obj.get('type')
902
935
 
@@ -971,7 +1004,7 @@ class LibStixImport(s_stormtypes.Lib):
971
1004
  await self.runt.snap.warnonce(f'STIX bundle ingest has no relationship definition for: {reltype}.')
972
1005
 
973
1006
  # attempt to resolve object_refs
974
- for obj in bundle.get('objects'):
1007
+ for obj in bundle.get('objects', ()):
975
1008
 
976
1009
  node = nodesbyid.get(obj.get('id'))
977
1010
  if node is None:
@@ -984,17 +1017,7 @@ class LibStixImport(s_stormtypes.Lib):
984
1017
 
985
1018
  await node.addEdge('refs', refsnode.iden())
986
1019
 
987
- if bundlenode is not None:
988
- for node in nodesbyid.values():
989
- await bundlenode.addEdge('refs', node.iden())
990
- await asyncio.sleep(0)
991
- yield bundlenode
992
-
993
- for node in nodesbyid.values():
994
- yield node
995
-
996
- if bundlenode:
997
- yield bundlenode
1020
+ return nodesbyid
998
1021
 
999
1022
  async def _callStorm(self, text, varz):
1000
1023
 
@@ -649,7 +649,7 @@ class Vault(s_stormtypes.Prim):
649
649
  'type': {'type': 'function', '_funcname': '_methSetPerm',
650
650
  'args': (
651
651
  {'name': 'iden', 'type': 'str', 'desc': 'The user or role to modify.'},
652
- {'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden. $lib.undef to remove an existing permission.'},
652
+ {'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden. $lib.null to remove an existing permission.'},
653
653
  ),
654
654
  'returns': {'type': 'boolean', 'desc': '$lib.true if the permission was set, $lib.false otherwise.', }}},
655
655
 
@@ -744,7 +744,7 @@ class Vault(s_stormtypes.Prim):
744
744
  s_stormtypes.confirmEasyPerm(vault, s_cell.PERM_ADMIN, mesg=mesg)
745
745
 
746
746
  iden = await s_stormtypes.tostr(iden)
747
- level = await s_stormtypes.toint(level)
747
+ level = await s_stormtypes.toint(level, noneok=True)
748
748
 
749
749
  return await self.runt.snap.core.setVaultPerm(self.valu, iden, level)
750
750
 
synapse/lib/stormtypes.py CHANGED
@@ -5277,7 +5277,7 @@ class Number(Prim):
5277
5277
  def __init__(self, valu, path=None):
5278
5278
  try:
5279
5279
  valu = s_common.hugenum(valu)
5280
- except decimal.DecimalException as e:
5280
+ except (TypeError, decimal.DecimalException) as e:
5281
5281
  mesg = f'Failed to make number from {valu!r}'
5282
5282
  raise s_exc.BadCast(mesg=mesg) from e
5283
5283
 
synapse/lib/types.py CHANGED
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  import asyncio
2
3
  import decimal
3
4
  import logging
@@ -78,6 +79,14 @@ class Type:
78
79
 
79
80
  self.postTypeInit()
80
81
 
82
+ normopts = dict(self.opts)
83
+ for optn, valu in normopts.items():
84
+ if isinstance(valu, float):
85
+ normopts[optn] = str(valu)
86
+
87
+ ctor = '.'.join([self.__class__.__module__, self.__class__.__qualname__])
88
+ self.typehash = sys.intern(s_common.guid((ctor, s_common.flatten(normopts))))
89
+
81
90
  def _storLiftSafe(self, cmpr, valu):
82
91
  try:
83
92
  return self.storlifts['=']('=', 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, 177, 0)
226
+ version = (2, 179, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'b7da795aeb690020e38e99dc5aa1f505cdc2d659'
228
+ commit = '1c51c58523e9012655d8d18bfa1ad149e5536c25'