EatlyticApp / app /core /security.py
Shaikhsarib's picture
refactor: Reorganize codebase to elite enterprise AI standards and clean legacy duplicate stubs
6c04bc0
Raw
History Blame Contribute Delete
2.23 kB
"""
app/core/security.py
Cryptographic signatures, cookie signing, rate limiting, and authorization verification.
"""
import os
import hmac
import hashlib
import uuid
import secrets
import logging
from fastapi import Request, Response
logger = logging.getLogger(__name__)
# --- SECURITY CONFIG ---
COOKIE_SECRET = os.environ.get("COOKIE_SECRET")
if not COOKIE_SECRET:
COOKIE_SECRET = secrets.token_urlsafe(32)
def sign_value(value: str) -> str:
"""Create a signature for a value."""
return hmac.new(COOKIE_SECRET.encode(), value.encode(), hashlib.sha256).hexdigest()
def get_device_key(request: Request, response: Response = None) -> str:
"""
Get or set a secure, signed device ID in a cookie.
"""
header_val = request.headers.get("X-Device-Key")
if header_val:
return header_val
cookie_val: str = request.cookies.get("eatlytic_did")
if cookie_val and ":" in cookie_val:
try:
did, sig = cookie_val.split(":", 1)
if hmac.compare_digest(sign_value(did), sig):
return did
except ValueError:
pass
# No valid cookie — generate a new one
new_did: str = str(uuid.uuid4())
if response:
sig: str = sign_value(new_did)
is_secure = os.environ.get("ENVIRONMENT", "dev").lower() not in ("dev", "development", "local")
response.set_cookie(
"eatlytic_did",
f"{new_did}:{sig}",
httponly=True,
secure=is_secure,
samesite="lax", # 'strict' breaks cross-origin redirects; lax is safer default
max_age=365*86400 # 1 year
)
return new_did
def sanitize_text(text: str, max_len: int = 5000) -> str:
if not text:
return ""
# Remove null bytes and limit length
clean: str = text.replace("\x00", "").strip()
return clean[:max_len]
def verify_admin(request: Request) -> bool:
ADMIN_TOKEN: str = os.environ.get("ADMIN_TOKEN", "")
token: str = request.headers.get("X-Admin-Token")
if not ADMIN_TOKEN or token != ADMIN_TOKEN:
from fastapi import HTTPException
raise HTTPException(status_code=403, detail="Forbidden: Admin access required.")
return True