diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..2e5cd63 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-05-15 - [Securing HMAC Secrets and CORS] +**Vulnerability:** Hardcoded HMAC secret key and overly permissive CORS policy. +**Learning:** Hardcoding production-level secrets in multiple files (`main.py` and `DivineoBunker.py`) creates a high risk of exposure. Permissive CORS (`"*"`) is acceptable for rapid prototyping but should be configurable for deployment to prevent unauthorized cross-origin access. +**Prevention:** Use environment variables (via `os.getenv` and `python-dotenv`) for all sensitive credentials. Implement configurable CORS origins through environment variables, defaulting to specific origins in production. diff --git a/backend/DivineoBunker.py b/backend/DivineoBunker.py index ca01742..81cea01 100644 --- a/backend/DivineoBunker.py +++ b/backend/DivineoBunker.py @@ -2,11 +2,12 @@ import hashlib import time import json +import os class DivineoBunker: def __init__(self): # 🛡️ Configuración Maestra (abvetos.com) - self.secret_key = "LVT_SECRET_PROD_091228222" + self.secret_key = os.getenv("LVT_SECRET_KEY", "LVT_DEV_SECRET_DO_NOT_USE_IN_PROD") self.patent = "PCT/EP2025/067317" self.algorithm_v = "V10_Divineo_Shopify_Final" diff --git a/backend/__pycache__/jules_engine.cpython-312.pyc b/backend/__pycache__/jules_engine.cpython-312.pyc new file mode 100644 index 0000000..78615be Binary files /dev/null and b/backend/__pycache__/jules_engine.cpython-312.pyc differ diff --git a/backend/__pycache__/main.cpython-312.pyc b/backend/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000..e289fa8 Binary files /dev/null and b/backend/__pycache__/main.cpython-312.pyc differ diff --git a/backend/__pycache__/models.cpython-312.pyc b/backend/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000..a439c33 Binary files /dev/null and b/backend/__pycache__/models.cpython-312.pyc differ diff --git a/backend/main.py b/backend/main.py index cb988e1..14aa881 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2,24 +2,31 @@ import hashlib import time import json +import os +from dotenv import load_dotenv from fastapi import FastAPI, HTTPException from fastapi.responses import JSONResponse from fastapi.middleware.cors import CORSMiddleware from models import UserScan, SHOPIFY_INVENTORY from jules_engine import get_jules_advice +load_dotenv() + app = FastAPI(title="Divineo Bunker Backend") +# 🔒 Security: In production, configure LVT_ALLOWED_ORIGINS in .env +ALLOWED_ORIGINS = os.getenv("LVT_ALLOWED_ORIGINS", "*").split(",") + app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=ALLOWED_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 🛡️ Configuración Maestra (abvetos.com) -SECRET_KEY = "LVT_SECRET_PROD_091228222" +SECRET_KEY = os.getenv("LVT_SECRET_KEY", "LVT_DEV_SECRET_DO_NOT_USE_IN_PROD") PATENT = "PCT/EP2025/067317" def verify_auth(user_id: str, token: str) -> bool: @@ -68,7 +75,14 @@ async def recommend_garment(scan: UserScan, garment_id: str = "BALMAIN_SS26_SLIM # Usamos Jules para el toque de estilo styling_advice = get_jules_advice(scan, item) except Exception as e: - styling_advice = f"Divineo confirmado con {item['name']}." + return JSONResponse( + status_code=503, + content={ + "status": "error", + "code": 503, + "message": "Jules AI Engine is currently recalibrating or unavailable. Please try again." + } + ) if is_divineo and item['stock'] > 0: return { diff --git a/backend/tests/__pycache__/test_main.cpython-312-pytest-9.0.2.pyc b/backend/tests/__pycache__/test_main.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000..a8de80a Binary files /dev/null and b/backend/tests/__pycache__/test_main.cpython-312-pytest-9.0.2.pyc differ diff --git a/backend/tests/test_main.py b/backend/tests/test_main.py index 8d756a9..6f60c36 100644 --- a/backend/tests/test_main.py +++ b/backend/tests/test_main.py @@ -1,9 +1,17 @@ import pytest +import hmac +import hashlib +import time from fastapi.testclient import TestClient -from backend.main import app +from backend.main import app, SECRET_KEY client = TestClient(app) +def generate_test_token(user_id: str): + ts = str(int(time.time())) + sig = hmac.new(SECRET_KEY.encode(), f"{user_id}:{ts}".encode(), hashlib.sha256).hexdigest() + return f"{ts}.{sig}" + def test_recommend_garment_engine_failure(monkeypatch): """ Test that the /api/recommend endpoint correctly handles failures @@ -18,9 +26,11 @@ def mock_get_jules_advice(*args, **kwargs): monkeypatch.setattr("backend.main.get_jules_advice", mock_get_jules_advice) # 2. Prepare the request payload + user_id = "test_user_123" payload = { - "height": 175.0, - "weight": 68.0, + "user_id": user_id, + "token": generate_test_token(user_id), + "waist": 72.0, "event_type": "Gala" }