2023-07-28 07:53:44 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Middleware
|
2024-02-16 06:16:54 -05:00
|
|
|
class CspScriptNonceInjector
|
2024-02-16 07:15:55 -05:00
|
|
|
PLACEHOLDER_HEADER = "Discourse-CSP-Nonce-Placeholder"
|
|
|
|
|
2023-07-28 07:53:44 -04:00
|
|
|
def initialize(app, settings = {})
|
|
|
|
@app = app
|
|
|
|
end
|
|
|
|
|
|
|
|
def call(env)
|
|
|
|
status, headers, response = @app.call(env)
|
|
|
|
|
2024-02-16 07:15:55 -05:00
|
|
|
if nonce_placeholder = headers.delete(PLACEHOLDER_HEADER)
|
2024-02-16 06:16:54 -05:00
|
|
|
nonce = SecureRandom.alphanumeric(25)
|
2023-07-28 07:53:44 -04:00
|
|
|
parts = []
|
2024-02-16 06:16:54 -05:00
|
|
|
response.each { |part| parts << part.to_s.gsub(nonce_placeholder, nonce) }
|
2023-07-28 07:53:44 -04:00
|
|
|
%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
|