Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/app/services/ai/encryption.py

80 lines
2.4 KiB
Python
Executable file

from __future__ import annotations
from typing import Optional
import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from app.core.settings import get_settings
_AI_ENCRYPTION_SALT = b"hesabix_ai_encryption_salt"
def _is_valid_fernet_key(key: str | bytes) -> bool:
try:
raw = key.encode() if isinstance(key, str) else key
Fernet(raw)
return True
except (ValueError, TypeError):
return False
def _derive_fernet_key(secret: str, *, salt: bytes = _AI_ENCRYPTION_SALT) -> bytes:
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
)
return base64.urlsafe_b64encode(kdf.derive(secret.encode()))
def _get_encryption_key() -> bytes:
"""دریافت کلید رمزگذاری از تنظیمات"""
settings = get_settings()
raw_key = (settings.encryption_key or "").strip()
if raw_key:
if _is_valid_fernet_key(raw_key):
return raw_key.encode()
# ENCRYPTION_KEY ممکن است hex یا secret خام باشد، نه کلید Fernet
return _derive_fernet_key(raw_key)
return _derive_fernet_key(settings.captcha_secret)
def _legacy_decryption_keys() -> list[bytes]:
"""کلیدهای قدیمی برای رمزگشایی داده‌هایی که قبل از اصلاح ذخیره شده‌اند."""
settings = get_settings()
keys: list[bytes] = []
if (settings.encryption_key or "").strip():
keys.append(_derive_fernet_key(settings.captcha_secret))
return keys
def encrypt_api_key(api_key: str) -> str:
"""رمزگذاری API Key"""
if not api_key:
return ""
fernet = Fernet(_get_encryption_key())
encrypted = fernet.encrypt(api_key.encode())
return encrypted.decode()
def decrypt_api_key(encrypted_key: str) -> Optional[str]:
"""رمزگشایی API Key"""
if not encrypted_key:
return None
candidate_keys = [_get_encryption_key(), *_legacy_decryption_keys()]
seen: set[bytes] = set()
for key in candidate_keys:
if key in seen:
continue
seen.add(key)
try:
decrypted = Fernet(key).decrypt(encrypted_key.encode())
return decrypted.decode()
except Exception:
continue
return None