Skip to content

Commit 1ca0f27

Browse files
authored
Merge pull request rails#53794 from alexandergitter/preload-links-csp-nonce
Add CSP nonce to preload links
2 parents 17a5ae1 + f56f08e commit 1ca0f27

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

actionview/lib/action_view/helpers/asset_tag_helper.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def javascript_include_tag(*sources)
127127
preload_link = "<#{href}>; rel=#{rel}; as=script"
128128
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
129129
preload_link += "; integrity=#{integrity}" unless integrity.nil?
130+
preload_link += "; nonce=#{content_security_policy_nonce}" if options["nonce"] == true
130131
preload_link += "; nopush" if nopush
131132
preload_links << preload_link
132133
end
@@ -215,6 +216,7 @@ def stylesheet_link_tag(*sources)
215216
preload_link = "<#{href}>; rel=preload; as=style"
216217
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
217218
preload_link += "; integrity=#{integrity}" unless integrity.nil?
219+
preload_link += "; nonce=#{content_security_policy_nonce}" if options["nonce"] == true
218220
preload_link += "; nopush" if nopush
219221
preload_links << preload_link
220222
end
@@ -362,6 +364,13 @@ def preload_link_tag(source, options = {})
362364
integrity = options[:integrity]
363365
nopush = options.delete(:nopush) || false
364366
rel = mime_type == "module" ? "modulepreload" : "preload"
367+
add_nonce = content_security_policy_nonce &&
368+
respond_to?(:request) &&
369+
request.content_security_policy_nonce_directives&.include?("#{as_type}-src")
370+
371+
if add_nonce
372+
options[:nonce] = content_security_policy_nonce
373+
end
365374

366375
link_tag = tag.link(
367376
rel: rel,
@@ -375,6 +384,7 @@ def preload_link_tag(source, options = {})
375384
preload_link += "; type=#{mime_type}" if mime_type
376385
preload_link += "; crossorigin=#{crossorigin}" if crossorigin
377386
preload_link += "; integrity=#{integrity}" if integrity
387+
preload_link += "; nonce=#{content_security_policy_nonce}" if add_nonce
378388
preload_link += "; nopush" if nopush
379389

380390
send_preload_links_header([preload_link])

actionview/test/template/asset_tag_helper_test.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class AssetTagHelperTest < ActionView::TestCase
2525
attr_reader :request, :response
2626

2727
class FakeRequest
28-
attr_accessor :script_name
28+
attr_accessor :script_name, :content_security_policy_nonce_directives
2929
def protocol() "http://" end
3030
def ssl?() false end
3131
def host_with_port() "localhost" end
@@ -724,6 +724,27 @@ def test_should_set_preload_links_with_integrity_hashes
724724
end
725725
end
726726

727+
def test_should_set_preload_links_with_nonce
728+
@request.content_security_policy_nonce_directives = %w(script-src)
729+
with_preload_links_header do
730+
preload_link_tag("http://example.com/preload.js")
731+
stylesheet_link_tag("http://example.com/style.css", nonce: true)
732+
javascript_include_tag("http://example.com/all.js", nonce: true)
733+
expected = "<http://example.com/preload.js>; rel=preload; as=script; type=text/javascript; nonce=iyhD0Yc0W+c=,<http://example.com/style.css>; rel=preload; as=style; nonce=iyhD0Yc0W+c=; nopush,<http://example.com/all.js>; rel=preload; as=script; nonce=iyhD0Yc0W+c=; nopush"
734+
assert_equal expected, @response.headers["link"]
735+
end
736+
end
737+
738+
def test_should_set_preload_link_tag_nonce_if_listed_in_csp_directives
739+
@request.content_security_policy_nonce_directives = %w(script-src)
740+
assert_equal %(<link rel="preload" href="/application.js" as="script" type="text/javascript" nonce="iyhD0Yc0W+c=">), preload_link_tag("/application.js")
741+
assert_equal %(<link rel="preload" href="/style.css" as="style" type="text/css">), preload_link_tag("/style.css")
742+
743+
@request.content_security_policy_nonce_directives = %w(style-src)
744+
assert_equal %(<link rel="preload" href="/application.js" as="script" type="text/javascript">), preload_link_tag("/application.js")
745+
assert_equal %(<link rel="preload" href="/style.css" as="style" type="text/css" nonce="iyhD0Yc0W+c=">), preload_link_tag("/style.css")
746+
end
747+
727748
def test_should_not_preload_links_when_disabled
728749
with_preload_links_header(false) do
729750
stylesheet_link_tag("http://example.com/style.css")

0 commit comments

Comments
 (0)