synapse 2.134.0__py311-none-any.whl → 2.136.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 CHANGED
@@ -1355,12 +1355,14 @@ class Axon(s_cell.Cell):
1355
1355
 
1356
1356
  link00, sock00 = await s_link.linksock(forceclose=True)
1357
1357
 
1358
+ feedtask = None
1359
+
1358
1360
  try:
1359
1361
  todo = s_common.todo(_spawn_readlines, sock00)
1360
1362
  async with await s_base.Base.anit() as scope:
1361
1363
 
1362
1364
  scope.schedCoro(s_coro.spawn(todo, log_conf=await self._getSpawnLogConf()))
1363
- scope.schedCoro(self._sha256ToLink(sha256, link00))
1365
+ feedtask = scope.schedCoro(self._sha256ToLink(sha256, link00))
1364
1366
 
1365
1367
  while not self.isfini:
1366
1368
 
@@ -1377,6 +1379,8 @@ class Axon(s_cell.Cell):
1377
1379
  finally:
1378
1380
  sock00.close()
1379
1381
  await link00.fini()
1382
+ if feedtask is not None:
1383
+ await feedtask
1380
1384
 
1381
1385
  async def csvrows(self, sha256, dialect='excel', **fmtparams):
1382
1386
  await self._reqHas(sha256)
@@ -1385,12 +1389,14 @@ class Axon(s_cell.Cell):
1385
1389
 
1386
1390
  link00, sock00 = await s_link.linksock(forceclose=True)
1387
1391
 
1392
+ feedtask = None
1393
+
1388
1394
  try:
1389
1395
  todo = s_common.todo(_spawn_readrows, sock00, dialect, fmtparams)
1390
1396
  async with await s_base.Base.anit() as scope:
1391
1397
 
1392
1398
  scope.schedCoro(s_coro.spawn(todo, log_conf=await self._getSpawnLogConf()))
1393
- scope.schedCoro(self._sha256ToLink(sha256, link00))
1399
+ feedtask = scope.schedCoro(self._sha256ToLink(sha256, link00))
1394
1400
 
1395
1401
  while not self.isfini:
1396
1402
 
@@ -1407,6 +1413,8 @@ class Axon(s_cell.Cell):
1407
1413
  finally:
1408
1414
  sock00.close()
1409
1415
  await link00.fini()
1416
+ if feedtask is not None:
1417
+ await feedtask
1410
1418
 
1411
1419
  async def jsonlines(self, sha256):
1412
1420
  async for line in self.readlines(sha256):
synapse/cortex.py CHANGED
@@ -82,6 +82,7 @@ import synapse.lib.stormlib.project as s_stormlib_project # NOQA
82
82
  import synapse.lib.stormlib.version as s_stormlib_version # NOQA
83
83
  import synapse.lib.stormlib.ethereum as s_stormlib_ethereum # NOQA
84
84
  import synapse.lib.stormlib.modelext as s_stormlib_modelext # NOQA
85
+ import synapse.lib.stormlib.compression as s_stormlib_compression # NOQA
85
86
  import synapse.lib.stormlib.notifications as s_stormlib_notifications # NOQA
86
87
 
87
88
  logger = logging.getLogger(__name__)
@@ -1176,6 +1177,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1176
1177
 
1177
1178
  self.view = None # The default/main view
1178
1179
 
1180
+ self._cortex_permdefs = []
1181
+ self._initCorePerms()
1182
+
1179
1183
  # Reset the storm:log:level from the config value to an int for internal use.
1180
1184
  self.conf['storm:log:level'] = s_common.normLogLevel(self.conf.get('storm:log:level'))
1181
1185
  self.stormlog = self.conf.get('storm:log')
@@ -1475,65 +1479,72 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1475
1479
  self.modsbyiface[name] = tuple(mods)
1476
1480
  return mods
1477
1481
 
