62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
from .base import * # noqa: F403,F401
|
|
import os
|
|
from urllib.parse import urlparse
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
|
|
DEBUG = False
|
|
|
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
USE_X_FORWARDED_HOST = True
|
|
SECURE_SSL_REDIRECT = os.getenv("DJANGO_SECURE_SSL_REDIRECT", "1") == "1"
|
|
SESSION_COOKIE_SECURE = True
|
|
CSRF_COOKIE_SECURE = True
|
|
SECURE_CONTENT_TYPE_NOSNIFF = True
|
|
SECURE_REFERRER_POLICY = "same-origin"
|
|
X_FRAME_OPTIONS = "DENY"
|
|
SECURE_HSTS_SECONDS = int(os.getenv("DJANGO_SECURE_HSTS_SECONDS", "31536000"))
|
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
|
SECURE_HSTS_PRELOAD = True
|
|
CSRF_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = os.getenv("DJANGO_SESSION_COOKIE_SAMESITE", "Lax")
|
|
CSRF_COOKIE_SAMESITE = os.getenv("DJANGO_CSRF_COOKIE_SAMESITE", "Lax")
|
|
|
|
def _is_local_host(hostname: str | None) -> bool:
|
|
return (hostname or "").lower() in {"localhost", "127.0.0.1", "::1", "0.0.0.0"}
|
|
|
|
|
|
def _is_safe_csrf_origin(origin: str) -> bool:
|
|
parsed = urlparse(origin)
|
|
if parsed.scheme != "https":
|
|
return False
|
|
return not _is_local_host(parsed.hostname)
|
|
|
|
|
|
if not CSRF_TRUSTED_ORIGINS: # noqa: F405
|
|
raise ImproperlyConfigured("DJANGO_CSRF_TRUSTED_ORIGINS must be explicitly set for production.")
|
|
|
|
invalid_origins = [origin for origin in CSRF_TRUSTED_ORIGINS if not _is_safe_csrf_origin(origin)] # noqa: F405
|
|
if invalid_origins:
|
|
joined = ", ".join(invalid_origins)
|
|
raise ImproperlyConfigured(
|
|
"DJANGO_CSRF_TRUSTED_ORIGINS contains unsafe values for production. "
|
|
f"Use explicit HTTPS origins only. Invalid: {joined}"
|
|
)
|
|
|
|
unsafe_hosts = [host for host in ALLOWED_HOSTS if host in {"localhost", "127.0.0.1", "::1", "0.0.0.0"}] # noqa: F405
|
|
if unsafe_hosts:
|
|
joined = ", ".join(unsafe_hosts)
|
|
raise ImproperlyConfigured(
|
|
"DJANGO_ALLOWED_HOSTS contains localhost-style values in production. "
|
|
f"Invalid: {joined}"
|
|
)
|
|
|
|
STORAGES = {
|
|
"default": {
|
|
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
|
},
|
|
"staticfiles": {
|
|
"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
|
|
},
|
|
}
|