synapse 2.176.0__py311-none-any.whl → 2.177.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/axon.py +24 -9
- synapse/cortex.py +329 -168
- synapse/cryotank.py +46 -37
- synapse/datamodel.py +17 -4
- synapse/exc.py +19 -0
- synapse/lib/agenda.py +7 -13
- synapse/lib/auth.py +1520 -0
- synapse/lib/cell.py +255 -53
- synapse/lib/grammar.py +5 -0
- synapse/lib/hive.py +24 -3
- synapse/lib/hiveauth.py +6 -32
- synapse/lib/layer.py +7 -4
- synapse/lib/link.py +21 -17
- synapse/lib/lmdbslab.py +149 -0
- synapse/lib/modelrev.py +1 -1
- synapse/lib/schemas.py +136 -0
- synapse/lib/storm.py +61 -29
- synapse/lib/stormlib/aha.py +1 -1
- synapse/lib/stormlib/auth.py +185 -10
- synapse/lib/stormlib/cortex.py +16 -5
- synapse/lib/stormlib/gen.py +80 -0
- synapse/lib/stormlib/model.py +55 -0
- synapse/lib/stormlib/modelext.py +60 -0
- synapse/lib/stormlib/tabular.py +212 -0
- synapse/lib/stormtypes.py +14 -1
- synapse/lib/trigger.py +1 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +55 -28
- synapse/models/base.py +7 -0
- synapse/models/biz.py +4 -0
- synapse/models/files.py +8 -1
- synapse/models/inet.py +8 -0
- synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
- synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
- synapse/tests/test_axon.py +7 -4
- synapse/tests/test_cortex.py +127 -82
- synapse/tests/test_cryotank.py +4 -4
- synapse/tests/test_datamodel.py +7 -0
- synapse/tests/test_lib_agenda.py +7 -0
- synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
- synapse/tests/test_lib_cell.py +161 -8
- synapse/tests/test_lib_httpapi.py +18 -14
- synapse/tests/test_lib_layer.py +33 -33
- synapse/tests/test_lib_link.py +42 -1
- synapse/tests/test_lib_lmdbslab.py +68 -0
- synapse/tests/test_lib_nexus.py +4 -4
- synapse/tests/test_lib_node.py +0 -7
- synapse/tests/test_lib_storm.py +45 -0
- synapse/tests/test_lib_stormlib_aha.py +1 -2
- synapse/tests/test_lib_stormlib_auth.py +21 -0
- synapse/tests/test_lib_stormlib_cortex.py +12 -12
- synapse/tests/test_lib_stormlib_gen.py +99 -0
- synapse/tests/test_lib_stormlib_model.py +108 -0
- synapse/tests/test_lib_stormlib_modelext.py +64 -0
- synapse/tests/test_lib_stormlib_tabular.py +226 -0
- synapse/tests/test_lib_stormsvc.py +4 -1
- synapse/tests/test_lib_stormtypes.py +10 -0
- synapse/tests/test_model_base.py +3 -0
- synapse/tests/test_model_biz.py +3 -0
- synapse/tests/test_model_files.py +12 -2
- synapse/tests/test_model_inet.py +24 -0
- synapse/tests/test_tools_changelog.py +196 -0
- synapse/tests/test_tools_healthcheck.py +4 -3
- synapse/tests/utils.py +1 -1
- synapse/tools/changelog.py +774 -15
- {synapse-2.176.0.dist-info → synapse-2.177.0.dist-info}/METADATA +3 -3
- {synapse-2.176.0.dist-info → synapse-2.177.0.dist-info}/RECORD +70 -64
- {synapse-2.176.0.dist-info → synapse-2.177.0.dist-info}/WHEEL +1 -1
- {synapse-2.176.0.dist-info → synapse-2.177.0.dist-info}/LICENSE +0 -0
- {synapse-2.176.0.dist-info → synapse-2.177.0.dist-info}/top_level.txt +0 -0
synapse/lib/hiveauth.py
CHANGED
|
@@ -277,7 +277,6 @@ class Auth(s_nexus.Pusher):
|
|
|
277
277
|
|
|
278
278
|
return user
|
|
279
279
|
|
|
280
|
-
@s_nexus.Pusher.onPushAuto('user:name')
|
|
281
280
|
async def setUserName(self, iden, name):
|
|
282
281
|
if not isinstance(name, str):
|
|
283
282
|
raise s_exc.BadArg(mesg='setUserName() name must be a string')
|
|
@@ -302,7 +301,6 @@ class Auth(s_nexus.Pusher):
|
|
|
302
301
|
}
|
|
303
302
|
await self.feedBeholder('user:name', beheld)
|
|
304
303
|
|
|
305
|
-
@s_nexus.Pusher.onPushAuto('role:name')
|
|
306
304
|
async def setRoleName(self, iden, name):
|
|
307
305
|
if not isinstance(name, str):
|
|
308
306
|
raise s_exc.BadArg(mesg='setRoleName() name must be a string')
|
|
@@ -346,7 +344,6 @@ class Auth(s_nexus.Pusher):
|
|
|
346
344
|
|
|
347
345
|
await self.fire('cell:beholder', **behold)
|
|
348
346
|
|
|
349
|
-
@s_nexus.Pusher.onPushAuto('user:info')
|
|
350
347
|
async def setUserInfo(self, iden, name, valu, gateiden=None, logged=True, mesg=None):
|
|
351
348
|
|
|
352
349
|
user = await self.reqUser(iden)
|
|
@@ -373,7 +370,6 @@ class Auth(s_nexus.Pusher):
|
|
|
373
370
|
# since any user info *may* effect auth
|
|
374
371
|
user.clearAuthCache()
|
|
375
372
|
|
|
376
|
-
@s_nexus.Pusher.onPushAuto('role:info')
|
|
377
373
|
async def setRoleInfo(self, iden, name, valu, gateiden=None, logged=True, mesg=None):
|
|
378
374
|
role = await self.reqRole(iden)
|
|
379
375
|
|
|
@@ -528,7 +524,6 @@ class Auth(s_nexus.Pusher):
|
|
|
528
524
|
|
|
529
525
|
return user
|
|
530
526
|
|
|
531
|
-
@s_nexus.Pusher.onPush('user:add')
|
|
532
527
|
async def _addUser(self, iden, name):
|
|
533
528
|
|
|
534
529
|
user = self.usersbyname.get(name)
|
|
@@ -554,7 +549,6 @@ class Auth(s_nexus.Pusher):
|
|
|
554
549
|
|
|
555
550
|
return self.role(iden)
|
|
556
551
|
|
|
557
|
-
@s_nexus.Pusher.onPush('role:add')
|
|
558
552
|
async def _addRole(self, iden, name):
|
|
559
553
|
|
|
560
554
|
role = self.rolesbyname.get(name)
|
|
@@ -574,7 +568,6 @@ class Auth(s_nexus.Pusher):
|
|
|
574
568
|
await self.reqUser(iden)
|
|
575
569
|
return await self._push('user:del', iden)
|
|
576
570
|
|
|
577
|
-
@s_nexus.Pusher.onPush('user:del')
|
|
578
571
|
async def _delUser(self, iden):
|
|
579
572
|
|
|
580
573
|
if iden == self.rootuser.iden:
|
|
@@ -608,7 +601,6 @@ class Auth(s_nexus.Pusher):
|
|
|
608
601
|
await self.reqRole(iden)
|
|
609
602
|
return await self._push('role:del', iden)
|
|
610
603
|
|
|
611
|
-
@s_nexus.Pusher.onPush('role:del')
|
|
612
604
|
async def _delRole(self, iden):
|
|
613
605
|
|
|
614
606
|
if iden == self.allrole.iden:
|
|
@@ -838,10 +830,7 @@ class HiveRole(HiveRuler):
|
|
|
838
830
|
}
|
|
839
831
|
|
|
840
832
|
async def _setRulrInfo(self, name, valu, gateiden=None, nexs=True, mesg=None):
|
|
841
|
-
|
|
842
|
-
return await self.auth.setRoleInfo(self.iden, name, valu, gateiden=gateiden, mesg=mesg)
|
|
843
|
-
else:
|
|
844
|
-
return await self.auth._hndlsetRoleInfo(self.iden, name, valu, gateiden=gateiden, logged=nexs, mesg=mesg)
|
|
833
|
+
return await self.auth.setRoleInfo(self.iden, name, valu, gateiden=gateiden, logged=nexs, mesg=mesg)
|
|
845
834
|
|
|
846
835
|
async def setName(self, name):
|
|
847
836
|
return await self.auth.setRoleName(self.iden, name)
|
|
@@ -929,10 +918,7 @@ class HiveUser(HiveRuler):
|
|
|
929
918
|
}
|
|
930
919
|
|
|
931
920
|
async def _setRulrInfo(self, name, valu, gateiden=None, nexs=True, mesg=None):
|
|
932
|
-
|
|
933
|
-
return await self.auth.setUserInfo(self.iden, name, valu, gateiden=gateiden, mesg=mesg)
|
|
934
|
-
else:
|
|
935
|
-
return await self.auth._hndlsetUserInfo(self.iden, name, valu, gateiden=gateiden, logged=nexs, mesg=mesg)
|
|
921
|
+
return await self.auth.setUserInfo(self.iden, name, valu, gateiden=gateiden, logged=nexs, mesg=mesg)
|
|
936
922
|
|
|
937
923
|
async def setName(self, name):
|
|
938
924
|
return await self.auth.setUserName(self.iden, name)
|
|
@@ -1232,10 +1218,7 @@ class HiveUser(HiveRuler):
|
|
|
1232
1218
|
|
|
1233
1219
|
roles.remove(role.iden)
|
|
1234
1220
|
mesg = {'name': 'role:revoke', 'iden': self.iden, 'role': role.pack()}
|
|
1235
|
-
|
|
1236
|
-
await self.auth.setUserInfo(self.iden, 'roles', roles, mesg=mesg)
|
|
1237
|
-
else:
|
|
1238
|
-
await self.auth._hndlsetUserInfo(self.iden, 'roles', roles, logged=nexs, mesg=mesg)
|
|
1221
|
+
await self.auth.setUserInfo(self.iden, 'roles', roles, logged=nexs, mesg=mesg)
|
|
1239
1222
|
|
|
1240
1223
|
def isLocked(self):
|
|
1241
1224
|
return self.info.get('locked')
|
|
@@ -1271,18 +1254,12 @@ class HiveUser(HiveRuler):
|
|
|
1271
1254
|
async def setAdmin(self, admin, gateiden=None, logged=True):
|
|
1272
1255
|
if not isinstance(admin, bool):
|
|
1273
1256
|
raise s_exc.BadArg(mesg='setAdmin requires a boolean')
|
|
1274
|
-
|
|
1275
|
-
await self.auth.setUserInfo(self.iden, 'admin', admin, gateiden=gateiden)
|
|
1276
|
-
else:
|
|
1277
|
-
await self.auth._hndlsetUserInfo(self.iden, 'admin', admin, gateiden=gateiden, logged=logged)
|
|
1257
|
+
await self.auth.setUserInfo(self.iden, 'admin', admin, gateiden=gateiden, logged=logged)
|
|
1278
1258
|
|
|
1279
1259
|
async def setLocked(self, locked, logged=True):
|
|
1280
1260
|
if not isinstance(locked, bool):
|
|
1281
1261
|
raise s_exc.BadArg(mesg='setLocked requires a boolean')
|
|
1282
|
-
|
|
1283
|
-
await self.auth.setUserInfo(self.iden, 'locked', locked)
|
|
1284
|
-
else:
|
|
1285
|
-
await self.auth._hndlsetUserInfo(self.iden, 'locked', locked, logged=logged)
|
|
1262
|
+
await self.auth.setUserInfo(self.iden, 'locked', locked, logged=logged)
|
|
1286
1263
|
|
|
1287
1264
|
async def setArchived(self, archived):
|
|
1288
1265
|
if not isinstance(archived, bool):
|
|
@@ -1347,7 +1324,4 @@ class HiveUser(HiveRuler):
|
|
|
1347
1324
|
shadow = await s_passwd.getShadowV2(passwd=passwd)
|
|
1348
1325
|
else:
|
|
1349
1326
|
raise s_exc.BadArg(mesg='Password must be a string')
|
|
1350
|
-
|
|
1351
|
-
await self.auth.setUserInfo(self.iden, 'passwd', shadow)
|
|
1352
|
-
else:
|
|
1353
|
-
await self.auth._hndlsetUserInfo(self.iden, 'passwd', shadow, logged=nexs)
|
|
1327
|
+
await self.auth.setUserInfo(self.iden, 'passwd', shadow, logged=nexs)
|
synapse/lib/layer.py
CHANGED
|
@@ -2034,7 +2034,7 @@ class Layer(s_nexus.Pusher):
|
|
|
2034
2034
|
'stortype': stortype})
|
|
2035
2035
|
|
|
2036
2036
|
async def pack(self):
|
|
2037
|
-
ret = self.layrinfo
|
|
2037
|
+
ret = deepcopy(self.layrinfo)
|
|
2038
2038
|
if ret.get('mirror'):
|
|
2039
2039
|
ret['mirror'] = s_urlhelp.sanitizeUrl(ret['mirror'])
|
|
2040
2040
|
ret['offset'] = await self.getEditIndx()
|
|
@@ -2810,9 +2810,11 @@ class Layer(s_nexus.Pusher):
|
|
|
2810
2810
|
|
|
2811
2811
|
# TODO when we can set more props, we may need to parse values.
|
|
2812
2812
|
if valu is None:
|
|
2813
|
-
|
|
2813
|
+
self.layrinfo.pop(name, None)
|
|
2814
2814
|
else:
|
|
2815
|
-
|
|
2815
|
+
self.layrinfo[name] = valu
|
|
2816
|
+
|
|
2817
|
+
self.core.layerdefs.set(self.iden, self.layrinfo)
|
|
2816
2818
|
|
|
2817
2819
|
await self.core.feedBeholder('layer:set', {'iden': self.iden, 'name': name, 'valu': valu}, gates=[self.iden])
|
|
2818
2820
|
return valu
|
|
@@ -4453,7 +4455,8 @@ class Layer(s_nexus.Pusher):
|
|
|
4453
4455
|
|
|
4454
4456
|
@s_nexus.Pusher.onPush('layer:set:modelvers')
|
|
4455
4457
|
async def _setModelVers(self, vers):
|
|
4456
|
-
|
|
4458
|
+
self.layrinfo['model:version'] = vers
|
|
4459
|
+
self.core.layerdefs.set(self.iden, self.layrinfo)
|
|
4457
4460
|
|
|
4458
4461
|
async def getStorNodes(self):
|
|
4459
4462
|
'''
|
synapse/lib/link.py
CHANGED
|
@@ -21,7 +21,7 @@ async def connect(host, port, ssl=None, hostname=None, linkinfo=None):
|
|
|
21
21
|
'''
|
|
22
22
|
Async connect and return a Link().
|
|
23
23
|
'''
|
|
24
|
-
info = {'host': host, 'port': port, 'ssl': ssl, 'hostname': hostname}
|
|
24
|
+
info = {'host': host, 'port': port, 'ssl': ssl, 'hostname': hostname, 'tls': bool(ssl)}
|
|
25
25
|
if linkinfo is not None:
|
|
26
26
|
info.update(linkinfo)
|
|
27
27
|
|
|
@@ -137,6 +137,25 @@ class Link(s_base.Base):
|
|
|
137
137
|
|
|
138
138
|
self.info = info
|
|
139
139
|
|
|
140
|
+
self._addrinfo = {}
|
|
141
|
+
# _addrinfo is populated in this order so that as first hit tls links (prod deployments)
|
|
142
|
+
# then unix links (unit tests with local sockets, container healthchecks, local tools )
|
|
143
|
+
# then tcp links ( unit tests and legacy deployments )
|
|
144
|
+
if self.info.get('tls'):
|
|
145
|
+
self._addrinfo['family'] = 'tls'
|
|
146
|
+
self._addrinfo['addr'] = self.sock.getpeername()
|
|
147
|
+
elif self.info.get('unix'):
|
|
148
|
+
self._addrinfo['family'] = 'unix'
|
|
149
|
+
# Unix sockets don't use getpeername
|
|
150
|
+
self._addrinfo['addr'] = self.sock.getsockname()
|
|
151
|
+
else:
|
|
152
|
+
self._addrinfo['family'] = 'tcp'
|
|
153
|
+
self._addrinfo['addr'] = self.sock.getpeername()
|
|
154
|
+
if self.sock.family == socket.AF_INET:
|
|
155
|
+
self._addrinfo['ipver'] = 'ipv4'
|
|
156
|
+
elif self.sock.family == socket.AF_INET6:
|
|
157
|
+
self._addrinfo['ipver'] = 'ipv6'
|
|
158
|
+
|
|
140
159
|
self.unpk = s_msgpack.Unpk()
|
|
141
160
|
|
|
142
161
|
async def fini():
|
|
@@ -212,22 +231,7 @@ class Link(s_base.Base):
|
|
|
212
231
|
'''
|
|
213
232
|
Get a summary of address information related to the link.
|
|
214
233
|
'''
|
|
215
|
-
|
|
216
|
-
'addr': self.sock.getpeername(),
|
|
217
|
-
}
|
|
218
|
-
# Set family information
|
|
219
|
-
if self.info.get('unix'):
|
|
220
|
-
ret['family'] = 'unix'
|
|
221
|
-
# Unix sockets don't use getpeername
|
|
222
|
-
ret['addr'] = self.sock.getsockname()
|
|
223
|
-
elif self.info.get('tls'):
|
|
224
|
-
ret['family'] = 'tls'
|
|
225
|
-
# Set ipver if needed
|
|
226
|
-
if self.sock.family == socket.AF_INET:
|
|
227
|
-
ret['ipver'] = 'ipv4'
|
|
228
|
-
if self.sock.family == socket.AF_INET6:
|
|
229
|
-
ret['ipver'] = 'ipv6'
|
|
230
|
-
return ret
|
|
234
|
+
return dict(self._addrinfo)
|
|
231
235
|
|
|
232
236
|
async def send(self, byts):
|
|
233
237
|
self.writer.write(byts)
|
synapse/lib/lmdbslab.py
CHANGED
|
@@ -166,6 +166,148 @@ class SlabDict:
|
|
|
166
166
|
self.set(name, curv)
|
|
167
167
|
return curv
|
|
168
168
|
|
|
169
|
+
class SafeKeyVal:
|
|
170
|
+
'''
|
|
171
|
+
Key/value storage that does not store items in memory and ensures keys are < 512 characters in length.
|
|
172
|
+
|
|
173
|
+
Note:
|
|
174
|
+
The key size limitation includes the length of any prefixes added by
|
|
175
|
+
using getSubKeyVal().
|
|
176
|
+
'''
|
|
177
|
+
def __init__(self, slab, name, prefix=''):
|
|
178
|
+
|
|
179
|
+
self.prefix = prefix
|
|
180
|
+
self._prefix = prefix.encode('utf8')
|
|
181
|
+
self.preflen = len(self._prefix)
|
|
182
|
+
|
|
183
|
+
if self.preflen > 510:
|
|
184
|
+
mesg = 'SafeKeyVal prefix lengths must be < 511 bytes.'
|
|
185
|
+
raise s_exc.BadArg(mesg, prefix=self._prefix[:1024])
|
|
186
|
+
|
|
187
|
+
self.name = name
|
|
188
|
+
self.slab = slab
|
|
189
|
+
self.valudb = slab.initdb(name)
|
|
190
|
+
|
|
191
|
+
def getSubKeyVal(self, prefix):
|
|
192
|
+
|
|
193
|
+
if not prefix or not isinstance(prefix, str):
|
|
194
|
+
mesg = 'SafeKeyVal.getSubKeyVal() requires a string prefix of at least one character.'
|
|
195
|
+
raise s_exc.BadArg(mesg, prefix=prefix)
|
|
196
|
+
|
|
197
|
+
if self.prefix:
|
|
198
|
+
prefix = self.prefix + prefix
|
|
199
|
+
|
|
200
|
+
return SafeKeyVal(self.slab, self.name, prefix=prefix)
|
|
201
|
+
|
|
202
|
+
def reqValidName(self, name):
|
|
203
|
+
|
|
204
|
+
_name = name.encode('utf-8')
|
|
205
|
+
|
|
206
|
+
if self._prefix:
|
|
207
|
+
_name = self._prefix + _name
|
|
208
|
+
|
|
209
|
+
if len(_name) > 511:
|
|
210
|
+
maxlen = 511 - self.preflen
|
|
211
|
+
mesg = f'SafeKeyVal keys with prefix {self.prefix} must be less < {maxlen} bytes in length.'
|
|
212
|
+
raise s_exc.BadArg(mesg, prefix=self.prefix, name=name[:1024])
|
|
213
|
+
return _name
|
|
214
|
+
|
|
215
|
+
def get(self, name, defv=None):
|
|
216
|
+
'''
|
|
217
|
+
Get the value for a key.
|
|
218
|
+
|
|
219
|
+
Note:
|
|
220
|
+
This may only be used for keys < 512 characters in length.
|
|
221
|
+
'''
|
|
222
|
+
name = self.reqValidName(name)
|
|
223
|
+
|
|
224
|
+
if (byts := self.slab.get(name, db=self.valudb)) is None:
|
|
225
|
+
return defv
|
|
226
|
+
return s_msgpack.un(byts)
|
|
227
|
+
|
|
228
|
+
def set(self, name, valu):
|
|
229
|
+
|
|
230
|
+
name = self.reqValidName(name)
|
|
231
|
+
|
|
232
|
+
self.slab.put(name, s_msgpack.en(valu), db=self.valudb)
|
|
233
|
+
return valu
|
|
234
|
+
|
|
235
|
+
def pop(self, name, defv=None):
|
|
236
|
+
|
|
237
|
+
name = self.reqValidName(name)
|
|
238
|
+
|
|
239
|
+
if (byts := self.slab.pop(name, db=self.valudb)) is not None:
|
|
240
|
+
return s_msgpack.un(byts)
|
|
241
|
+
return defv
|
|
242
|
+
|
|
243
|
+
def delete(self, name):
|
|
244
|
+
'''
|
|
245
|
+
Delete a key.
|
|
246
|
+
'''
|
|
247
|
+
name = self.reqValidName(name)
|
|
248
|
+
return self.slab.delete(name, db=self.valudb)
|
|
249
|
+
|
|
250
|
+
async def truncate(self, pref=''):
|
|
251
|
+
'''
|
|
252
|
+
Delete all keys.
|
|
253
|
+
'''
|
|
254
|
+
pref = self.reqValidName(pref)
|
|
255
|
+
|
|
256
|
+
if not pref:
|
|
257
|
+
genr = self.slab.scanKeys(db=self.valudb)
|
|
258
|
+
else:
|
|
259
|
+
genr = self.slab.scanKeysByPref(pref, db=self.valudb)
|
|
260
|
+
|
|
261
|
+
for lkey in genr:
|
|
262
|
+
self.slab.delete(lkey, db=self.valudb)
|
|
263
|
+
await asyncio.sleep(0)
|
|
264
|
+
|
|
265
|
+
def items(self, pref=''):
|
|
266
|
+
|
|
267
|
+
pref = self.reqValidName(pref)
|
|
268
|
+
|
|
269
|
+
if not pref:
|
|
270
|
+
genr = self.slab.scanByFull(db=self.valudb)
|
|
271
|
+
else:
|
|
272
|
+
genr = self.slab.scanByPref(pref, db=self.valudb)
|
|
273
|
+
|
|
274
|
+
if self.prefix:
|
|
275
|
+
for lkey, byts in genr:
|
|
276
|
+
yield lkey[self.preflen:].decode('utf8'), s_msgpack.un(byts)
|
|
277
|
+
return
|
|
278
|
+
|
|
279
|
+
for lkey, byts in genr:
|
|
280
|
+
yield lkey.decode('utf8'), s_msgpack.un(byts)
|
|
281
|
+
|
|
282
|
+
def keys(self, pref=''):
|
|
283
|
+
|
|
284
|
+
pref = self.reqValidName(pref)
|
|
285
|
+
|
|
286
|
+
if not pref:
|
|
287
|
+
genr = self.slab.scanKeys(db=self.valudb)
|
|
288
|
+
else:
|
|
289
|
+
genr = self.slab.scanKeysByPref(pref, db=self.valudb)
|
|
290
|
+
|
|
291
|
+
if self.prefix:
|
|
292
|
+
for lkey in genr:
|
|
293
|
+
yield lkey[self.preflen:].decode('utf8')
|
|
294
|
+
return
|
|
295
|
+
|
|
296
|
+
for lkey in genr:
|
|
297
|
+
yield lkey.decode('utf8')
|
|
298
|
+
|
|
299
|
+
def values(self, pref=''):
|
|
300
|
+
|
|
301
|
+
pref = self.reqValidName(pref)
|
|
302
|
+
|
|
303
|
+
if not pref:
|
|
304
|
+
genr = self.slab.scanByFull(db=self.valudb)
|
|
305
|
+
else:
|
|
306
|
+
genr = self.slab.scanByPref(pref, db=self.valudb)
|
|
307
|
+
|
|
308
|
+
for lkey, byts in genr:
|
|
309
|
+
yield s_msgpack.un(byts)
|
|
310
|
+
|
|
169
311
|
class SlabAbrv:
|
|
170
312
|
'''
|
|
171
313
|
A utility for translating arbitrary bytes into fixed with id bytes
|
|
@@ -845,6 +987,13 @@ class Slab(s_base.Base):
|
|
|
845
987
|
self.onfini(mq)
|
|
846
988
|
return mq
|
|
847
989
|
|
|
990
|
+
def getSafeKeyVal(self, name, prefix='', create=True):
|
|
991
|
+
if not create and not self.dbexists(name):
|
|
992
|
+
mesg = f'Database {name=} does not exist.'
|
|
993
|
+
raise s_exc.BadArg(mesg=mesg)
|
|
994
|
+
|
|
995
|
+
return SafeKeyVal(self, name, prefix=prefix)
|
|
996
|
+
|
|
848
997
|
def statinfo(self):
|
|
849
998
|
return {
|
|
850
999
|
'locking_memory': self.locking_memory, # whether the memory lock loop was started and hasn't ended
|
synapse/lib/modelrev.py
CHANGED
synapse/lib/schemas.py
CHANGED
|
@@ -288,6 +288,93 @@ _stormPoolOptsSchema = {
|
|
|
288
288
|
}
|
|
289
289
|
reqValidStormPoolOpts = s_config.getJsValidator(_stormPoolOptsSchema)
|
|
290
290
|
|
|
291
|
+
_authRulesSchema = {
|
|
292
|
+
'type': 'array',
|
|
293
|
+
'items': {
|
|
294
|
+
'type': 'array',
|
|
295
|
+
'items': [
|
|
296
|
+
{'type': 'boolean'},
|
|
297
|
+
{'type': 'array', 'items': {'type': 'string'}},
|
|
298
|
+
],
|
|
299
|
+
'minItems': 2,
|
|
300
|
+
'maxItems': 2,
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
reqValidRules = s_config.getJsValidator(_authRulesSchema)
|
|
304
|
+
|
|
305
|
+
_passwdPolicySchema = {
|
|
306
|
+
'type': 'object',
|
|
307
|
+
'properties': {
|
|
308
|
+
'complexity': {
|
|
309
|
+
'type': ['object', 'null'],
|
|
310
|
+
'properties': {
|
|
311
|
+
'length': {
|
|
312
|
+
'type': ['number', 'null'],
|
|
313
|
+
'minimum': 1,
|
|
314
|
+
'description': 'Minimum password character length.',
|
|
315
|
+
},
|
|
316
|
+
'sequences': {
|
|
317
|
+
'type': ['number', 'null'],
|
|
318
|
+
'minimum': 2,
|
|
319
|
+
'description': 'Maximum sequence length in a password. Sequences can be letters or number, forward or reverse.',
|
|
320
|
+
},
|
|
321
|
+
'upper:count': {
|
|
322
|
+
'type': ['number', 'null'],
|
|
323
|
+
'description': 'The minimum number of uppercase characters required in password.',
|
|
324
|
+
},
|
|
325
|
+
'upper:valid': {
|
|
326
|
+
'type': ['string', 'null'],
|
|
327
|
+
'minLength': 1,
|
|
328
|
+
'description': 'All valid uppercase characters.',
|
|
329
|
+
},
|
|
330
|
+
'lower:count': {
|
|
331
|
+
'type': ['number', 'null'],
|
|
332
|
+
'minimum': 0,
|
|
333
|
+
'description': 'The minimum number of lowercase characters required in password.',
|
|
334
|
+
},
|
|
335
|
+
'lower:valid': {
|
|
336
|
+
'type': ['string', 'null'],
|
|
337
|
+
'minLength': 1,
|
|
338
|
+
'description': 'All valid lowercase characters.',
|
|
339
|
+
},
|
|
340
|
+
'special:count': {
|
|
341
|
+
'type': ['number', 'null'],
|
|
342
|
+
'minimum': 0,
|
|
343
|
+
'description': 'The minimum number of special characters required in password.',
|
|
344
|
+
},
|
|
345
|
+
'special:valid': {
|
|
346
|
+
'type': ['string', 'null'],
|
|
347
|
+
'minLength': 1,
|
|
348
|
+
'description': 'All valid special characters.',
|
|
349
|
+
},
|
|
350
|
+
'number:count': {
|
|
351
|
+
'type': ['number', 'null'],
|
|
352
|
+
'minimum': 0,
|
|
353
|
+
'description': 'The minimum number of digit characters required in password.',
|
|
354
|
+
},
|
|
355
|
+
'number:valid': {
|
|
356
|
+
'type': ['string', 'null'],
|
|
357
|
+
'minLength': 1,
|
|
358
|
+
'description': 'All valid digit characters.',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
'additionalProperties': False,
|
|
362
|
+
},
|
|
363
|
+
'attempts': {
|
|
364
|
+
'type': ['number', 'null'],
|
|
365
|
+
'minimum': 1,
|
|
366
|
+
'description': 'Maximum number of incorrect attempts before locking user account.',
|
|
367
|
+
},
|
|
368
|
+
'previous': {
|
|
369
|
+
'type': ['number', 'null'],
|
|
370
|
+
'minimum': 1,
|
|
371
|
+
'description': 'Number of previous passwords to disallow.',
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
'additionalProperties': False,
|
|
375
|
+
}
|
|
376
|
+
reqValidPasswdPolicy = s_config.getJsValidator(_passwdPolicySchema)
|
|
377
|
+
|
|
291
378
|
# These types are order sensitive
|
|
292
379
|
_changelogTypes = {'migration': 'Automatic Migrations',
|
|
293
380
|
'model': 'Model Changes',
|
|
@@ -318,3 +405,52 @@ _changelogSchema = {
|
|
|
318
405
|
'required': ['type', 'desc']
|
|
319
406
|
}
|
|
320
407
|
_reqChanglogSchema = s_config.getJsValidator(_changelogSchema)
|
|
408
|
+
|
|
409
|
+
tabularConfSchema = {
|
|
410
|
+
'type': 'object',
|
|
411
|
+
'properties': {
|
|
412
|
+
'separators': {
|
|
413
|
+
'type': 'object',
|
|
414
|
+
'properties': {
|
|
415
|
+
'row:outline': {'type': 'boolean', 'default': False,
|
|
416
|
+
'description': 'Add the row separator before the header data and after each row.'},
|
|
417
|
+
'column:outline': {'type': 'boolean', 'default': False,
|
|
418
|
+
'description': 'Add the column separator to the beginning and end of each row.'},
|
|
419
|
+
'header:row': {'type': 'string', 'default': '=',
|
|
420
|
+
'description': 'The string to use to create a separator row when printing the header.'},
|
|
421
|
+
'data:row': {'type': 'string', 'default': '-',
|
|
422
|
+
'description': 'The string to use to create a separator row when printing data rows.'},
|
|
423
|
+
'column': {'type': 'string', 'default': '|',
|
|
424
|
+
'description': 'The string to use to separate columns.'},
|
|
425
|
+
},
|
|
426
|
+
'additionalProperties': False,
|
|
427
|
+
},
|
|
428
|
+
'columns': {
|
|
429
|
+
'type': 'array',
|
|
430
|
+
'items': {
|
|
431
|
+
'type': 'object',
|
|
432
|
+
'properties': {
|
|
433
|
+
'name': {'type': 'string',
|
|
434
|
+
'description': 'The column name which will be used in the header row.'},
|
|
435
|
+
'width': {'type': 'number', 'default': None, 'exclusiveMinimum': 0,
|
|
436
|
+
'description': 'If not provided each cell will expand to fit the data.'},
|
|
437
|
+
'justify': {'type': 'string', 'default': 'left', 'enum': ['left', 'center', 'right'],
|
|
438
|
+
'description': 'Justification for the header titles and data rows.'},
|
|
439
|
+
'overflow': {'type': 'string', 'default': 'trim', 'enum': ['wrap', 'trim'],
|
|
440
|
+
'description': 'For text exceeding the width, '
|
|
441
|
+
'either wrap text in multiple lines or trim and append "...".'},
|
|
442
|
+
'newlines': {'type': 'string', 'default': 'replace', 'enum': ['replace', 'split'],
|
|
443
|
+
'description': 'Replace newlines with a space or split into multiple lines.'
|
|
444
|
+
'Split is only applied if width is undefined.'},
|
|
445
|
+
},
|
|
446
|
+
'required': ['name'],
|
|
447
|
+
'minItems': 1,
|
|
448
|
+
'additionalProperties': False,
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
'required': ['columns'],
|
|
453
|
+
'additionalProperties': False,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
reqValidTabularConf = s_config.getJsValidator(tabularConfSchema)
|