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,127 @@
1
+ # shared/protocols/negotiation/challenge.py
2
+
3
+ import json
4
+ import secrets
5
+ from time import time
6
+ from uuid6 import uuid7
7
+
8
+ from .models import AuthenticationChallenge, AuthenticationResponse
9
+ from shared.cryptography.signatures import sign_data, verify_signature
10
+
11
+
12
+ SCHEMA_VERSION = 1
13
+
14
+ CHALLENGE_TYPE_SERVER_AUTHENTICATION = "server_authentication"
15
+ CHALLENGE_TYPE_CLIENT_AUTHENTICATION = "client_authentication"
16
+
17
+
18
+ class ChallengeProtocol:
19
+
20
+ # -----------------------------
21
+ # SERIALIZATION CANÓNICA
22
+ # -----------------------------
23
+ @staticmethod
24
+ def _serialize(data: dict) -> dict:
25
+ return json.loads(
26
+ json.dumps(data, sort_keys=True, separators=(",", ":"))
27
+ )
28
+
29
+ @staticmethod
30
+ def _challenge_payload(challenge: AuthenticationChallenge) -> dict:
31
+ # SOLO campos relevantes para firma (CRÍTICO)
32
+ return ChallengeProtocol._serialize({
33
+ "schema": challenge.schema,
34
+ "challenge_type": challenge.challenge_type,
35
+ "challenge_id": challenge.challenge_id,
36
+ "issuer_uid": challenge.issuer_uid,
37
+ "target_uid": challenge.target_uid,
38
+ "nonce": challenge.nonce,
39
+ "issued_at": challenge.issued_at,
40
+ "expires_at": challenge.expires_at,
41
+ })
42
+
43
+ # -----------------------------
44
+ # CREACIÓN
45
+ # -----------------------------
46
+ @staticmethod
47
+ def create(challenge_type: str, issuer_uid: str, target_uid: str, expires_in: int = 60):
48
+ now = int(time())
49
+
50
+ return AuthenticationChallenge(
51
+ schema=SCHEMA_VERSION,
52
+ challenge_type=challenge_type,
53
+ challenge_id=str(uuid7()),
54
+ issuer_uid=issuer_uid,
55
+ target_uid=target_uid,
56
+ nonce=secrets.token_hex(32),
57
+ issued_at=now,
58
+ expires_at=now + expires_in
59
+ )
60
+
61
+ # -----------------------------
62
+ # FIRMA
63
+ # -----------------------------
64
+ @staticmethod
65
+ def sign(private_key: str, challenge: AuthenticationChallenge) -> AuthenticationResponse:
66
+ payload = ChallengeProtocol._challenge_payload(challenge)
67
+
68
+ signature = sign_data(private_key, payload)
69
+
70
+ return AuthenticationResponse(
71
+ schema=SCHEMA_VERSION,
72
+ challenge_id=challenge.challenge_id,
73
+ responder_uid=challenge.target_uid,
74
+ signature=signature
75
+ )
76
+
77
+ # -----------------------------
78
+ # VERIFICACIÓN
79
+ # -----------------------------
80
+ @staticmethod
81
+ def verify(public_key: str, challenge: AuthenticationChallenge, response: AuthenticationResponse) -> bool:
82
+ payload = ChallengeProtocol._challenge_payload(challenge)
83
+ return verify_signature(public_key, payload, response.signature)
84
+
85
+ # -----------------------------
86
+ # UTILIDADES
87
+ # -----------------------------
88
+ @staticmethod
89
+ def is_expired(challenge) -> bool:
90
+ return int(time()) > challenge.expires_at
91
+
92
+ @staticmethod
93
+ def validate_type(challenge, expected_type: str) -> bool:
94
+ return challenge.challenge_type == expected_type
95
+
96
+ # -----------------------------
97
+ # SERIALIZACIÓN ROBUSTA
98
+ # -----------------------------
99
+ @staticmethod
100
+ def challenge_to_dict(challenge) -> dict:
101
+ return {
102
+ "schema": challenge.schema,
103
+ "challenge_type": challenge.challenge_type,
104
+ "challenge_id": challenge.challenge_id,
105
+ "issuer_uid": challenge.issuer_uid,
106
+ "target_uid": challenge.target_uid,
107
+ "nonce": challenge.nonce,
108
+ "issued_at": challenge.issued_at,
109
+ "expires_at": challenge.expires_at,
110
+ }
111
+
112
+ @staticmethod
113
+ def response_to_dict(response) -> dict:
114
+ return {
115
+ "schema": response.schema,
116
+ "challenge_id": response.challenge_id,
117
+ "responder_uid": response.responder_uid,
118
+ "signature": response.signature,
119
+ }
120
+
121
+ @staticmethod
122
+ def challenge_from_dict(data: dict):
123
+ return AuthenticationChallenge(**data)
124
+
125
+ @staticmethod
126
+ def response_from_dict(data: dict):
127
+ return AuthenticationResponse(**data)
@@ -0,0 +1,28 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class AuthenticationChallenge:
6
+ schema: int
7
+
8
+ challenge_type: str
9
+
10
+ challenge_id: str
11
+
12
+ issuer_uid: str
13
+ target_uid: str
14
+
15
+ nonce: str
16
+
17
+ issued_at: int
18
+ expires_at: int
19
+
20
+ @dataclass
21
+ class AuthenticationResponse:
22
+ schema: int
23
+
24
+ challenge_id: str
25
+
26
+ responder_uid: str
27
+
28
+ signature: str
standards/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ from enum import Enum
2
+
3
+
4
+ class CertificateStatus(str, Enum):
5
+ ACTIVE = "ACTIVE"
6
+ REVOKED = "REVOKED"
7
+ EXPIRED = "EXPIRED"
8
+ COMPROMISED = "COMPROMISED"
9
+
10
+ @staticmethod
11
+ def exists(value: str) -> bool:
12
+ return value in CertificateStatus._value2member_map_
@@ -0,0 +1,11 @@
1
+ from enum import Enum
2
+
3
+ SCHEMA_VERSION = 1
4
+
5
+ class CertificateType(str, Enum):
6
+ DOMAIN_MANAGEMENT = "DOMAIN_MANAGEMENT"
7
+ MANAGER_AUTHORIZATION = "MANAGER_AUTHORIZATION"
8
+
9
+ @staticmethod
10
+ def exists(value: str) -> bool:
11
+ return value in CertificateType._value2member_map_
File without changes
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+
3
+
4
+ class EntityType(str, Enum):
5
+
6
+ AGENT = "AGENT"
7
+
8
+ CONSOLE = "CONSOLE"
9
+
10
+ PROXY = "PROXY"
11
+
12
+ MANAGER = "MANAGER"
13
+
14
+ ROOT_AUTHORITY = "ROOT_AUTHORITY"
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class EntityRegisteredEventDetails:
6
+
7
+ schema: int
8
+
9
+ source: str
10
+
11
+ method: str
12
+
13
+ fingerprint: str
@@ -0,0 +1,18 @@
1
+ from enum import Enum
2
+
3
+
4
+ class EventType(str, Enum):
5
+
6
+ ENTITY_REGISTERED = "entity.registered"
7
+
8
+ ENTITY_REVOKED = "entity.revoked"
9
+
10
+ DOMAIN_CREATED = "domain.created"
11
+
12
+ DOMAIN_UPDATED = "domain.updated"
13
+
14
+ DOMAIN_DELETED = "domain.deleted"
15
+
16
+ MEMBERSHIP_CREATED = "membership.created"
17
+
18
+ TRUST_ESTABLISHED = "trust.established"
File without changes
@@ -0,0 +1,5 @@
1
+ from enum import Enum
2
+
3
+ class PASSPORT_TYPE(str, Enum):
4
+ OPEN = "OPEN"
5
+ CLOSED = "CLOSED"
File without changes
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Permission(str, Enum):
5
+
6
+ DOMAIN_READ = "domain.read"
7
+
8
+ DOMAIN_WRITE = "domain.write"
9
+
10
+ ENTITY_REGISTER = "entity.register"
11
+
12
+ ENTITY_REVOKE = "entity.revoke"
13
+
14
+ PROXY_USE = "proxy.use"
File without changes
@@ -0,0 +1,8 @@
1
+ from enum import Enum
2
+
3
+ class ROLE(str, Enum):
4
+ PROPIETARY = "PROPIETARY"
5
+ ADMINISTRATOR = "ADMINISTRATOR"
6
+ OPERATOR = "OPERATOR"
7
+ AGENT = "AGENT"
8
+ SUPERVISOR = "SUPERVISOR"
File without changes
@@ -0,0 +1,24 @@
1
+ from enum import Enum
2
+
3
+
4
+ class TransportType(str, Enum):
5
+ TCP = "TCP"
6
+ UDP = "UDP"
7
+
8
+ HTTP = "HTTP"
9
+ HTTPS = "HTTPS"
10
+
11
+ WEBSOCKET = "WEBSOCKET"
12
+ WEBSOCKET_SECURE = "WEBSOCKET_SECURE"
13
+
14
+ QUIC = "QUIC"
15
+
16
+ BLUETOOTH = "BLUETOOTH"
17
+ SERIAL = "SERIAL"
18
+
19
+ TOR = "TOR"
20
+
21
+
22
+ @staticmethod
23
+ def exists(value: str) -> bool:
24
+ return value in TransportType._value2member_map_