tba-concrete-cwt 0.4.0.dev2__tar.gz
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.
- tba_concrete_cwt-0.4.0.dev2/PKG-INFO +19 -0
- tba_concrete_cwt-0.4.0.dev2/README.md +3 -0
- tba_concrete_cwt-0.4.0.dev2/pyproject.toml +17 -0
- tba_concrete_cwt-0.4.0.dev2/src/tba_concrete_cwt/__init__.py +13 -0
- tba_concrete_cwt-0.4.0.dev2/src/tba_concrete_cwt/claims.py +46 -0
- tba_concrete_cwt-0.4.0.dev2/src/tba_concrete_cwt/py.typed +0 -0
- tba_concrete_cwt-0.4.0.dev2/src/tba_concrete_cwt/tagged.py +23 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tba-concrete-cwt
|
|
3
|
+
Version: 0.4.0.dev2
|
|
4
|
+
Summary: Deterministic provider-free CWT claims-set objects.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10,<3.15
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: cbor2 (==6.1.3)
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# tba-concrete-cwt
|
|
17
|
+
|
|
18
|
+
Deterministic RFC 8392 CWT claims-set encoding and decoding. COSE protection, trust, profile validation, and proof verification remain separate concerns.
|
|
19
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tba-concrete-cwt"
|
|
3
|
+
version = "0.4.0.dev2"
|
|
4
|
+
description = "Deterministic provider-free CWT claims-set objects."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10,<3.15"
|
|
7
|
+
license = "Apache-2.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"cbor2==6.1.3",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[build-system]
|
|
13
|
+
requires = ["poetry-core>=1.0.0"]
|
|
14
|
+
build-backend = "poetry.core.masonry.api"
|
|
15
|
+
|
|
16
|
+
[tool.poetry]
|
|
17
|
+
packages = [{ include = "tba_concrete_cwt", from = "src" }]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Deterministic RFC 8392 CWT claim-set values."""
|
|
2
|
+
|
|
3
|
+
from .claims import CWT_CLAIM_LABELS, CwtClaimsSet, decode_cwt_claims
|
|
4
|
+
from .tagged import CWT_TAG, decode_tagged_cwt, encode_tagged_cwt
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"CWT_CLAIM_LABELS",
|
|
8
|
+
"CWT_TAG",
|
|
9
|
+
"CwtClaimsSet",
|
|
10
|
+
"decode_cwt_claims",
|
|
11
|
+
"decode_tagged_cwt",
|
|
12
|
+
"encode_tagged_cwt",
|
|
13
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Deterministic RFC 8392 CWT claim-set values."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from types import MappingProxyType
|
|
5
|
+
from typing import Mapping
|
|
6
|
+
|
|
7
|
+
import cbor2
|
|
8
|
+
|
|
9
|
+
CWT_CLAIM_LABELS = MappingProxyType(
|
|
10
|
+
{"iss": 1, "sub": 2, "aud": 3, "exp": 4, "nbf": 5, "iat": 6, "cti": 7, "cnf": 8}
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True, slots=True)
|
|
15
|
+
class CwtClaimsSet:
|
|
16
|
+
claims: Mapping[str | int, object]
|
|
17
|
+
|
|
18
|
+
def __post_init__(self) -> None:
|
|
19
|
+
normalized = dict(self.claims)
|
|
20
|
+
if not normalized:
|
|
21
|
+
raise ValueError("CWT claims set must not be empty")
|
|
22
|
+
if not all(
|
|
23
|
+
not isinstance(label, bool) and isinstance(label, (str, int))
|
|
24
|
+
for label in normalized
|
|
25
|
+
):
|
|
26
|
+
raise ValueError("CWT claim labels must be text strings or integers")
|
|
27
|
+
object.__setattr__(self, "claims", MappingProxyType(normalized))
|
|
28
|
+
|
|
29
|
+
def get_registered(self, name: str, default: object = None) -> object:
|
|
30
|
+
label = CWT_CLAIM_LABELS[name]
|
|
31
|
+
return self.claims.get(label, self.claims.get(name, default))
|
|
32
|
+
|
|
33
|
+
def encode(self) -> bytes:
|
|
34
|
+
return cbor2.dumps(dict(self.claims), canonical=True)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def decode_cwt_claims(encoded: bytes) -> CwtClaimsSet:
|
|
38
|
+
if not isinstance(encoded, bytes) or not encoded:
|
|
39
|
+
raise ValueError("encoded CWT claims are required")
|
|
40
|
+
try:
|
|
41
|
+
value = cbor2.loads(encoded)
|
|
42
|
+
except (ValueError, TypeError) as exc:
|
|
43
|
+
raise ValueError("invalid CBOR CWT claims set") from exc
|
|
44
|
+
if not isinstance(value, Mapping):
|
|
45
|
+
raise ValueError("CWT claims set must be a CBOR map")
|
|
46
|
+
return CwtClaimsSet(value)
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from collections.abc import Mapping
|
|
2
|
+
|
|
3
|
+
import cbor2
|
|
4
|
+
from .claims import CwtClaimsSet
|
|
5
|
+
|
|
6
|
+
CWT_TAG = 61
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def encode_tagged_cwt(claims: CwtClaimsSet) -> bytes:
|
|
10
|
+
return cbor2.dumps(cbor2.CBORTag(CWT_TAG, dict(claims.claims)), canonical=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def decode_tagged_cwt(encoded: bytes, *, require_tag: bool = True) -> CwtClaimsSet:
|
|
14
|
+
value = cbor2.loads(encoded)
|
|
15
|
+
if isinstance(value, cbor2.CBORTag):
|
|
16
|
+
if value.tag != CWT_TAG:
|
|
17
|
+
raise ValueError(f"unexpected CBOR tag: {value.tag}")
|
|
18
|
+
value = value.value
|
|
19
|
+
elif require_tag:
|
|
20
|
+
raise ValueError("CWT tag 61 is required")
|
|
21
|
+
if not isinstance(value, Mapping):
|
|
22
|
+
raise ValueError("CWT payload must be a map")
|
|
23
|
+
return CwtClaimsSet(dict(value))
|