Skip to content

Commit 318e2da

Browse files
authored
CSP: apply extra CSP rules only when ext-theme is enabled (#11466)
This is breaking our gold view on the org site (no beta). This is since we don't have script-src defined on .com, and when applying the extra rules, we are defining it with just that value.
1 parent 7d40ba9 commit 318e2da

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

readthedocs/gold/tests/test_views.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22

33
from django.contrib.auth.models import User
4-
from django.test import TestCase
4+
from django.test import TestCase, override_settings
55
from django.urls import reverse
66
from django_dynamic_fixture import get
77

@@ -12,7 +12,16 @@ def setUp(self):
1212

1313
def test_csp_headers(self):
1414
self.client.force_login(self.user)
15-
response = self.client.get(reverse("gold_detail"))
16-
self.assertEqual(response.status_code, 200)
17-
csp = response["Content-Security-Policy"]
18-
self.assertTrue(re.match(r".*\s+script-src [^;]*'unsafe-inline'", csp))
15+
csp_header = "Content-Security-Policy"
16+
script_src_regex = re.compile(r".*\s+script-src [^;]*'unsafe-inline'")
17+
url = reverse("gold_detail")
18+
19+
with override_settings(RTD_EXT_THEME_ENABLED=False):
20+
resp = self.client.get(url)
21+
self.assertEqual(resp.status_code, 200)
22+
self.assertIsNone(script_src_regex.match(resp[csp_header]))
23+
24+
with override_settings(RTD_EXT_THEME_ENABLED=True):
25+
resp = self.client.get(url)
26+
self.assertEqual(resp.status_code, 200)
27+
self.assertTrue(script_src_regex.match(resp[csp_header]))

readthedocs/gold/views.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44

55
import stripe
66
import structlog
7-
from csp.decorators import csp_update
87
from django.conf import settings
98
from django.contrib import messages
109
from django.contrib.auth.models import User
1110
from django.http import HttpResponseRedirect, JsonResponse
1211
from django.shortcuts import get_object_or_404
1312
from django.urls import reverse_lazy
1413
from django.utils import timezone
15-
from django.utils.decorators import method_decorator
1614
from django.utils.translation import gettext_lazy as _
1715
from rest_framework import permissions
1816
from rest_framework.renderers import JSONRenderer
@@ -29,14 +27,6 @@
2927
log = structlog.get_logger(__name__)
3028

3129

32-
@method_decorator(
33-
# Allow inline scripts for the gold view.
34-
# We are using inline javascript to initialize Stripe Checkout.
35-
# Allowing inline scripts defeats the purpose of using CSP,
36-
# but we are limiting it to this view.
37-
csp_update(SCRIPT_SRC="'unsafe-inline'"),
38-
name="dispatch",
39-
)
4030
class GoldSubscription(
4131
PrivateViewMixin,
4232
DetailView,
@@ -49,6 +39,18 @@ class GoldSubscription(
4939
form_class = GoldSubscriptionForm
5040
template_name = "gold/subscription_detail.html"
5141

42+
def dispatch(self, request, *args, **kwargs):
43+
response = super().dispatch(request, *args, **kwargs)
44+
# Allow inline scripts for the gold view.
45+
# We are using inline javascript to initialize Stripe Checkout.
46+
# Allowing inline scripts defeats the purpose of using CSP,
47+
# but we are limiting it to this view.
48+
# TODO: use the `@csp_update` decorator once we are running
49+
# ext-theme by default.
50+
if settings.RTD_EXT_THEME_ENABLED:
51+
response._csp_update = {"script-src": "'unsafe-inline'"}
52+
return response
53+
5254
def get(self, *args, **kwargs):
5355
subscribed = self.request.GET.get("subscribed", None)
5456
if subscribed == "true":

0 commit comments

Comments
 (0)