openshell-shared 0.1.2__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 (62) hide show
  1. api/__init__.py +1 -0
  2. api/manager/__init__.py +1 -0
  3. api/manager/v1/__init__.py +78 -0
  4. api/manager/v1/authentication.py +278 -0
  5. api/manager/v1/client.py +111 -0
  6. api/manager/v1/domains.py +64 -0
  7. api/manager/v1/entities.py +97 -0
  8. api/manager/v1/exceptions.py +98 -0
  9. api/manager/v1/identity.py +44 -0
  10. api/manager/v1/models.py +342 -0
  11. api/manager/v1/passports.py +131 -0
  12. api/manager/v1/sessions.py +83 -0
  13. api/manager/v1/transport.py +253 -0
  14. api/manager/v1/tunnels.py +120 -0
  15. cryptography/__init__.py +0 -0
  16. cryptography/certificate.py +390 -0
  17. cryptography/encoding.py +0 -0
  18. cryptography/identity.py +124 -0
  19. cryptography/keys.py +463 -0
  20. cryptography/signatures.py +63 -0
  21. cryptography/utils.py +0 -0
  22. domain/__init__.py +0 -0
  23. domain/domain.py +80 -0
  24. domain/membership.py +21 -0
  25. domain/permissions.py +14 -0
  26. domain/policies.py +2 -0
  27. identity/__init__.py +0 -0
  28. identity/identification.py +64 -0
  29. identity/store.py +150 -0
  30. modules/__init__.py +0 -0
  31. modules/shell/__init__.py +0 -0
  32. modules/shell/client.py +361 -0
  33. modules/shell/models.py +61 -0
  34. modules/shell/protocol.py +249 -0
  35. modules/shell/server.py +511 -0
  36. modules/shell/session.py +339 -0
  37. modules/utils.py +212 -0
  38. openshell_shared-0.1.2.dist-info/METADATA +59 -0
  39. openshell_shared-0.1.2.dist-info/RECORD +62 -0
  40. openshell_shared-0.1.2.dist-info/WHEEL +5 -0
  41. openshell_shared-0.1.2.dist-info/top_level.txt +7 -0
  42. protocols/__init__.py +0 -0
  43. protocols/negotiation/challenge.py +127 -0
  44. protocols/negotiation/models.py +28 -0
  45. standards/__init__.py +0 -0
  46. standards/certificates/__init__.py +0 -0
  47. standards/certificates/status.py +12 -0
  48. standards/certificates/types.py +11 -0
  49. standards/entities/__init__.py +0 -0
  50. standards/entities/types.py +14 -0
  51. standards/events/__init__.py +0 -0
  52. standards/events/schemas/__init__.py +0 -0
  53. standards/events/schemas/entity_registered.py +13 -0
  54. standards/events/types.py +18 -0
  55. standards/passports/__init__.py +0 -0
  56. standards/passports/types.py +5 -0
  57. standards/permissions/__init__.py +0 -0
  58. standards/permissions/types.py +14 -0
  59. standards/roles/__init__.py +0 -0
  60. standards/roles/types.py +8 -0
  61. standards/transports/__init__.py +0 -0
  62. standards/transports/types.py +24 -0
