DEV: Support passing relative URLs CSP builder (#19176)

Raw paths like `/test/path` are not supported natively in the CSP. This commit prepends the site's base URL to these paths. This allows plugins to add 'local' assets to the CSP without needing to hardcode the site's hostname.
This commit is contained in:
David Taylor 2022-11-24 11:27:47 +00:00 committed by GitHub
parent a34838d671
commit 174a8b431b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 8 deletions

View File

@ -27,12 +27,13 @@ class ContentSecurityPolicy
def initialize(base_url:)
@directives = Default.new(base_url: base_url).directives
@base_url = base_url
end
def <<(extension)
return unless valid_extension?(extension)
extension.each { |directive, sources| extend_directive(normalize(directive), sources) }
extension.each { |directive, sources| extend_directive(normalize_directive(directive), sources) }
end
def build
@ -51,20 +52,27 @@ class ContentSecurityPolicy
private
def normalize(directive)
def normalize_directive(directive)
directive.to_s.gsub('-', '_').to_sym
end
def normalize_source(source)
if source.starts_with?("/")
"#{@base_url}#{source}"
else
source
end
rescue URI::ParseError
source
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
sources = Array(sources).map { |s| normalize_source(s) }
@directives[directive].concat(sources)
@directives[directive].delete(:none) if @directives[directive].count > 1
end

View File

@ -6,7 +6,7 @@
# authors: xrav3nz
extend_content_security_policy(
script_src: ['https://from-plugin.com'],
script_src: ['https://from-plugin.com', '/local/path'],
object_src: ['https://test-stripping.com'],
frame_ancestors: ['https://frame-ancestors-plugin.ext'],
manifest_src: ['https://manifest-src.com']

View File

@ -222,6 +222,7 @@ RSpec.describe ContentSecurityPolicy do
plugin.enabled = true
expect(parse(policy)['script-src']).to include('https://from-plugin.com')
expect(parse(policy)['script-src']).to include('http://test.localhost/local/path')
expect(parse(policy)['object-src']).to include('https://test-stripping.com')
expect(parse(policy)['object-src']).to_not include("'none'")
expect(parse(policy)['manifest-src']).to include("'self'")