Files
Deal/archive/leadradar-legacy/backend/app/crypto.py
T
Rustam Khalimov 713d554dc2 Нормализовать переводы строк в LF
Решение по TD-STYLE-ANALYZERS: LF — инструменты проекта (Python/Node) пишут LF,
CRLF-.sh не работают на Linux CI (sh scripts/ci.sh), большинство файлов уже были
LF. Добавлен .gitattributes (* text=auto eol=lf, бинарные исключения),
.editorconfig переведён на lf, 1029 файлов конвертированы, git add --renormalize.
Из индекса убраны закравшиеся archive/**/__pycache__/*.pyc.
2026-09-11 19:01:42 +03:00

71 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Шифрование секретов, хранимых в БД (Telegram api_hash, ключи AI).
Решение по итогам ревью: ключи шифруются симметричным ключом; ключ шифрования
пока живёт в env (LEADRADAR_ENCRYPTION_KEY). Для локальной разработки без env
ключ генерируется и кладётся в data/encryption.key (с предупреждением).
"""
from __future__ import annotations
import base64
import logging
import os
from cryptography.fernet import Fernet, InvalidToken
from . import config
log = logging.getLogger("leadradar.crypto")
_fernet: Fernet | None = None
def _get_fernet() -> Fernet:
global _fernet
if _fernet is not None:
return _fernet
key = config.ENCRYPTION_KEY
if key:
try:
_fernet = Fernet(key.encode() if not key.endswith("=") else key.encode())
return _fernet
except Exception: # noqa: BLE001
log.error("LEADRADAR_ENCRYPTION_KEY не похож на Fernet-ключ (32 байта urlsafe b64)")
raise
if config.ENCRYPTION_KEY_FILE.exists():
key = config.ENCRYPTION_KEY_FILE.read_text(encoding="utf-8").strip()
else:
config.ensure_dirs()
key = Fernet.generate_key().decode()
config.ENCRYPTION_KEY_FILE.write_text(key, encoding="utf-8")
log.warning("Ключ шифрования создан в %s (для продакшена задайте LEADRADAR_ENCRYPTION_KEY)", config.ENCRYPTION_KEY_FILE)
_fernet = Fernet(key.encode())
return _fernet
def encrypt_text(value: str) -> str:
if not value:
return ""
token = _get_fernet().encrypt(value.encode())
return "enc:" + token.decode()
def decrypt_text(value: str) -> str:
if not value:
return ""
if not value.startswith("enc:"):
return value # совместимость с незашифрованными значениями ранних версий
try:
return _get_fernet().decrypt(value[4:].encode()).decode()
except InvalidToken:
log.error("Не удалось расшифровать секрет (неверный ключ шифрования)")
return ""
def maybe_encrypt(value: str) -> str:
"""Шифруем только непустые значения."""
return encrypt_text(value) if value else ""
def random_key() -> str:
return Fernet.generate_key().decode()