1478
- async def _getPermDefs(self):
1479
-
1480
- permdefs = list(await s_cell.Cell._getPermDefs(self))
1481
- permdefs.extend((
1482
- {'perm': ('view',), 'gate': 'view',
1483
- 'desc': 'Used to control all view permissions.'},
1482
+ def _initCorePerms(self):
1483
+ self._cortex_permdefs.extend((
1484
+ {'perm': ('view',), 'gate': 'cortex',
1485
+ 'desc': 'Controls all view permissions.'},
1486
+ {'perm': ('view', 'add'), 'gate': 'cortex',
1487
+ 'desc': 'Controls access to add a new view including forks.'},
1484
1488
  {'perm': ('view', 'read'), 'gate': 'view',
1485
- 'desc': 'Used to control read access to a view.'},
1489
+ 'desc': 'Used to control read access to a view.'},
1486
1490
 
1487
1491
  {'perm': ('node',), 'gate': 'layer',
1488
- 'desc': 'Controls all node edits in a layer.'},
1492
+ 'desc': 'Controls all node edits in a layer.'},
1489
1493
  {'perm': ('node', 'add'), 'gate': 'layer',
1490
- 'desc': 'Controls adding any form of node in a layer.'},
1494
+ 'desc': 'Controls adding any form of node in a layer.'},
1491
1495
  {'perm': ('node', 'del'), 'gate': 'layer',
1492
- 'desc': 'Controls removing any form of node in a layer.'},
1496
+ 'desc': 'Controls removing any form of node in a layer.'},
1493
1497
 
1494
1498
  {'perm': ('node', 'add', '<form>'), 'gate': 'layer',
1495
- 'ex': 'node.add.inet:ipv4',
1496
- 'desc': 'Controls adding a specific form of node in a layer.'},
1499
+ 'ex': 'node.add.inet:ipv4',
1500
+ 'desc': 'Controls adding a specific form of node in a layer.'},
1497
1501
  {'perm': ('node', 'del', '<form>'), 'gate': 'layer',
1498
- 'desc': 'Controls removing a specific form of node in a layer.'},
1502
+ 'desc': 'Controls removing a specific form of node in a layer.'},
1499
1503
 
1500
1504
  {'perm': ('node', 'tag'), 'gate': 'layer',
1501
- 'desc': 'Controls editing any tag on any node in a layer.'},
1505
+ 'desc': 'Controls editing any tag on any node in a layer.'},
1502
1506
  {'perm': ('node', 'tag', 'add'), 'gate': 'layer',
1503
- 'desc': 'Controls adding any tag on any node in a layer.'},
1507
+ 'desc': 'Controls adding any tag on any node in a layer.'},
1504
1508
  {'perm': ('node', 'tag', 'del'), 'gate': 'layer',
1505
- 'desc': 'Controls removing any tag on any node in a layer.'},
1509
+ 'desc': 'Controls removing any tag on any node in a layer.'},
1506
1510
 
1507
1511
  {'perm': ('node', 'tag', 'add', '<tag...>'), 'gate': 'layer',
1508
- 'ex': 'node.tag.add.cno.mal.redtree',
1509
- 'desc': 'Controls adding a specific tag on any node in a layer.'},
1512
+ 'ex': 'node.tag.add.cno.mal.redtree',
1513
+ 'desc': 'Controls adding a specific tag on any node in a layer.'},
1510
1514
  {'perm': ('node', 'tag', 'del', '<tag...>'), 'gate': 'layer',
1511
- 'ex': 'node.tag.del.cno.mal.redtree',
1512
- 'desc': 'Controls removing a specific tag on any node in a layer.'},
1515
+ 'ex': 'node.tag.del.cno.mal.redtree',
1516
+ 'desc': 'Controls removing a specific tag on any node in a layer.'},
1513
1517
 
1514
1518
  {'perm': ('node', 'prop'), 'gate': 'layer',
1515
- 'desc': 'Controls editing any prop on any node in the layer.'},
1519
+ 'desc': 'Controls editing any prop on any node in the layer.'},
1516
1520
 
