Files
finance/backend/app/imports/crypto.py
T
k1nq d582f15681 feat: add tests for import polling, login page, money utilities, and query keys
- Implemented tests for import polling functionality, ensuring correct behavior for active and terminal import statuses.
- Created tests for the login page, validating user interactions and error handling.
- Added unit tests for money utility functions, covering parsing, formatting, and summation of monetary values.
- Developed tests for query keys, ensuring proper scoping and invalidation roots.

chore: setup testing environment and configuration

- Added setup file for testing with Vitest and Testing Library.
- Configured TypeScript and Vite for the frontend project.
- Created Docker and Nginx configurations for local development and production environments.
- Established a PostgreSQL initialization script for setting up application roles.

docs: add README and environment configuration for infra

- Included README for the infra directory, detailing local development setup and service descriptions.
- Created an example environment configuration file for local development with placeholders for sensitive information.
2026-09-14 09:26:33 +05:00

59 lines
1.6 KiB
Python

import os
from dataclasses import dataclass
from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from app.config import get_settings
from app.errors import AppError
_DEK_AAD = b"finance-import-dek-v1"
@dataclass(frozen=True)
class EncryptedFile:
ciphertext: bytes
content_nonce: bytes
dek_wrapped: bytes
wrap_nonce: bytes
def encrypt_file(plaintext: bytes) -> EncryptedFile:
"""Per-file random DEK; DEK wrapped with the KEK from the secret manager."""
kek = get_settings().kek
dek = os.urandom(32)
content_nonce = os.urandom(12)
ciphertext = AESGCM(dek).encrypt(content_nonce, plaintext, None)
wrap_nonce = os.urandom(12)
dek_wrapped = AESGCM(kek).encrypt(wrap_nonce, dek, _DEK_AAD)
return EncryptedFile(
ciphertext=ciphertext,
content_nonce=content_nonce,
dek_wrapped=dek_wrapped,
wrap_nonce=wrap_nonce,
)
def decrypt_file(
*,
ciphertext: bytes,
content_nonce: bytes,
dek_wrapped: bytes,
wrap_nonce: bytes,
) -> bytes:
kek = get_settings().kek
try:
dek = AESGCM(kek).decrypt(wrap_nonce, dek_wrapped, _DEK_AAD)
return AESGCM(dek).decrypt(content_nonce, ciphertext, None)
except InvalidTag as exc:
raise AppError(
"Encrypted document failed integrity verification",
code="IMPORT_DECRYPT_FAILED",
status_code=409,
) from exc
def shred_dek_material() -> None:
"""Crypto-shred hook: deleting wrapped DEK rows in DB plus blobs removes access."""
return None