synapse 2.187.0__py311-none-any.whl → 2.188.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 (45) hide show
  1. synapse/cortex.py +131 -7
  2. synapse/datamodel.py +20 -4
  3. synapse/exc.py +14 -1
  4. synapse/lib/ast.py +6 -4
  5. synapse/lib/auth.py +9 -0
  6. synapse/lib/httpapi.py +2 -1
  7. synapse/lib/nexus.py +6 -0
  8. synapse/lib/node.py +5 -3
  9. synapse/lib/scrape.py +18 -104
  10. synapse/lib/storm.py +44 -28
  11. synapse/lib/stormlib/modelext.py +31 -0
  12. synapse/lib/stormlib/scrape.py +1 -4
  13. synapse/lib/stormtypes.py +17 -1
  14. synapse/lib/version.py +2 -2
  15. synapse/lib/view.py +9 -3
  16. synapse/models/base.py +27 -0
  17. synapse/models/files.py +22 -0
  18. synapse/models/inet.py +49 -4
  19. synapse/models/orgs.py +64 -2
  20. synapse/models/proj.py +1 -6
  21. synapse/models/risk.py +65 -0
  22. synapse/tests/test_cortex.py +21 -0
  23. synapse/tests/test_lib_agenda.py +13 -0
  24. synapse/tests/test_lib_auth.py +15 -0
  25. synapse/tests/test_lib_cell.py +1 -1
  26. synapse/tests/test_lib_httpapi.py +6 -0
  27. synapse/tests/test_lib_nexus.py +26 -0
  28. synapse/tests/test_lib_scrape.py +14 -6
  29. synapse/tests/test_lib_storm.py +48 -0
  30. synapse/tests/test_lib_stormlib_modelext.py +76 -1
  31. synapse/tests/test_lib_stormlib_scrape.py +0 -8
  32. synapse/tests/test_lib_stormtypes.py +1 -1
  33. synapse/tests/test_lib_trigger.py +8 -0
  34. synapse/tests/test_lib_view.py +24 -0
  35. synapse/tests/test_model_base.py +11 -0
  36. synapse/tests/test_model_files.py +19 -0
  37. synapse/tests/test_model_inet.py +33 -0
  38. synapse/tests/test_model_orgs.py +39 -0
  39. synapse/tests/test_model_proj.py +11 -1
  40. synapse/tests/test_model_risk.py +32 -0
  41. {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/METADATA +1 -1
  42. {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/RECORD +45 -45
  43. {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/LICENSE +0 -0
  44. {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/WHEEL +0 -0
  45. {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py CHANGED
@@ -425,13 +425,14 @@ class CoreApi(s_cell.CellApi):
425
425
  async for item in self.cell.syncLayerNodeEdits(layr.iden, offs, wait=wait):
426
426
  yield item
427
427
 
428
- async def getPropNorm(self, prop, valu):
428
+ async def getPropNorm(self, prop, valu, typeopts=None):
429
429
  '''
430
430
  Get the normalized property value based on the Cortex data model.
431
431
 
432
432
  Args:
433
433
  prop (str): The property to normalize.
434
434
  valu: The value to normalize.
435
+ typeopts: A Synapse type opts dictionary used to further normalize the value.
435
436
 
436
437
  Returns:
437
438
  (tuple): A two item tuple, containing the normed value and the info dictionary.
@@ -440,15 +441,16 @@ class CoreApi(s_cell.CellApi):
440
441
  s_exc.NoSuchProp: If the prop does not exist.
441
442
  s_exc.BadTypeValu: If the value fails to normalize.
442
443
  '''
443
- return await self.cell.getPropNorm(prop, valu)
444
+ return await self.cell.getPropNorm(prop, valu, typeopts=typeopts)
444
445
 
445
- async def getTypeNorm(self, name, valu):
446
+ async def getTypeNorm(self, name, valu, typeopts=None):
446
447
  '''
447
448
  Get the normalized type value based on the Cortex data model.
448
449
 
449
450
  Args:
450
451
  name (str): The type to normalize.
451
452
  valu: The value to normalize.
453
+ typeopts: A Synapse type opts dictionary used to further normalize the value.
452
454
 
453
455
  Returns:
454
456
  (tuple): A two item tuple, containing the normed value and the info dictionary.
@@ -457,7 +459,7 @@ class CoreApi(s_cell.CellApi):
457
459
  s_exc.NoSuchType: If the type does not exist.
458
460
  s_exc.BadTypeValu: If the value fails to normalize.
459
461
  '''
460
- return await self.cell.getTypeNorm(name, valu)
462
+ return await self.cell.getTypeNorm(name, valu, typeopts=typeopts)
461
463
 
462
464
  async def addForm(self, formname, basetype, typeopts, typeinfo):
463
465
  '''
@@ -1350,6 +1352,17 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1350
1352
  'desc': 'Controls access to deleting specific extended model forms.',
1351
1353
  'ex': 'model.form.del._foo:bar'},
1352
1354
 
1355
+ {'perm': ('model', 'type', 'add'), 'gate': 'cortex',
1356
+ 'desc': 'Controls access to adding extended model types.'},
1357
+ {'perm': ('model', 'type', 'add', '<type>'), 'gate': 'cortex',
1358
+ 'desc': 'Controls access to adding specific extended model types.',
1359
+ 'ex': 'model.type.add._foo:bar'},
1360
+ {'perm': ('model', 'type', 'del'), 'gate': 'cortex',
1361
+ 'desc': 'Controls access to deleting extended model types.'},
1362
+ {'perm': ('model', 'type', 'del', '<type>'), 'gate': 'cortex',
1363
+ 'desc': 'Controls access to deleting specific extended model types.',
1364
+ 'ex': 'model.type.del._foo:bar'},
1365
+
1353
1366
  {'perm': ('model', 'prop', 'add'), 'gate': 'cortex',
1354
1367
  'desc': 'Controls access to adding extended model properties.'},
1355
1368
  {'perm': ('model', 'prop', 'add', '<form>'), 'gate': 'cortex',
@@ -3183,12 +3196,19 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3183
3196
 
3184
3197
  async def _loadExtModel(self):
3185
3198
 
3199
+ self.exttypes = self.cortexdata.getSubKeyVal('model:types:')
3186
3200
  self.extforms = self.cortexdata.getSubKeyVal('model:forms:')
3187
3201
  self.extprops = self.cortexdata.getSubKeyVal('model:props:')
3188
3202
  self.extunivs = self.cortexdata.getSubKeyVal('model:univs:')
3189
3203
  self.extedges = self.cortexdata.getSubKeyVal('model:edges:')
3190
3204
  self.exttagprops = self.cortexdata.getSubKeyVal('model:tagprops:')
3191
3205
 
3206
+ for typename, basetype, typeopts, typeinfo in self.exttypes.values():
3207
+ try:
3208
+ self.model.addType(typename, basetype, typeopts, typeinfo)
3209
+ except Exception as e:
3210
+ logger.warning(f'Extended type ({typename}) error: {e}')
3211
+
3192
3212
  for formname, basetype, typeopts, typeinfo in self.extforms.values():
3193
3213
  try:
3194
3214
  self.model.addType(formname, basetype, typeopts, typeinfo)
@@ -3238,6 +3258,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3238
3258
  dict: A dictionary containing forms, form properties, universal properties and tag properties.
3239
3259
  '''
3240
3260
  ret = collections.defaultdict(list)
3261
+ for typename, basetype, typeopts, typeinfo in self.exttypes.values():
3262
+ ret['types'].append((typename, basetype, typeopts, typeinfo))
3263
+
3241
3264
  for formname, basetype, typeopts, typeinfo in self.extforms.values():
3242
3265
  ret['forms'].append((formname, basetype, typeopts, typeinfo))
3243
3266
 
@@ -3277,18 +3300,30 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3277
3300
  emodl = await self.getExtModel()
3278
3301
  amodl = collections.defaultdict(list)
3279
3302
 
3303
+ types = {info[0]: info for info in model.get('types', ())}
3280
3304
  forms = {info[0]: info for info in model.get('forms', ())}
3281
3305
  props = {(info[0], info[1]): info for info in model.get('props', ())}
3282
3306
  tagprops = {info[0]: info for info in model.get('tagprops', ())}
3283
3307
  univs = {info[0]: info for info in model.get('univs', ())}
3284
3308
  edges = {info[0]: info for info in model.get('edges', ())}
3285
3309
 
3310
+ etyps = {info[0]: info for info in emodl.get('types', ())}
3286
3311
  efrms = {info[0]: info for info in emodl.get('forms', ())}
3287
3312
  eprops = {(info[0], info[1]): info for info in emodl.get('props', ())}
3288
3313
  etagprops = {info[0]: info for info in emodl.get('tagprops', ())}
3289
3314
  eunivs = {info[0]: info for info in emodl.get('univs', ())}
3290
3315
  eedges = {info[0]: info for info in emodl.get('edges', ())}
3291
3316
 
3317
+ for (name, info) in types.items():
3318
+ enfo = etyps.get(name)
3319
+ if enfo is None:
3320
+ amodl['types'].append(info)
3321
+ continue
3322
+ if enfo == info:
3323
+ continue
3324
+ mesg = f'Extended type definition differs from existing definition for {name}.'
3325
+ raise s_exc.BadTypeDef(mesg=mesg, name=name)
3326
+
3292
3327
  for (name, info) in forms.items():
3293
3328
  enfo = efrms.get(name)
3294
3329
  if enfo is None:
@@ -3341,6 +3376,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3341
3376
  mesg = f'Extended edge definition differs from existing definition for {info[0]}'
3342
3377
  raise s_exc.BadEdgeDef(mesg=mesg, n1form=n1form, verb=verb, n2form=n2form)
3343
3378
 
3379
+ for typename, basetype, typeopts, typeinfo in amodl['types']:
3380
+ await self.addType(typename, basetype, typeopts, typeinfo)
3381
+
3344
3382
  for formname, basetype, typeopts, typeinfo in amodl['forms']:
3345
3383
  await self.addForm(formname, basetype, typeopts, typeinfo)
3346
3384
 
@@ -3405,9 +3443,15 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3405
3443
  if not formname.startswith('_'):
3406
3444
  mesg = 'Extended form must begin with "_"'
3407
3445
  raise s_exc.BadFormDef(form=formname, mesg=mesg)
3446
+
3408
3447
  if self.model.form(formname) is not None:
3409
3448
  mesg = f'Form name already exists: {formname}'
3410
3449
  raise s_exc.DupFormName(mesg=mesg)
3450
+
3451
+ if self.model.type(formname) is not None:
3452
+ mesg = f'Type already exists: {formname}'
3453
+ raise s_exc.DupTypeName.init(formname)
3454
+
3411
3455
  return await self._push('model:form:add', formname, basetype, typeopts, typeinfo)
3412
3456
 
3413
3457
  @s_nexus.Pusher.onPush('model:form:add')
@@ -3462,6 +3506,74 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3462
3506
  await self.fire('core:extmodel:change', form=formname, act='del', type='form')
3463
3507
  await self.feedBeholder('model:form:del', {'form': formname})
3464
3508
 
3509
+ async def addType(self, typename, basetype, typeopts, typeinfo):
3510
+ if not isinstance(typeopts, dict):
3511
+ mesg = 'Type options should be a dict.'
3512
+ raise s_exc.BadArg(type=typename, mesg=mesg)
3513
+
3514
+ if not isinstance(typeinfo, dict):
3515
+ mesg = 'Type info should be a dict.'
3516
+ raise s_exc.BadArg(type=typename, mesg=mesg)
3517
+
3518
+ if not typename.startswith('_'):
3519
+ mesg = 'Extended type must begin with "_".'
3520
+ raise s_exc.BadTypeDef(type=typename, mesg=mesg)
3521
+
3522
+ if self.model.type(typename) is not None:
3523
+ raise s_exc.DupTypeName.init(typename)
3524
+
3525
+ if (base := self.model.type(basetype)) is None:
3526
+ mesg = f'Specified base type {basetype} does not exist.'
3527
+ raise s_exc.NoSuchType(mesg=mesg, name=basetype)
3528
+
3529
+ base.clone(typeopts)
3530
+
3531
+ return await self._push('model:type:add', typename, basetype, typeopts, typeinfo)
3532
+
3533
+ @s_nexus.Pusher.onPush('model:type:add')
3534
+ async def _addType(self, typename, basetype, typeopts, typeinfo):
3535
+ if self.model.type(typename) is not None:
3536
+ return
3537
+
3538
+ ifaces = typeinfo.get('interfaces')
3539
+
3540
+ if ifaces and 'taxonomy' in ifaces:
3541
+ logger.warning(f'{typename} is using the deprecated taxonomy interface, updating to meta:taxonomy.')
3542
+
3543
+ ifaces = set(ifaces)
3544
+ ifaces.remove('taxonomy')
3545
+ ifaces.add('meta:taxonomy')
3546
+ typeinfo['interfaces'] = tuple(ifaces)
3547
+
3548
+ self.model.addType(typename, basetype, typeopts, typeinfo)
3549
+
3550
+ self.exttypes.set(typename, (typename, basetype, typeopts, typeinfo))
3551
+ await self.fire('core:extmodel:change', name=typename, act='add', type='type')
3552
+
3553
+ if (_type := self.model.type(typename)) is not None:
3554
+ await self.feedBeholder('model:type:add', {'type': _type.pack()})
3555
+
3556
+ async def delType(self, typename):
3557
+ if not typename.startswith('_'):
3558
+ mesg = 'Extended type must begin with "_".'
3559
+ raise s_exc.BadTypeDef(type=typename, mesg=mesg)
3560
+
3561
+ if self.model.type(typename) is None:
3562
+ raise s_exc.NoSuchType.init(typename)
3563
+
3564
+ return await self._push('model:type:del', typename)
3565
+
3566
+ @s_nexus.Pusher.onPush('model:type:del')
3567
+ async def _delType(self, typename):
3568
+ if self.model.type(typename) is None:
3569
+ return
3570
+
3571
+ self.model.delType(typename)
3572
+
3573
+ self.exttypes.pop(typename, None)
3574
+ await self.fire('core:extmodel:change', name=typename, act='del', type='type')
3575
+ await self.feedBeholder('model:type:del', {'type': typename})
3576
+
3465
3577
  async def addFormProp(self, form, prop, tdef, info):
3466
3578
  if not isinstance(tdef, tuple):
3467
3579
  mesg = 'Form property type definitions should be a tuple.'
@@ -6282,13 +6394,14 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
6282
6394
  logger.exception('mod load fail: %s' % (ctor,))
6283
6395
  return None
6284
6396
 
6285
- async def getPropNorm(self, prop, valu):
6397
+ async def getPropNorm(self, prop, valu, typeopts=None):
6286
6398
  '''
6287
6399
  Get the normalized property value based on the Cortex data model.
6288
6400
 
6289
6401
  Args:
6290
6402
  prop (str): The property to normalize.
6291
6403
  valu: The value to normalize.
6404
+ typeopts: A Synapse type opts dictionary used to further normalize the value.
6292
6405
 
6293
6406
  Returns:
6294
6407
  (tuple): A two item tuple, containing the normed value and the info dictionary.
@@ -6301,16 +6414,22 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
6301
6414
  if pobj is None:
6302
6415
  raise s_exc.NoSuchProp(mesg=f'The property {prop} does not exist.',
6303
6416
  prop=prop)
6304
- norm, info = pobj.type.norm(valu)
6417
+
6418
+ tobj = pobj.type
6419
+ if typeopts:
6420
+ tobj = tobj.clone(typeopts)
6421
+
6422
+ norm, info = tobj.norm(valu)
6305
6423
  return norm, info
6306
6424
 
6307
- async def getTypeNorm(self, name, valu):
6425
+ async def getTypeNorm(self, name, valu, typeopts=None):
6308
6426
  '''
6309
6427
  Get the normalized type value based on the Cortex data model.
6310
6428
 
6311
6429
  Args:
6312
6430
  name (str): The type to normalize.
6313
6431
  valu: The value to normalize.
6432
+ typeopts: A Synapse type opts dictionary used to further normalize the value.
6314
6433
 
6315
6434
  Returns:
6316
6435
  (tuple): A two item tuple, containing the normed value and the info dictionary.
@@ -6323,6 +6442,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
6323
6442
  if tobj is None:
6324
6443
  raise s_exc.NoSuchType(mesg=f'The type {name} does not exist.',
6325
6444
  name=name)
6445
+ if typeopts:
6446
+ tobj = tobj.clone(typeopts)
6447
+
6326
6448
  norm, info = tobj.norm(valu)
6327
6449
  return norm, info
6328
6450
 
@@ -6411,6 +6533,8 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
6411
6533
  if appt is not None:
6412
6534
  return appt.pack()
6413
6535
 
6536
+ self.auth.reqNoAuthGate(iden)
6537
+
6414
6538
  user = await self.auth.reqUser(cdef['creator'])
6415
6539
 
6416
6540
  cdef = await self.agenda.add(cdef)
synapse/datamodel.py CHANGED
@@ -853,13 +853,17 @@ class Model:
853
853
  for _, mdef in mods:
854
854
 
855
855
  for formname, forminfo, propdefs in mdef.get('forms', ()):
856
- self.addForm(formname, forminfo, propdefs)
856
+ self.addForm(formname, forminfo, propdefs, checks=False)
857
857
 
858
858
  # now we can load edge definitions...
859
859
  for _, mdef in mods:
860
860
  for etype, einfo in mdef.get('edges', ()):
861
861
  self.addEdge(etype, einfo)
862
862
 
863
+ # now we can check the forms display settings...
864
+ for form in self.forms.values():
865
+ self._checkFormDisplay(form)
866
+
863
867
  def addEdge(self, edgetype, edgeinfo):
864
868
 
865
869
  n1form, verb, n2form = edgetype
@@ -915,7 +919,7 @@ class Model:
915
919
  self.types[typename] = newtype
916
920
  self._modeldef['types'].append(newtype.getTypeDef())
917
921
 
918
- def addForm(self, formname, forminfo, propdefs):
922
+ def addForm(self, formname, forminfo, propdefs, checks=True):
919
923
 
920
924
  if not s_grammar.isFormName(formname):
921
925
  mesg = f'Invalid form name {formname}'
@@ -949,7 +953,8 @@ class Model:
949
953
  for ifname in form.type.info.get('interfaces', ()):
950
954
  self._addFormIface(form, ifname)
951
955
 
952
- self._checkFormDisplay(form)
956
+ if checks:
957
+ self._checkFormDisplay(form)
953
958
 
954
959
  self.formprefixcache.clear()
955
960
 
@@ -1029,10 +1034,21 @@ class Model:
1029
1034
  return
1030
1035
 
1031
1036
  if self.propsbytype.get(typename):
1032
- raise s_exc.CantDelType(name=typename)
1037
+ mesg = f'Cannot delete type {typename} as it is still in use by properties.'
1038
+ raise s_exc.CantDelType(mesg=mesg, name=typename)
1039
+
1040
+ for _type in self.types.values():
1041
+ if typename in _type.info['bases']:
1042
+ mesg = f'Cannot delete type {typename} as it is still in use by other types.'
1043
+ raise s_exc.CantDelType(mesg=mesg, name=typename)
1044
+
1045
+ if _type.isarray and _type.arraytype.name == typename:
1046
+ mesg = f'Cannot delete type {typename} as it is still in use by array types.'
1047
+ raise s_exc.CantDelType(mesg=mesg, name=typename)
1033
1048
 
1034
1049
  self.types.pop(typename, None)
1035
1050
  self.propsbytype.pop(typename, None)
1051
+ self.arraysbytype.pop(typename, None)
1036
1052
 
1037
1053
  def _addFormUniv(self, form, name, tdef, info):
1038
1054
 
synapse/exc.py CHANGED
@@ -193,6 +193,13 @@ class DupTagPropName(SynErr): pass
193
193
  class DupUserName(SynErr): pass
194
194
  class DupStormSvc(SynErr): pass
195
195
 
196
+ class DupTypeName(SynErr):
197
+ @classmethod
198
+ def init(cls, name, mesg=None):
199
+ if mesg is None:
200
+ mesg = f'Type already exists: {name}.'
201
+ return DupTypeName(mesg=mesg, name=name)
202
+
196
203
  class DupEdgeType(SynErr):
197
204
 
198
205
  @classmethod
@@ -245,6 +252,13 @@ class NoSuchForm(SynErr):
245
252
  mesg = f'No form named {name}.'
246
253
  return NoSuchForm(mesg=mesg, name=name)
247
254
 
255
+ class NoSuchType(SynErr):
256
+ @classmethod
257
+ def init(cls, name, mesg=None):
258
+ if mesg is None:
259
+ mesg = f'No type named {name}.'
260
+ return NoSuchType(mesg=mesg, name=name)
261
+
248
262
  class NoSuchProp(SynErr):
249
263
 
250
264
  @classmethod
@@ -289,7 +303,6 @@ class NoSuchPath(SynErr): pass
289
303
  class NoSuchPivot(SynErr): pass
290
304
  class NoSuchUniv(SynErr): pass
291
305
  class NoSuchRole(SynErr): pass
292
- class NoSuchType(SynErr): pass
293
306
  class NoSuchUser(SynErr): pass
294
307
  class NoSuchVar(SynErr): pass
295
308
  class NoSuchView(SynErr): pass
synapse/lib/ast.py CHANGED
@@ -731,7 +731,7 @@ class SubQuery(Oper):
731
731
  async with runt.getSubRuntime(self.kids[0]) as runt:
732
732
  async for valunode, valupath in runt.execute():
733
733
 
734
- retn.append(valunode.ndef[1])
734
+ retn.append(valunode)
735
735
 
736
736
  if len(retn) > limit:
737
737
  query = self.kids[0].text
@@ -1387,7 +1387,7 @@ class SwitchCase(Oper):
1387
1387
  varv = await self.kids[0].compute(runt, path)
1388
1388
 
1389
1389
  # TODO: when we have var type system, do type-aware comparison
1390
- subq = self.cases.get(str(varv))
1390
+ subq = self.cases.get(await s_stormtypes.tostr(varv))
1391
1391
  if subq is None and self.defcase is not None:
1392
1392
  subq = self.defcase
1393
1393
 
@@ -1401,7 +1401,7 @@ class SwitchCase(Oper):
1401
1401
  # no nodes and a runt safe value should execute
1402
1402
  varv = await self.kids[0].compute(runt, None)
1403
1403
 
1404
- subq = self.cases.get(str(varv))
1404
+ subq = self.cases.get(await s_stormtypes.tostr(varv))
1405
1405
  if subq is None and self.defcase is not None:
1406
1406
  subq = self.defcase
1407
1407
 
@@ -4177,9 +4177,11 @@ class EditPropSet(Edit):
4177
4177
  # runt node property permissions are enforced by the callback
4178
4178
  runt.confirmPropSet(prop)
4179
4179
 
4180
+ isndef = isinstance(prop.type, s_types.Ndef)
4180
4181
  isarray = isinstance(prop.type, s_types.Array)
4181
4182
 
4182
4183
  try:
4184
+
4183
4185
  if isarray and isinstance(rval, SubQuery):
4184
4186
  valu = await rval.compute_array(runt, path)
4185
4187
  expand = False
@@ -4187,7 +4189,7 @@ class EditPropSet(Edit):
4187
4189
  else:
4188
4190
  valu = await rval.compute(runt, path)
4189
4191
 
4190
- valu = await s_stormtypes.tostor(valu)
4192
+ valu = await s_stormtypes.tostor(valu, isndef=isndef)
4191
4193
 
4192
4194
  if isadd or issub:
4193
4195
 
synapse/lib/auth.py CHANGED
@@ -493,6 +493,11 @@ class Auth(s_nexus.Pusher):
493
493
  raise s_exc.NoSuchAuthGate(iden=iden, mesg=mesg)
494
494
  return gate
495
495
 
496
+ def reqNoAuthGate(self, iden):
497
+ if self.authgates.get(iden) is not None:
498
+ mesg = f'An auth gate already exists with iden: ({iden}).'
499
+ raise s_exc.DupIden(iden=iden, mesg=mesg)
500
+
496
501
  def checkUserLimit(self):
497
502
  '''
498
503
  Check if we're at the specified user limit.
@@ -570,6 +575,8 @@ class Auth(s_nexus.Pusher):
570
575
  if user is not None:
571
576
  return
572
577
 
578
+ self.reqNoAuthGate(iden)
579
+
573
580
  info = {
574
581
  'iden': iden,
575
582
  'name': name,
@@ -626,6 +633,8 @@ class Auth(s_nexus.Pusher):
626
633
  if role is not None:
627
634
  return
628
635
 
636
+ self.reqNoAuthGate(iden)
637
+
629
638
  info = {
630
639
  'iden': iden,
631
640
  'name': name,
synapse/lib/httpapi.py CHANGED
@@ -1056,13 +1056,14 @@ class ModelNormV1(Handler):
1056
1056
 
1057
1057
  propname = body.get('prop')
1058
1058
  propvalu = body.get('value')
1059
+ typeopts = body.get('typeopts')
1059
1060
 
1060
1061
  if propname is None:
1061
1062
  self.sendRestErr('MissingField', 'The property normalization API requires a prop name.')
1062
1063
  return
1063
1064
 
1064
1065
  try:
1065
- valu, info = await self.cell.getPropNorm(propname, propvalu)
1066
+ valu, info = await self.cell.getPropNorm(propname, propvalu, typeopts=typeopts)
1066
1067
  except s_exc.NoSuchProp:
1067
1068
  return self.sendRestErr('NoSuchProp', 'The property {propname} does not exist.')
1068
1069
  except Exception as e:
synapse/lib/nexus.py CHANGED
@@ -341,6 +341,12 @@ class NexsRoot(s_base.Base):
341
341
  if meta is None:
342
342
  meta = {}
343
343
 
344
+ if (nexus := self._nexskids.get(nexsiden)) is None:
345
+ raise s_exc.NoSuchIden(mesg=f'No Nexus Pusher with iden {nexsiden}.', iden=nexsiden)
346
+
347
+ if event not in nexus._nexshands:
348
+ raise s_exc.NoSuchName(mesg=f'No Nexus handler for event {event}.', name=event)
349
+
344
350
  async with self.cell.nexslock:
345
351
  self.reqNotReadOnly()
346
352
  # Keep a reference to the shielded task to ensure it isn't GC'd
synapse/lib/node.py CHANGED
@@ -173,11 +173,13 @@ class Node:
173
173
  if prop is None:
174
174
  return None
175
175
 
176
- if prop.modl.form(prop.type.name) is None:
176
+ if prop.modl.form(prop.type.name) is not None:
177
+ buid = s_common.buid((prop.type.name, valu))
178
+ elif prop.type.name == 'ndef':
179
+ buid = s_common.buid(valu)
180
+ else:
177
181
  return None
178
182
 
179
- buid = s_common.buid((prop.type.name, valu))
180
-
181
183
  step = cache.get(buid, s_common.novalu)
182
184
  if step is s_common.novalu:
183
185
  step = cache[buid] = await node.snap.getNodeByBuid(buid)