1517
1521
  {'perm': ('node', 'prop', 'set'), 'gate': 'layer',
1518
- 'desc': 'Controls setting any prop on any node in a layer.'},
1522
+ 'desc': 'Controls setting any prop on any node in a layer.'},
1519
1523
  {'perm': ('node', 'prop', 'set', '<prop>'), 'gate': 'layer',
1520
- 'ex': 'node.prop.set.inet:ipv4:asn',
1521
- 'desc': 'Controls setting a specific property on a node in a layer.'},
1524
+ 'ex': 'node.prop.set.inet:ipv4:asn',
1525
+ 'desc': 'Controls setting a specific property on a node in a layer.'},
1522
1526
 
1523
1527
  {'perm': ('node', 'prop', 'del'), 'gate': 'layer',
1524
- 'desc': 'Controls removing any prop on any node in a layer.'},
1528
+ 'desc': 'Controls removing any prop on any node in a layer.'},
1525
1529
  {'perm': ('node', 'prop', 'del', '<prop>'), 'gate': 'layer',
1526
- 'ex': 'node.prop.del.inet:ipv4:asn',
1527
- 'desc': 'Controls removing a specific property from a node in a layer.'},
1530
+ 'ex': 'node.prop.del.inet:ipv4:asn',
1531
+ 'desc': 'Controls removing a specific property from a node in a layer.'},
1528
1532
  ))
1533
+ for pdef in self._cortex_permdefs:
1534
+ s_storm.reqValidPermDef(pdef)
1529
1535
 
1530
- # TODO declare perm defs in storm libraries and include them here...
1536
+ async def _getPermDefs(self):
1537
+
1538
+ permdefs = list(await s_cell.Cell._getPermDefs(self))
1539
+ permdefs.extend(self._cortex_permdefs)
1531
1540
 
1532
1541
  for spkg in await self.getStormPkgs():
1533
1542
  permdefs.extend(spkg.get('perms', ()))
1534
1543
 
1535
1544
  for (path, ctor) in self.stormlibs:
1536
- permdefs.extend(getattr(ctor, '_storm_lib_perms', ()))
1545
+ permdefs.extend(ctor._storm_lib_perms)
1546
+
1547
+ permdefs.sort(key=lambda x: x['perm'])
1537
1548
 
1538
1549
  return tuple(permdefs)
1539
1550
 
