diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index caee16ffc..13ebd5f64 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -20,4 +20,4 @@ var AdminDashboard = { } } } -setTimeout("AdminDashboard.init()", 900); +setTimeout(function() { AdminDashboard.init(); }, 900); diff --git a/app/assets/javascripts/ohloh_suggests.js b/app/assets/javascripts/ohloh_suggests.js index 477feafbc..c1992ec06 100644 --- a/app/assets/javascripts/ohloh_suggests.js +++ b/app/assets/javascripts/ohloh_suggests.js @@ -94,7 +94,7 @@ StackShow = { if (StackShow.timeoutPreview != null) { clearTimeout(StackShow.timeoutPreview); } - StackShow.timeoutPreview = setTimeout('StackShow.update_callback()', StackShow.timeoutDelay); + StackShow.timeoutPreview = setTimeout(function() { StackShow.update_callback(); }, StackShow.timeoutDelay); }, update_callback: function() { StackShow.update_widget_preview(); @@ -205,7 +205,7 @@ StackShow = { } if (StackShow.getting_more) { if (StackShow.get_more_timer != null) { clearTimeout(StackShow.get_more_timer); } - StackShow.get_more_timer = setTimeout('StackShow.get_more('+skip_projects+',null)', 1000); + StackShow.get_more_timer = setTimeout(function() { StackShow.get_more(skip_projects, null); }, 1000); return; } else { StackShow.getting_more = true; diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index e022f63fd..b3a63e386 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -22,4 +22,4 @@ var ProjectDashboard = { } } } -setTimeout("ProjectDashboard.init()", 900); \ No newline at end of file +setTimeout(function() { ProjectDashboard.init(); }, 900); \ No newline at end of file diff --git a/app/helpers/map_helper.rb b/app/helpers/map_helper.rb index 2a9942ad8..ceab5a5ec 100644 --- a/app/helpers/map_helper.rb +++ b/app/helpers/map_helper.rb @@ -35,13 +35,13 @@ def map_near_contributors_json(project, params) def map_script_load key = Rails.application.config.google_maps_api_key - uri = "#{request.ssl? ? 'https' : 'http'}://maps.googleapis.com/maps/api/js?v=3&key=#{key}" + uri = "https://maps.googleapis.com/maps/api/js?v=3&key=#{key}" "" end def map_js_initialization(id, zoom, lat = nil, lng = nil) jump_callback = lat && lng ? "EditMap.jumpMeTo(#{lat}, #{lng});" : '' - javascript_tag <<-JSCRIPT + javascript_tag(<<-JSCRIPT, nonce: true) function initOhMap() { OH_Map.load('#{id}', 25, 12, 2); OH_Map.moveTo(25, 12, #{zoom}); diff --git a/app/views/factoids/index.html.haml b/app/views/factoids/index.html.haml index a1ed7399a..334ea2bd7 100644 --- a/app/views/factoids/index.html.haml +++ b/app/views/factoids/index.html.haml @@ -1,6 +1,6 @@ - content_for(:html_title) { t('.page_title') } - content_for :javascript do - = javascript_tag '$(document).on("page:change", Factoids.highlight);' + = javascript_tag '$(document).on("page:change", Factoids.highlight);', nonce: true %h2.float_left = link_to t('.project_Summary'), project_path(@project) diff --git a/app/views/layouts/tracking_scripts/_google_analytics.html.haml b/app/views/layouts/tracking_scripts/_google_analytics.html.haml index 3d66093da..fc57bba09 100644 --- a/app/views/layouts/tracking_scripts/_google_analytics.html.haml +++ b/app/views/layouts/tracking_scripts/_google_analytics.html.haml @@ -1,6 +1,7 @@ %script{async: "", src: "https://www.googletagmanager.com/gtag/js?id=G-6NX4NYJ2SJ"} -:javascript - window.dataLayer = window.dataLayer || []; - function gtag(){dataLayer.push(arguments);} - gtag('js', new Date()); - gtag('config', 'G-6NX4NYJ2SJ'); +%script{ nonce: content_security_policy_nonce } + :plain + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'G-6NX4NYJ2SJ'); diff --git a/app/views/oh_admin/license_permissions/new.html.haml b/app/views/oh_admin/license_permissions/new.html.haml index 0c0b829f8..08bd049fc 100644 --- a/app/views/oh_admin/license_permissions/new.html.haml +++ b/app/views/oh_admin/license_permissions/new.html.haml @@ -47,12 +47,13 @@ - else %h2= 'No License Permissions Found' -:javascript - function ToggleSelection(radio) { - var elements = document.getElementsByName(radio.name); - for (var i = 0, l = elements.length; i < l; i++) { - if (elements[i] != radio) { - elements[i].checked = false; + %script{ nonce: content_security_policy_nonce } + :plain + function ToggleSelection(radio) { + var elements = document.getElementsByName(radio.name); + for (var i = 0, l = elements.length; i < l; i++) { + if (elements[i] != radio) { + elements[i].checked = false; + } + } } - } - } diff --git a/app/views/project_licenses/new.html.haml b/app/views/project_licenses/new.html.haml index a279d5e62..95bffbef6 100644 --- a/app/views/project_licenses/new.html.haml +++ b/app/views/project_licenses/new.html.haml @@ -9,7 +9,7 @@ $('#error').show(); \ } \ });" - javascript_tag(js) + javascript_tag(js, nonce: true) end - content_for :header_title do diff --git a/app/views/project_widgets/_cocomo_js.html.haml b/app/views/project_widgets/_cocomo_js.html.haml index cdc4a5f67..caaa70fc9 100644 --- a/app/views/project_widgets/_cocomo_js.html.haml +++ b/app/views/project_widgets/_cocomo_js.html.haml @@ -1,63 +1,64 @@ -:javascript - function number_with_delimiter(n) { - var d = ","; - n = n.toString(); +%script{ nonce: content_security_policy_nonce } + :plain + function number_with_delimiter(n) { + var d = ","; + n = n.toString(); - if (n.length > 3) { - var mod = n.length % 3; - var output = (mod > 0 ? (n.substring(0,mod)) : ""); - for (i=0 ; i < Math.floor(n.length / 3); i++) { - if ((mod == 0) && (i == 0)) - output += n.substring(mod+ 3 * i, mod + 3 * i + 3); - else - output+= d + n.substring(mod + 3 * i, mod + 3 * i + 3); + if (n.length > 3) { + var mod = n.length % 3; + var output = (mod > 0 ? (n.substring(0,mod)) : ""); + for (i=0 ; i < Math.floor(n.length / 3); i++) { + if ((mod == 0) && (i == 0)) + output += n.substring(mod+ 3 * i, mod + 3 * i + 3); + else + output+= d + n.substring(mod + 3 * i, mod + 3 * i + 3); + } + return output; + } + else { + return n; } - return output; - } - else { - return n; } - } - function calc_man_years(loc) { - var a_term = 2.4; - var b_term = 1.05; - var months = a_term * Math.pow(loc/1000.0, b_term); - return months/12; - } + function calc_man_years(loc) { + var a_term = 2.4; + var b_term = 1.05; + var months = a_term * Math.pow(loc/1000.0, b_term); + return months/12; + } - function loc_from_index(i) { - var cocomo_loc = document.getElementById("cocomo_loc_dropdown"); - return parseInt(cocomo_loc.options[i].value); - } + function loc_from_index(i) { + var cocomo_loc = document.getElementById("cocomo_loc_dropdown"); + return parseInt(cocomo_loc.options[i].value); + } - function update_cocomo() { - var cocomo_loc = document.getElementById("cocomo_loc_dropdown"); - var man_years = 0; - var loc_markup = loc_from_index(1); - var loc_code = loc_from_index(2); - var loc = 0; + function update_cocomo() { + var cocomo_loc = document.getElementById("cocomo_loc_dropdown"); + var man_years = 0; + var loc_markup = loc_from_index(1); + var loc_code = loc_from_index(2); + var loc = 0; - switch(cocomo_loc.selectedIndex) { - case 0: - loc = loc_markup + loc_code; - man_years = calc_man_years(loc_markup) + calc_man_years(loc_code); - break; - case 1: - loc = loc_markup; - man_years = calc_man_years(loc); - break; - case 2: - loc = loc_code; - man_years = calc_man_years(loc); - break; - } + switch(cocomo_loc.selectedIndex) { + case 0: + loc = loc_markup + loc_code; + man_years = calc_man_years(loc_markup) + calc_man_years(loc_code); + break; + case 1: + loc = loc_markup; + man_years = calc_man_years(loc); + break; + case 2: + loc = loc_code; + man_years = calc_man_years(loc); + break; + } - salary = parseFloat(document.getElementById("cocomo_salary").value); - final_cost = man_years * salary; - if (isNaN(final_cost)) final_cost = 0; + salary = parseFloat(document.getElementById("cocomo_salary").value); + final_cost = man_years * salary; + if (isNaN(final_cost)) final_cost = 0; - document.getElementById("cocomo_years").innerHTML = number_with_delimiter(Math.round(man_years)); - document.getElementById("cocomo_loc").innerHTML = number_with_delimiter(Math.round(loc)); - document.getElementById("cocomo_value").innerHTML = number_with_delimiter(Math.round(final_cost)); - } + document.getElementById("cocomo_years").innerHTML = number_with_delimiter(Math.round(man_years)); + document.getElementById("cocomo_loc").innerHTML = number_with_delimiter(Math.round(loc)); + document.getElementById("cocomo_value").innerHTML = number_with_delimiter(Math.round(final_cost)); + } diff --git a/app/views/project_widgets/_ohloh_code_header.html.haml b/app/views/project_widgets/_ohloh_code_header.html.haml index bd48c8cb1..a60c118bd 100644 --- a/app/views/project_widgets/_ohloh_code_header.html.haml +++ b/app/views/project_widgets/_ohloh_code_header.html.haml @@ -1,10 +1,11 @@ -:javascript - function validate_ohloh_search_form(val){ - val = val.replace(/^\s+|\s+$/g, ''); - if(val == 'Enter Search Terms...' || val == '') - return false; - return true; - } +%script{ nonce: content_security_policy_nonce } + :plain + function validate_ohloh_search_form(val){ + val = val.replace(/^\s+|\s+$/g, ''); + if(val == 'Enter Search Terms...' || val == '') + return false; + return true; + } = render partial: 'widgets/web_fonts' diff --git a/app/views/project_widgets/_project_users_js.html.haml b/app/views/project_widgets/_project_users_js.html.haml index 2fca3f7c0..3656b4a1d 100644 --- a/app/views/project_widgets/_project_users_js.html.haml +++ b/app/views/project_widgets/_project_users_js.html.haml @@ -1,29 +1,31 @@ :ruby background = '-webkit-gradient(linear, left top, right bottom, color-stop(0%, #828181), '\ 'color-stop(55%, #A4A3A3), color-stop(130%, #828181))' -:javascript - function mouseOverForUsers(parent) { - var elem = parent.getElementsByClassName('used_link')[0]; - elem.style.background = '#ffffff'; - elem.style.backgroundColor = '#ffffff'; - elem.style.color = '#000000'; - } + js = <<~JS + function mouseOverForUsers(parent) { + var elem = parent.getElementsByClassName('used_link')[0]; + elem.style.background = '#ffffff'; + elem.style.backgroundColor = '#ffffff'; + elem.style.color = '#000000'; + } - function mouseOutForUsers(parent) { - var elem = parent.getElementsByClassName('used_link')[0]; - elem.style.color = '#ffffff'; - elem.style.background = '#828181'; - elem.style.background = 'linear-gradient(to right, #828181, #A4A3A3, #828181)'; - elem.style.background = '#{background}'; - elem.style.backgroundColor = '#828181'; - } + function mouseOutForUsers(parent) { + var elem = parent.getElementsByClassName('used_link')[0]; + elem.style.color = '#ffffff'; + elem.style.background = '#828181'; + elem.style.background = 'linear-gradient(to right, #828181, #A4A3A3, #828181)'; + elem.style.background = '#{background}'; + elem.style.backgroundColor = '#828181'; + } - function mouseOverForUsersWithoutStyle(parent) { - parent.getElementsByClassName('non_css_used_link')[0].style.color = '#000'; - parent.getElementsByClassName('non_css_used_link')[0].style.fontWeight = 'bold'; - } + function mouseOverForUsersWithoutStyle(parent) { + parent.getElementsByClassName('non_css_used_link')[0].style.color = '#000'; + parent.getElementsByClassName('non_css_used_link')[0].style.fontWeight = 'bold'; + } - function mouseOutForUsersWithoutStyle(parent) { - parent.getElementsByClassName('non_css_used_link')[0].style.color = '#5F6062'; - parent.getElementsByClassName('non_css_used_link')[0].style.fontWeight = 'normal'; - } + function mouseOutForUsersWithoutStyle(parent) { + parent.getElementsByClassName('non_css_used_link')[0].style.color = '#5F6062'; + parent.getElementsByClassName('non_css_used_link')[0].style.fontWeight = 'normal'; + } + JS += javascript_tag js, nonce: true diff --git a/app/views/project_widgets/_users_logo_js.html.haml b/app/views/project_widgets/_users_logo_js.html.haml index c464e01b8..3c8ded09f 100644 --- a/app/views/project_widgets/_users_logo_js.html.haml +++ b/app/views/project_widgets/_users_logo_js.html.haml @@ -1,10 +1,11 @@ -:javascript - function usersLogoMouseOver(elem){ - elem.style.background='#A5A3A5'; - elem.style.color='#ffffff'; - } +%script{ nonce: content_security_policy_nonce } + :plain + function usersLogoMouseOver(elem){ + elem.style.background='#A5A3A5'; + elem.style.color='#ffffff'; + } - function usersLogoMouseOut(elem){ - elem.style.background='none transparent'; - elem.style.color='#000000'; - } + function usersLogoMouseOut(elem){ + elem.style.background='none transparent'; + elem.style.color='#000000'; + } diff --git a/app/views/projects/estimated_cost.html.haml b/app/views/projects/estimated_cost.html.haml index 1cd07df8a..39700eebc 100644 --- a/app/views/projects/estimated_cost.html.haml +++ b/app/views/projects/estimated_cost.html.haml @@ -22,7 +22,7 @@   .col-md-6 - js = "var project_analysis = #{man_years.to_json};" - %script{ type: 'text/javascript' } + %script{ type: 'text/javascript', nonce: content_security_policy_nonce } \ // diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 0fea66b50..082c23828 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -1,13 +1,20 @@ # frozen_string_literal: true -allowed_script_sources = %w[www.google.com www.gstatic.com maps.googleapis.com maps.gstatic.com s7.addthis.com - cdnjs.cloudflare.com] +allowed_script_sources = %w[https://www.google.com https://www.gstatic.com https://maps.googleapis.com + https://maps.gstatic.com https://s7.addthis.com https://cdnjs.cloudflare.com + https://www.googletagmanager.com] Rails.application.config.content_security_policy do |policy| policy.default_src :self, :https + policy.connect_src :self, :https, 'maps.googleapis.com' policy.font_src :self, :https, :data policy.img_src :self, :https, :data policy.object_src :none - policy.script_src :self, :https, :unsafe_inline, :unsafe_eval, *allowed_script_sources + policy.script_src :self, *allowed_script_sources policy.style_src :self, :https, :unsafe_inline + policy.base_uri :self + policy.form_action :self end + +Rails.application.config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) } +Rails.application.config.content_security_policy_nonce_directives = %w[script-src]