Files
lux_fiscal/backend/app/core/crypto.py
lauadminandClaude Opus 5.5 b8f2fe6b6e Translate UI and user-facing messages to Ukrainian (#5)
- All frontend pages, labels, notices and errors; html lang=uk, uk-UA money format
- Brand "Assistant System" in the top bar and page title
- Backend error details returned to the UI (auth, orders, receipts,
  cash registers, Checkbox/CRM/NP errors) and CLI output
- Tests updated for the new messages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:27:39 +03:00

60 lines
2.2 KiB
Python

"""Симметричное шифрование секретов, хранимых в БД.
Ключи лицензий Checkbox и токены CRM попадают в таблицы. В открытом виде
они там лежать не должны: дамп базы не обязан давать возможность пробивать
чеки от лица клиента.
Используется Fernet (AES-128-CBC + HMAC-SHA256) из `cryptography`.
"""
from __future__ import annotations
from functools import lru_cache
from cryptography.fernet import Fernet, InvalidToken
from app.core.config import settings
class DecryptionError(Exception):
"""Значение не расшифровывается — как правило, сменился ENCRYPTION_KEY."""
@lru_cache
def _fernet() -> Fernet:
try:
return Fernet(settings.encryption_key.encode())
except (ValueError, TypeError) as exc:
raise RuntimeError(
"ENCRYPTION_KEY некоректний. Згенеруйте валідний ключ: "
"python -c \"from cryptography.fernet import Fernet; "
'print(Fernet.generate_key().decode())"'
) from exc
def encrypt(value: str) -> str:
return _fernet().encrypt(value.encode()).decode()
def decrypt(value: str) -> str:
try:
return _fernet().decrypt(value.encode()).decode()
except InvalidToken as exc:
raise DecryptionError(
"Не вдалося розшифрувати значення. Імовірна причина — ENCRYPTION_KEY "
"змінився з моменту збереження. Секрет потрібно ввести заново."
) from exc
def mask(value: str, visible: int = 4) -> str:
"""Маска для показа секрета в интерфейсе: `****ab12`.
Наружу секреты отдаются только в таком виде — расшифрованное значение
не покидает бэкенд.
"""
if not value:
return ""
if len(value) <= visible:
return "*" * len(value)
return "*" * (len(value) - visible) + value[-visible:]