@@ -3874,6 +3885,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
3874
3885
  '''
3875
3886
 
3876
3887
  for path, ctor in s_stormtypes.registry.iterLibs():
3888
+ # Ensure each ctor's permdefs are valid
3889
+ for pdef in ctor._storm_lib_perms:
3890
+ s_storm.reqValidPermDef(pdef)
3877
3891
  # Skip libbase which is registered as a default ctor in the storm Runtime
3878
3892
  if path:
3879
3893
  self.addStormLib(path, ctor)
synapse/lib/ast.py CHANGED
@@ -1322,7 +1322,7 @@ class LiftTag(LiftOper):
1322
1322
 
1323
1323
  async def lift(self, runt, path):
1324
1324
 
1325
- tag = await tostr(await self.kids[0].compute(runt, path))
1325
+ tag = await self.kids[0].compute(runt, path)
1326
1326
 
1327
1327
  if len(self.kids) == 3:
1328
1328
 
@@ -1403,7 +1403,7 @@ class LiftTagTag(LiftOper):
1403
1403
 
1404
1404
  async def lift(self, runt, path):
1405
1405
 
1406
- tagname = await tostr(await self.kids[0].compute(runt, path))
1406
+ tagname = await self.kids[0].compute(runt, path)
1407
1407
 
1408
1408
  node = await runt.snap.getNodeByNdef(('syn:tag', tagname))
1409
1409
  if node is None:
@@ -1448,7 +1448,7 @@ class LiftFormTag(LiftOper):
1448
1448
  if not runt.model.form(form):
1449
1449
  raise self.kids[0].addExcInfo(s_exc.NoSuchForm.init(form))
1450
1450
 
1451
- tag = await tostr(await self.kids[1].compute(runt, path))
1451
+ tag = await self.kids[1].compute(runt, path)
1452
1452
 
1453
1453
  if len(self.kids) == 4:
1454
1454
 
@@ -2507,7 +2507,18 @@ class HasTagPropCond(Cond):
2507
2507
  async def getCondEval(self, runt):
2508
2508
 
2509
2509
  async def cond(node, path):
2510
- tag, name = await self.kids[0].compute(runt, path)
2510
+ tag = await self.kids[0].compute(runt, path)
2511
+ name = await self.kids[1].compute(runt, path)
2512
+
2513
+ if tag == '*':
2514
+ return any(name in props for props in node.tagprops.values())
2515
+
2516
+ if '*' in tag:
2517
+ reobj = s_cache.getTagGlobRegx(tag)
2518
+ for tagname, props in node.tagprops.items():
2519
+ if reobj.fullmatch(tagname) and name in props:
2520
+ return True
2521
+
2511
2522
  return node.hasTagProp(tag, name)
2512
2523
 
2513
2524
  return cond
@@ -2707,11 +2718,12 @@ class TagPropCond(Cond):
2707
2718
 
2708
2719
  async def getCondEval(self, runt):
2709
2720
 
2710
- cmpr = await self.kids[1].compute(runt, None)
2721
+ cmpr = await self.kids[2].compute(runt, None)
2711
2722
 
2712
2723
  async def cond(node, path):
2713
2724
 
2714
- tag, name = await self.kids[0].compute(runt, path)
2725
+ tag = await self.kids[0].compute(runt, path)
2726
+ name = await self.kids[1].compute(runt, path)
2715
2727
 
2716
2728
  prop = runt.model.getTagProp(name)
2717
2729
  if prop is None:
@@ -2719,7 +2731,7 @@ class TagPropCond(Cond):
2719
2731
  raise self.kids[0].addExcInfo(s_exc.NoSuchTagProp(name=name, mesg=mesg))
2720
2732
 
2721
2733
  # TODO cache on (cmpr, valu) for perf?
2722
- valu = await self.kids[2].compute(runt, path)
2734
+ valu = await self.kids[3].compute(runt, path)
2723
2735
 
2724
2736
  ctor = prop.type.getCmprCtor(cmpr)
2725
2737
  if ctor is None:
@@ -3086,16 +3098,71 @@ class TagName(Value):
3086
3098
  if self.isconst:
3087
3099
  return self.constval
3088
3100
 
3101
+ if not isinstance(self.kids[0], Const):
3102
+ valu = await self.kids[0].compute(runt, path)
3103
+ valu = await s_stormtypes.toprim(valu)
3104
+
3105
+ if not isinstance(valu, str):
3106
+ mesg = 'Invalid value type for tag name, tag names must be strings.'
3107
+ raise s_exc.BadTypeValu(mesg=mesg)
3108
+
3109
+ normtupl = await runt.snap.getTagNorm(valu)
3110
+ return normtupl[0]
3111
+
3089
3112
  vals = []
3090
3113
  for kid in self.kids:
3091
3114
  part = await kid.compute(runt, path)
3092
3115
  if part is None:
3093
3116
  mesg = f'Null value from var ${kid.name} is not allowed in tag names.'
3094
3117
  raise kid.addExcInfo(s_exc.BadTypeValu(mesg=mesg))
3095
- vals.append(await tostr(part))
3118
+
3119
+ part = await tostr(part)
3120
+ partnorm = await runt.snap.getTagNorm(part)
3121
+ vals.append(partnorm[0])
3096
3122
 
3097
3123
  return '.'.join(vals)
3098
3124
 
3125
+ async def computeTagArray(self, runt, path, excignore=()):
3126
+
3127
+ if self.isconst:
3128
+ return (self.constval,)
3129
+
3130
+ if not isinstance(self.kids[0], Const):
3131
+ tags = []
3132
+ vals = await self.kids[0].compute(runt, path)
3133
+ vals = await s_stormtypes.toprim(vals)
3134
+
3135
+ if not isinstance(vals, (tuple, list, set)):
3136
+ vals = (vals,)
3137
+
3138
+ for valu in vals:
3139
+ try:
3140
+ if not isinstance(valu, str):
3141
+ mesg = 'Invalid value type for tag name, tag names must be strings.'
3142
+ raise s_exc.BadTypeValu(mesg=mesg)
3143
+
3144
+ normtupl = await runt.snap.getTagNorm(valu)
3145
+ if normtupl is None:
3146
+ continue
3147
+
3148
+ tags.append(normtupl[0])
3149
+ except excignore:
3150
+ pass
3151
+ return tags
3152
+
3153
+ vals = []
3154
+ for kid in self.kids:
3155
+ part = await kid.compute(runt, path)
3156
+ if part is None:
3157
+ mesg = f'Null value from var ${kid.name} is not allowed in tag names.'
3158
+ raise kid.addExcInfo(s_exc.BadTypeValu(mesg=mesg))
3159
+
3160
+ part = await tostr(part)
3161
+ partnorm = await runt.snap.getTagNorm(part)
3162
+ vals.append(partnorm[0])
3163
+
3164
+ return ('.'.join(vals),)
3165
+
3099
3166
  class TagMatch(TagName):
3100
3167
  '''
