discourse/lib/middleware/csp_script_nonce_injector.rb

29 lines
822 B
Ruby

# frozen_string_literal: true
module Middleware
class CspScriptNonceInjector
PLACEHOLDER_HEADER = "Discourse-CSP-Nonce-Placeholder"
def initialize(app, settings = {})
@app = app
end
def call(env)
status, headers, response = @app.call(env)
if nonce_placeholder = headers.delete(PLACEHOLDER_HEADER)
nonce = SecureRandom.alphanumeric(25)
parts = []
response.each { |part| parts << part.to_s.gsub(nonce_placeholder, nonce) }
%w[Content-Security-Policy Content-Security-Policy-Report-Only].each do |name|
next if headers[name].blank?
headers[name] = headers[name].sub("script-src ", "script-src 'nonce-#{nonce}' ")
end
[status, headers, parts]
else
[status, headers, response]
end
end
end
end