mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-09-08 03:07:14 +02:00
fix(csp): always include internal CDN in script-src/connect-src and update tests accordingly
See ChatGPT conversation: https://chatgpt.com/share/68b492b8-847c-800f-82a9-fb890d4add7f
This commit is contained in:
@@ -139,10 +139,9 @@ class FilterModule(object):
|
||||
if matomo_domain:
|
||||
tokens.append(f"{web_protocol}://{matomo_domain}")
|
||||
|
||||
# Allow the loading of js from the cdn
|
||||
if self.is_feature_enabled(applications, 'logout', application_id) or self.is_feature_enabled(applications, 'desktop', application_id):
|
||||
domain = domains.get('web-svc-cdn')[0]
|
||||
tokens.append(f"{web_protocol}://{domain}")
|
||||
# Allow fetching from internal CDN as default for all applications
|
||||
domain = domains.get('web-svc-cdn')[0]
|
||||
tokens.append(f"{web_protocol}://{domain}")
|
||||
|
||||
# ReCaptcha integration: allow loading scripts from Google if feature enabled
|
||||
if self.is_feature_enabled(applications, 'recaptcha', application_id):
|
||||
|
@@ -45,7 +45,7 @@ class TestCspFilters(unittest.TestCase):
|
||||
"body { background: #fff; }",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
'app2': {}
|
||||
@@ -85,18 +85,16 @@ class TestCspFilters(unittest.TestCase):
|
||||
header = self.filter.build_csp_header(self.apps, 'app1', self.domains, web_protocol='https')
|
||||
# Ensure core directives are present
|
||||
self.assertIn("default-src 'self';", header)
|
||||
# script-src directive should include unsafe-eval, Matomo domain and CDN (hash may follow)
|
||||
# script-src-elem should include 'self', Matomo, internes CDN und explizite Whitelist-CDN
|
||||
self.assertIn("script-src-elem 'self'", header)
|
||||
self.assertIn("https://matomo.example.org", header)
|
||||
self.assertIn("https://cdn.example.org", header) # internes CDN
|
||||
self.assertIn("https://cdn.example.com", header) # Whitelist
|
||||
# script-src directive should include unsafe-eval
|
||||
self.assertIn("script-src 'self' 'unsafe-eval'", header)
|
||||
# connect-src directive
|
||||
self.assertIn(
|
||||
"script-src-elem 'self' https://matomo.example.org https://cdn.example.com",
|
||||
header
|
||||
)
|
||||
self.assertIn(
|
||||
"script-src 'self' 'unsafe-eval'",
|
||||
header
|
||||
)
|
||||
# connect-src directive unchanged (no inline hash)
|
||||
self.assertIn(
|
||||
"connect-src 'self' https://matomo.example.org https://api.example.com;",
|
||||
"connect-src 'self' https://matomo.example.org https://cdn.example.org https://api.example.com;",
|
||||
header
|
||||
)
|
||||
# ends with img-src
|
||||
@@ -106,8 +104,9 @@ class TestCspFilters(unittest.TestCase):
|
||||
header = self.filter.build_csp_header(self.apps, 'app2', self.domains)
|
||||
# default-src only contains 'self'
|
||||
self.assertIn("default-src 'self';", header)
|
||||
# no external URLs
|
||||
self.assertNotIn('http', header)
|
||||
self.assertIn('https://cdn.example.org', header)
|
||||
self.assertNotIn('matomo.example.org', header)
|
||||
self.assertNotIn('www.google.com', header)
|
||||
# ends with img-src
|
||||
self.assertTrue(header.strip().endswith('img-src * data: blob:;'))
|
||||
|
||||
@@ -154,7 +153,6 @@ class TestCspFilters(unittest.TestCase):
|
||||
style_hash = self.filter.get_csp_hash("body { background: #fff; }")
|
||||
self.assertNotIn(style_hash, header)
|
||||
|
||||
|
||||
def test_build_csp_header_recaptcha_toggle(self):
|
||||
"""
|
||||
When the 'recaptcha' feature is enabled, 'https://www.google.com'
|
||||
@@ -185,7 +183,7 @@ class TestCspFilters(unittest.TestCase):
|
||||
self.domains['web-app-desktop'] = ['domain-example.com']
|
||||
|
||||
header = self.filter.build_csp_header(self.apps, 'app1', self.domains, web_protocol='https')
|
||||
# Expect '*.domain-example.com' in the frame-ancestors directive
|
||||
# Expect 'domain-example.com' in the frame-ancestors directive
|
||||
self.assertRegex(
|
||||
header,
|
||||
r"frame-ancestors\s+'self'\s+domain-example\.com;"
|
||||
@@ -194,9 +192,9 @@ class TestCspFilters(unittest.TestCase):
|
||||
# Now disable the feature and rebuild
|
||||
self.apps['app1']['features']['desktop'] = False
|
||||
header_no = self.filter.build_csp_header(self.apps, 'app1', self.domains, web_protocol='https')
|
||||
# Should no longer contain the wildcarded sld.tld
|
||||
self.assertNotIn("*.domain-example.com", header_no)
|
||||
# Should no longer contain the SLD+TLD
|
||||
self.assertNotIn("domain-example.com", header_no)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
unittest.main()
|
||||
|
Reference in New Issue
Block a user