3101
3168
  Like TagName, but can have asterisks
@@ -3105,6 +3172,32 @@ class TagMatch(TagName):
3105
3172
  # TODO support vars with asterisks?
3106
3173
  return any('*' in kid.valu for kid in self.kids if isinstance(kid, Const))
3107
3174
 
3175
+ async def compute(self, runt, path):
3176
+
3177
+ if self.isconst:
3178
+ return self.constval
3179
+
3180
+ if not isinstance(self.kids[0], Const):
3181
+ valu = await self.kids[0].compute(runt, path)
3182
+ valu = await s_stormtypes.toprim(valu)
3183
+
3184
+ if not isinstance(valu, str):
3185
+ mesg = 'Invalid value type for tag name, tag names must be strings.'
3186
+ raise s_exc.BadTypeValu(mesg=mesg)
3187
+
3188
+ return valu
3189
+
3190
+ vals = []
3191
+ for kid in self.kids:
3192
+ part = await kid.compute(runt, path)
3193
+ if part is None:
3194
+ mesg = f'Null value from var ${kid.name} is not allowed in tag names.'
3195
+ raise s_exc.BadTypeValu(mesg=mesg)
3196
+
3197
+ vals.append(await tostr(part))
3198
+
3199
+ return '.'.join(vals)
3200
+
3108
3201
  class Const(Value):
3109
3202
 
3110
3203
  def __init__(self, astinfo, valu, kids=()):
@@ -3756,27 +3849,15 @@ class EditTagAdd(Edit):
3756
3849
  async for node, path in genr:
3757
3850
 
3758
3851
  try:
3759
- names = await self.kids[oper_offset].compute(runt, path)
3760
- names = await s_stormtypes.toprim(names)
3852
+ names = await self.kids[oper_offset].computeTagArray(runt, path, excignore=excignore)
3761
3853
  except excignore:
3762
3854
  yield node, path
3763
3855
  await asyncio.sleep(0)
3764
3856
  continue
3765
3857
 
3766
- if not isinstance(names, tuple):
3767
- names = (names,)
3768
-
3769
3858
  for name in names:
3770
3859
 
3771
3860
  try:
3772
- if name is None:
3773
- raise self.addExcInfo(s_exc.BadTypeValu(mesg='Null tag names are not allowed.'))
3774
-
3775
- normtupl = await runt.snap.getTagNorm(name)
3776
- if normtupl is None:
3777
- continue
3778
-
3779
- name, info = normtupl
3780
3861
  parts = name.split('.')
3781
3862
 
3782
3863
  runt.layerConfirm(('node', 'tag', 'add', *parts))
@@ -3802,26 +3883,15 @@ class EditTagDel(Edit):
3802
3883
 
3803
3884
  async for node, path in genr:
3804
3885
 
3805
- names = await self.kids[0].compute(runt, path)
3806
- names = await s_stormtypes.toprim(names)
3807
-
3808
- if not isinstance(names, tuple):
3809
- names = (names,)
3886
+ names = await self.kids[0].computeTagArray(runt, path, excignore=(s_exc.BadTypeValu,))
3810
3887
 