@@ -0,0 +1,339 @@
1
+ # shell/session.py
2
+
3
+ # =====================================================
4
+ # LIBRARY IMPORTS
5
+ # =====================================================
6
+
7
+ import os
8
+ import pty
9
+ import fcntl
10
+ import signal
11
+ import struct
12
+ import termios
13
+ import asyncio
14
+ import subprocess
15
+
16
+
17
+ # =====================================================
18
+ # SHELL SESSION
19
+ # =====================================================
20
+
21
+ class ShellSession:
22
+
23
+ def __init__(
24
+ self,
25
+ session_token: str
26
+ ):
27
+
28
+ self.session_token = (
29
+ session_token
30
+ )
31
+
32
+ self.process = None
33
+
34
+ self.master_fd = None
35
+ self.slave_fd = None
36
+
37
+ self._lock = asyncio.Lock()
38
+
39
+ # =================================================
40
+ # START
41
+ # =================================================
42
+
43
+ async def start(self):
44
+
45
+ if self.process is not None:
46
+ return
47
+
48
+ self.master_fd, self.slave_fd = (
49
+ pty.openpty()
50
+ )
51
+
52
+ self.process = subprocess.Popen(
53
+ [
54
+ "/bin/bash",
55
+ "-i"
56
+ ],
57
+ stdin=self.slave_fd,
58
+ stdout=self.slave_fd,
59
+ stderr=self.slave_fd,
60
+ start_new_session=True,
61
+ close_fds=True
62
+ )
63
+
64
+ os.set_blocking(
65
+ self.master_fd,
66
+ False
67
+ )
68
+
69
+ # =================================================
70
+ # WRITE
71
+ # =================================================
72
+
73
+ async def write(
74
+ self,
75
+ data: str
76
+ ):
77
+
78
+ async with self._lock:
79
+
80
+ if self.process is None:
81
+
82
+ await self.start()
83
+
84
+ if isinstance(
85
+ data,
86
+ str
87
+ ):
88
+
89
+ data = data.encode()
90
+
91
+ os.write(
92
+ self.master_fd,
93
+ data
94
+ )
95
+
96
+ # =================================================
97
+ # READ
98
+ # =================================================
99
+
100
+ async def read(
101
+ self,
102
+ max_bytes: int = 65536
103
+ ) -> str:
104
+
105
+ if self.process is None:
106
+ return ""
107
+
108
+ try:
109
+
110
+ data = os.read(
111
+ self.master_fd,
112
+ max_bytes
113
+ )
114
+
115
+ return data.decode(
116
+ errors="ignore"
117
+ )
118
+
119
+ except BlockingIOError:
120
+
121
+ return ""
122
+
123
+ except OSError:
124
+
125
+ return ""
126
+
127
+ # =================================================
128
+ # READ AVAILABLE
129
+ # =================================================
130
+
131
+ async def read_available(
132
+ self,
133
+ chunk_size: int = 65536
134
+ ) -> str:
135
+
136
+ output = []
137
+
138
+ while True:
139
+
140
+ try:
141
+
142
+ chunk = os.read(
143
+ self.master_fd,
144
+ chunk_size
145
+ )
146
+
147
+ if not chunk:
148
+ break
149
+
150
+ output.append(
151
+ chunk.decode(
152
+ errors="ignore"
153
+ )
154
+ )
155
+
156
+ except BlockingIOError:
157
+
158
+ break
159
+
160
+ except OSError:
161
+
162
+ break
163
+
164
+ return "".join(
165
+ output
166
+ )
167
+
168
+ # =================================================
169
+ # RESIZE
170
+ # =================================================
171
+
172
+ async def resize(
173
+ self,
174
+ rows: int,
175
+ cols: int
176
+ ):
177
+
178
+ if self.master_fd is None:
179
+ return
180
+
181
+ winsize = struct.pack(
182
+ "HHHH",
183
+ rows,
184
+ cols,
185
+ 0,
186
+ 0
187
+ )
188
+
189
+ fcntl.ioctl(
190
+ self.master_fd,
191
+ termios.TIOCSWINSZ,
192
+ winsize
193
+ )
194
+
195
+ # =================================================
196
+ # SIGNAL
197
+ # =================================================
198
+
199
+ async def signal(
200
+ self,
201
+ signal_name: str
202
+ ):
203
+
204
+ if self.process is None:
205
+ return
206
+
207
+ sig = getattr(
208
+ signal,
209
+ signal_name,
210
+ None
211
+ )
212
+
213
+ if sig is None:
214
+ return
215
+
216
+ try:
217
+
218
+ os.killpg(
219
+ self.process.pid,
220
+ sig
221
+ )
222
+
223
+ except Exception:
224
+
225
+ pass
226
+
227
+ # =================================================
228
+ # PID
229
+ # =================================================
230
+
231
+ @property
232
+ def pid(
233
+ self
234
+ ):
235
+
236
+ if self.process is None:
237
+ return None
238
+
239
+ return (
240
+ self.process.pid
241
+ )
242
+
243
+ # =================================================
244
+ # IS ALIVE
245
+ # =================================================
246
+
247
+ def is_alive(
248
+ self
249
+ ) -> bool:
250
+
251
+ if self.process is None:
252
+ return False
253
+
254
+ return (
255
+ self.process.poll()
256
+ is None
257
+ )
258
+
259
+ # =================================================
260
+ # RETURN CODE
261
+ # =================================================
262
+
263
+ def return_code(
264
+ self
265
+ ):
266
+
267
+ if self.process is None:
268
+ return None
269
+
270
+ return (
271
+ self.process.poll()
272
+ )
273
+
274
+ # =================================================
275
+ # CLOSE
276
+ # =================================================
277
+
278
+ async def close(self):
279
+
280
+ if self.process is None:
281
+ return
282
+
283
+ try:
284
+
285
+ os.killpg(
286
+ self.process.pid,
287
+ signal.SIGTERM
288
+ )
289
+
290
+ except Exception:
291
+
292
+ pass
293
+
294
+ try:
295
+
296
+ await asyncio.wait_for(
297
+ asyncio.to_thread(
298
+ self.process.wait
299
+ ),
300
+ timeout=3
301
+ )
302
+
303
+ except asyncio.TimeoutError:
304
+
305
+ try:
306
+
307
+ os.killpg(
308
+ self.process.pid,
309
+ signal.SIGKILL
310
+ )
311
+
312
+ except Exception:
313
+
314
+ pass
315
+
316
+ try:
317
+
318
+ os.close(
319
+ self.master_fd
320
+ )
321
+
322
+ except Exception:
323
+
324
+ pass
325
+
326
+ try:
327
+
328
+ os.close(
329
+ self.slave_fd
330
+ )
331
+
332
+ except Exception:
333
+
334
+ pass
335
+
336
+ self.process = None
337
+
338
+ self.master_fd = None
339
+ self.slave_fd = None
modules/utils.py ADDED
@@ -0,0 +1,212 @@
1
+ import asyncio
2
+ import websockets
3
+
4
+ from asyncdatapackage import AsyncDataPackage
5
+
6
+
7
+ class WSStreamClient:
8
+ """
9
+ Convierte WebSocket en stream tipo TCP para AsyncDataPackage.
10
+ """
11
+
12
+ def __init__(self, host: str, port: int):
13
+
14
+ self._host = host
15
+ self._port = port
16
+
17
+ self._ws = None
18
+
19
+ self._buffer = bytearray()
20
+ self._recv_queue = asyncio.Queue()
21
+
22
+ self._reader_task = None
23
+ self._running = False
24
+
25
+ # =====================================================
26
+ # CONNECT
27
+ # =====================================================
28
+
29
+ async def connect(self):
30
+
31
+ uri = f"ws://{self._host}:{self._port}"
32
+
33
+ self._ws = await websockets.connect(
34
+ uri,
35
+ max_size=None,
36
+ ping_interval=None
37
+ )
38
+
39
+ self._running = True
40
+
41
+ self._reader_task = asyncio.create_task(
42
+ self._reader_loop()
43
+ )
44
+
45
+ # =====================================================
46
+ # READER LOOP (WS → STREAM BUFFER)
47
+ # =====================================================
48
+
49
+ async def _reader_loop(self):
50
+
51
+ try:
52
+ async for message in self._ws:
53
+
54
+ if isinstance(message, str):
55
+ message = message.encode("utf-8")
56
+
57
+ self._buffer.extend(message)
58
+
59
+ except Exception:
60
+ self._running = False
61
+
62
+ # =====================================================
63
+ # WRITE (STREAM → WS)
64
+ # =====================================================
65
+
66
+ async def write(self, data: bytes) -> bool:
67
+
68
+ if not self._ws:
69
+ return False
70
+
71
+ try:
72
+ await self._ws.send(data)
73
+ return True
74
+ except Exception:
75
+ return False
76
+
77
+ # =====================================================
78
+ # READ (TCP-LIKE SEMANTICS)
79
+ # =====================================================
80
+
81
+ # =====================================================
82
+ # READ (TCP-LIKE SEMANTICS FIXED)
83
+ # =====================================================
84
+
85
+ async def read(self, amount: int) -> bytes:
86
+
87
+ # Bloquear solo si no hay absolutamente nada que leer
88
+ while len(self._buffer) == 0:
89
+ if not self._running:
90
+ return b""
91
+ await asyncio.sleep(0.001)
92
+
93
+ # Extraer hasta 'amount' bytes, o la longitud actual (lo que sea menor)
94
+ chunk_size = min(amount, len(self._buffer))
95
+
96
+ result = bytes(self._buffer[:chunk_size])
97
+ del self._buffer[:chunk_size]
98
+
99
+ return result
100
+
101
+ # =====================================================
102
+ # CLOSE
103
+ # =====================================================
104
+
105
+ async def close(self):
106
+
107
+ self._running = False
108
+
109
+ if self._ws:
110
+ await self._ws.close()
111
+
112
+ if self._reader_task:
113
+ self._reader_task.cancel()
114
+
115
+ try:
116
+ await self._reader_task
117
+ except:
118
+ pass
119
+
120
+
121
+ # =========================================================
122
+ # COMMUNICATION HANDLER (DROP-IN COMPATIBLE)
123
+ # =========================================================
124
+
125
+ class CommunicationHandler:
126
+
127
+ def __init__(
128
+ self,
129
+ auth_token: str,
130
+ tunnel_token: str,
131
+ tunnel_port: int,
132
+ tunnel_host: str = "127.0.0.1"
133
+ ):
134
+ self.auth_token = auth_token
135
+ self.tunnel_token = tunnel_token
136
+
137
+ self.tunnel_host = tunnel_host
138
+ self.tunnel_port = tunnel_port
139
+
140
+ self._stream = None
141
+ self.datapackage = None
142
+
143
+ # =====================================================
144
+ # CONNECTION
145
+ # =====================================================
146
+
147
+ async def connect(self):
148
+
149
+ self._stream = WSStreamClient(
150
+ self.tunnel_host,
151
+ self.tunnel_port
152
+ )
153
+
154
+ await self._stream.connect()
155
+
156
+ async def write_fn(data: bytes):
157
+ return await self._stream.write(data)
158
+
159
+ async def read_fn():
160
+ # IMPORTANT: AsyncDataPackage expects chunk reads
161
+ return await self._stream.read(65536)
162
+
163
+ self.datapackage = AsyncDataPackage(
164
+ write_function=write_fn,
165
+ read_function=read_fn,
166
+ backpressure_mode="drop_oldest"
167
+ )
168
+
169
+ await self.datapackage.start()
170
+
171
+ await self._bind()
172
+
173
+ # =====================================================
174
+ # BIND
175
+ # =====================================================
176
+
177
+ async def _bind(self):
178
+
179
+ await self.datapackage.send_datapackage({
180
+ "auth_token": self.auth_token,
181
+ "tunnel_token": self.tunnel_token,
182
+ "packet_type": "CONTROL",
183
+ "packet_control": "BIND"
184
+ })
185
+
186
+ # =====================================================
187
+ # SEND
188
+ # =====================================================
189
+
190
+ async def send_datapackage(self, packet: dict):
191
+
192
+ await self.datapackage.send_datapackage(packet)
193
+
194
+ # =====================================================
195
+ # RECEIVE
196
+ # =====================================================
197
+
198
+ async def receive_datapackage(self):
199
+
200
+ return await self.datapackage.receive_datapackage()
201
+
202
+ # =====================================================
203
+ # CLOSE
204
+ # =====================================================
205
+
206
+ async def close(self):
207
+
208
+ if self.datapackage:
209
+ await self.datapackage.stop()
210
+
211
+ if self._stream:
212
+ await self._stream.close()
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: openshell-shared
3
+ Version: 0.1.2
4
+ Summary: Shared library for OpenShell (OSAM/OSA/OSAC)
5
+ Author: Daniel Pérez
6
+ License: Proprietary
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: httpx
10
+ Requires-Dist: cryptography
11
+ Requires-Dist: websockets
12
+ Requires-Dist: uuid6
13
+
14
+ # OpenShell Shared
15
+
16
+ Librería compartida usada por los componentes de OpenShell (OSAM, OSA, OSAC).
17
+
18
+ Contiene:
19
+
20
+ - **identity/** — Identidad lógica de las entidades (`EntityIdentity`, `Identification`) y su
21
+ persistencia (`store.py`).
22
+ - **cryptography/** — Primitivas Ed25519 (`keys.py`, `signatures.py`), identidad criptográfica
23
+ (`identity.py`) y certificados (`certificate.py`). `encoding.py` y `utils.py` son módulos
24
+ reservados para trabajo futuro (actualmente sin implementación).
25
+ - **protocols/negotiation/** — Protocolo de challenge-response (`challenge.py`) y sus modelos.
26
+ - **domain/** — Modelo de dominio (`Domain`, `Membership`, `Permission`) y políticas de
27
+ autorización. `policies.py` es un stub pendiente de implementación real.
28
+ - **standards/** — Enumeraciones y contratos compartidos entre componentes: tipos de entidad,
29
+ certificados, eventos, roles, permisos, passports y transportes.
30
+ - **modules/shell/** — Implementación del subsistema de shell remoto (cliente, servidor, sesión
31
+ y protocolo de framing) usado por OSA y OSAC.
32
+ - **api/manager/v1/** — SDK oficial async para consumir la API HTTP de OSAM (`OSAMClient`).
33
+ Todo el sistema (OSAC, OSA, herramientas internas) debe consumir OSAM exclusivamente a través
34
+ de este paquete; ningún otro componente debe importar `httpx`/`requests` directamente para
35
+ hablar con OSAM.
36
+
37
+ ## Notas de la fusión (v2.1.0)
38
+
39
+ Esta versión unifica dos ramas que habían divergido:
40
+
41
+ - Se conserva la estructura de empaquetado (`pyproject.toml`, layout `src`) y los módulos
42
+ `domain/` y `standards/`, introducidos en la rama de refactor v2.
43
+ - Se restaura `modules/shell/` y se sustituye el cliente HTTP monolítico
44
+ (`api/manager/1/osam_client.py`) por el SDK modular (`api/manager/v1/`), que es la versión
45
+ vigente y más completa (excepciones tipadas, dataclasses, suite de tests con mock transport).
46
+
47
+ ### Deuda técnica pendiente identificada durante la fusión
48
+
49
+ 1. `domain/permissions.py` y `standards/permissions/types.py` definen dos enums `Permission`
50
+ distintos y no compatibles entre sí (`AGENT_READ/AGENT_EXECUTE/DOMAIN_ADMIN/PROXY_USE` vs.
51
+ `DOMAIN_READ/DOMAIN_WRITE/ENTITY_REGISTER/ENTITY_REVOKE/PROXY_USE`). No se han unificado
52
+ automáticamente porque implica una decisión de diseño (cuál es la fuente de verdad de
53
+ permisos). Requiere consolidación manual.
54
+ 2. `cryptography/encoding.py`, `cryptography/utils.py` y `domain/policies.py` son placeholders
55
+ vacíos o triviales (`Policy.evaluate` siempre retorna `True`). No implementan lógica real.
56
+ 3. El SDK (`api/manager/v1/`) no reexpone los helpers de alto nivel `full_connect` /
57
+ `open_and_link` que existían en el cliente monolítico anterior (composición de
58
+ autenticación + túnel + sesión en una sola llamada). Si se siguen usando, conviene
59
+ reimplementarlos como métodos de conveniencia sobre `OSAMClient`.
@@ -0,0 +1,62 @@
1
+ api/__init__.py,sha256=gxFxYhnSvtNu2Bvd3C1vrlOFkVKAJY5Vzk1qTB9IOVk,21
2
+ api/manager/__init__.py,sha256=66EsLcAnZvOfbhmRKT3uY_LPJu3o_rHicCdkAVqpdEs,16
3
+ api/manager/v1/__init__.py,sha256=JPUvoGHq3y47eYmUVNypTZtPixdE9P-lrMnYoK5aljU,1739
4
+ api/manager/v1/authentication.py,sha256=KswoqDUhjiSLeZmnlprg0pfJNZfMK-kHYbAcE40LRdI,7034
5
+ api/manager/v1/client.py,sha256=oIlq0FjUDj42eCzGp1_SHZ-mtK94KQ2Oi3r5g2aLdOk,3885
6
+ api/manager/v1/domains.py,sha256=5v_mSFXRqbdRBshAlO0IN8oBfJsF2W2EVmoejuMYjfg,2048
7
+ api/manager/v1/entities.py,sha256=W2_51oGBHejQO0_tDRmC3_0bfJTjQon72_FjBYtpFY8,3663
8
+ api/manager/v1/exceptions.py,sha256=YqLAFrFHSgkedmFwwT9y-ay4QBOnHyYKAjORI2RGHIE,3627
9
+ api/manager/v1/identity.py,sha256=P_H6FtvS6TiqBNOPG3slAJmmia7frAOcZo11PEdpodw,1669
10
+ api/manager/v1/models.py,sha256=OZCHN9ozVGs46ZR71QDw-iQgdOMGPl7LqNpZG6KoRIs,12223
11
+ api/manager/v1/passports.py,sha256=BOSFhP11d9fBsu9PAKnpOZkfhwUjDiS2f6XUp7SGnPY,4957
12
+ api/manager/v1/sessions.py,sha256=hWi_cb1tejKAkZ0_9ecE2sCmZj7GJgUt9P-2xYziWKk,2435
13
+ api/manager/v1/transport.py,sha256=fiRKiYMjT6dnViL-dB63HQFG2sIGgphxG86YHRvwTiQ,8452
14
+ api/manager/v1/tunnels.py,sha256=Yn6YPwA6_GM0G5HbrJVounGLK7_oOtqHELRJBJDtsoA,4042
15
+ cryptography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ cryptography/certificate.py,sha256=GlacatBv26w2ltJ32vNzaJ68dffKntM6Y7o-NLSsn6U,9736
17
+ cryptography/encoding.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ cryptography/identity.py,sha256=8ngNnn76CoRdgdctKSl6b2AGCp1P04O8v_MZ7KveyiU,3557
19
+ cryptography/keys.py,sha256=QLdiIMLCvqmnw2zlQXnE5Me_8StJ_mSjo5KXe9JTWHA,8333
20
+ cryptography/signatures.py,sha256=7jrpZjCYKzeGLckPg3wq8BoR9Sj2EKMPdKYzZijRLvg,1143
21
+ cryptography/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ domain/domain.py,sha256=p4qh0Pee06IY9pmA_QyVovBlvhFJX1R8QjK_xebo2zY,1734
24
+ domain/membership.py,sha256=X5BAiv2CKoIYZ095ZDGw5YJgBrhQsuIS40glTv8C30I,425
25
+ domain/permissions.py,sha256=ppZZU_-vVuQQ9SujYAKbR4u0brP7OGeRz7_Oq2IO5Ks,222
26
+ domain/policies.py,sha256=jkBzdWKjcwIa1UlrpzCZGhxDXOivX2QHLaj8y68TzqI,66
27
+ identity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ identity/identification.py,sha256=KQ5XpxDj9TrG-U116j_FC5cMn-0sB_FtSZVwA_QcFgQ,1495
29
+ identity/store.py,sha256=s40UTbBenQYkPZnS7x8jkVzyg4OPQTLeEB3Hd32udVE,4317
30
+ modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ modules/utils.py,sha256=c2R9RkuU1WQyFnXT8mNvD0qBtsBeeHJKrvNplcyvSXs,5515
32
+ modules/shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ modules/shell/client.py,sha256=D2yAXwj6yr7CRa5PUKtrV8Rk3_6n8Q8AbP7_aJWDeGs,8094
34
+ modules/shell/models.py,sha256=_a1c-xzai_B5UBhVa8zjfPMrM8hotCTNpje5x62Pgi4,1200
35
+ modules/shell/protocol.py,sha256=JlhboJIOM9FQAyqZWKeS4Xbk8lcbUEdq7HOGowjq-ac,4619
36
+ modules/shell/server.py,sha256=Pfm2JINcMZTyxy5uTE425o8ZM6Dtc_p8B67lc_-ktqM,11902
37
+ modules/shell/session.py,sha256=g1VjO0UOii2zITkXHc222C3a_gF2XYFqiV9t30wpfSk,6226
38
+ protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
+ protocols/negotiation/challenge.py,sha256=OJN_S1aHuvAQkIWVp8QLtGBTD8CuSSgd4AfyFbVQOL8,4134
40
+ protocols/negotiation/models.py,sha256=lNbRds5zyhWV6eEHmm6aFkSunmGPWTMIUKoFJYb04ro,363
41
+ standards/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ standards/certificates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
+ standards/certificates/status.py,sha256=wI_0WKo34l-jYyHfkI6EVVJ54iB0VZkcY-v6r7p6hL4,277
44
+ standards/certificates/types.py,sha256=0EJ8-OrP1I_-YIxGl1rgpMDSIlsoGxT_80XxUy5-FYs,286
45
+ standards/entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ standards/entities/types.py,sha256=rcCV5XaUskf8ZKeIJyZAj0rTfhrH5QDo-g-AQrB8Ax8,183
47
+ standards/events/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ standards/events/types.py,sha256=OcZ8ibQv1dPOISM01wUSB7ckwYuxBDdCf0PwNm26WZM,348
49
+ standards/events/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ standards/events/schemas/entity_registered.py,sha256=BMCvnv2WHJKff5Zd7vx9sUyrXbBOuiPjcfqkQS6dG2I,155
51
+ standards/passports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
+ standards/passports/types.py,sha256=NRTHSV6TdavW5mBklLvBg587LR2-3dmdrdnq_sY8uMk,88
53
+ standards/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
+ standards/permissions/types.py,sha256=ktyRE1CDRMs9ISgsMMWer2-KDP4pcpvIvFuSckoT_3o,227
55
+ standards/roles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
+ standards/roles/types.py,sha256=ZDCUTGz7s3WslocydW9ZhSEA-LeVwr9mD-5iIp-dScM,172
57
+ standards/transports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
+ standards/transports/types.py,sha256=rkJhZlunaGCkND-bhYixg8wBFtrrd4nwOZUiKuw3tmk,397
59
+ openshell_shared-0.1.2.dist-info/METADATA,sha256=IikTmxI49ECBLiFR6za92qc2ZbVLdXEYnTtA8yOHmB4,3210
60
+ openshell_shared-0.1.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
61
+ openshell_shared-0.1.2.dist-info/top_level.txt,sha256=t4a8dGEQBmWWTub6GnION4QEEYGWGBChA8jUHIpeCw0,61
62
+ openshell_shared-0.1.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,7 @@
1
+ api
2
+ cryptography
3
+ domain
4
+ identity
5
+ modules
6
+ protocols
7
+ standards
protocols/__init__.py ADDED
File without changes