from __future__ import annotations import os import secrets from pathlib import Path BASE_DIR = Path(__file__).resolve().parents[1] DATA_DIR = Path(os.getenv("CODEXPI_DATA_DIR", BASE_DIR / "data")) DATA_DIR.mkdir(parents=True, exist_ok=True) def env_bool(name: str, default: bool) -> bool: value = os.getenv(name) return default if value is None else value.lower() in {"1", "true", "yes", "on"} def secret_key() -> str: configured_file = os.getenv("CODEXPI_DJANGO_SECRET_KEY_FILE") if configured_file: value = Path(configured_file).read_text(encoding="utf-8").strip() if len(value) < 32: raise RuntimeError("CODEXPI_DJANGO_SECRET_KEY_FILE doit contenir un secret d’au moins 32 caractères") return value configured = os.getenv("CODEXPI_DJANGO_SECRET_KEY") if configured: if len(configured) < 32: raise RuntimeError("CODEXPI_DJANGO_SECRET_KEY doit contenir au moins 32 caractères") return configured path = DATA_DIR / "django_secret_key" if not path.exists(): try: descriptor = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(descriptor, "w", encoding="utf-8") as target: target.write(secrets.token_urlsafe(64)) except FileExistsError: pass return path.read_text(encoding="utf-8").strip() SECRET_KEY = secret_key() DEBUG = False ALLOWED_HOSTS = [item.strip() for item in os.getenv("CODEXPI_DJANGO_ALLOWED_HOSTS", "localhost,127.0.0.1,.ts.net,nginx").split(",") if item.strip()] CSRF_TRUSTED_ORIGINS = [item.strip() for item in os.getenv("CODEXPI_TRUSTED_ORIGINS", "https://*.ts.net").split(",") if item.strip()] INSTALLED_APPS = [ "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django_ui.identity", ] MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] ROOT_URLCONF = "django_ui.urls" ASGI_APPLICATION = "django_ui.asgi.application" WSGI_APPLICATION = "django_ui.wsgi.application" DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": DATA_DIR / "django.sqlite3", "OPTIONS": {"timeout": 30}}} DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" USE_TZ = True TIME_ZONE = "Europe/Paris" AUTH_PASSWORD_VALIDATORS = [ {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", "OPTIONS": {"min_length": 12}}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] PASSWORD_HASHERS = [ "django.contrib.auth.hashers.Argon2PasswordHasher", "django.contrib.auth.hashers.PBKDF2PasswordHasher", ] SESSION_ENGINE = "django.contrib.sessions.backends.db" SESSION_COOKIE_NAME = os.getenv("CODEXPI_COOKIE_NAME", "codexpi_session") SESSION_COOKIE_AGE = int(os.getenv("CODEXPI_SESSION_HOURS", "12")) * 3600 SESSION_COOKIE_SECURE = env_bool("CODEXPI_COOKIE_SECURE", True) SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = "Strict" SESSION_SAVE_EVERY_REQUEST = False CSRF_COOKIE_SECURE = SESSION_COOKIE_SECURE CSRF_COOKIE_HTTPONLY = True CSRF_COOKIE_SAMESITE = "Strict" CSRF_HEADER_NAME = "HTTP_X_CSRF_TOKEN" SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") USE_X_FORWARDED_HOST = True SECURE_CONTENT_TYPE_NOSNIFF = True SECURE_REFERRER_POLICY = "no-referrer" SECURE_HSTS_SECONDS = 31_536_000 X_FRAME_OPTIONS = "DENY" CACHES = {"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache", "LOCATION": "codexpi-login-limiter"}}