Merge pull request #45115 from ghiculescu/csp-helpers
Fix using helpers in `content_security_policy` and `permissions_policy`
This commit is contained in:
commit
6731fa8203
@ -1,3 +1,17 @@
|
||||
* Allow using `helper_method`s in `content_security_policy` and `permissions_policy`
|
||||
|
||||
Previously you could access basic helpers (defined in helper modules), but not
|
||||
helper methods defined using `helper_method`. Now you can use either.
|
||||
|
||||
```ruby
|
||||
content_security_policy do |p|
|
||||
p.default_src "https://example.com"
|
||||
p.script_src "https://example.com" if helpers.script_csp?
|
||||
end
|
||||
```
|
||||
|
||||
*Alex Ghiculescu*
|
||||
|
||||
* Reimplement `ActionController::Parameters#has_value?` and `#value?` to avoid parameters and hashes comparison.
|
||||
|
||||
Deprecated equality between parameters and hashes is going to be removed in Rails 7.2.
|
||||
|
@ -40,7 +40,7 @@ def content_security_policy(enabled = true, **options, &block)
|
||||
before_action(options) do
|
||||
if block_given?
|
||||
policy = current_content_security_policy
|
||||
yield policy
|
||||
instance_exec(policy, &block)
|
||||
request.content_security_policy = policy
|
||||
end
|
||||
|
||||
|
@ -27,7 +27,7 @@ def permissions_policy(**options, &block)
|
||||
before_action(options) do
|
||||
if block_given?
|
||||
policy = request.permissions_policy.clone
|
||||
yield policy
|
||||
instance_exec(policy, &block)
|
||||
request.permissions_policy = policy
|
||||
end
|
||||
end
|
||||
|
@ -661,3 +661,76 @@ def test_generate_nonce_only_specified_in_nonce_directives
|
||||
assert_no_match "style-src https: 'nonce-iyhD0Yc0W+c='", response.headers["Content-Security-Policy"]
|
||||
end
|
||||
end
|
||||
|
||||
class HelpersContentSecurityPolicyIntegrationTest < ActionDispatch::IntegrationTest
|
||||
module ApplicationHelper
|
||||
def pigs_can_fly?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
helper_method :sky_is_blue?
|
||||
def sky_is_blue?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class PolicyController < ApplicationController
|
||||
content_security_policy do |p|
|
||||
p.default_src "https://example.com"
|
||||
p.script_src "https://example.com" if helpers.sky_is_blue?
|
||||
p.style_src "https://example.com" unless helpers.pigs_can_fly?
|
||||
end
|
||||
|
||||
def index
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
ROUTES = ActionDispatch::Routing::RouteSet.new
|
||||
ROUTES.draw do
|
||||
scope module: "helpers_content_security_policy_integration_test" do
|
||||
get "/", to: "policy#index"
|
||||
end
|
||||
end
|
||||
|
||||
POLICY = ActionDispatch::ContentSecurityPolicy.new do |p|
|
||||
p.default_src -> { :self }
|
||||
p.script_src -> { :https }
|
||||
p.style_src -> { :https }
|
||||
end
|
||||
|
||||
class PolicyConfigMiddleware
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env["action_dispatch.content_security_policy"] = POLICY
|
||||
env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
|
||||
env["action_dispatch.content_security_policy_report_only"] = false
|
||||
env["action_dispatch.show_exceptions"] = false
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
APP = build_app(ROUTES) do |middleware|
|
||||
middleware.use PolicyConfigMiddleware
|
||||
middleware.use ActionDispatch::ContentSecurityPolicy::Middleware
|
||||
end
|
||||
|
||||
def app
|
||||
APP
|
||||
end
|
||||
|
||||
def test_can_call_helper_methods_in_csp
|
||||
get "/"
|
||||
|
||||
assert_response :success
|
||||
assert_match "default-src https://example.com", response.headers["Content-Security-Policy"]
|
||||
assert_match "script-src https://example.com", response.headers["Content-Security-Policy"]
|
||||
assert_match "style-src https://example.com", response.headers["Content-Security-Policy"]
|
||||
end
|
||||
end
|
||||
|
@ -140,3 +140,85 @@ def assert_policy(expected)
|
||||
assert_equal expected, response.headers["Feature-Policy"]
|
||||
end
|
||||
end
|
||||
|
||||
class PermissionsPolicyWithHelpersIntegrationTest < ActionDispatch::IntegrationTest
|
||||
module ApplicationHelper
|
||||
def pigs_can_fly?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
helper_method :sky_is_blue?
|
||||
def sky_is_blue?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class PolicyController < ApplicationController
|
||||
permissions_policy do |f|
|
||||
f.gyroscope :none unless helpers.pigs_can_fly?
|
||||
f.usb :self if helpers.sky_is_blue?
|
||||
end
|
||||
|
||||
def index
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
|
||||
ROUTES = ActionDispatch::Routing::RouteSet.new
|
||||
ROUTES.draw do
|
||||
scope module: "permissions_policy_with_helpers_integration_test" do
|
||||
get "/", to: "policy#index"
|
||||
end
|
||||
end
|
||||
|
||||
POLICY = ActionDispatch::PermissionsPolicy.new do |p|
|
||||
p.gyroscope :self
|
||||
end
|
||||
|
||||
class PolicyConfigMiddleware
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
env["action_dispatch.permissions_policy"] = POLICY
|
||||
env["action_dispatch.show_exceptions"] = false
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
|
||||
APP = build_app(ROUTES) do |middleware|
|
||||
middleware.use PolicyConfigMiddleware
|
||||
middleware.use ActionDispatch::PermissionsPolicy::Middleware
|
||||
end
|
||||
|
||||
def app
|
||||
APP
|
||||
end
|
||||
|
||||
def test_generates_permissions_policy_header
|
||||
get "/"
|
||||
assert_policy "gyroscope 'none'; usb 'self'"
|
||||
end
|
||||
|
||||
private
|
||||
def env_config
|
||||
Rails.application.env_config
|
||||
end
|
||||
|
||||
def permissions_policy
|
||||
env_config["action_dispatch.permissions_policy"]
|
||||
end
|
||||
|
||||
def permissions_policy=(policy)
|
||||
env_config["action_dispatch.permissions_policy"] = policy
|
||||
end
|
||||
|
||||
def assert_policy(expected)
|
||||
assert_response :success
|
||||
assert_equal expected, response.headers["Feature-Policy"]
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user