From 7ba726b91e553c4dd317aadbc930a5ea70ca0160 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Fri, 1 Nov 2024 13:58:05 -0700 Subject: [PATCH] Allow response.content_security_plugin = false to avoid setting policy in content_security_policy plugin This is useful if you are serving multiple subdomains in the same application, and want only want to use the policy in a subset of the subdomains. --- CHANGELOG | 4 ++++ lib/roda/plugins/content_security_policy.rb | 20 +++++++++++++++++--- spec/plugin/content_security_policy_spec.rb | 8 ++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 402c95d1..e91ba8bf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ += master + +* Allow response.content_security_plugin = false to avoid setting policy in content_security_policy plugin (jeremyevans) + = 3.85.0 (2024-10-11) * Avoid deprecation warning in public plugin when using Ruby 3.4.0-preview2 (jeremyevans) diff --git a/lib/roda/plugins/content_security_policy.rb b/lib/roda/plugins/content_security_policy.rb index 77f3a99b..1d3cc498 100644 --- a/lib/roda/plugins/content_security_policy.rb +++ b/lib/roda/plugins/content_security_policy.rb @@ -293,15 +293,20 @@ def content_security_policy end module ResponseMethods + # Set the content security policy for the response. Can be set to false + # to disable setting the content-security-policy header in the response. + attr_writer :content_security_policy + # Unset any content security policy when reinitializing def initialize super - @content_security_policy &&= nil + @content_security_policy = nil end # The current content security policy to be used for this response. def content_security_policy - @content_security_policy ||= roda_class.opts[:content_security_policy].dup + return @content_security_policy unless @content_security_policy.nil? + @content_security_policy = roda_class.opts[:content_security_policy].dup end private @@ -309,7 +314,16 @@ def content_security_policy # Set the appropriate content security policy header. def set_default_headers super - (@content_security_policy || roda_class.opts[:content_security_policy]).set_header(headers) + + csp = @content_security_policy + + if csp.nil? + csp = roda_class.opts[:content_security_policy] + end + + if csp + csp.set_header(headers) + end end end end diff --git a/spec/plugin/content_security_policy_spec.rb b/spec/plugin/content_security_policy_spec.rb index 3b284254..660e5b1d 100644 --- a/spec/plugin/content_security_policy_spec.rb +++ b/spec/plugin/content_security_policy_spec.rb @@ -149,6 +149,14 @@ header(RodaResponseHeaders::CONTENT_SECURITY_POLICY).must_equal "default_src 'none';" end + it "should not set policy if response.content_security_policy = false" do + app(:content_security_policy) do |r| + response.content_security_policy = false + '' + end + header(RodaResponseHeaders::CONTENT_SECURITY_POLICY).must_be_nil + end + it "works with error_handler" do app(:bare) do plugin(:error_handler){|_| ''}