3811
3888
  for name in names:
3812
3889
 
3813
- # special case for backward compatibility
3814
- if name:
3815
- normtupl = await runt.snap.getTagNorm(name)
3816
- if normtupl is None:
3817
- continue
3818
-
3819
- name, info = normtupl
3820
- parts = name.split('.')
3890
+ parts = name.split('.')
3821
3891
 
3822
- runt.layerConfirm(('node', 'tag', 'del', *parts))
3892
+ runt.layerConfirm(('node', 'tag', 'del', *parts))
3823
3893
 
3824
- await node.delTag(name)
3894
+ await node.delTag(name)
3825
3895
 
3826
3896
  yield node, path
3827
3897
 
@@ -3847,11 +3917,6 @@ class EditTagPropSet(Edit):
3847
3917
  valu = await self.kids[2].compute(runt, path)
3848
3918
  valu = await s_stormtypes.tostor(valu)
3849
3919
 
3850
- normtupl = await runt.snap.getTagNorm(tag)
3851
- if normtupl is None:
3852
- continue
3853
-
3854
- tag, info = normtupl
3855
3920
  tagparts = tag.split('.')
3856
3921
 
3857
3922
  # for now, use the tag add perms
@@ -3881,13 +3946,6 @@ class EditTagPropDel(Edit):
3881
3946
  async for node, path in genr:
3882
3947
 
3883
3948
  tag, prop = await self.kids[0].compute(runt, path)
3884
-
3885
- normtupl = await runt.snap.getTagNorm(tag)
3886
- if normtupl is None:
3887
- continue
3888
-
3889
- tag, info = normtupl
3890
-
3891
3949
  tagparts = tag.split('.')
3892
3950
 
3893
3951
  # for now, use the tag add perms
synapse/lib/cell.py CHANGED
@@ -570,8 +570,8 @@ class CellApi(s_base.Base):
570
570
  return await self.cell.setUserEmail(useriden, email)
571
571
 
572
572
  @adminapi(log=True)
573
- async def addUserRole(self, useriden, roleiden):
574
- return await self.cell.addUserRole(useriden, roleiden)
573
+ async def addUserRole(self, useriden, roleiden, indx=None):
574
+ return await self.cell.addUserRole(useriden, roleiden, indx=indx)
575
575
 
576
576
  @adminapi(log=True)
577
577
  async def setUserRoles(self, useriden, roleidens):
@@ -884,6 +884,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
884
884
  'type': 'object',
885
885
  'hidecmdl': True,
886
886
  },
887
+ 'https:parse:proxy:remoteip': {
888
+ 'description': 'Enable the HTTPS server to parse X-Forwarded-For and X-Real-IP headers to determine requester IP addresses.',
889
+ 'type': 'boolean',
890
+ 'default': False,
891
+ },
887
892
  'backup:dir': {
888
893
  'description': 'A directory outside the service directory where backups will be saved. Defaults to ./backups in the service storage directory.',
889
894
  'type': 'string',
@@ -2286,10 +2291,10 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
2286
2291
  extra=await self.getLogExtra(target_user=user.iden, target_username=user.name,
2287
2292
  gateiden=gateiden))
2288
2293
 
2289
- async def addUserRole(self, useriden, roleiden):
2294
+ async def addUserRole(self, useriden, roleiden, indx=None):
2290
2295
  user = await self.auth.reqUser(useriden)
2291
2296
  role = await self.auth.reqRole(roleiden)
2292
- await user.grant(roleiden)
2297
+ await user.grant(roleiden, indx=indx)
2293
2298
  logger.info(f'Granted role {role.name} to user {user.name}',
2294
2299
  extra=await self.getLogExtra(target_user=user.iden, target_username=user.name,
2295
2300
  target_role=role.iden, target_rolename=role.name))
@@ -2584,7 +2589,10 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
2584
2589
 
2585
2590
  sslctx = self.initSslCtx(certpath, pkeypath)
2586
2591
 
