Commit 79945d29 authored by dcouture's avatar dcouture

Force a nonce on all script tags

This leverages an existing helper we had to set defer attributes
everywhere and adds nonce to all script tags regardless of if the
script is inline or external.

It also removes all the now-redundant nonce: true used in various
places.
parent 840299c3
......@@ -4,7 +4,21 @@ module DeferScriptTagHelper
# Override the default ActionView `javascript_include_tag` helper to support page specific deferred loading.
# PLEASE NOTE: `defer` is also critical so that we don't run JavaScript entrypoints before the DOM is ready.
# Please see https://gitlab.com/groups/gitlab-org/-/epics/4538#note_432159769.
# The helper also makes sure the `nonce` attribute is included in every script when the content security
# policy is enabled.
def javascript_include_tag(*sources)
super(*sources, defer: true)
super(*sources, defer: true, nonce: true)
end
# The helper makes sure the `nonce` attribute is included in every script when the content security
# policy is enabled.
def javascript_tag(content_or_options_with_block = nil, html_options = {})
if content_or_options_with_block.is_a?(Hash)
content_or_options_with_block[:nonce] = true
else
html_options[:nonce] = true
end
super
end
end
= javascript_tag nonce: true do
= javascript_tag do
:plain
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']);
......
- if google_tag_manager_enabled?
= javascript_tag nonce: true do
= javascript_tag do
:plain
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
......
= javascript_tag nonce: true do
= javascript_tag do
:plain
if ('loading' in HTMLImageElement.prototype) {
document.querySelectorAll('img.lazy').forEach(img => {
......
......@@ -4,7 +4,7 @@
- datasources = autocomplete_data_sources(object, noteable_type)
- if object
= javascript_tag nonce: true do
= javascript_tag do
:plain
gl = window.gl || {};
gl.GfmAutoComplete = gl.GfmAutoComplete || {};
......
- client = client_js_flags
- if client
= javascript_tag nonce: true do
= javascript_tag do
:plain
gl = window.gl || {};
gl.client = #{client.to_json};
- return unless Gitlab::CurrentSettings.snowplow_enabled?
= javascript_tag nonce: true do
= javascript_tag do
:plain
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
......
- return unless use_startup_css?
= javascript_tag nonce: true do
= javascript_tag do
:plain
document.querySelectorAll('link[media="print"]').forEach(linkTag => {
linkTag.setAttribute('data-startupcss', 'loading');
......
- return unless page_startup_api_calls.present? || page_startup_graphql_calls.present?
= javascript_tag nonce: true do
= javascript_tag do
:plain
var gl = window.gl || {};
gl.startup_calls = #{page_startup_api_calls.to_json};
......
......@@ -8,7 +8,7 @@
%body
.page-container
= yield
= javascript_tag nonce: true do
= javascript_tag do
:plain
(function(){
var goBackElement = document.querySelector('.js-go-back');
......
......@@ -8,7 +8,7 @@
- content_for :page_specific_javascripts do
- if current_user
= javascript_tag nonce: true do
= javascript_tag do
:plain
window.uploads_path = "#{group_uploads_path(@group)}";
......
......@@ -10,7 +10,7 @@
- content_for :project_javascripts do
- project = @target_project || @project
- if current_user
= javascript_tag nonce: true do
= javascript_tag do
:plain
window.uploads_path = "#{project_uploads_path(project)}";
......
......@@ -4,7 +4,7 @@
- content_for :page_specific_javascripts do
- if snippets_upload_path
= javascript_tag nonce: true do
= javascript_tag do
:plain
window.uploads_path = "#{snippets_upload_path}";
......
= javascript_tag nonce: true do
= javascript_tag do
:plain
window.gl = window.gl || {};
window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget', issues_links: true)}
......
= render_ce "projects/merge_requests/show"
= javascript_tag nonce: true do
= javascript_tag do
:plain
// Append static, server-generated data not included in merge request entity (EE-Only)
// Object.assign would be useful here, but it blows up Phantom.js in tests
......
......@@ -3,12 +3,42 @@
require 'spec_helper'
RSpec.describe DeferScriptTagHelper do
describe 'script tag' do
script_url = 'test.js'
before do
allow_any_instance_of(DeferScriptTagHelper).to receive(:content_security_policy_nonce).and_return('noncevalue')
end
describe 'external script tag' do
let(:script_url) { 'test.js' }
it 'returns an script tag with defer=true' do
it 'returns a script tag with defer=true and a nonce' do
expect(javascript_include_tag(script_url).to_s)
.to eq "<script src=\"/javascripts/#{script_url}\" defer=\"defer\"></script>"
.to eq "<script src=\"/javascripts/#{script_url}\" defer=\"defer\" nonce=\"noncevalue\"></script>"
end
end
describe 'inline script tag' do
let(:tag_with_nonce) {"<script nonce=\"noncevalue\">\n//<![CDATA[\nalert(1)\n//]]>\n</script>"}
let(:tag_with_nonce_and_type) {"<script type=\"application/javascript\" nonce=\"noncevalue\">\n//<![CDATA[\nalert(1)\n//]]>\n</script>"}
it 'returns a script tag with a nonce using block syntax' do
expect(javascript_tag { 'alert(1)' }.to_s).to eq tag_with_nonce
end
it 'returns a script tag with a nonce using block syntax with options' do
expect(javascript_tag(type: 'application/javascript') { 'alert(1)' }.to_s).to eq tag_with_nonce_and_type
end
it 'returns a script tag with a nonce using argument syntax' do
expect(javascript_tag('alert(1)').to_s).to eq tag_with_nonce
end
it 'returns a script tag with a nonce using argument syntax with options' do
expect(javascript_tag( 'alert(1)', type: 'application/javascript').to_s).to eq tag_with_nonce_and_type
end
# This scenario does not really make sense, but it's supported so we test it
it 'returns a script tag with a nonce using argument and block syntax with options' do
expect(javascript_tag( '// ignored', type: 'application/javascript') { 'alert(1)' }.to_s).to eq tag_with_nonce_and_type
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment