km-keybind 1.0.0__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.
- keybind/__init__.py +19 -0
- keybind/chunker.py +30 -0
- keybind/compressor.py +41 -0
- keybind/config.py +42 -0
- keybind/constants.py +24 -0
- keybind/crypto.py +71 -0
- keybind/enums.py +29 -0
- keybind/exceptions.py +79 -0
- keybind/hasher.py +31 -0
- keybind/hkdf.py +34 -0
- keybind/identities.py +23 -0
- keybind/interfaces.py +27 -0
- keybind/keybind.py +316 -0
- keybind/merkle.py +40 -0
- keybind/nonce.py +25 -0
- keybind/serializer.py +27 -0
- keybind/validator.py +31 -0
- km_keybind-1.0.0.dist-info/METADATA +241 -0
- km_keybind-1.0.0.dist-info/RECORD +22 -0
- km_keybind-1.0.0.dist-info/WHEEL +5 -0
- km_keybind-1.0.0.dist-info/licenses/LICENSE +170 -0
- km_keybind-1.0.0.dist-info/top_level.txt +1 -0
keybind/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from .keybind import Keybind
|
|
16
|
+
|
|
17
|
+
__all__ = ["Keybind"]
|
|
18
|
+
|
|
19
|
+
|
keybind/chunker.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ChunkManager:
|
|
19
|
+
|
|
20
|
+
def __init__(self, chunk_size: int = 1024 * 1024) -> None:
|
|
21
|
+
self.chunk_size = chunk_size
|
|
22
|
+
|
|
23
|
+
def split(self, payload: bytes) -> list[bytes]:
|
|
24
|
+
if payload is None:
|
|
25
|
+
return []
|
|
26
|
+
if len(payload) == 0:
|
|
27
|
+
return [b""]
|
|
28
|
+
return [payload[i : i + self.chunk_size] for i in range(0, len(payload), self.chunk_size)]
|
|
29
|
+
|
|
30
|
+
|
keybind/compressor.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import zstandard as zstd
|
|
18
|
+
|
|
19
|
+
from .exceptions import CompressionError, raise_from
|
|
20
|
+
from .interfaces import Compressor
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ZstdCompressor(Compressor):
|
|
24
|
+
|
|
25
|
+
def __init__(self, level: int = 3) -> None:
|
|
26
|
+
self._compressor = zstd.ZstdCompressor(level=level)
|
|
27
|
+
self._decompressor = zstd.ZstdDecompressor()
|
|
28
|
+
|
|
29
|
+
def compress(self, payload: bytes) -> bytes:
|
|
30
|
+
try:
|
|
31
|
+
return self._compressor.compress(payload)
|
|
32
|
+
except Exception as exc:
|
|
33
|
+
raise_from(exc, CompressionError, "Compression failed")
|
|
34
|
+
|
|
35
|
+
def decompress(self, payload: bytes) -> bytes:
|
|
36
|
+
try:
|
|
37
|
+
return self._decompressor.decompress(payload)
|
|
38
|
+
except Exception as exc:
|
|
39
|
+
raise_from(exc, CompressionError, "Decompression failed")
|
|
40
|
+
|
|
41
|
+
|
keybind/config.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(slots=True)
|
|
21
|
+
class KeybindConfig:
|
|
22
|
+
|
|
23
|
+
version: str = "SC1"
|
|
24
|
+
chunk_size: int = 8 * 1024 * 1024
|
|
25
|
+
compression_threshold: int = 256
|
|
26
|
+
compression_level: int = 3
|
|
27
|
+
stream_block_size: int = 64 * 1024
|
|
28
|
+
enable_compression: bool = True
|
|
29
|
+
enable_signature: bool = False
|
|
30
|
+
purpose: str = "keybind"
|
|
31
|
+
hash_algorithm: str = "blake3"
|
|
32
|
+
nonce_size: int = 24
|
|
33
|
+
tag_size: int = 16
|
|
34
|
+
max_token_size: int = 8 * 1024 * 1024 * 1024
|
|
35
|
+
max_chain_depth: int = 128
|
|
36
|
+
default_expiration_seconds: int | None = None
|
|
37
|
+
default_issued_at: bool = True
|
|
38
|
+
|
|
39
|
+
def clone(self) -> "KeybindConfig":
|
|
40
|
+
return KeybindConfig(**self.__dict__)
|
|
41
|
+
|
|
42
|
+
|
keybind/constants.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Final
|
|
18
|
+
|
|
19
|
+
MAGIC: Final[bytes] = b"KB1"
|
|
20
|
+
DEFAULT_PURPOSE: Final[str] = "keybind"
|
|
21
|
+
DEFAULT_VERSION: Final[str] = "KB1"
|
|
22
|
+
HEADER_VERSION: Final[int] = 1
|
|
23
|
+
|
|
24
|
+
|
keybind/crypto.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from .exceptions import CryptoError, raise_from
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from cryptography.hazmat.primitives.ciphers.aead import XChaCha20Poly1305 as _CryptoXChaCha20Poly1305
|
|
21
|
+
except ImportError:
|
|
22
|
+
_CryptoXChaCha20Poly1305 = None
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from nacl.bindings import (
|
|
26
|
+
crypto_aead_xchacha20poly1305_ietf_decrypt as _lib_decrypt,
|
|
27
|
+
crypto_aead_xchacha20poly1305_ietf_encrypt as _lib_encrypt,
|
|
28
|
+
)
|
|
29
|
+
except ImportError:
|
|
30
|
+
_lib_encrypt = None
|
|
31
|
+
_lib_decrypt = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Encryptor:
|
|
35
|
+
def __init__(self, key: bytes) -> None:
|
|
36
|
+
if len(key) != 32:
|
|
37
|
+
raise CryptoError("Key must be 32 bytes")
|
|
38
|
+
self._key = key
|
|
39
|
+
self._cipher = _CryptoXChaCha20Poly1305(key) if _CryptoXChaCha20Poly1305 is not None else None
|
|
40
|
+
|
|
41
|
+
def encrypt(self, plaintext: bytes, nonce: bytes) -> bytes:
|
|
42
|
+
if len(nonce) != 24:
|
|
43
|
+
raise CryptoError("Nonce must be 24 bytes")
|
|
44
|
+
if self._cipher is not None:
|
|
45
|
+
try:
|
|
46
|
+
return self._cipher.encrypt(nonce, plaintext, None)
|
|
47
|
+
except Exception as exc:
|
|
48
|
+
raise_from(exc, CryptoError, "Encryption failed")
|
|
49
|
+
if _lib_encrypt is None:
|
|
50
|
+
raise CryptoError("No XChaCha20-Poly1305 backend is available")
|
|
51
|
+
try:
|
|
52
|
+
return _lib_encrypt(plaintext, b"", nonce, self._key)
|
|
53
|
+
except Exception as exc:
|
|
54
|
+
raise_from(exc, CryptoError, "Encryption failed")
|
|
55
|
+
|
|
56
|
+
def decrypt(self, ciphertext: bytes, nonce: bytes) -> bytes:
|
|
57
|
+
if len(nonce) != 24:
|
|
58
|
+
raise CryptoError("Nonce must be 24 bytes")
|
|
59
|
+
if self._cipher is not None:
|
|
60
|
+
try:
|
|
61
|
+
return self._cipher.decrypt(nonce, ciphertext, None)
|
|
62
|
+
except Exception as exc:
|
|
63
|
+
raise_from(exc, CryptoError, "Decryption failed")
|
|
64
|
+
if _lib_decrypt is None:
|
|
65
|
+
raise CryptoError("No XChaCha20-Poly1305 backend is available")
|
|
66
|
+
try:
|
|
67
|
+
return _lib_decrypt(ciphertext, b"", nonce, self._key)
|
|
68
|
+
except Exception as exc:
|
|
69
|
+
raise_from(exc, CryptoError, "Decryption failed")
|
|
70
|
+
|
|
71
|
+
|
keybind/enums.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from enum import Enum
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CompressionMethod(str, Enum):
|
|
21
|
+
NONE = "none"
|
|
22
|
+
ZSTANDARD = "zstd"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class HashAlgorithm(str, Enum):
|
|
26
|
+
BLAKE3 = "blake3"
|
|
27
|
+
SHA3_256 = "sha3_256"
|
|
28
|
+
|
|
29
|
+
|
keybind/exceptions.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class KeybindError(Exception):
|
|
19
|
+
"""Base class for all Keybind errors."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, message: str = "Keybind operation failed") -> None:
|
|
22
|
+
super().__init__(message)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class InvalidToken(KeybindError):
|
|
26
|
+
"""Raised when a token has invalid structure or encoding."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ExpiredToken(KeybindError):
|
|
30
|
+
"""Raised when the token validity window has elapsed."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TamperedToken(KeybindError):
|
|
34
|
+
"""Raised when authentication or integrity checks fail."""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class IdentityMismatch(KeybindError):
|
|
38
|
+
"""Raised when the identities used to decode do not match the token."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class InvalidSignature(KeybindError):
|
|
42
|
+
"""Raised when a signature cannot be verified."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class CompressionError(KeybindError):
|
|
46
|
+
"""Raised when compression or decompression fails."""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class SerializationError(KeybindError):
|
|
50
|
+
"""Raised when serialization or deserialization fails."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ChunkError(KeybindError):
|
|
54
|
+
"""Raised when chunk parsing or reconstruction fails."""
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class MerkleError(KeybindError):
|
|
58
|
+
"""Raised when Merkle verification fails."""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class CryptoError(KeybindError):
|
|
62
|
+
"""Raised when cryptographic operations fail."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class StorageError(KeybindError):
|
|
66
|
+
"""Raised when persistence operations fail."""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def raise_from(exc: Exception, error_cls: type[KeybindError], message: str | None = None) -> None:
|
|
70
|
+
if isinstance(exc, KeybindError) and isinstance(exc, error_cls):
|
|
71
|
+
raise exc
|
|
72
|
+
raise error_cls(message or "Keybind operation failed") from exc
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def ensure(condition: bool, error_cls: type[KeybindError], message: str) -> None:
|
|
76
|
+
if not condition:
|
|
77
|
+
raise error_cls(message)
|
|
78
|
+
|
|
79
|
+
|
keybind/hasher.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import hashlib
|
|
18
|
+
|
|
19
|
+
import blake3
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class HashManager:
|
|
23
|
+
@staticmethod
|
|
24
|
+
def blake3_digest(data: bytes) -> str:
|
|
25
|
+
return blake3.blake3(data).hexdigest()
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
def sha3_256_digest(data: bytes) -> str:
|
|
29
|
+
return hashlib.sha3_256(data).hexdigest()
|
|
30
|
+
|
|
31
|
+
|
keybind/hkdf.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from cryptography.hazmat.primitives import hashes
|
|
18
|
+
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class KeyDeriver:
|
|
22
|
+
@staticmethod
|
|
23
|
+
def derive_key(
|
|
24
|
+
master_key: bytes,
|
|
25
|
+
primary_identity: str,
|
|
26
|
+
secondary_identity: str,
|
|
27
|
+
version: str,
|
|
28
|
+
purpose: str = "keybind",
|
|
29
|
+
) -> bytes:
|
|
30
|
+
info = f"{version}:{purpose}:{primary_identity}:{secondary_identity}".encode("utf-8")
|
|
31
|
+
hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=b"keybind", info=info)
|
|
32
|
+
return hkdf.derive(master_key)
|
|
33
|
+
|
|
34
|
+
|
keybind/identities.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class IdentityManager:
|
|
19
|
+
@staticmethod
|
|
20
|
+
def normalize(value: str) -> str:
|
|
21
|
+
return value.strip().lower()
|
|
22
|
+
|
|
23
|
+
|
keybind/interfaces.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright 2026 Pravanjan Roy
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from abc import ABC, abstractmethod
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Compressor(ABC):
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def compress(self, payload: bytes) -> bytes:
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def decompress(self, payload: bytes) -> bytes:
|
|
27
|
+
raise NotImplementedError
|