mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: allow plugins and themes to extend the default CSP (#6704)
* FEATURE: allow plugins and themes to extend the default CSP For plugins: ``` extend_content_security_policy( script_src: ['https://domain.com/script.js', 'https://your-cdn.com/'], style_src: ['https://domain.com/style.css'] ) ``` For themes and components: ``` extend_content_security_policy: type: list default: "script_src:https://domain.com/|style_src:https://domain.com" ``` * clear CSP base url before each test we have a test that stubs `Rails.env.development?` to true * Only allow extending directives that core includes, for now
This commit is contained in:
78
lib/content_security_policy/builder.rb
Normal file
78
lib/content_security_policy/builder.rb
Normal file
@@ -0,0 +1,78 @@
|
||||
# frozen_string_literal: true
|
||||
require_dependency 'content_security_policy/default'
|
||||
|
||||
class ContentSecurityPolicy
|
||||
class Builder
|
||||
EXTENDABLE_DIRECTIVES = %i[
|
||||
script_src
|
||||
worker_src
|
||||
].freeze
|
||||
|
||||
# Make extending these directives no-op, until core includes them in default CSP
|
||||
TO_BE_EXTENDABLE = %i[
|
||||
base_uri
|
||||
connect_src
|
||||
default_src
|
||||
font_src
|
||||
form_action
|
||||
frame_ancestors
|
||||
frame_src
|
||||
img_src
|
||||
manifest_src
|
||||
media_src
|
||||
object_src
|
||||
prefetch_src
|
||||
style_src
|
||||
].freeze
|
||||
|
||||
def initialize
|
||||
@directives = Default.new.directives
|
||||
end
|
||||
|
||||
def <<(extension)
|
||||
return unless valid_extension?(extension)
|
||||
|
||||
extension.each { |directive, sources| extend_directive(normalize(directive), sources) }
|
||||
end
|
||||
|
||||
def build
|
||||
policy = ActionDispatch::ContentSecurityPolicy.new
|
||||
|
||||
@directives.each do |directive, sources|
|
||||
if sources.is_a?(Array)
|
||||
policy.public_send(directive, *sources)
|
||||
else
|
||||
policy.public_send(directive, sources)
|
||||
end
|
||||
end
|
||||
|
||||
policy.build
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalize(directive)
|
||||
directive.to_s.gsub('-', '_').to_sym
|
||||
end
|
||||
|
||||
def extend_directive(directive, sources)
|
||||
return unless extendable?(directive)
|
||||
|
||||
@directives[directive] ||= []
|
||||
|
||||
if sources.is_a?(Array)
|
||||
@directives[directive].concat(sources)
|
||||
else
|
||||
@directives[directive] << sources
|
||||
end
|
||||
end
|
||||
|
||||
def extendable?(directive)
|
||||
EXTENDABLE_DIRECTIVES.include?(directive)
|
||||
end
|
||||
|
||||
def valid_extension?(extension)
|
||||
extension.is_a?(Hash)
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user