crowdata / app /config.py
YOSOYYONOSOYOTRO's picture
Upload folder using huggingface_hub
83bdb4a verified
Raw
History Blame Contribute Delete
3.82 kB
import os
from pathlib import Path
from pydantic_settings import BaseSettings
from functools import lru_cache
from pydantic import field_validator
_backend_dir = str(Path(__file__).resolve().parent.parent)
class Settings(BaseSettings):
# App
app_name: str = "CrowData API"
environment: str = "development"
debug: bool = False # Default: False por seguridad. Usar ENVIRONMENT=development para debug.
# Database
database_url: str = ""
# Redis
redis_url: str = "redis://localhost:6379/0"
# Security — MUST be set in .env
secret_key: str = ""
reset_password_token_secret: str = "" # Separate secret for password reset tokens
verification_token_secret: str = "" # Separate secret for email verification tokens
# MFA Encryption Key (for encrypting TOTP secrets and backup codes in DB)
mfa_encryption_key: str = "" # Fernet key (32 bytes base64)
# JWT RS256 (asymmetric) — new keys for production
jwt_private_key: str = "" # RS256 private key (PEM)
jwt_public_key: str = "" # RS256 public key (PEM)
jwt_algorithm: str = "RS256" # New tokens signed with RS256
jwt_key_id: str = "key-1" # Key ID for rotation
# Legacy HS256 (symmetric) — for backward compatibility during transition
jwt_legacy_secret_key: str = "" # HS256 secret (same as secret_key)
jwt_legacy_algorithm: str = "HS256"
jwt_legacy_enabled: bool = False # Disabled by default in production
access_token_expire_minutes: int = 15 # 15 minutes (short-lived access token)
refresh_token_expire_days: int = 7 # 7 days (refresh token in HttpOnly cookie)
# Auth transport
use_cookie_auth: bool = True # Enable HttpOnly cookie auth
cookie_secure: bool = True # Secure cookie (HTTPS only)
cookie_samesite: str = "lax" # Lax for cross-site top-level nav, Strict for more security
# Cache
cache_ttl_seconds: int = 86400 # 24 hours
# Database pool
db_pool_size: int = 10
db_max_overflow: int = 20
# Scrapers
playwright_headless: bool = True
scraper_timeout_seconds: int = 30
proxy_url: str | None = None
proxy_list: list[str] = []
captcha_api_key: str | None = None # 2Captcha API key
nopecha_api_key: str | None = None # NopeCHA API key (reCAPTCHA v3 solver)
groq_api_key: str | None = None
searchapi_key: str | None = None
searchapi_keys: list[str] = []
ai_verification_enabled: bool = True
# Payments — default: empty string (must be set in .env for production)
mp_access_token: str = ""
mp_public_key: str = ""
# AFIP
afip_cuit_representada: str = ""
afip_cert_path: str = ""
afip_key_path: str = ""
afip_cache_file: str = ""
# Email / SMTP
smtp_host: str = "localhost"
smtp_port: int = 587
smtp_user: str = ""
smtp_password: str = ""
smtp_use_tls: bool = True
from_email: str = "crowsistemas@proton.me"
from_name: str = "CrowData"
# Allowed Origins (for CORS)
allowed_origins: str = ""
# ─── Validation ───
@field_validator("secret_key", "reset_password_token_secret", "verification_token_secret",
"mfa_encryption_key", "jwt_private_key", "jwt_public_key",
mode="before")
@classmethod
def _require_secrets_in_prod(cls, v, info):
# Solo validar en producción
if info.data.get("environment") == "production" and not v:
raise ValueError(f"{info.field_name} must be set in production")
return v
class Config:
env_file = os.path.join(_backend_dir, ".env")
env_file_encoding = "utf-8"
extra = "allow"
@lru_cache()
def get_settings() -> Settings:
return Settings()