Deliver Step 1: Backend cleanup — secrets scrubbed, is_admin column, Telegram optional, crypto service, v4-v7 migrations, .env.example, setup.sh
This commit is contained in:
parent
8e630233f6
commit
cb892564d9
11 changed files with 212 additions and 37 deletions
42
backend/app/services/crypto.py
Normal file
42
backend/app/services/crypto.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""Fernet encryption for integration credentials.
|
||||
|
||||
Derives a Fernet-compatible key from the app SECRET_KEY using HKDF.
|
||||
The SECRET_KEY can be any format (hex string, random bytes, passphrase).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||
import base64
|
||||
|
||||
_fernet_instance: Fernet | None = None
|
||||
|
||||
|
||||
def _derive_fernet_key(secret_key: str) -> bytes:
|
||||
"""Derive a Fernet-compatible key from the app SECRET_KEY."""
|
||||
hkdf = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=b"diligence-integration-encryption",
|
||||
info=b"fernet-key",
|
||||
)
|
||||
raw = hkdf.derive(secret_key.encode())
|
||||
return base64.urlsafe_b64encode(raw)
|
||||
|
||||
|
||||
def get_fernet(secret_key: str) -> Fernet:
|
||||
global _fernet_instance
|
||||
if _fernet_instance is None:
|
||||
_fernet_instance = Fernet(_derive_fernet_key(secret_key))
|
||||
return _fernet_instance
|
||||
|
||||
|
||||
def encrypt_value(secret_key: str, plaintext: str) -> str:
|
||||
"""Encrypt a plaintext string. Returns base64-encoded ciphertext."""
|
||||
return get_fernet(secret_key).encrypt(plaintext.encode()).decode()
|
||||
|
||||
|
||||
def decrypt_value(secret_key: str, ciphertext: str) -> str:
|
||||
"""Decrypt a ciphertext string. Returns plaintext."""
|
||||
return get_fernet(secret_key).decrypt(ciphertext.encode()).decode()
|
||||
|
|
@ -5,7 +5,7 @@ import httpx
|
|||
from app.schemas.food import FoodSearchResult
|
||||
|
||||
OFF_BASE = "https://world.openfoodfacts.org"
|
||||
USER_AGENT = "FitnessRewards/1.0 (fitness.littlefake.com)"
|
||||
USER_AGENT = "Diligence/1.0"
|
||||
|
||||
|
||||
async def lookup_barcode(barcode: str) -> FoodSearchResult | None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue