moat-kv 0.70.24__py3-none-any.whl → 0.71.6__py3-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.
Files changed (127) hide show
  1. moat/kv/__init__.py +6 -7
  2. moat/kv/_cfg.yaml +5 -8
  3. moat/kv/actor/__init__.py +2 -1
  4. moat/kv/actor/deletor.py +4 -1
  5. moat/kv/auth/__init__.py +12 -13
  6. moat/kv/auth/_test.py +4 -1
  7. moat/kv/auth/password.py +11 -7
  8. moat/kv/backend/mqtt.py +4 -8
  9. moat/kv/client.py +20 -39
  10. moat/kv/code.py +3 -3
  11. moat/kv/command/data.py +4 -3
  12. moat/kv/command/dump/__init__.py +29 -29
  13. moat/kv/command/internal.py +2 -3
  14. moat/kv/command/job.py +1 -2
  15. moat/kv/command/type.py +3 -6
  16. moat/kv/data.py +9 -8
  17. moat/kv/errors.py +16 -8
  18. moat/kv/mock/__init__.py +2 -12
  19. moat/kv/model.py +28 -32
  20. moat/kv/obj/__init__.py +3 -3
  21. moat/kv/obj/command.py +3 -3
  22. moat/kv/runner.py +4 -5
  23. moat/kv/server.py +106 -126
  24. moat/kv/types.py +8 -6
  25. {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/METADATA +7 -6
  26. moat_kv-0.71.6.dist-info/RECORD +47 -0
  27. {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/WHEEL +1 -1
  28. moat_kv-0.71.6.dist-info/licenses/LICENSE +3 -0
  29. moat_kv-0.71.6.dist-info/licenses/LICENSE.APACHE2 +202 -0
  30. moat_kv-0.71.6.dist-info/licenses/LICENSE.MIT +20 -0
  31. moat_kv-0.71.6.dist-info/top_level.txt +1 -0
  32. build/lib/docs/source/conf.py +0 -201
  33. build/lib/examples/pathify.py +0 -45
  34. build/lib/moat/kv/__init__.py +0 -19
  35. build/lib/moat/kv/_cfg.yaml +0 -97
  36. build/lib/moat/kv/_main.py +0 -91
  37. build/lib/moat/kv/actor/__init__.py +0 -98
  38. build/lib/moat/kv/actor/deletor.py +0 -139
  39. build/lib/moat/kv/auth/__init__.py +0 -444
  40. build/lib/moat/kv/auth/_test.py +0 -166
  41. build/lib/moat/kv/auth/password.py +0 -234
  42. build/lib/moat/kv/auth/root.py +0 -58
  43. build/lib/moat/kv/backend/__init__.py +0 -67
  44. build/lib/moat/kv/backend/mqtt.py +0 -74
  45. build/lib/moat/kv/backend/serf.py +0 -45
  46. build/lib/moat/kv/client.py +0 -1025
  47. build/lib/moat/kv/code.py +0 -236
  48. build/lib/moat/kv/codec.py +0 -11
  49. build/lib/moat/kv/command/__init__.py +0 -1
  50. build/lib/moat/kv/command/acl.py +0 -180
  51. build/lib/moat/kv/command/auth.py +0 -261
  52. build/lib/moat/kv/command/code.py +0 -293
  53. build/lib/moat/kv/command/codec.py +0 -186
  54. build/lib/moat/kv/command/data.py +0 -265
  55. build/lib/moat/kv/command/dump/__init__.py +0 -143
  56. build/lib/moat/kv/command/error.py +0 -149
  57. build/lib/moat/kv/command/internal.py +0 -248
  58. build/lib/moat/kv/command/job.py +0 -433
  59. build/lib/moat/kv/command/log.py +0 -53
  60. build/lib/moat/kv/command/server.py +0 -114
  61. build/lib/moat/kv/command/type.py +0 -201
  62. build/lib/moat/kv/config.py +0 -46
  63. build/lib/moat/kv/data.py +0 -216
  64. build/lib/moat/kv/errors.py +0 -561
  65. build/lib/moat/kv/exceptions.py +0 -126
  66. build/lib/moat/kv/mock/__init__.py +0 -101
  67. build/lib/moat/kv/mock/mqtt.py +0 -159
  68. build/lib/moat/kv/mock/serf.py +0 -250
  69. build/lib/moat/kv/mock/tracer.py +0 -63
  70. build/lib/moat/kv/model.py +0 -1069
  71. build/lib/moat/kv/obj/__init__.py +0 -646
  72. build/lib/moat/kv/obj/command.py +0 -241
  73. build/lib/moat/kv/runner.py +0 -1347
  74. build/lib/moat/kv/server.py +0 -2809
  75. build/lib/moat/kv/types.py +0 -513
  76. debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
  77. debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
  78. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
  79. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -97
  80. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
  81. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
  82. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
  83. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
  84. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
  85. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
  86. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
  87. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
  88. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -74
  89. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/serf.py +0 -45
  90. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
  91. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
  92. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
  93. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
  94. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
  95. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
  96. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
  97. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
  98. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
  99. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
  100. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
  101. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
  102. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
  103. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
  104. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
  105. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
  106. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
  107. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
  108. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
  109. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
  110. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
  111. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
  112. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/serf.py +0 -250
  113. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
  114. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
  115. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
  116. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
  117. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
  118. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
  119. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
  120. docs/source/conf.py +0 -201
  121. examples/pathify.py +0 -45
  122. moat/kv/backend/serf.py +0 -45
  123. moat/kv/codec.py +0 -11
  124. moat/kv/mock/serf.py +0 -250
  125. moat_kv-0.70.24.dist-info/RECORD +0 -137
  126. moat_kv-0.70.24.dist-info/top_level.txt +0 -9
  127. {moat_kv-0.70.24.dist-info → moat_kv-0.71.6.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,444 +0,0 @@
1
- # moat.kv.auth
2
- # template for authorization
3
-
4
- """
5
- This set of modules authenticates users.
6
-
7
- A submodule is expected to export a "load(type:str, make:bool, server:bool)"
8
- method that returns a class.
9
-
10
- It must recognize, at minimum:
11
-
12
- * load("stream", server:bool):
13
-
14
- A filter used for logging in a user.
15
-
16
- * load("user", server:bool, make:bool)
17
-
18
- A class used to represent the user, or a way to create/manipulate a user record.
19
-
20
- The client process is:
21
-
22
- * create a user:
23
-
24
- * Create a :class:`BaseUserMaker` by calling :meth:`BaseUserMaker.build`
25
- with a record conforming to its schema.
26
-
27
- * Export that and save it to the server, at (None,"auth","user",NAME).
28
-
29
- * modify a user:
30
-
31
- * Call :class:`BaseUserMaker.import` with the value from the server.
32
-
33
- * Log in:
34
-
35
- * Create a :class:`BaseUser` by calling :meth:`BaseUserMaker.build`
36
- with a record conforming to its schema.
37
-
38
- * Call :meth:`BaseUser.auth`.
39
-
40
- The server process is:
41
-
42
- * create a user:
43
-
44
- * The server intercepts the write call and uses the data to call
45
- :meth:`BaseServerAuthMaker.build`.
46
-
47
- * It calls :meth:`BaseServerMaker.save` and stores the actual result.
48
-
49
- * modify a user:
50
-
51
- * the server calls :meth:`BaseServerAuth.read` with the stored data,
52
- then sends a record created with :meth:`BaseServerAuth.save` to the client.
53
-
54
- * verify a user:
55
-
56
- * The server calls :meth:`BaseServerAuth.read` with the stored data.
57
-
58
- * The server calls :meth:`BaseServerAuth.auth` with the record from the client.
59
-
60
- """
61
-
62
- from __future__ import annotations
63
-
64
- import io
65
- from importlib import import_module
66
-
67
- import jsonschema
68
- from moat.util import NotGiven, Path, attrdict, split_arg, yload
69
-
70
- from ..client import Client, NoData
71
- from ..exceptions import NoAuthModuleError
72
- from ..model import Entry
73
- from ..server import ServerClient, StreamCommand
74
- from ..types import ACLFinder, NullACL
75
-
76
- # Empty schema
77
- null_schema = {"type": "object", "additionalProperties": False}
78
-
79
- # Additional schema data for specific types
80
- add_schema = {
81
- "user": {
82
- "acl": {
83
- "type": "object",
84
- "additionalProperties": False,
85
- "properties": {"key": {type: "string", "minLength": 1}},
86
- },
87
- "conv": {
88
- "type": "object",
89
- "additionalProperties": False,
90
- "properties": {"key": {type: "string", "minLength": 1}},
91
- },
92
- },
93
- }
94
-
95
-
96
- def loader(method: str, typ: str, *a, **k):
97
- m = method
98
- if "." not in m:
99
- m = "moat.kv.auth." + m
100
- cls = import_module(m).load(typ, *a, **k)
101
- cls._auth_method = method
102
- cls._auth_typ = typ
103
- cls.aux_schemas = add_schema.get(typ, null_schema)
104
- return cls
105
-
106
-
107
- def gen_auth(s: str):
108
- """
109
- Generate auth data from parameters or YAML file (if first char is '=').
110
- """
111
- if not isinstance(s, str):
112
- return s # called twice. Oh well.
113
-
114
- m, *p = s.split()
115
- if len(p) == 0 and m[0] == "=":
116
- with open(m[1:], encoding="utf-8") as f:
117
- kw = yload(f)
118
- m = kw.pop("type")
119
- else:
120
- kw = {}
121
- for pp in p:
122
- split_arg(pp, kw)
123
- try:
124
- m = loader(m, "user", server=False)
125
- except ModuleNotFoundError:
126
- raise NoAuthModuleError(m) from None
127
- return m.build(kw)
128
-
129
-
130
- def load(typ: str, *, make: bool = False, server: bool):
131
- """
132
- This procedure is used to load and return a user management class.
133
-
134
- Arguments:
135
- typ: the type of module to load.
136
- make: flag that the caller wants a record-generating, not a
137
- record-using class.
138
- server: flag that the class is to be used on the server, not on the
139
- client.
140
-
141
- Types:
142
- stream: the filter used for authorizing the user.
143
- user: represents a user record.
144
- """
145
- raise NotImplementedError("You need to implement me") # pragma: no cover
146
-
147
-
148
- async def null_server_login(stream):
149
- return stream
150
-
151
-
152
- async def null_client_login(stream, user: BaseClientAuth): # pylint: disable=unused-argument
153
- return stream
154
-
155
-
156
- def _load_example(typ: str, make: bool, server: bool): # pragma: no cover
157
- """example code for :proc:`load`"""
158
- if typ == "client":
159
- if server:
160
- return null_server_login
161
- else:
162
- return null_client_login
163
- if typ != "user":
164
- raise NotImplementedError("This module only handles users")
165
- if server:
166
- if make:
167
- return BaseServerAuthMaker
168
- else:
169
- return BaseServerAuth
170
- else:
171
- if make:
172
- return BaseClientAuthMaker
173
- else:
174
- return BaseClientAuth
175
-
176
-
177
- class _AuthLoaded:
178
- # This class is mainly there to appease pylint
179
- _auth_method = None
180
-
181
-
182
- class BaseClientAuth(_AuthLoaded):
183
- """
184
- This class is used for creating a data record which authenticates a user.
185
-
186
- The schema verifies the input to :meth:`build`.
187
- """
188
-
189
- schema = null_schema
190
-
191
- def __init__(self, **data):
192
- jsonschema.validate(instance=data, schema=type(self).schema)
193
- for k, v in data.items():
194
- setattr(self, k, v)
195
-
196
- @classmethod
197
- def build(cls, user):
198
- """
199
- Create a user record from the data conforming to this schema.
200
- """
201
- return cls(**user)
202
-
203
- @property
204
- def ident(self):
205
- """Some user identifier.
206
- Required so that the server can actually find the record.
207
- """
208
- return "*"
209
-
210
- async def auth(self, client: Client, chroot=()):
211
- """
212
- Authorizes this record with the server.
213
- """
214
- try:
215
- await client._request(
216
- action="auth",
217
- typ=self._auth_method,
218
- iter=False,
219
- chroot=chroot,
220
- ident=self.ident,
221
- data=self.auth_data(),
222
- )
223
- except NoData:
224
- pass
225
-
226
- def auth_data(self):
227
- """
228
- Additional data for the initial auth message.
229
-
230
- Does NOT include 'ident', that gets added explicitly by :meth:`auth`.
231
- """
232
- return {}
233
-
234
-
235
- class BaseClientAuthMaker(_AuthLoaded):
236
- """
237
- This class is used for creating a data record which describes a user record.
238
-
239
- While :class:`BaseClientAuth` is used solely for authentication,
240
- this class is used to represent the server's user data.
241
-
242
- The schema verifies the input to :meth:`build`.
243
- """
244
-
245
- gen_schema = null_schema
246
- mod_schema = null_schema
247
- _chain = None
248
-
249
- def __init__(self, _initial=True, **data):
250
- if _initial:
251
- jsonschema.validate(instance=data, schema=type(self).gen_schema)
252
- else:
253
- jsonschema.validate(instance=data, schema=type(self).mod_schema)
254
- for k, v in data.items():
255
- setattr(self, k, v)
256
-
257
- @classmethod
258
- def build(cls, user, _initial=True):
259
- """
260
- Create a user record from the data conforming to this schema.
261
- """
262
- return cls(**user, _initial=_initial)
263
-
264
- def export(self):
265
- """Return the data required to re-create the user via :meth:`build`."""
266
- return {} # pragma: no cover
267
-
268
- @property
269
- def ident(self):
270
- """The identifier for this user.
271
-
272
- Required so that the server can actually find the record.
273
- """
274
- return "*" # pragma: no cover
275
-
276
- @classmethod
277
- async def recv(cls, client: Client, ident: str, _kind="user", _initial=True):
278
- """Read this user from the server.
279
-
280
- Sample code …
281
- """
282
- # pragma: no cover
283
- res = await client._request(
284
- "auth_get",
285
- typ=cls._auth_method,
286
- kind=_kind,
287
- ident=ident,
288
- nchain=0 if _initial else 2,
289
- )
290
- self = cls(_initial=_initial)
291
- self._chain = res.chain
292
- return self
293
-
294
- async def send(self, client: Client, _kind="user"):
295
- """Send this user to the server."""
296
- try:
297
- await client._request(
298
- "auth_set",
299
- iter=False,
300
- typ=type(self)._auth_method,
301
- kind=_kind,
302
- ident=self.ident,
303
- chain=self._chain,
304
- data=self.send_data(),
305
- )
306
- except NoData:
307
- pass
308
-
309
- def send_data(self):
310
- return {}
311
-
312
-
313
- class BaseServerAuth(_AuthLoaded):
314
- """
315
- This class is used on the server to represent / verify a user.
316
-
317
- The schema verifies whatever data the associated ``ClientAuth`` initially sends.
318
- """
319
-
320
- schema = null_schema.copy()
321
- schema["additionalProperties"] = True
322
-
323
- is_super_root = False
324
- can_create_subtree = False
325
- can_auth_read = False
326
- can_auth_write = False
327
-
328
- def __init__(self, data: dict = {}): # pylint: disable=dangerous-default-value
329
- if data:
330
- for k, v in data.items():
331
- setattr(self, k, v)
332
-
333
- @classmethod
334
- def load(cls, data: Entry):
335
- """Create a ServerAuth object from existing stored data"""
336
- return cls(data.data)
337
-
338
- async def auth(self, cmd: StreamCommand, data): # pylint: disable=unused-argument
339
- """Verify that @data authenticates this user."""
340
- jsonschema.validate(instance=data.get("data", {}), schema=type(self).schema)
341
-
342
- def aux_conv(self, data: Entry, root: Entry):
343
- from ..types import ConvNull
344
-
345
- try:
346
- data = data["conv"].data["key"]
347
- res, _ = root.follow_acl(Path(None, "conv", data), create=False, nulls_ok=True)
348
- return res
349
- except (KeyError, AttributeError):
350
- return ConvNull
351
-
352
- def aux_acl(self, data: Entry, root: Entry):
353
- try:
354
- data = data["acl"].data["key"]
355
- if data == "*":
356
- return NullACL
357
- acl, _ = root.follow_acl(Path(None, "acl", data), create=False, nulls_ok=True)
358
- return ACLFinder(acl)
359
- except (KeyError, AttributeError):
360
- return NullACL
361
-
362
- def info(self):
363
- """
364
- Return whatever public data the user might want to have displayed.
365
-
366
- This includes information to identify the user, but not anything
367
- that'd be suitable for verifying or even faking authorization.
368
- """
369
- return {}
370
-
371
- async def check_read(self, *path, client: ServerClient, data=None): # pylint: disable=unused-argument
372
- """Check that this user may read the element at this location.
373
- This method may modify the data.
374
- """
375
- return data
376
-
377
- async def check_write(self, *path, client: ServerClient, data=None): # pylint: disable=unused-argument
378
- """Check that this user may write the element at this location.
379
- This method may modify the data.
380
- """
381
- return data
382
-
383
-
384
- class RootServerUser(BaseServerAuth):
385
- """The default user when no auth is required
386
-
387
- Interim record. TODO: create a separate ACL thing.
388
- """
389
-
390
- is_super_root = True
391
- can_create_subtree = True
392
- can_auth_read = True
393
- can_auth_write = True
394
-
395
-
396
- class BaseServerAuthMaker(_AuthLoaded):
397
- """
398
- This class is used on the server to verify the transmitted user record
399
- and to store it in MoaT-KV.
400
-
401
- The schema verifies the data from the client.
402
- """
403
-
404
- schema = null_schema
405
- aux_schemas = None # set by the loader
406
-
407
- def __init__(self, chain=None, data=None):
408
- if data is not None and data is not NotGiven:
409
- for k, v in data.items():
410
- setattr(self, k, v)
411
- self._chain = chain
412
-
413
- @classmethod
414
- def load(cls, data: Entry):
415
- """Read the user data from MoaT-KV"""
416
- return cls(chain=data.chain, data=data.data)
417
-
418
- @classmethod
419
- async def recv(
420
- cls,
421
- cmd: StreamCommand,
422
- data: attrdict, # pylint: disable=unused-argument
423
- ) -> BaseServerAuthMaker:
424
- """Create/update a new user by reading the record from the client"""
425
- dt = data.get("data", None) or {}
426
- jsonschema.validate(instance=dt, schema=cls.schema)
427
- self = cls(chain=data["chain"], data=dt)
428
- return self
429
-
430
- @property
431
- def ident(self):
432
- """The record to store this user under."""
433
- return "*"
434
-
435
- def save(self):
436
- """Return a record to represent this user, suitable for saving to MoaT-KV"""
437
- # does NOT contain "ident" or "chain"!
438
- return {}
439
-
440
- async def send(self, cmd: StreamCommand): # pylint: disable=unused-argument
441
- """Send a record to the client, possibly multi-step / secured / whatever"""
442
- res = {}
443
- res["chain"] = self._chain.serialize() if self._chain else None
444
- return res
@@ -1,166 +0,0 @@
1
- #
2
- """
3
- Test auth method.
4
-
5
- Does not limit anything, allows everything.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import logging
11
-
12
- log = logging.getLogger(__name__)
13
-
14
- from ..client import Client
15
- from . import (
16
- BaseClientAuth,
17
- BaseClientAuthMaker,
18
- BaseServerAuthMaker,
19
- RootServerUser,
20
- null_client_login,
21
- null_server_login,
22
- )
23
-
24
-
25
- def load(typ: str, *, make: bool = False, server: bool):
26
- if typ == "client":
27
- if server:
28
- return null_server_login
29
- else:
30
- return null_client_login
31
- if typ != "user":
32
- raise NotImplementedError("This module only handles users")
33
- if server:
34
- if make:
35
- return ServerUserMaker
36
- else:
37
- return ServerUser
38
- else:
39
- if make:
40
- return ClientUserMaker
41
- else:
42
- return ClientUser
43
-
44
-
45
- class ServerUserMaker(BaseServerAuthMaker):
46
- name = None
47
-
48
- @property
49
- def ident(self):
50
- return self.name
51
-
52
- # Overly-complicated methods of exchanging the user name
53
-
54
- @classmethod
55
- async def recv(cls, cmd, data):
56
- await cmd.send(step="GiveName")
57
- msg = await cmd.recv()
58
- assert msg.step == "HasName"
59
- self = cls()
60
- self.name = msg.name
61
- return self
62
-
63
- async def send(self, cmd):
64
- await cmd.send(step="SendWant")
65
- msg = await cmd.recv()
66
- assert msg.step == "WantName"
67
- await cmd.send(step="SendName", name=self.name, chain=self._chain.serialize(nchain=3))
68
- msg = await cmd.recv()
69
-
70
- # Annoying methods to read+save the user name from/to KV
71
-
72
- @classmethod
73
- def load(cls, data):
74
- self = super().load(data)
75
- self.name = data.name
76
- return self
77
-
78
-
79
- class ServerUser(RootServerUser):
80
- pass
81
-
82
-
83
- class ClientUserMaker(BaseClientAuthMaker):
84
- gen_schema = dict(
85
- type="object",
86
- additionalProperties=False,
87
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
88
- required=["name"],
89
- )
90
- mod_schema = dict(
91
- type="object",
92
- additionalProperties=False,
93
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
94
- # required=[],
95
- )
96
- name = None
97
-
98
- @property
99
- def ident(self):
100
- return self.name
101
-
102
- # Overly-complicated methods of exchanging the user name
103
-
104
- @classmethod
105
- async def recv(cls, client: Client, ident: str, _kind: str = "user", _initial=True):
106
- """Read a record representing a user from the server."""
107
- async with client._stream(
108
- action="auth_get",
109
- typ=cls._auth_method,
110
- kind=_kind,
111
- ident=ident,
112
- stream=True,
113
- nchain=0 if _initial else 2,
114
- ) as s:
115
- m = await s.recv()
116
- assert m.step == "SendWant", m
117
- await s.send(step="WantName")
118
- m = await s.recv()
119
- assert m.step == "SendName", m
120
- assert m.name == ident
121
-
122
- self = cls(name=m.name, _initial=_initial)
123
- self._chain = m.chain
124
- return self
125
-
126
- async def send(self, client: Client, _kind="user"):
127
- """Send a record representing this user to the server."""
128
- async with client._stream(
129
- action="auth_set",
130
- typ=type(self)._auth_method,
131
- kind=_kind,
132
- ident=self.ident,
133
- stream=True,
134
- ) as s:
135
- # we could initially send the ident but don't here, for testing
136
- m = await s.recv()
137
- assert m.step == "GiveName", m
138
- await s.send(step="HasName", name=self.name, chain=self._chain)
139
- m = await s.recv()
140
- assert m.chain.prev is None
141
-
142
- def export(self):
143
- """Return the data required to re-create the user via :meth:`build`."""
144
- return {"name": self.name}
145
-
146
-
147
- class ClientUser(BaseClientAuth):
148
- name = None
149
-
150
- schema = dict(
151
- type="object",
152
- additionalProperties=False,
153
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
154
- required=["name"],
155
- )
156
- _name = None
157
-
158
- @property
159
- def ident(self):
160
- return self.name
161
-
162
- @classmethod
163
- def build(cls, user):
164
- self = super().build(user)
165
- self.name = user["name"]
166
- return self