2587
- serv = self.wapp.listen(port, address=addr, ssl_options=sslctx)
2592
+ kwargs = {
2593
+ 'xheaders': self.conf.reqConfValu('https:parse:proxy:remoteip')
2594
+ }
2595
+ serv = self.wapp.listen(port, address=addr, ssl_options=sslctx, **kwargs)
2588
2596
  self.httpds.append(serv)
2589
2597
  return list(serv._sockets.values())[0].getsockname()
2590
2598
 
synapse/lib/layer.py CHANGED
@@ -2483,7 +2483,10 @@ class Layer(s_nexus.Pusher):
2483
2483
  self.logedits = valu
2484
2484
 
2485
2485
  # TODO when we can set more props, we may need to parse values.
2486
- await self.layrinfo.set(name, valu)
2486
+ if valu is None:
2487
+ await self.layrinfo.pop(name)
2488
+ else:
2489
+ await self.layrinfo.set(name, valu)
2487
2490
 
2488
2491
  await self.core.feedBeholder('layer:set', {'iden': self.iden, 'name': name, 'valu': valu}, gates=[self.iden])
2489
2492
  return valu
@@ -3247,6 +3250,15 @@ class Layer(s_nexus.Pusher):
3247
3250
  oldv, oldt = tp_dict.get(prop, (None, None))
3248
3251
  if oldv is not None:
3249
3252
 
3253
+ if stortype == STOR_TYPE_IVAL:
3254
+ valu = (min(*oldv, *valu), max(*oldv, *valu))
3255
+
3256
+ elif stortype == STOR_TYPE_MINTIME:
3257
+ valu = min(valu, oldv)
3258
+
3259
+ elif stortype == STOR_TYPE_MAXTIME:
3260
+ valu = max(valu, oldv)
3261
+
3250
3262
  if valu == oldv and stortype == oldt:
3251
3263
  return ()
3252
3264
 
