mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-13 04:59:59 +02:00
Update Django settings
Provide a sensible set of starting settings for a good degree of security and document them well enough that future operations people don't have to dig for hours to understand what is being done.
This commit is contained in:
parent
8f41050f76
commit
4ace5b4128
3 changed files with 433 additions and 94 deletions
|
@ -14,3 +14,4 @@ psycopg2-binary = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
django-debug-toolbar = "*"
|
django-debug-toolbar = "*"
|
||||||
|
nplusone = "*"
|
44
src/Pipfile.lock
generated
44
src/Pipfile.lock
generated
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "3c3bdeb59b98dcd8c01350c36619ab12b593f8c25846dc3425f481b587fc0ae8"
|
"sha256": "9a25a3e7f6574f0253c8f94b397b651448658dc9ac3ffb7faa9ac1f5e89d8dba"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {},
|
"requires": {},
|
||||||
|
@ -103,11 +103,11 @@
|
||||||
},
|
},
|
||||||
"marshmallow": {
|
"marshmallow": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb",
|
"sha256:1172ce82765bf26c24a3f9299ed6dbeeca4d213f638eaa39a37772656d7ce408",
|
||||||
"sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"
|
"sha256:48e2d88d4ab431ad5a17c25556d9da529ea6e966876f2a38d274082e270287f0"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.17.0"
|
"version": "==3.17.1"
|
||||||
},
|
},
|
||||||
"orderedmultidict": {
|
"orderedmultidict": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -204,11 +204,11 @@
|
||||||
},
|
},
|
||||||
"setuptools": {
|
"setuptools": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:7a2e7e95c3bf33f356b4c59aee7a6848585c4219dd3e941e43cc117888f210e4",
|
"sha256:2e24e0bec025f035a2e72cdd1961119f557d78ad331bb00ff82efb2ab8da8e82",
|
||||||
"sha256:c04a012ae3a1b2cc2aeed4893377b70ea61c6c143d0acceea16ec4b60de6e40d"
|
"sha256:7732871f4f7fa58fb6bdcaeadb0161b2bd046c85905dbaa066bdcbcc81953b57"
|
||||||
],
|
],
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==65.0.1"
|
"version": "==65.3.0"
|
||||||
},
|
},
|
||||||
"six": {
|
"six": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
@ -236,6 +236,14 @@
|
||||||
"markers": "python_version >= '3.7'",
|
"markers": "python_version >= '3.7'",
|
||||||
"version": "==3.5.2"
|
"version": "==3.5.2"
|
||||||
},
|
},
|
||||||
|
"blinker": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1eb563df6fdbc39eeddc177d953203f99f097e9bf0e2b8f9f3cf18b6ca425e36",
|
||||||
|
"sha256:923e5e2f69c155f2cc42dafbbd70e16e3fde24d2d4aa2ab72fbe386238892462"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
|
"version": "==1.5"
|
||||||
|
},
|
||||||
"django": {
|
"django": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
|
"sha256:031ccb717782f6af83a0063a1957686e87cb4581ea61b47b3e9addf60687989a",
|
||||||
|
@ -246,11 +254,27 @@
|
||||||
},
|
},
|
||||||
"django-debug-toolbar": {
|
"django-debug-toolbar": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:89a52128309eb4da12738801ff0c202d2ff8730d1c3225fac6acf630c303e661",
|
"sha256:95fc2fd29c56cc86678aae9f6919ececefe892f2a78c4004b193a223a8380c3d",
|
||||||
"sha256:97965f2630692de316ea0c1ca5bfa81660d7ba13146dbc6be2059cf55b35d0e5"
|
"sha256:fe7fe3f21865218827e2162ecc06eba386dfe8cffe4f3501c49bb4359e06a0e6"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==3.5.0"
|
"version": "==3.6.0"
|
||||||
|
},
|
||||||
|
"nplusone": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1726c0a10c0aa7eabb04e24db2882ff97b6b7ee29d729a8d97dcbd12ef5a5651",
|
||||||
|
"sha256:96b1e6e29e6af3e71b67d0cc012a5ec8c97c6a2f5399f4ba41a2bbe0e253a9ac"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.0.0"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||||
|
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==1.16.0"
|
||||||
},
|
},
|
||||||
"sqlparse": {
|
"sqlparse": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
"""
|
"""
|
||||||
Django settings for .gov registrar project.
|
Django settings for .gov registrar project.
|
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 4.0.6.
|
|
||||||
|
|
||||||
For more information on this file, see
|
For more information on this file, see
|
||||||
https://docs.djangoproject.com/en/4.0/topics/settings/
|
https://docs.djangoproject.com/en/4.0/topics/settings/
|
||||||
|
|
||||||
|
@ -19,70 +17,144 @@ $ docker-compose exec app python manage.py shell
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import environs
|
import environs
|
||||||
import os
|
|
||||||
from cfenv import AppEnv
|
from cfenv import AppEnv
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
### ###
|
||||||
|
# Setup code goes here #
|
||||||
|
### ###
|
||||||
|
|
||||||
env = environs.Env()
|
env = environs.Env()
|
||||||
|
|
||||||
# Get secrets from Cloud.gov user provided service, if exists
|
# Get secrets from Cloud.gov user provided service, if exists
|
||||||
# If not, get secrets from environment variables
|
# If not, get secrets from environment variables
|
||||||
key_service = AppEnv().get_service(name="getgov-credentials")
|
key_service = AppEnv().get_service(name='getgov-credentials')
|
||||||
if key_service and key_service.credentials:
|
if key_service and key_service.credentials:
|
||||||
secret = key_service.credentials.get
|
secret = key_service.credentials.get
|
||||||
else:
|
else:
|
||||||
secret = env
|
secret = env
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
### ###
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
# Values obtained externally #
|
||||||
|
### ###
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
path = Path(__file__)
|
||||||
SECRET_KEY = secret("DJANGO_SECRET_KEY")
|
|
||||||
|
env_db_url = env.dj_db_url("DATABASE_URL")
|
||||||
|
env_debug = env.bool("DJANGO_DEBUG", default=False)
|
||||||
|
env_log_level = env.str("DJANGO_LOG_LEVEL", "DEBUG")
|
||||||
|
|
||||||
|
secret_key = secret("DJANGO_SECRET_KEY")
|
||||||
|
|
||||||
|
# region: Basic Django Config-----------------------------------------------###
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / "subdir".
|
||||||
|
BASE_DIR = path.resolve().parent.parent
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = env.bool("DJANGO_DEBUG", default=False)
|
DEBUG = env_debug
|
||||||
|
|
||||||
# TODO: configure and document security settings
|
|
||||||
ALLOWED_HOSTS = ["getgov-unstable.app.cloud.gov", "get.gov"]
|
|
||||||
ALLOWED_CIDR_NETS = ["10.0.0.0/8"] # nosec
|
|
||||||
USE_X_FORWARDED_HOST = True
|
|
||||||
SESSION_COOKIE_SECURE = True
|
|
||||||
SESSION_COOKIE_HTTPONLY = True
|
|
||||||
CSRF_COOKIE_SECURE = True
|
|
||||||
CSRF_COOKIE_HTTPONLY = True
|
|
||||||
CORS_ALLOW_ALL_ORIGINS = False
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: are all of these needed? Need others?
|
# Applications are modular pieces of code.
|
||||||
|
# They are provided by Django, by third-parties, or by yourself.
|
||||||
|
# Installing them here makes them available for execution.
|
||||||
|
# Do not access INSTALLED_APPS directly. Use `django.apps.apps` instead.
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
# Django automatic admin interface reads metadata
|
||||||
|
# from database models to provide a quick, model-centric
|
||||||
|
# interface where trusted users can manage content
|
||||||
"django.contrib.admin",
|
"django.contrib.admin",
|
||||||
|
|
||||||
|
# vv Required by django.contrib.admin vv
|
||||||
|
# the "user" model! *\o/*
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
|
# generic interface for Django models
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
|
# required for CSRF protection and many other things
|
||||||
"django.contrib.sessions",
|
"django.contrib.sessions",
|
||||||
|
# framework for displaying messages to the user
|
||||||
"django.contrib.messages",
|
"django.contrib.messages",
|
||||||
|
# ^^ Required by django.contrib.admin ^^
|
||||||
|
|
||||||
|
# collects static files from each of your applications
|
||||||
|
# (and any other places you specify) into a single location
|
||||||
|
# that can easily be served in production
|
||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: document these for future maintainers
|
# Middleware are routines for processing web requests.
|
||||||
|
# Adding them here turns them "on"; Django will perform the
|
||||||
|
# specified routines on each incoming request and outgoing response.
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
# django-allow-cidr: enable use of CIDR IP ranges in ALLOWED_HOSTS
|
||||||
"allow_cidr.middleware.AllowCIDRMiddleware",
|
"allow_cidr.middleware.AllowCIDRMiddleware",
|
||||||
|
|
||||||
|
# provide security enhancements to the request/response cycle
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
|
|
||||||
|
# store and retrieve arbitrary data on a per-site-visitor basis
|
||||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||||
|
|
||||||
|
# add a few conveniences for perfectionists, see documentation
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
|
||||||
|
# add protection against Cross Site Request Forgeries by adding
|
||||||
|
# hidden form fields to POST forms and checking requests for the correct value
|
||||||
"django.middleware.csrf.CsrfViewMiddleware",
|
"django.middleware.csrf.CsrfViewMiddleware",
|
||||||
|
|
||||||
|
# add `user` (the currently-logged-in user) to incoming HttpRequest objects
|
||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
|
|
||||||
|
# provide framework for displaying messages to the user, see documentation
|
||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
|
|
||||||
|
# provide clickjacking protection via the X-Frame-Options header
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
|
|
||||||
|
# django-csp: enable use of Content-Security-Policy header
|
||||||
"csp.middleware.CSPMiddleware",
|
"csp.middleware.CSPMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# application object used by Django’s built-in servers (e.g. `runserver`)
|
||||||
|
WSGI_APPLICATION = "registrar.config.wsgi.application"
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Assets and HTML and Caching---------------------------------------###
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
||||||
|
|
||||||
|
|
||||||
|
# Caching is disabled by default.
|
||||||
|
# For a low to medium traffic site, caching causes more
|
||||||
|
# problems than it solves. Should caching be desired,
|
||||||
|
# a reasonable start might be:
|
||||||
|
# CACHES = {
|
||||||
|
# "default": {
|
||||||
|
# "BACKEND": "django.core.cache.backends.db.DatabaseCache",
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Absolute path to the directory where `collectstatic`
|
||||||
|
# will place static files for deployment.
|
||||||
|
# Do not use this directory for permanent storage -
|
||||||
|
# it is for Django!
|
||||||
|
STATIC_ROOT = BASE_DIR / "static"
|
||||||
|
|
||||||
# TODO: decide on template engine and document in ADR
|
# TODO: decide on template engine and document in ADR
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||||
"DIRS": [BASE_DIR / "templates"],
|
"DIRS": [BASE_DIR / "templates"],
|
||||||
|
# look for templates inside installed apps
|
||||||
|
# required by django-debug-toolbar
|
||||||
"APP_DIRS": True,
|
"APP_DIRS": True,
|
||||||
"OPTIONS": {
|
"OPTIONS": {
|
||||||
|
# IMPORTANT security setting: escapes HTMLEntities,
|
||||||
|
# helping to prevent XSS attacks
|
||||||
|
"autoescape": True,
|
||||||
|
# context processors are callables which return
|
||||||
|
# dicts - Django merges them into the context
|
||||||
|
# dictionary used to render the templates
|
||||||
"context_processors": [
|
"context_processors": [
|
||||||
"django.template.context_processors.debug",
|
"django.template.context_processors.debug",
|
||||||
"django.template.context_processors.request",
|
"django.template.context_processors.request",
|
||||||
|
@ -93,15 +165,116 @@ TEMPLATES = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Database----------------------------------------------------------###
|
||||||
|
|
||||||
|
# Wrap each view in a transaction on the database
|
||||||
|
# A decorator can be used for views which have no database activity:
|
||||||
|
# from django.db import transaction
|
||||||
|
# @transaction.non_atomic_requests
|
||||||
|
env_db_url["ATOMIC_REQUESTS"] = True
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
# dj-database-url package takes the supplied Postgres connection string
|
||||||
|
# and converts it into a dictionary with the correct USER, HOST, etc
|
||||||
|
"default": env_db_url,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Specify default field type to use for primary keys
|
||||||
|
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Email-------------------------------------------------------------###
|
||||||
|
|
||||||
|
# email address to use for various automated correspondence
|
||||||
|
# TODO: pick something sensible here
|
||||||
|
DEFAULT_FROM_EMAIL = "registrar@get.gov"
|
||||||
|
|
||||||
|
# connect to an (external) SMTP server for sending email
|
||||||
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
|
|
||||||
|
# TODO: configure these when the values are known
|
||||||
|
# EMAIL_HOST = ""
|
||||||
|
# EMAIL_HOST_PASSWORD = ""
|
||||||
|
# EMAIL_HOST_USER = ""
|
||||||
|
# EMAIL_PORT = 587
|
||||||
|
|
||||||
|
# for mail sent with mail_admins or mail_managers
|
||||||
|
EMAIL_SUBJECT_PREFIX = "[Attn: .gov admin] "
|
||||||
|
|
||||||
|
# use a TLS (secure) connection when talking to the SMTP server
|
||||||
|
# TLS generally uses port 587
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
|
||||||
|
# mutually exclusive with EMAIL_USE_TLS = True
|
||||||
|
# SSL generally uses port 465
|
||||||
|
EMAIL_USE_SSL = False
|
||||||
|
|
||||||
|
# timeout in seconds for blocking operations, like the connection attempt
|
||||||
|
EMAIL_TIMEOUT = 30
|
||||||
|
|
||||||
|
# email address to use for sending error reports
|
||||||
|
SERVER_EMAIL = "root@get.gov"
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Headers-----------------------------------------------------------###
|
||||||
|
|
||||||
|
# Content-Length header is set by django.middleware.common.CommonMiddleware
|
||||||
|
|
||||||
|
# X-Frame-Options header is set by django.middleware.clickjacking.XFrameOptionsMiddleware
|
||||||
|
# and configured in the Security and Privacy section of this file.
|
||||||
|
# Strict-Transport-Security is set by django.middleware.security.SecurityMiddleware
|
||||||
|
# and configured in the Security and Privacy section of this file.
|
||||||
|
|
||||||
|
# prefer contents of X-Forwarded-Host header to Host header
|
||||||
|
# as Host header may contain a proxy rather than the actual client
|
||||||
|
USE_X_FORWARDED_HOST = True
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Internationalisation----------------------------------------------###
|
||||||
|
|
||||||
|
# https://docs.djangoproject.com/en/4.0/topics/i18n/
|
||||||
|
|
||||||
|
# Charset to use for HttpResponse objects; used in Content-Type header
|
||||||
|
DEFAULT_CHARSET = "utf-8"
|
||||||
|
|
||||||
|
# provide fallback language if translation file is missing or
|
||||||
|
# user's locale is not supported - requires USE_I18N = True
|
||||||
|
LANGUAGE_CODE = "en-us"
|
||||||
|
|
||||||
|
# allows language cookie to be sent if the user
|
||||||
|
# is coming to our site from an external page.
|
||||||
|
LANGUAGE_COOKIE_SAMESITE = None
|
||||||
|
|
||||||
|
# only send via HTTPS connection
|
||||||
|
LANGUAGE_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# to display datetimes in templates
|
||||||
|
# and to interpret datetimes entered in forms
|
||||||
|
TIME_ZONE = "UTC"
|
||||||
|
|
||||||
|
# enable Django’s translation system
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
# enable localized formatting of numbers and dates
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
# make datetimes timezone-aware by default
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Logging-----------------------------------------------------------###
|
||||||
|
|
||||||
# No file logger is configured, because containerized apps
|
# No file logger is configured, because containerized apps
|
||||||
# do not log to the file system.
|
# do not log to the file system.
|
||||||
|
# TODO: Configure better logging options
|
||||||
LOGGING = {
|
LOGGING = {
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"disable_existing_loggers": False,
|
"disable_existing_loggers": False,
|
||||||
"formatters": {
|
"formatters": {
|
||||||
"verbose": {
|
"verbose": {
|
||||||
"format": "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] "
|
"format": "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] "
|
||||||
"%(message)s", # noqa
|
"%(message)s",
|
||||||
"datefmt": "%d/%b/%Y %H:%M:%S",
|
"datefmt": "%d/%b/%Y %H:%M:%S",
|
||||||
},
|
},
|
||||||
"simple": {
|
"simple": {
|
||||||
|
@ -110,7 +283,7 @@ LOGGING = {
|
||||||
},
|
},
|
||||||
"handlers": {
|
"handlers": {
|
||||||
"console": {
|
"console": {
|
||||||
"level": "DEBUG" if DEBUG else "INFO",
|
"level": "INFO",
|
||||||
"class": "logging.StreamHandler",
|
"class": "logging.StreamHandler",
|
||||||
"formatter": "verbose",
|
"formatter": "verbose",
|
||||||
},
|
},
|
||||||
|
@ -119,7 +292,7 @@ LOGGING = {
|
||||||
"django": {
|
"django": {
|
||||||
"handlers": ["console"],
|
"handlers": ["console"],
|
||||||
"propagate": True,
|
"propagate": True,
|
||||||
"level": os.getenv("DJANGO_LOG_LEVEL", "DEBUG"),
|
"level": env_log_level,
|
||||||
},
|
},
|
||||||
"django.template": {
|
"django.template": {
|
||||||
"handlers": ["console"],
|
"handlers": ["console"],
|
||||||
|
@ -134,67 +307,208 @@ LOGGING = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# Database
|
#endregion
|
||||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
|
# region: Login-------------------------------------------------------------###
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
"default": env.dj_db_url("DATABASE_URL"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/4.0/topics/i18n/
|
|
||||||
|
|
||||||
LANGUAGE_CODE = "en-us"
|
|
||||||
TIME_ZONE = "UTC"
|
|
||||||
USE_I18N = True
|
|
||||||
USE_TZ = True
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/4.0/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_ROOT = BASE_DIR / "static"
|
|
||||||
|
|
||||||
STATIC_URL = "static/"
|
|
||||||
ADMIN_URL = "admin/"
|
|
||||||
|
|
||||||
ROOT_URLCONF = "registrar.config.urls"
|
|
||||||
WSGI_APPLICATION = "registrar.config.wsgi.application"
|
|
||||||
|
|
||||||
# TODO: FAC example for REST framework
|
|
||||||
API_VERSION = "0"
|
|
||||||
REST_FRAMEWORK = {
|
|
||||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
|
||||||
"rest_framework.authentication.BasicAuthentication",
|
|
||||||
"users.auth.ExpiringTokenAuthentication",
|
|
||||||
],
|
|
||||||
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
|
||||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
|
||||||
"PAGE_SIZE": 10,
|
|
||||||
"TEST_REQUEST_RENDERER_CLASSES": [
|
|
||||||
"rest_framework.renderers.MultiPartRenderer",
|
|
||||||
"rest_framework.renderers.JSONRenderer",
|
|
||||||
"rest_framework.renderers.TemplateHTMLRenderer",
|
|
||||||
"rest_framework.renderers.BrowsableAPIRenderer",
|
|
||||||
],
|
|
||||||
"TEST_REQUEST_DEFAULT_FORMAT": "api",
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO: FAC example for login.gov
|
# TODO: FAC example for login.gov
|
||||||
SIMPLE_JWT = {
|
# SIMPLE_JWT = {
|
||||||
"ALGORITHM": "RS256",
|
# "ALGORITHM": "RS256",
|
||||||
"AUDIENCE": None,
|
# "AUDIENCE": None,
|
||||||
"ISSUER": "https://idp.int.identitysandbox.gov/",
|
# "ISSUER": "https://idp.int.identitysandbox.gov/",
|
||||||
"JWK_URL": "https://idp.int.identitysandbox.gov/api/openid_connect/certs",
|
# "JWK_URL": "https://idp.int.identitysandbox.gov/api/openid_connect/certs",
|
||||||
"LEEWAY": 0,
|
# "LEEWAY": 0,
|
||||||
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.UntypedToken",),
|
# "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.UntypedToken",),
|
||||||
"USER_ID_CLAIM": "sub",
|
# "USER_ID_CLAIM": "sub",
|
||||||
}
|
# }
|
||||||
TOKEN_AUTH = {"TOKEN_TTL": 3600}
|
# TOKEN_AUTH = {"TOKEN_TTL": 3600}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Rest Framework/API------------------------------------------------###
|
||||||
|
|
||||||
|
# Enable CORS if api is served at subdomain
|
||||||
|
# https://github.com/adamchainz/django-cors-headers
|
||||||
|
# TODO: FAC example for REST framework
|
||||||
|
# API_VERSION = "0"
|
||||||
|
# REST_FRAMEWORK = {
|
||||||
|
# "DEFAULT_AUTHENTICATION_CLASSES": [
|
||||||
|
# "rest_framework.authentication.BasicAuthentication",
|
||||||
|
# "users.auth.ExpiringTokenAuthentication",
|
||||||
|
# ],
|
||||||
|
# "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
|
||||||
|
# "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
||||||
|
# "PAGE_SIZE": 10,
|
||||||
|
# "TEST_REQUEST_RENDERER_CLASSES": [
|
||||||
|
# "rest_framework.renderers.MultiPartRenderer",
|
||||||
|
# "rest_framework.renderers.JSONRenderer",
|
||||||
|
# "rest_framework.renderers.TemplateHTMLRenderer",
|
||||||
|
# "rest_framework.renderers.BrowsableAPIRenderer",
|
||||||
|
# ],
|
||||||
|
# "TEST_REQUEST_DEFAULT_FORMAT": "api",
|
||||||
|
# }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Routing-----------------------------------------------------------###
|
||||||
|
|
||||||
|
## Set by django.middleware.common.CommonMiddleware
|
||||||
|
# APPEND_SLASH = True
|
||||||
|
# PREPEND_WWW = False
|
||||||
|
|
||||||
|
# full Python import path to the root URLconf
|
||||||
|
ROOT_URLCONF = "registrar.config.urls"
|
||||||
|
|
||||||
|
# URL to use when referring to static files located in STATIC_ROOT
|
||||||
|
# Must be relative and end with "/"
|
||||||
|
STATIC_URL = "public/"
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Security and Privacy----------------------------------------------###
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = secret_key
|
||||||
|
|
||||||
|
# Use this variable for doing SECRET_KEY rotation, see documentation
|
||||||
|
SECRET_KEY_FALLBACKS = []
|
||||||
|
|
||||||
|
## Set by django.middleware.security.SecurityMiddleware
|
||||||
|
# SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||||
|
# SECURE_CROSS_ORIGIN_OPENER_POLICY = "same-origin"
|
||||||
|
# SECURE_REDIRECT_EXEMPT = []
|
||||||
|
# SECURE_REFERRER_POLICY = "same-origin"
|
||||||
|
# SECURE_SSL_HOST = None
|
||||||
|
|
||||||
|
## Overridden from django.middleware.security.SecurityMiddleware
|
||||||
|
# adds the includeSubDomains directive to the HTTP Strict Transport Security header
|
||||||
|
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||||
|
# adds the preload directive to the HTTP Strict Transport Security header
|
||||||
|
SECURE_HSTS_PRELOAD = True
|
||||||
|
# TODO: set this value to 31536000 (1 year) for production
|
||||||
|
SECURE_HSTS_SECONDS = 300
|
||||||
|
# redirect all non-HTTPS requests to HTTPS
|
||||||
|
SECURE_SSL_REDIRECT = True
|
||||||
|
|
||||||
|
## Set by django.middleware.common.CommonMiddleware
|
||||||
|
# DISALLOWED_USER_AGENTS = []
|
||||||
|
|
||||||
|
# The host/domain names that Django can serve.
|
||||||
|
# This is a security measure to prevent HTTP Host header attacks,
|
||||||
|
# which are possible even under many seemingly-safe
|
||||||
|
# web server configurations.
|
||||||
|
ALLOWED_HOSTS = [
|
||||||
|
"getgov-unstable.app.cloud.gov",
|
||||||
|
"get.gov",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# Default primary key field type
|
# Extend ALLOWED_HOSTS.
|
||||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
# IP addresses can also be hosts, which are used by internal
|
||||||
|
# load balancers for health checks, etc.
|
||||||
|
ALLOWED_CIDR_NETS = ["10.0.0.0/8"]
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
## Below are some protections from cross-site request forgery.
|
||||||
|
# This is canonically done by including a nonce value
|
||||||
|
# in pages sent to the user, which the user is expected
|
||||||
|
# to send back. The specifics of implementation are
|
||||||
|
# intricate and varied.
|
||||||
|
|
||||||
|
# Store the token server-side, do not send it
|
||||||
|
# to the user via a cookie. This means each page
|
||||||
|
# which requires protection must place the token
|
||||||
|
# in the HTML explicitly, otherwise the user will
|
||||||
|
# get a 403 error when they submit.
|
||||||
|
CSRF_USE_SESSIONS = True
|
||||||
|
|
||||||
|
# Expiry of CSRF cookie, in seconds.
|
||||||
|
# None means "use session-based CSRF cookies".
|
||||||
|
CSRF_COOKIE_AGE = None
|
||||||
|
|
||||||
|
# Prevent JavaScript from reading the CSRF cookie.
|
||||||
|
# Has no effect with CSRF_USE_SESSIONS = True.
|
||||||
|
CSRF_COOKIE_HTTPONLY = True
|
||||||
|
|
||||||
|
# Only send the cookie via HTTPS connections.
|
||||||
|
# Has no effect with CSRF_USE_SESSIONS = True.
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# Protect from non-targeted attacks by obscuring
|
||||||
|
# the CSRF cookie name from the default.
|
||||||
|
# Has no effect with CSRF_USE_SESSIONS = True.
|
||||||
|
CSRF_COOKIE_NAME = "CrSiReFo"
|
||||||
|
|
||||||
|
# Prevents CSRF cookie from being sent if the user
|
||||||
|
# is coming to our site from an external page.
|
||||||
|
# Has no effect with CSRF_USE_SESSIONS = True.
|
||||||
|
CSRF_COOKIE_SAMESITE = "Strict"
|
||||||
|
|
||||||
|
# Change header name to match cookie name.
|
||||||
|
# Has no effect with CSRF_USE_SESSIONS = True.
|
||||||
|
CSRF_HEADER_NAME = "HTTP_X_CRSIREFO"
|
||||||
|
|
||||||
|
# Max parameters that may be received via GET or POST
|
||||||
|
# TODO: 1000 is the default, may need to tune upward for
|
||||||
|
# large DNS zone files, if records are represented by
|
||||||
|
# individual form fields.
|
||||||
|
DATA_UPLOAD_MAX_NUMBER_FIELDS = 1000
|
||||||
|
|
||||||
|
# age of session cookies, in seconds (28800 = 8 hours)
|
||||||
|
SESSION_COOKIE_AGE = 28800
|
||||||
|
|
||||||
|
# instruct the browser to forbid client-side JavaScript
|
||||||
|
# from accessing the cookie
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
|
||||||
|
# are we a spring boot application? who knows!
|
||||||
|
SESSION_COOKIE_NAME = "JSESSIONID"
|
||||||
|
|
||||||
|
# Prevents session cookie from being sent if the user
|
||||||
|
# is coming to our site from an external page.
|
||||||
|
SESSION_COOKIE_SAMESITE = "Strict"
|
||||||
|
|
||||||
|
# instruct browser to only send cookie via HTTPS
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
## Set by django.middleware.clickjacking.XFrameOptionsMiddleware
|
||||||
|
# prevent clickjacking by instructing the browser not to load
|
||||||
|
# our site within an iframe
|
||||||
|
# X_FRAME_OPTIONS = "Deny"
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
# region: Testing-----------------------------------------------------------###
|
||||||
|
|
||||||
|
# Additional directories searched for fixture files.
|
||||||
|
# The fixtures directory of each application is searched by default.
|
||||||
|
# Must use unix style "/" path separators.
|
||||||
|
FIXTURE_DIRS = []
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
### ###
|
||||||
|
# Development settings #
|
||||||
|
### ###
|
||||||
|
|
||||||
|
if DEBUG:
|
||||||
|
# used by debug() context processor
|
||||||
|
INTERNAL_IPS = [
|
||||||
|
"127.0.0.1",
|
||||||
|
"::1",
|
||||||
|
]
|
||||||
|
|
||||||
|
# allow dev laptop to connect
|
||||||
|
ALLOWED_HOSTS += ("localhost",)
|
||||||
|
SECURE_SSL_REDIRECT = False
|
||||||
|
SECURE_HSTS_PRELOAD = False
|
||||||
|
|
||||||
|
# discover potentially inefficient database queries
|
||||||
|
# TODO: use settings overrides to ensure this always is True during tests
|
||||||
|
INSTALLED_APPS += ("nplusone.ext.django",)
|
||||||
|
MIDDLEWARE += ("nplusone.ext.django.NPlusOneMiddleware",)
|
||||||
|
NPLUSONE_RAISE = True
|
||||||
|
|
||||||
|
# insert the amazing django-debug-toolbar
|
||||||
|
INSTALLED_APPS += ("debug_toolbar",)
|
||||||
|
MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware")
|
||||||
|
|
||||||
|
DEBUG_TOOLBAR_CONFIG = {
|
||||||
|
# due to Docker, bypass Debug Toolbar's check on INTERNAL_IPS
|
||||||
|
"SHOW_TOOLBAR_CALLBACK": lambda _: True,
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue