"""
Django settings for vuln_demo project.

Generated by 'django-admin startproject' using Django 5.0.3.

For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""

from pathlib import Path
from socket import gethostbyname, gethostname

from vuln_demo.util.config import config_cast_list, get_config
from vuln_demo.util.log import setup_logging

# Disable constant redefinition pyright errors. This treats all SCREAMING_SNAKE_CASE variables as
# constants, marking them as Final. This is not ideal for Django settings, as while we don't
# explicitly mutate them during runtime, we also don't meet the single assignment rule. Some of
# the settings are conditionally set based on environment variables, in mutually exclusive blocks
# (if-else). This is however considered as a multiple assignments, and breaks this check.
# pyright: reportConstantRedefinition=false

DEBUG = get_config("DEBUG", cast=bool, default=False)

# This means production mode is enabled (DEBUG=0), but the site is running in a testing mode
# (e.g. for development or demonstration purposes). This allows us to test production mode
# without actually deploying the site.
PRODUCTION_TESTING = get_config("PRODUCTION_TESTING", cast=bool, default=False)

if DEBUG is True and PRODUCTION_TESTING is True:
    raise ValueError("DEBUG and PRODUCTION_TESTING cannot be both set to True")

if DEBUG:
    SECRET_KEY = "django-insecure-0&^l_r9+-8#g4!r5crd63$6kw2alm8!tc-yzx^0ginp-(5g%51"  # noqa: S105
    ALLOWED_HOSTS = get_config(
        "ALLOWED_HOSTS",
        cast=config_cast_list(str),
        default=["*"],
    )
    # Allow cross-site requests from ngrok
    # This is useful when showing this application to others while debugging
    # (This doesn't support a full wildcard like ["*"], at least the TLD needs
    # to be present.)
    CSRF_TRUSTED_ORIGINS = get_config(
        "CSRF_TRUSTED_ORIGINS",
        cast=config_cast_list(str),
        default=[
            "https://*.ngrok-free.app",
            "https://*.fai.utb.cz",
            "http://*.fai.utb.cz",
        ],
    )
else:
    SECRET_KEY = get_config("SECRET_KEY")

    _default_trusted_origins = ["https://hts-demo.fai.utb.cz"]
    if PRODUCTION_TESTING:
        _default_trusted_origins.append("https://*.ngrok-free.app")
        _default_trusted_origins.append("http://hts-demo.fai.utb.cz:8000")

    CSRF_TRUSTED_ORIGINS = get_config(
        "CSRF_TRUSTED_ORIGINS",
        cast=config_cast_list(str),
        default=_default_trusted_origins,
    )

    _default_allowed_hosts = [
        "localhost",
        gethostname(),  # computer's network hostname
        gethostbyname(gethostname()),  # LAN IP
        "hts-demo.fai.utb.cz",
    ]
    if PRODUCTION_TESTING:
        _default_allowed_hosts.append("hts-demo.fai.utb.cz:8000")
        _default_allowed_hosts.append(".ngrok-free.app")

    ALLOWED_HOSTS = get_config(
        "ALLOWED_HOSTS",
        cast=config_cast_list(str),
        default=_default_allowed_hosts,
    )

    if not PRODUCTION_TESTING:
        # Enable HSTS only in production mode. This will make the browser only allow connecting
        # to the site over HTTPS. Browsers will cache this value for the specified duration.
        # We enable this on all subdomains from the accessed domain.
        SECURE_HSTS_SECONDS = 31536000  # 1 year
        SECURE_HSTS_PRELOAD = True
        SECURE_HSTS_INCLUDE_SUBDOMAINS = True

        # Automatically redirect all HTTP requests to HTTPS
        SECURE_SSL_REDIRECT = True

        # Use secure cookies in production mode. This will break HTTP connections, but we don't
        # care allow those in production mode anyways
        CSRF_COOKIE_SECURE = not DEBUG
        SESSION_COOKIE_SECURE = not DEBUG

# The Django server will actually be behind a reverse proxy, so to check whether or not SSL is used,
# we need to check the X-Forwarded-Proto header. This is set by the reverse proxy.
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Application definition
INSTALLED_APPS = [
    "daphne",
    "channels",
    "crispy_forms",
    "crispy_bootstrap5",

    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",

    "vuln_demo.apps.general",
    "vuln_demo.apps.vulnerabilities",
]  # fmt: skip # disable autoformat to allow spaces between the list elements

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "csp.middleware.CSPMiddleware",
    "vuln_demo.middleware.corp.CrossOriginResourcePolicyMiddleware",
    "vuln_demo.middleware.coep.CrossOriginEmbedderPolicyMiddleware",
    "django_permissions_policy.PermissionsPolicyMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

ROOT_URLCONF = "vuln_demo.urls"

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR.joinpath("vuln_demo", "templates")],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

ASGI_APPLICATION = "vuln_demo.asgi.application"


# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": get_config("POSTGRES_DB"),
        "USER": get_config("POSTGRES_USER"),
        "PASSWORD": get_config("POSTGRES_PASSWORD"),
        "HOST": get_config("POSTGRES_HOST"),
        "PORT": get_config("POSTGRES_PORT"),
    },
}

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": get_config("REDIS_LOCATION"),
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        },
    }
}


# Password validation
# https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators

if DEBUG:
    AUTH_PASSWORD_VALIDATORS = []
else:
    AUTH_PASSWORD_VALIDATORS = [
        {
            "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
        },
        {
            "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
        },
        {
            "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
        },
        {
            "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
        },
    ]

# Logging
# https://docs.djangoproject.com/en/5.0/topics/logging/
# We disable Django logging in favor of a custom logging configuration
LOGGING_CONFIG = None
setup_logging()

# Internationalization
# https://docs.djangoproject.com/en/5.0/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = get_config("TIME_ZONE", default="CET")
USE_I18N = True
USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR.joinpath("vuln_demo", "static")]
STATIC_ROOT = get_config("STATIC_ROOT", default=str(BASE_DIR.joinpath("staticfiles")))


# Static files are served under STATIC_URL when in DEBUG automatically (using django.contrib.staticfiles)
# When not in production, you're expected to serve these files under /static endpoint yourself. To allow
# testing the site in production mode, you can still set INSECURE_AUTO_SERVE_STATIC, which will enable
# serving static files even without DEBUG=True (implemented in urls.py).
if DEBUG:
    INSECURE_AUTO_SERVE_STATIC = False
else:
    INSECURE_AUTO_SERVE_STATIC = get_config("INSECURE_AUTO_SERVE_STATIC", cast=bool, default=False)

# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

# Settings for django.contrib.auth
LOGIN_REDIRECT_URL = "home"
LOGOUT_REDIRECT_URL = "home"

# Email/SMTP configuration
# https://docs.djangoproject.com/en/5.0/ref/settings/#email-backend
_LOCAL_EMAILS = get_config("LOCAL_EMAILS", cast=bool, default=DEBUG)
if _LOCAL_EMAILS:
    # Sends emails to console
    EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
else:
    EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
    EMAIL_HOST = get_config("EMAIL_HOST")
    EMAIL_PORT = get_config("EMAIL_PORT", cast=int, default=25)
    EMAIL_HOST_USER = get_config("EMAIL_HOST_USER", default="")
    EMAIL_HOST_PASSWORD = get_config("EMAIL_HOST_PASSWORD", default="")
    EMAIL_USE_TLS = get_config("EMAIL_USE_TLS", cast=bool, default=False)  # explicit TLS on port 587
    EMAIL_USE_SSL = get_config("EMAIL_USE_SSL", cast=bool, default=False)  # implicit TLS on port 465
    EMAIL_SSL_CERTFILE = get_config(
        "EMAIL_SSL_CERTFILE", default=""
    )  # optionally set PEM formatted cert if use tls/ssl is on
    EMAIL_SSL_KEYFILE = get_config(
        "EMAIL_SSL_KEYFILE", default=""
    )  # optionally set PEM formatted private key if use tls/ssl is on
    EMAIL_TIMEOUT = get_config("EMAIL_TIMEOUT", cast=float, default=3)
    EMAIL_SUBJECT_PREFIX = get_config("EMAIL_SUBJECT_PREFIX", default="[Vulnerability DEMO Portal] ")


# django-crispy-forms
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

# django-csp

CSP_DEFAULT_SRC = ["'self'"]
CSP_SCRIPT_SRC = ["'self'", "cdn.jsdelivr.net", "unpkg.com", "ajax.googleapis.com", "kit.fontawesome.com"]
CSP_IMG_SRC = ["'self'", "data:", "www.apache.org"]
CSP_FONT_SRC = ["'self'", "cdn.jsdelivr.net", "kit.fontawesome.com", "ka-f.fontawesome.com"]
CSP_STYLE_SRC = ["'self'", "'unsafe-inline'", "cdn.jsdelivr.net", "kit.fontawesome.com"]
CSP_CONNECT_SRC = ["'self'", "ka-f.fontawesome.com"]

# django-permissions-policy

PERMISSIONS_POLICY = {
    "accelerometer": [],
    "ambient-light-sensor": [],
    "autoplay": [],
    "camera": [],
    "display-capture": [],
    "document-domain": [],
    "encrypted-media": [],
    "fullscreen": [],
    "geolocation": [],
    "gyroscope": [],
    "interest-cohort": [],
    "magnetometer": [],
    "microphone": [],
    "midi": [],
    "payment": [],
    "usb": [],
}