synapse/lib/parser.py CHANGED
@@ -56,6 +56,7 @@ terminalEnglishMap = {
56
56
  'EXPRNEG': '-',
57
57
  'EXPRPLUS': '+',
58
58
  'EXPRPOW': '**',
59
+ 'EXPRTAGSEGNOVAR': 'non-variable tag segment',
59
60
  'EXPRTIMES': '*',
60
61
  'FOR': 'for',
61
62
  'FORMATSTRING': 'backtick-quoted format string',
@@ -84,8 +85,8 @@ terminalEnglishMap = {
84
85
  'SETTAGOPER': '?',
85
86
  'SINGLEQUOTEDSTRING': 'single-quoted string',
86
87
  'SWITCH': 'switch',
88
+ 'TAGSEGNOVAR': 'non-variable tag segment',
87
89
  'TRY': 'try',
88
- 'TAGMATCH': 'tag name potentially with asterisks',
89
90
  'TRIPLEQUOTEDSTRING': 'triple-quoted string',
90
91
  'TRYSET': '?=',
91
92
  'TRYSETPLUS': '?+=',
@@ -98,6 +99,7 @@ terminalEnglishMap = {
98
99
  'WHILE': 'while',
99
100
  'WHITETOKN': 'An unquoted string terminated by whitespace',
100
101
  'WILDCARD': '*',
102
+ 'WILDTAGSEGNOVAR': 'tag segment potentially with asterisks',
101
103
  'YIELD': 'yield',
102
104
  '_ARRAYCONDSTART': '*[',
103
105
  '_COLONDOLLAR': ':$',
@@ -111,21 +113,21 @@ terminalEnglishMap = {
111
113
  '_EDGEN2FINI': ')-',
112
114
  '_ELSE': 'else',
113
115
  '_EMBEDQUERYSTART': '${',
116
+ '_EXPRCOLONNOSPACE': ':',
114
117
  '_EMIT': 'emit',
115
118
  '_FINI': 'fini',
116
119
  '_HASH': '#',
117
- '_EXPRHASH': '#',
118
120
  '_HASHSPACE': '#',
119
- '_EXPRHASHSPACE': '#',
120
121
  '_INIT': 'init',
121
122
  '_LEFTJOIN': '<+-',
122
123
  '_LEFTPIVOT': '<-',
123
124
  '_LPARNOSPACE': '(',
125
+ '_MATCHHASH': '#',
126
+ '_MATCHHASHSPACE': '#',
124
127
  '_RETURN': 'return',
125
128
  '_RIGHTJOIN': '-+>',
126
129
  '_RIGHTPIVOT': '->',
127
130
  '_STOP': 'stop',
128
- '_TAGSEGNOVAR': 'tag segment potentially with asterisks',
129
131
  '_WALKNPIVON1': '-->',
130
132
  '_WALKNPIVON2': '<--',
131
133
  '$END': 'end of input',
@@ -404,25 +406,6 @@ class AstConverter(lark.Transformer):
404
406
 
405
407
  return argv
406
408
 
407
- @classmethod
408
- def _tagsplit(cls, astinfo, tag):
409
-
410
- if '$' not in tag:
411
- return [s_ast.Const(astinfo, tag)]
412
-
413
- kids = []
414
- segs = tag.split('.')
415
-
416
- for seg in segs:
417
-
418
- if seg[0] == '$':
419
- kids.append(s_ast.VarValue(astinfo, kids=[s_ast.Const(astinfo, seg[1:])]))
420
- continue
421
-
422
- kids.append(s_ast.Const(astinfo, seg))
423
-
424
- return kids
425
-
426
409
  @lark.v_args(meta=True)
427
410
  def varderef(self, meta, kids):
428
411
  assert kids and len(kids) in (3, 4)
@@ -435,22 +418,6 @@ class AstConverter(lark.Transformer):
435
418
  newkid = self._convert_child(kids[2])
436
419
  return s_ast.VarDeref(astinfo, kids=(kids[0], newkid))
437
420
 
438
- @lark.v_args(meta=True)
439
- def tagname(self, meta, kids):
440
- assert kids and len(kids) == 1
441
- astinfo = self.metaToAstInfo(meta)
442
- kid = kids[0]
443
- if not isinstance(kid, lark.lexer.Token):
444
- return self._convert_child(kid)
445
-
446
- valu = kid.value
447
- if '*' in valu:
448
- mesg = f"Invalid wildcard usage in tag {valu}"
449
- self.raiseBadSyntax(mesg, astinfo)
450
-
451
- kids = self._tagsplit(astinfo, valu)
452
- return s_ast.TagName(astinfo, kids=kids)
453
-
454
421
  @lark.v_args(meta=True)
455
422
  def switchcase(self, meta, kids):
456
423
 
@@ -639,7 +606,6 @@ terminalClassMap = {
639
606
  'HEXNUMBER': lambda astinfo, x: s_ast.Const(astinfo, s_ast.parseNumber(x)),
640
607
  'BOOL': lambda astinfo, x: s_ast.Bool(astinfo, x == 'true'),
641
608
  'SINGLEQUOTEDSTRING': lambda astinfo, x: s_ast.Const(astinfo, x[1:-1]), # drop quotes
642
- 'TAGMATCH': lambda astinfo, x: s_ast.TagMatch(astinfo, kids=AstConverter._tagsplit(astinfo, x)),
643
609
  'NONQUOTEWORD': massage_vartokn,
644
610
  'VARTOKN': massage_vartokn,
645
611
  'EXPRVARTOKN': massage_vartokn,
@@ -734,6 +700,8 @@ ruleClassMap = {
734
700
  'stormcmd': lambda astinfo, kids: s_ast.CmdOper(astinfo, kids=kids if len(kids) == 2 else (kids[0], s_ast.Const(astinfo, tuple()))),
735
701
  'stormfunc': s_ast.Function,
736
702
  'tagcond': s_ast.TagCond,
703
+ 'tagname': s_ast.TagName,
704
+ 'tagmatch': s_ast.TagMatch,
737
705
  'tagprop': s_ast.TagProp,
738
706
  'tagvalu': s_ast.TagValue,
739
707
  'tagpropvalu': s_ast.TagPropValue,