"""Application configuration. Env-driven, Dev/Prod classes.""" import os from dotenv import load_dotenv load_dotenv() def _bool(val, default=False): if val is None: return default return str(val).strip().lower() in ("1", "true", "yes", "on") class BaseConfig: SECRET_KEY = os.environ.get("SECRET_KEY", "dev-insecure-change-me") # --- Database --- @staticmethod def _database_uri(): url = os.environ.get("DATABASE_URL") if url: return url user = os.environ.get("DB_USER", "classifieds") pwd = os.environ.get("DB_PASSWORD", "") host = os.environ.get("DB_HOST", "127.0.0.1") port = os.environ.get("DB_PORT", "3306") name = os.environ.get("DB_NAME", "classifieds") return f"mysql+pymysql://{user}:{pwd}@{host}:{port}/{name}?charset=utf8mb4" SQLALCHEMY_DATABASE_URI = _database_uri.__func__() SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = {"pool_pre_ping": True, "pool_recycle": 280} # --- Redis --- REDIS_URL = os.environ.get("REDIS_URL", "redis://127.0.0.1:6379/0") RATELIMIT_STORAGE_URI = REDIS_URL # --- i18n --- DEFAULT_LOCALE = os.environ.get("DEFAULT_LOCALE", "en") SUPPORTED_LOCALES = [ s.strip() for s in os.environ.get("SUPPORTED_LOCALES", "en,vi,es").split(",") if s.strip() ] BABEL_DEFAULT_LOCALE = DEFAULT_LOCALE BABEL_TRANSLATION_DIRECTORIES = "translations" # --- Email --- MAIL_SERVER = os.environ.get("MAIL_SERVER", "") MAIL_PORT = int(os.environ.get("MAIL_PORT", "587")) MAIL_USE_TLS = _bool(os.environ.get("MAIL_USE_TLS"), True) MAIL_USERNAME = os.environ.get("MAIL_USERNAME", "") MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD", "") MAIL_FROM = os.environ.get("MAIL_FROM", "no-reply@example.com") MAIL_FROM_NAME = os.environ.get("MAIL_FROM_NAME", "Classifieds") # --- Turnstile --- TURNSTILE_SITE_KEY = os.environ.get("TURNSTILE_SITE_KEY", "") TURNSTILE_SECRET_KEY = os.environ.get("TURNSTILE_SECRET_KEY", "") # --- Token lifetimes --- TOKEN_VERIFY_MAX_AGE = int(os.environ.get("TOKEN_VERIFY_MAX_AGE", "86400")) TOKEN_RESET_MAX_AGE = int(os.environ.get("TOKEN_RESET_MAX_AGE", "3600")) # --- Media (uploaded images) --- MEDIA_ROOT = os.environ.get("MEDIA_ROOT") or None # default: instance/media # --- Stripe --- STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "") STRIPE_PUBLISHABLE_KEY = os.environ.get("STRIPE_PUBLISHABLE_KEY", "") STRIPE_WEBHOOK_SECRET = os.environ.get("STRIPE_WEBHOOK_SECRET", "") # --- Session cookie hardening --- SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = "Lax" PREFERRED_URL_SCHEME = "https" class DevConfig(BaseConfig): DEBUG = True SESSION_COOKIE_SECURE = False class ProdConfig(BaseConfig): DEBUG = False SESSION_COOKIE_SECURE = True SERVER_NAME = os.environ.get("SERVER_NAME") or None def get_config(): name = os.environ.get("FLASK_CONFIG", "dev").lower() return ProdConfig if name == "prod" else DevConfig