discourse/lib/content_security_policy/builder.rb
Kyle Zhao 488fba3c5f
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
2018-11-30 09:51:45 -05:00

79 lines
1.6 KiB
Ruby

# 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