apppy-generic 0.12.0__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.
@@ -0,0 +1,28 @@
1
+ __generated__/
2
+ dist/
3
+ *.egg-info
4
+ .env
5
+ .env.*
6
+ *.env
7
+ !.github/ci/.env.local
8
+ .file_store/
9
+ *.pid
10
+ .python-version
11
+ *.secrets
12
+ .secrets
13
+ *.tar.gz
14
+ *.test_output/
15
+ .test_output/
16
+ uv.lock
17
+ *.whl
18
+
19
+ # System files
20
+ __pycache__
21
+ .DS_Store
22
+
23
+ # Editor files
24
+ *.sublime-project
25
+ *.sublime-workspace
26
+ .vscode/*
27
+ !.vscode/settings.json
28
+
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: apppy-generic
3
+ Version: 0.12.0
4
+ Summary: Generic Python definitions for server development
5
+ Project-URL: Homepage, https://github.com/spals/apppy
6
+ Author: Tim Kral
7
+ License: MIT
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Requires-Python: >=3.11
11
+ Requires-Dist: cryptography==43.0.3
File without changes
@@ -0,0 +1,26 @@
1
+ ifndef APPPY_GENERIC_MK_INCLUDED
2
+ APPPY_GENERIC_MK_INCLUDED := 1
3
+ GENERIC_PKG_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
4
+
5
+ .PHONY: generic generic-dev generic/build generic/clean generic/install generic/install-dev
6
+
7
+ generic: generic/clean generic/install
8
+
9
+ generic-dev: generic/clean generic/install-dev
10
+
11
+ generic/build:
12
+ cd $(GENERIC_PKG_DIR) && uvx --from build pyproject-build
13
+
14
+ generic/clean:
15
+ cd $(GENERIC_PKG_DIR) && rm -rf dist/ *.egg-info .venv
16
+
17
+ generic/install: generic/build
18
+ cd $(GENERIC_PKG_DIR) && uv pip install dist/*.whl
19
+
20
+ generic/install-dev:
21
+ cd $(GENERIC_PKG_DIR) && uv pip install -e .
22
+
23
+ generic/publish: generic/clean generic/install
24
+ twine upload $(GENERIC_PKG_DIR)/dist/* || exit 1
25
+
26
+ endif # APPPY_GENERIC_MK_INCLUDED
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [dependency-groups]
6
+ dev = []
7
+
8
+ [project]
9
+ name = "apppy-generic"
10
+ description = "Generic Python definitions for server development"
11
+ dynamic = ["version"]
12
+ readme = "README.md"
13
+ requires-python = ">=3.11"
14
+ license = {text = "MIT"}
15
+ authors = [{ name = "Tim Kral" }]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: OSI Approved :: MIT License",
19
+ ]
20
+ dependencies = [
21
+ "cryptography==43.0.3",
22
+ ]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/spals/apppy"
26
+
27
+ [tool.hatch.build.targets.wheel]
28
+ packages = ["src/apppy"]
29
+
30
+ [tool.hatch.version]
31
+ path = "../../VERSION"
32
+ pattern = "^(?P<version>\\d+\\.\\d+\\.\\d+)$"
33
+ source = "regex"
File without changes
@@ -0,0 +1,77 @@
1
+ from os import urandom
2
+
3
+ from cryptography.hazmat.backends import default_backend
4
+ from cryptography.hazmat.primitives import hashes, padding
5
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
6
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
7
+
8
+ BLOCK_SIZE = 16 # AES block size in bytes
9
+
10
+
11
+ class DecryptionFailedError(Exception):
12
+ """Raised when there is an error while trying ot decrypt bytes"""
13
+
14
+ def __init__(self):
15
+ super().__init__("unable_to_decrypt")
16
+
17
+
18
+ class BytesEncrypter:
19
+ """
20
+ Service to encrypt data bytes.integers into strings based on a static
21
+ alphabet. This allows the system to ofuscate the integer
22
+ values to outside parties (e.g. database primary keys)
23
+ """
24
+
25
+ def __init__(self, passphrase: str, salt: str | bytes) -> None:
26
+ self._passphrase = passphrase
27
+ if isinstance(salt, str):
28
+ self._salt = salt.encode("utf-8")
29
+ else:
30
+ self._salt = salt
31
+
32
+ self._encryption_key = self.__derive_encryption_key()
33
+
34
+ def __derive_encryption_key(self) -> bytes:
35
+ passphrase_encoded = self._passphrase.encode()
36
+ kdf = PBKDF2HMAC(
37
+ algorithm=hashes.SHA256(),
38
+ length=32, # AES-256 requires 32 bytes
39
+ salt=self._salt,
40
+ iterations=100000,
41
+ backend=default_backend(),
42
+ )
43
+ return kdf.derive(passphrase_encoded)
44
+
45
+ def encrypt_bytes(self, data: bytes) -> bytes:
46
+ """
47
+ Encrypt the entire data stream with AES-CBC and PKCS7 padding.
48
+ A new IV is generated for each encryption operation.
49
+ """
50
+ iv = urandom(BLOCK_SIZE)
51
+ cipher = Cipher(
52
+ algorithms.AES(self._encryption_key), modes.CBC(iv), backend=default_backend()
53
+ )
54
+ encryptor = cipher.encryptor()
55
+ padder = padding.PKCS7(BLOCK_SIZE * 8).padder()
56
+ padded_data = padder.update(data) + padder.finalize()
57
+ encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
58
+ return iv + encrypted_data
59
+
60
+ def decrypt_bytes(self, data: bytes) -> bytes:
61
+ """
62
+ Decrypt the data stream with AES-CBC and PKCS7 unpadding.
63
+ The IV is extracted from the first block of the encrypted data.
64
+ """
65
+ iv = data[:BLOCK_SIZE]
66
+ encrypted_data = data[BLOCK_SIZE:]
67
+
68
+ cipher = Cipher(
69
+ algorithms.AES(self._encryption_key), modes.CBC(iv), backend=default_backend()
70
+ )
71
+ decryptor = cipher.decryptor()
72
+ decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
73
+ unpadder = padding.PKCS7(BLOCK_SIZE * 8).unpadder()
74
+ try:
75
+ return unpadder.update(decrypted_data) + unpadder.finalize()
76
+ except ValueError as e:
77
+ raise DecryptionFailedError() from e