diff --git a/.idea/runConfigurations/API_testy_komplet.xml b/.idea/runConfigurations/API_testy_komplet.xml
index 0f055c3f..9443b2cf 100644
--- a/.idea/runConfigurations/API_testy_komplet.xml
+++ b/.idea/runConfigurations/API_testy_komplet.xml
@@ -5,6 +5,7 @@
+
diff --git a/.idea/runConfigurations/PRODUCTION_komplet.xml b/.idea/runConfigurations/PRODUCTION_komplet.xml
index c6b02b81..6b6a5feb 100644
--- a/.idea/runConfigurations/PRODUCTION_komplet.xml
+++ b/.idea/runConfigurations/PRODUCTION_komplet.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/.idea/runConfigurations/UI_testy_FAST_HEADLESS.xml b/.idea/runConfigurations/UI_testy_FAST_HEADLESS.xml
index ee537a25..acd65bc7 100644
--- a/.idea/runConfigurations/UI_testy_FAST_HEADLESS.xml
+++ b/.idea/runConfigurations/UI_testy_FAST_HEADLESS.xml
@@ -6,6 +6,7 @@
+
diff --git a/.idea/runConfigurations/UI_testy_komplet_BROWSER.xml b/.idea/runConfigurations/UI_testy_komplet_BROWSER.xml
index 9029ad7a..ca97963d 100644
--- a/.idea/runConfigurations/UI_testy_komplet_BROWSER.xml
+++ b/.idea/runConfigurations/UI_testy_komplet_BROWSER.xml
@@ -6,6 +6,7 @@
+
diff --git a/.idea/runConfigurations/UI_testy_komplet_HEADLESS.xml b/.idea/runConfigurations/UI_testy_komplet_HEADLESS.xml
index a8f44029..cdd11c60 100644
--- a/.idea/runConfigurations/UI_testy_komplet_HEADLESS.xml
+++ b/.idea/runConfigurations/UI_testy_komplet_HEADLESS.xml
@@ -6,6 +6,7 @@
+
diff --git a/.idea/runConfigurations/django_DEV.xml b/.idea/runConfigurations/django_DEV.xml
index 163e7bec..cb639c95 100644
--- a/.idea/runConfigurations/django_DEV.xml
+++ b/.idea/runConfigurations/django_DEV.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/Pipfile b/Pipfile
index 2bf28b50..0ef2459d 100644
--- a/Pipfile
+++ b/Pipfile
@@ -20,11 +20,12 @@ sentry-sdk = "~=0.14.0"
uritemplate = "~=3.0.0"
vulture = "~=1.2"
whitenoise = "~=5.0"
+django-csp = "~=3.5"
[dev-packages]
behave-django = "~=1.3.0"
black = "~=19.3b0"
-coverage = "~=5.0.3"
+coverage = "~=5.1"
codecov = "~=2.0.16"
selenium = "~=3.141.0"
mypy = "~=0.770"
diff --git a/Pipfile.lock b/Pipfile.lock
index 01c1ee16..0f44e396 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "60aa67a83f921d88179d7be2cc1a15d8386b48de82ae1200af4835bc83b681ee"
+ "sha256": "13db91b26758ed5f293a7f9d5ebc7652a0bd571f8c11784a61f3c6d03f1b271f"
},
"pipfile-spec": 6,
"requires": {
@@ -45,6 +45,14 @@
"index": "pypi",
"version": "==3.0.5"
},
+ "django-csp": {
+ "hashes": [
+ "sha256:0a38aa9618c675cbf5f5e517e20d5846a3e100ef7b307e32e7fb18c58aa47723",
+ "sha256:d9ee5a8c6442aa54854e8de627c2826786208ed38fb4ea8ced08c42332673eb1"
+ ],
+ "index": "pypi",
+ "version": "==3.6"
+ },
"django-debug-toolbar": {
"hashes": [
"sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943",
@@ -307,40 +315,40 @@
},
"coverage": {
"hashes": [
- "sha256:03f630aba2b9b0d69871c2e8d23a69b7fe94a1e2f5f10df5049c0df99db639a0",
- "sha256:046a1a742e66d065d16fb564a26c2a15867f17695e7f3d358d7b1ad8a61bca30",
- "sha256:0a907199566269e1cfa304325cc3b45c72ae341fbb3253ddde19fa820ded7a8b",
- "sha256:165a48268bfb5a77e2d9dbb80de7ea917332a79c7adb747bd005b3a07ff8caf0",
- "sha256:1b60a95fc995649464e0cd48cecc8288bac5f4198f21d04b8229dc4097d76823",
- "sha256:1f66cf263ec77af5b8fe14ef14c5e46e2eb4a795ac495ad7c03adc72ae43fafe",
- "sha256:2e08c32cbede4a29e2a701822291ae2bc9b5220a971bba9d1e7615312efd3037",
- "sha256:3844c3dab800ca8536f75ae89f3cf566848a3eb2af4d9f7b1103b4f4f7a5dad6",
- "sha256:408ce64078398b2ee2ec08199ea3fcf382828d2f8a19c5a5ba2946fe5ddc6c31",
- "sha256:443be7602c790960b9514567917af538cac7807a7c0c0727c4d2bbd4014920fd",
- "sha256:4482f69e0701139d0f2c44f3c395d1d1d37abd81bfafbf9b6efbe2542679d892",
- "sha256:4a8a259bf990044351baf69d3b23e575699dd60b18460c71e81dc565f5819ac1",
- "sha256:513e6526e0082c59a984448f4104c9bf346c2da9961779ede1fc458e8e8a1f78",
- "sha256:5f587dfd83cb669933186661a351ad6fc7166273bc3e3a1531ec5c783d997aac",
- "sha256:62061e87071497951155cbccee487980524d7abea647a1b2a6eb6b9647df9006",
- "sha256:641e329e7f2c01531c45c687efcec8aeca2a78a4ff26d49184dce3d53fc35014",
- "sha256:65a7e00c00472cd0f59ae09d2fb8a8aaae7f4a0cf54b2b74f3138d9f9ceb9cb2",
- "sha256:6ad6ca45e9e92c05295f638e78cd42bfaaf8ee07878c9ed73e93190b26c125f7",
- "sha256:73aa6e86034dad9f00f4bbf5a666a889d17d79db73bc5af04abd6c20a014d9c8",
- "sha256:7c9762f80a25d8d0e4ab3cb1af5d9dffbddb3ee5d21c43e3474c84bf5ff941f7",
- "sha256:85596aa5d9aac1bf39fe39d9fa1051b0f00823982a1de5766e35d495b4a36ca9",
- "sha256:86a0ea78fd851b313b2e712266f663e13b6bc78c2fb260b079e8b67d970474b1",
- "sha256:8a620767b8209f3446197c0e29ba895d75a1e272a36af0786ec70fe7834e4307",
- "sha256:922fb9ef2c67c3ab20e22948dcfd783397e4c043a5c5fa5ff5e9df5529074b0a",
- "sha256:9fad78c13e71546a76c2f8789623eec8e499f8d2d799f4b4547162ce0a4df435",
- "sha256:a37c6233b28e5bc340054cf6170e7090a4e85069513320275a4dc929144dccf0",
- "sha256:c3fc325ce4cbf902d05a80daa47b645d07e796a80682c1c5800d6ac5045193e5",
- "sha256:cda33311cb9fb9323958a69499a667bd728a39a7aa4718d7622597a44c4f1441",
- "sha256:db1d4e38c9b15be1521722e946ee24f6db95b189d1447fa9ff18dd16ba89f732",
- "sha256:eda55e6e9ea258f5e4add23bcf33dc53b2c319e70806e180aecbff8d90ea24de",
- "sha256:f372cdbb240e09ee855735b9d85e7f50730dcfb6296b74b95a3e5dea0615c4c1"
+ "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a",
+ "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355",
+ "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65",
+ "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7",
+ "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9",
+ "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1",
+ "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0",
+ "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55",
+ "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c",
+ "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6",
+ "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef",
+ "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019",
+ "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e",
+ "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0",
+ "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf",
+ "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24",
+ "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2",
+ "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c",
+ "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4",
+ "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0",
+ "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd",
+ "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04",
+ "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e",
+ "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730",
+ "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2",
+ "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768",
+ "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796",
+ "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7",
+ "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a",
+ "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489",
+ "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"
],
"index": "pypi",
- "version": "==5.0.4"
+ "version": "==5.1"
},
"django": {
"hashes": [
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 7c463013..547e004b 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -1,3 +1,5 @@
+import { config } from "@fortawesome/fontawesome-svg-core"
+import "@fortawesome/fontawesome-svg-core/styles.css"
import * as Sentry from "@sentry/browser"
import "bootstrap/dist/css/bootstrap.css"
import * as React from "react"
@@ -12,6 +14,9 @@ import history from "./global/history"
import "./index.css"
import Main from "./Main"
+// opatreni kvuli CSP pro FontAwesome, viz https://fontawesome.com/how-to-use/on-the-web/other-topics/security
+config.autoAddCss = false
+
// CI provede substituci stringu za URL, promenna prostredi ale musi existovat, jinak nefunguje (proto podminka)
if (isHosted()) {
Sentry.init({
diff --git a/manage.py b/manage.py
index 29b938c7..2bdc2e32 100644
--- a/manage.py
+++ b/manage.py
@@ -7,7 +7,7 @@
if __name__ == "__main__":
# nastaveni vychoziho souboru s nastavenim
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "up.settings")
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "up.settings.local")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
diff --git a/mypy.ini b/mypy.ini
index d19482a4..ee894a64 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -13,7 +13,7 @@ warn_unreachable = True
warn_unused_ignores = True
[mypy.plugins.django-stubs]
-django_settings_module = "up.settings"
+django_settings_module = "up.settings.local"
[mypy-*.migrations.*]
# Django migrations should not produce any errors:
diff --git a/scripts/shell/release_tasks.sh b/scripts/shell/release_tasks.sh
index 1aa4014e..407af609 100644
--- a/scripts/shell/release_tasks.sh
+++ b/scripts/shell/release_tasks.sh
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
-export DJANGO_SETTINGS_MODULE=up.production_settings
+export DJANGO_SETTINGS_MODULE=up.settings.production
python manage.py collectstatic --noinput
python manage.py migrate
diff --git a/tests/ui_environment.py b/tests/ui_environment.py
index 58c29fbb..f1adcbe8 100644
--- a/tests/ui_environment.py
+++ b/tests/ui_environment.py
@@ -1,8 +1,8 @@
+from django.conf import settings
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from tests import fixtures
-from up.settings import HEADLESS
SCREEN_WIDTH = 1920
SCREEN_HEIGHT = 1080
@@ -10,7 +10,7 @@
def before_all(context):
options = Options()
- options.headless = HEADLESS
+ options.headless = settings.HEADLESS
context.browser = webdriver.Firefox(options=options)
context.browser.set_window_size(SCREEN_WIDTH, SCREEN_HEIGHT)
diff --git a/up/settings.py b/up/settings/base.py
similarity index 84%
rename from up/settings.py
rename to up/settings/base.py
index a7024419..c417a263 100644
--- a/up/settings.py
+++ b/up/settings/base.py
@@ -1,5 +1,6 @@
"""
-Výchozí konfigurace Django projektu.
+Základní konfigurace Django projektu.
+Je základem pro konfigurace v souborech local.py a production.py.
"""
import os
import sys
@@ -8,7 +9,7 @@
import environ
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# env promenne
env = environ.Env(
@@ -46,7 +47,6 @@
# Django konstanty
DEBUG = env("DEBUG")
SECRET_KEY = env("SECRET_KEY")
-ALLOWED_HOSTS = ["*"]
# Application definition
INSTALLED_APPS = [
@@ -88,6 +88,7 @@
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
+ "csp.middleware.CSPMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"debug_toolbar.middleware.DebugToolbarMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
@@ -172,3 +173,27 @@
X_FRAME_OPTIONS = "DENY"
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
+
+# CSP
+# CSP pro Google Analytics, viz https://developers.google.com/tag-manager/web/csp#universal_analytics_google_analytics
+CSPURL_GOOGLE_ANALYTICS = "https://www.google-analytics.com"
+CSPURL_GOOGLE_ANALYTICS_SSL = "https://ssl.google-analytics.com"
+# CSP pro Google Fonts
+CSPURL_GOOGLE_FONTS_STYLE = "fonts.googleapis.com"
+CSPURL_GOOGLE_FONTS_FONT = "fonts.gstatic.com"
+# CSP pro Sentry
+CSPURL_SENTRY = "https://sentry.io"
+
+CSP_SELF = "'self'"
+
+# CSP konfigurace
+CSP_DEFAULT_SRC = ("'none'",)
+CSP_STYLE_SRC = (
+ CSP_SELF,
+ "'unsafe-inline'",
+ CSPURL_GOOGLE_FONTS_STYLE,
+) # 'unsafe-inline' kvuli inline CSS v Sentry feedback formulari
+CSP_CONNECT_SRC = (CSP_SELF, CSPURL_GOOGLE_ANALYTICS, CSPURL_SENTRY)
+CSP_SCRIPT_SRC = (CSP_SELF, CSPURL_SENTRY, CSPURL_GOOGLE_ANALYTICS, CSPURL_GOOGLE_ANALYTICS_SSL)
+CSP_FONT_SRC = (CSP_SELF, CSPURL_GOOGLE_FONTS_FONT)
+CSP_IMG_SRC = (CSP_SELF, CSPURL_GOOGLE_ANALYTICS, "data:")
diff --git a/up/settings/local.py b/up/settings/local.py
new file mode 100644
index 00000000..5ec5245c
--- /dev/null
+++ b/up/settings/local.py
@@ -0,0 +1,15 @@
+"""
+Lokální (vývojová) konfigurace Django projektu.
+Rozšiřuje základní konfiguraci ze souboru base.py.
+"""
+from .base import * # lgtm [py/polluting-import]
+
+# Django konstanty
+ALLOWED_HOSTS = ["*"]
+
+# CSP
+CSPURL_LOCALHOST = ("*:3000",)
+
+CSP_STYLE_SRC = CSP_STYLE_SRC + CSPURL_LOCALHOST
+CSP_CONNECT_SRC = CSP_CONNECT_SRC + CSPURL_LOCALHOST + ("ws://*:3000",)
+CSP_SCRIPT_SRC = CSP_SCRIPT_SRC + CSPURL_LOCALHOST + ("'unsafe-eval'", "'unsafe-inline'")
diff --git a/up/production_settings.py b/up/settings/production.py
similarity index 92%
rename from up/production_settings.py
rename to up/settings/production.py
index 8efb0851..931c3c22 100644
--- a/up/production_settings.py
+++ b/up/settings/production.py
@@ -1,12 +1,12 @@
"""
Produkční konfigurace Django projektu.
Používá se pro nasazené aplikace, případně pro simulaci nasazené aplikace na lokálu (MANUAL_PRODUCTION).
-Rozšiřuje výchozí konfiguraci ze souboru settings.py.
+Rozšiřuje základní konfiguraci ze souboru base.py.
"""
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
-from .settings import * # lgtm [py/polluting-import]
+from .base import * # lgtm [py/polluting-import]
# pro korektni build a fungovani na Travisu
if os.getenv("TRAVIS"):
diff --git a/up/wsgi.py b/up/wsgi.py
index f1cd71f9..465dc7fe 100644
--- a/up/wsgi.py
+++ b/up/wsgi.py
@@ -6,6 +6,6 @@
from django.core.wsgi import get_wsgi_application
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "up.settings")
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "up.settings.local")
application = get_wsgi_application()