mirror of
https://github.com/discourse/discourse.git
synced 2025-05-23 07:31:02 +08:00
DEV: Remove unsafe-eval from development CSP (#8569)
- Refactor source_url to avoid using eval in development - Precompile handlebars in development - Include template compilers when running qunit - Remove unsafe-eval in development CSP - Include unsafe-eval only for qunit routes in development
This commit is contained in:
1
app/assets/javascripts/template_include.js
Normal file
1
app/assets/javascripts/template_include.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
//= require handlebars.runtime
|
@ -1,8 +0,0 @@
|
|||||||
<%
|
|
||||||
if Rails.env.development? || Rails.env.test?
|
|
||||||
require_asset ("handlebars.js")
|
|
||||||
require_asset ("ember-template-compiler.js")
|
|
||||||
else
|
|
||||||
require_asset ("handlebars.runtime.js")
|
|
||||||
end
|
|
||||||
%>
|
|
||||||
|
@ -30,7 +30,7 @@ Discourse::Application.configure do
|
|||||||
config.active_record.migration_error = :page_load
|
config.active_record.migration_error = :page_load
|
||||||
config.watchable_dirs['lib'] = [:rb]
|
config.watchable_dirs['lib'] = [:rb]
|
||||||
|
|
||||||
config.handlebars.precompile = false
|
config.handlebars.precompile = true
|
||||||
|
|
||||||
# we recommend you use mailcatcher https://github.com/sj26/mailcatcher
|
# we recommend you use mailcatcher https://github.com/sj26/mailcatcher
|
||||||
config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
|
config.action_mailer.smtp_settings = { address: "localhost", port: 1025 }
|
||||||
|
@ -5,7 +5,7 @@ require 'discourse_iife'
|
|||||||
Rails.application.config.assets.configure do |env|
|
Rails.application.config.assets.configure do |env|
|
||||||
env.register_preprocessor('application/javascript', DiscourseIIFE)
|
env.register_preprocessor('application/javascript', DiscourseIIFE)
|
||||||
|
|
||||||
unless Rails.env.production? || ENV["DISABLE_EVAL"]
|
unless Rails.env.production?
|
||||||
require 'source_url'
|
require 'source_url'
|
||||||
env.register_postprocessor('application/javascript', SourceURL)
|
env.register_postprocessor('application/javascript', SourceURL)
|
||||||
end
|
end
|
||||||
|
@ -4,8 +4,8 @@ require 'content_security_policy/extension'
|
|||||||
|
|
||||||
class ContentSecurityPolicy
|
class ContentSecurityPolicy
|
||||||
class << self
|
class << self
|
||||||
def policy(theme_ids = [])
|
def policy(theme_ids = [], path_info: "/")
|
||||||
new.build(theme_ids)
|
new.build(theme_ids, path_info: path_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
def base_url
|
def base_url
|
||||||
@ -14,12 +14,13 @@ class ContentSecurityPolicy
|
|||||||
attr_writer :base_url
|
attr_writer :base_url
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(theme_ids)
|
def build(theme_ids, path_info: "/")
|
||||||
builder = Builder.new
|
builder = Builder.new
|
||||||
|
|
||||||
Extension.theme_extensions(theme_ids).each { |extension| builder << extension }
|
Extension.theme_extensions(theme_ids).each { |extension| builder << extension }
|
||||||
Extension.plugin_extensions.each { |extension| builder << extension }
|
Extension.plugin_extensions.each { |extension| builder << extension }
|
||||||
builder << Extension.site_setting_extension
|
builder << Extension.site_setting_extension
|
||||||
|
builder << Extension.path_specific_extension(path_info)
|
||||||
|
|
||||||
builder.build
|
builder.build
|
||||||
end
|
end
|
||||||
|
@ -51,7 +51,6 @@ class ContentSecurityPolicy
|
|||||||
"#{base_url}/mini-profiler-resources/",
|
"#{base_url}/mini-profiler-resources/",
|
||||||
*script_assets
|
*script_assets
|
||||||
].tap do |sources|
|
].tap do |sources|
|
||||||
sources << :unsafe_eval if Rails.env.development? # TODO Remove this when we stop using `eval` in development mode
|
|
||||||
sources << 'https://www.google-analytics.com/analytics.js' if SiteSetting.ga_universal_tracking_code.present?
|
sources << 'https://www.google-analytics.com/analytics.js' if SiteSetting.ga_universal_tracking_code.present?
|
||||||
sources << 'https://www.googletagmanager.com/gtm.js' if SiteSetting.gtm_container_id.present?
|
sources << 'https://www.googletagmanager.com/gtm.js' if SiteSetting.gtm_container_id.present?
|
||||||
end
|
end
|
||||||
|
@ -7,6 +7,13 @@ class ContentSecurityPolicy
|
|||||||
{ script_src: SiteSetting.content_security_policy_script_src.split('|') }
|
{ script_src: SiteSetting.content_security_policy_script_src.split('|') }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def path_specific_extension(path_info)
|
||||||
|
{}.tap do |obj|
|
||||||
|
for_qunit_route = !Rails.env.production? && ["/qunit", "/wizard/qunit"].include?(path_info)
|
||||||
|
obj[:script_src] = :unsafe_eval if for_qunit_route
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def plugin_extensions
|
def plugin_extensions
|
||||||
[].tap do |extensions|
|
[].tap do |extensions|
|
||||||
Discourse.plugins.each do |plugin|
|
Discourse.plugins.each do |plugin|
|
||||||
|
@ -15,8 +15,9 @@ class ContentSecurityPolicy
|
|||||||
ContentSecurityPolicy.base_url = request.host_with_port if Rails.env.development?
|
ContentSecurityPolicy.base_url = request.host_with_port if Rails.env.development?
|
||||||
|
|
||||||
theme_ids = env[:resolved_theme_ids]
|
theme_ids = env[:resolved_theme_ids]
|
||||||
headers['Content-Security-Policy'] = policy(theme_ids) if SiteSetting.content_security_policy
|
|
||||||
headers['Content-Security-Policy-Report-Only'] = policy(theme_ids) if SiteSetting.content_security_policy_report_only
|
headers['Content-Security-Policy'] = policy(theme_ids, path_info: env["PATH_INFO"]) if SiteSetting.content_security_policy
|
||||||
|
headers['Content-Security-Policy-Report-Only'] = policy(theme_ids, path_info: env["PATH_INFO"]) if SiteSetting.content_security_policy_report_only
|
||||||
|
|
||||||
response
|
response
|
||||||
end
|
end
|
||||||
|
@ -16,10 +16,9 @@ class SourceURL < Tilt::Template
|
|||||||
end
|
end
|
||||||
|
|
||||||
def evaluate(scope, locals, &block)
|
def evaluate(scope, locals, &block)
|
||||||
code = +"eval("
|
code = +"\n//# BEGIN sourceURL=#{scope.logical_path}\n"
|
||||||
code << data.inspect
|
code << data
|
||||||
code << " + \"\\n//# sourceURL=#{scope.logical_path}\""
|
code << "\n//# END sourceURL=#{scope.logical_path}\n"
|
||||||
code << ");\n"
|
|
||||||
code
|
code
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -123,6 +123,12 @@ describe ContentSecurityPolicy do
|
|||||||
Discourse.plugins.pop
|
Discourse.plugins.pop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'only includes unsafe-inline for qunit paths' do
|
||||||
|
expect(parse(policy(path_info: "/qunit"))['script-src']).to include("'unsafe-eval'")
|
||||||
|
expect(parse(policy(path_info: "/wizard/qunit"))['script-src']).to include("'unsafe-eval'")
|
||||||
|
expect(parse(policy(path_info: "/"))['script-src']).to_not include("'unsafe-eval'")
|
||||||
|
end
|
||||||
|
|
||||||
context "with a theme" do
|
context "with a theme" do
|
||||||
let!(:theme) {
|
let!(:theme) {
|
||||||
Fabricate(:theme).tap do |t|
|
Fabricate(:theme).tap do |t|
|
||||||
@ -174,7 +180,7 @@ describe ContentSecurityPolicy do
|
|||||||
end.to_h
|
end.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
def policy(theme_ids = [])
|
def policy(theme_ids = [], path_info: "/")
|
||||||
ContentSecurityPolicy.policy(theme_ids)
|
ContentSecurityPolicy.policy(theme_ids, path_info: path_info)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
//= require env
|
//= require env
|
||||||
//= require jquery.debug
|
//= require jquery.debug
|
||||||
//= require jquery.ui.widget
|
//= require jquery.ui.widget
|
||||||
//= require handlebars
|
|
||||||
//= require ember.debug
|
//= require ember.debug
|
||||||
//= require ember-template-compiler
|
|
||||||
//= require message-bus
|
//= require message-bus
|
||||||
//= require qunit/qunit/qunit
|
//= require qunit/qunit/qunit
|
||||||
//= require ember-qunit
|
//= require ember-qunit
|
||||||
@ -26,6 +24,11 @@
|
|||||||
//= require application
|
//= require application
|
||||||
//= require admin
|
//= require admin
|
||||||
|
|
||||||
|
// These are not loaded in prod or development
|
||||||
|
// But we need them for testing handlebars templates in qunit
|
||||||
|
//= require handlebars
|
||||||
|
//= require ember-template-compiler
|
||||||
|
|
||||||
//= require sinon/pkg/sinon
|
//= require sinon/pkg/sinon
|
||||||
|
|
||||||
//= require helpers/assertions
|
//= require helpers/assertions
|
||||||
|
Reference in New Issue
Block a user