testing / config /settings.py
Danielsz's picture
Add localhost:5174 to CORS and CSRF origins
becbdb5
Raw
History Blame Contribute Delete
6.79 kB
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 5.2.15.
For more information on this file, see
https://docs.djangoproject.com/en/5.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.2/ref/settings/
"""
import os
from pathlib import Path
from dotenv import load_dotenv
import dj_database_url
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
load_dotenv(BASE_DIR / '.env')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-e(r31o54hfnysa&0=99)la3kyvac3j)4e_hr-vj(*oj(d)3kn1')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'corsheaders',
'rest_framework_simplejwt',
'auth_api',
'interview',
]
AUTH_USER_MODEL = 'auth_api.User'
MIDDLEWARE = [
'config.middleware.ForceCredentialsMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'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',
]
# Security Headers (Production)
if not DEBUG:
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
else:
X_FRAME_OPTIONS = 'SAMEORIGIN'
# CSRF configuration for decoupled frontends
CSRF_COOKIE_SAMESITE = 'None' if not DEBUG else 'Lax'
CSRF_COOKIE_HTTPONLY = False # Must be false so frontend JS (Axios) can read it
CSRF_TRUSTED_ORIGINS = [o.strip() for o in os.getenv(
'CORS_ALLOWED_ORIGINS',
'http://localhost:5173,http://localhost:5174,http://localhost:5175,http://127.0.0.1:5173,http://127.0.0.1:5174,http://127.0.0.1:5175,https://franciscoquezada.vercel.app'
).split(',') if o.strip()]
# CORS: restrict to known origins. Set CORS_ALLOWED_ORIGINS in .env for production.
# Default allows local dev ports for Dashboard and Frontend.
CORS_ALLOW_CREDENTIALS = True # Required for cross-origin cookie-based auth
_raw_cors = os.getenv(
'CORS_ALLOWED_ORIGINS',
'http://localhost:5173,http://localhost:5174,http://localhost:5175,http://127.0.0.1:5173,http://127.0.0.1:5174,http://127.0.0.1:5175,https://franciscoquezada.vercel.app'
)
CORS_ALLOWED_ORIGINS = [o.strip() for o in _raw_cors.split(',') if o.strip()]
CORS_ALLOWED_ORIGINS.extend([
"https://franciscoquezada.vercel.app",
"http://localhost:5175",
"http://localhost:5174",
"http://localhost:5173"
])
CSRF_TRUSTED_ORIGINS.extend([
"https://franciscoquezada.vercel.app",
"http://localhost:5175",
"http://localhost:5174",
"http://localhost:5173"
])
CORS_ALLOWED_ORIGIN_REGEXES = [
r"^https://.*$",
r"^http://localhost:.*$",
r"^http://127\.0\.0\.1:.*$",
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
'default': dj_database_url.config(
default=os.getenv('DATABASE_URL', f'sqlite:///{BASE_DIR / "db.sqlite3"}')
)
}
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'auth_api.authentication.CookieJWTAuthentication',
),
# All endpoints require authentication by default.
# Public endpoints must explicitly override with @permission_classes([AllowAny]).
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day',
'login': '10/minute'
},
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': False,
'AUTH_COOKIE': 'access_token',
'AUTH_COOKIE_REFRESH': 'refresh_token',
'AUTH_COOKIE_SECURE': not DEBUG, # True in production (HTTPS)
'AUTH_COOKIE_HTTP_ONLY': True,
'AUTH_COOKIE_SAMESITE': 'None' if not DEBUG else 'Lax',
}
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
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',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = 'es'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Media files
MEDIA_URL = '/api/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Interview video paths
INTERVIEW_VIDEOS_DIR = os.path.join(BASE_DIR, 'static', 'videos')
INTERVIEW_LOOP_VIDEO = os.path.join(BASE_DIR, 'static', 'loop_pingpong.mp4')
INTERVIEW_BIENVENIDA_VIDEO = os.path.join(BASE_DIR, 'static', 'final_bienvenida.mp4')
INTERVIEW_DESPEDIDA_VIDEO = os.path.join(BASE_DIR, 'static', 'final_despedida.mp4')