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:
Claude 2026-06-15 14:29:53 +00:00
parent 8e630233f6
commit cb892564d9
11 changed files with 212 additions and 37 deletions

View 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()

View file

@ -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: