diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 96d3c11a659..06e8be21459 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -95,9 +95,10 @@ module ApplicationHelper path = ActionController::Base.helpers.asset_path("#{script}.js") if GlobalSetting.use_s3? && GlobalSetting.s3_cdn_url + resolved_s3_asset_cdn_url = GlobalSetting.s3_asset_cdn_url.presence || GlobalSetting.s3_cdn_url if GlobalSetting.cdn_url folder = ActionController::Base.config.relative_url_root || "/" - path = path.gsub(File.join(GlobalSetting.cdn_url, folder, "/"), File.join(GlobalSetting.s3_cdn_url, "/")) + path = path.gsub(File.join(GlobalSetting.cdn_url, folder, "/"), File.join(resolved_s3_asset_cdn_url, "/")) else # we must remove the subfolder path here, assets are uploaded to s3 # without it getting involved @@ -105,7 +106,7 @@ module ApplicationHelper path = path.sub(ActionController::Base.config.relative_url_root, "") end - path = "#{GlobalSetting.s3_cdn_url}#{path}" + path = "#{resolved_s3_asset_cdn_url}#{path}" end # assets needed for theme testing are not compressed because they take a fair diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index d45d0d1f4fa..74b202d0645 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -229,6 +229,9 @@ s3_endpoint = s3_http_continue_timeout = s3_install_cors_rule = +# Optionally, specify a separate CDN to be used for static JS assets stored on S3 +s3_asset_cdn_url = + ### rate limits apply to all sites max_user_api_reqs_per_minute = 20 max_user_api_reqs_per_day = 2880 diff --git a/lib/content_security_policy/default.rb b/lib/content_security_policy/default.rb index 7245bac31d2..ef67672b059 100644 --- a/lib/content_security_policy/default.rb +++ b/lib/content_security_policy/default.rb @@ -37,7 +37,7 @@ class ContentSecurityPolicy ['/svg-sprite/', false, true, false], ] - def script_assets(base = base_url, s3_cdn = GlobalSetting.s3_cdn_url, cdn = GlobalSetting.cdn_url, worker: false) + def script_assets(base = base_url, s3_cdn = GlobalSetting.s3_asset_cdn_url.presence || GlobalSetting.s3_cdn_url, cdn = GlobalSetting.cdn_url, worker: false) SCRIPT_ASSET_DIRECTORIES.map do |dir, can_use_s3_cdn, can_use_cdn, for_worker| next if worker && !for_worker if can_use_s3_cdn && s3_cdn diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index e00f88c5eaf..f16b287d055 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -88,6 +88,12 @@ RSpec.describe ApplicationHelper do link = helper.preload_script('discourse/tests/theme_qunit_ember_jquery') expect(link).to eq(script_tag("https://s3cdn.com/assets/discourse/tests/theme_qunit_ember_jquery.js")) end + + it "uses separate asset CDN if configured" do + global_setting :s3_asset_cdn_url, "https://s3-asset-cdn.example.com" + expect(helper.preload_script("discourse")).to include("https://s3-asset-cdn.example.com/assets/discourse.js") + end + end end diff --git a/spec/lib/content_security_policy_spec.rb b/spec/lib/content_security_policy_spec.rb index 8fba63c1f74..46f11f63be6 100644 --- a/spec/lib/content_security_policy_spec.rb +++ b/spec/lib/content_security_policy_spec.rb @@ -133,6 +133,19 @@ RSpec.describe ContentSecurityPolicy do https://cdn.com/theme-javascripts/ http://test.localhost/extra-locales/ ]) + + global_setting(:s3_asset_cdn_url, 'https://s3-asset-cdn.com') + + script_srcs = parse(policy)['script-src'] + expect(script_srcs).to include(*%w[ + https://s3-asset-cdn.com/assets/ + https://s3-asset-cdn.com/brotli_asset/ + https://cdn.com/highlight-js/ + https://cdn.com/javascripts/ + https://cdn.com/plugins/ + https://cdn.com/theme-javascripts/ + http://test.localhost/extra-locales/ + ]) end it 'adds subfolder to CDN assets' do