mirror of
https://github.com/discourse/discourse.git
synced 2024-12-18 13:03:46 +08:00
c5e6e271a5
When Discourse first introduced brotli support, reverse-proxy/CDN support for passing through the accept-encoding header to our NGINX server was very poor. Therefore, a separate `/brotli_assets/...` path was introduced to serve the brotli assets. This worked well, but introduces additional complexity and inconsistencies. Nowadays, Brotli encoding is well supported, so we don't need the separate paths any more. Requests can be routed to the asset `.js` URLs, and NGINX will serve the brotli/gzip version of the asset automatically.
113 lines
3.3 KiB
Ruby
113 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
require "content_security_policy"
|
|
|
|
class ContentSecurityPolicy
|
|
class Default
|
|
attr_reader :directives
|
|
|
|
def initialize(base_url:)
|
|
@base_url = base_url
|
|
@directives =
|
|
{}.tap do |directives|
|
|
directives[:upgrade_insecure_requests] = [] if SiteSetting.force_https
|
|
directives[:base_uri] = [:self]
|
|
directives[:object_src] = [:none]
|
|
directives[:script_src] = script_src
|
|
directives[:worker_src] = worker_src
|
|
directives[
|
|
:report_uri
|
|
] = report_uri if SiteSetting.content_security_policy_collect_reports
|
|
directives[:frame_ancestors] = frame_ancestors if restrict_embed?
|
|
directives[:manifest_src] = ["'self'"]
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def base_url
|
|
@base_url
|
|
end
|
|
|
|
SCRIPT_ASSET_DIRECTORIES = [
|
|
# [dir, can_use_s3_cdn, can_use_cdn, for_worker]
|
|
["/assets/", true, true, true],
|
|
["/extra-locales/", false, false, false],
|
|
["/highlight-js/", false, true, false],
|
|
["/javascripts/", false, true, true],
|
|
["/plugins/", false, true, true],
|
|
["/theme-javascripts/", false, true, false],
|
|
["/svg-sprite/", false, true, 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
|
|
s3_cdn + dir
|
|
elsif can_use_cdn && cdn
|
|
cdn + Discourse.base_path + dir
|
|
else
|
|
base + dir
|
|
end
|
|
end
|
|
.compact
|
|
end
|
|
|
|
def script_src
|
|
[
|
|
"#{base_url}/logs/",
|
|
"#{base_url}/sidekiq/",
|
|
"#{base_url}/mini-profiler-resources/",
|
|
*script_assets,
|
|
].tap do |sources|
|
|
sources << :report_sample if SiteSetting.content_security_policy_collect_reports
|
|
sources << :unsafe_eval if Rails.env.development? # TODO remove this once we have proper source maps in dev
|
|
|
|
# Support Ember CLI Live reload
|
|
if Rails.env.development?
|
|
sources << "#{base_url}/ember-cli-live-reload.js"
|
|
sources << "#{base_url}/_lr/"
|
|
end
|
|
|
|
# we need analytics.js still as gtag/js is a script wrapper for it
|
|
if SiteSetting.ga_universal_tracking_code.present?
|
|
sources << "https://www.google-analytics.com/analytics.js"
|
|
end
|
|
if SiteSetting.ga_universal_tracking_code.present? && SiteSetting.ga_version == "v4_gtag"
|
|
sources << "https://www.googletagmanager.com/gtag/js"
|
|
end
|
|
if SiteSetting.gtm_container_id.present?
|
|
sources << "https://www.googletagmanager.com/gtm.js"
|
|
end
|
|
|
|
sources << "'#{SplashScreenHelper.fingerprint}'" if SiteSetting.splash_screen
|
|
end
|
|
end
|
|
|
|
def worker_src
|
|
[
|
|
"'self'", # For service worker
|
|
*script_assets(worker: true),
|
|
]
|
|
end
|
|
|
|
def report_uri
|
|
"#{base_url}/csp_reports"
|
|
end
|
|
|
|
def frame_ancestors
|
|
["'self'", *EmbeddableHost.pluck(:host).map { |host| "https://#{host}" }]
|
|
end
|
|
|
|
def restrict_embed?
|
|
SiteSetting.content_security_policy_frame_ancestors && !SiteSetting.embed_any_origin
|
|
end
|
|
end
|
|
end
|