Skip to content

Commit

Permalink
feat: add Content Security Policy header
Browse files Browse the repository at this point in the history
  • Loading branch information
bethesque committed Jun 15, 2020
1 parent 081d158 commit fd2e81f
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 0 deletions.
11 changes: 11 additions & 0 deletions lib/pact_broker/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
require 'rack/pact_broker/convert_404_to_hal'
require 'rack/pact_broker/reset_thread_data'
require 'rack/pact_broker/add_vary_header'
require 'rack/pact_broker/use_when'
require 'sucker_punch'

module PactBroker

class App
include PactBroker::Logging
using Rack::PactBroker::UseWhen

attr_accessor :configuration

Expand Down Expand Up @@ -162,6 +164,15 @@ def configure_middleware
# NOTE THAT NONE OF THIS IS PROTECTED BY AUTH - is that ok?
if configuration.use_rack_protection
@app_builder.use Rack::Protection, except: [:path_traversal, :remote_token, :session_hijacking, :http_origin]

is_hal_browser = ->(env) { env['PATH_INFO'] == '/hal-browser/browser.html' }
not_hal_browser = ->(env) { env['PATH_INFO'] != '/hal-browser/browser.html' }

@app_builder.use_when not_hal_browser,
Rack::Protection::ContentSecurityPolicy, configuration.content_security_policy
@app_builder.use_when is_hal_browser,
Rack::Protection::ContentSecurityPolicy,
configuration.content_security_policy.merge(configuration.hal_browser_content_security_policy_overrides)
end
@app_builder.use Rack::PactBroker::InvalidUriProtection
@app_builder.use Rack::PactBroker::ResetThreadData
Expand Down
15 changes: 15 additions & 0 deletions lib/pact_broker/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Configuration
attr_accessor :semver_formats
attr_accessor :enable_public_badge_access, :shields_io_base_url, :badge_provider_mode
attr_accessor :disable_ssl_verification
attr_accessor :content_security_policy, :hal_browser_content_security_policy_overrides
attr_accessor :base_equality_only_on_content_that_affects_verification_results
attr_reader :api_error_reporters
attr_reader :custom_logger
Expand Down Expand Up @@ -90,6 +91,20 @@ def self.default_configuration
config.webhook_http_method_whitelist = ['POST']
config.webhook_scheme_whitelist = ['https']
config.webhook_host_whitelist = []
# TODO get rid of unsafe-inline
config.content_security_policy = {
script_src: "'self' 'unsafe-inline'",
style_src: "'self' 'unsafe-inline'",
img_src: "'self' data:",
font_src: "'self' data:",
base_uri: "'self'",
frame_src: "'self'",
frame_ancestors: "'self'"
}
config.hal_browser_content_security_policy_overrides = {
script_src: "'self' 'unsafe-inline' 'unsafe-eval'",
frame_ancestors: "'self'"
}
config
end

Expand Down
55 changes: 55 additions & 0 deletions lib/rack/pact_broker/use_when.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
=begin
Conditionally use Rack Middleware.
Usage:
condition_proc = ->(env) { env['PATH_INFO'] == '/match' }
use_when condition_proc, SomeMiddleware, options
I feel sure there must be something like this officially supported somewhere, but I can't find it.
=end

module Rack
module PactBroker
module UseWhen
class ConditionallyUseMiddleware
def initialize(app, condition_proc, middleware, *args, &block)
@app_without_middleware = app
@condition_proc = condition_proc
@middleware = middleware
@args = args
@block = block
end

def call(env)
if condition_proc.call(env)
app_with_middleware.call(env)
else
app_without_middleware.call(env)
end
end

private

attr_reader :app_without_middleware, :condition_proc, :middleware, :args, :block

def app_with_middleware
@app_with_middleware ||= begin
rack_builder = ::Rack::Builder.new
rack_builder.use middleware, *args, &block
rack_builder.run app_without_middleware
rack_builder.to_app
end
end
end

refine Rack::Builder do
def use_when(condition_proc, middleware, *args, &block)
use(ConditionallyUseMiddleware, condition_proc, middleware, *args, &block)
end
end
end
end
end
49 changes: 49 additions & 0 deletions spec/lib/rack/pact_broker/use_when_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'rack/pact_broker/use_when'
require 'rack/test'

module Rack
module PactBroker
describe UseWhen do

using Rack::PactBroker::UseWhen
include Rack::Test::Methods

class TestMiddleware
def initialize(app, additional_headers)
@app = app
@additional_headers = additional_headers
end

def call(env)
status, headers, body = @app.call(env)
[status, headers.merge(@additional_headers), body]
end
end

let(:app) do
target_app = -> (env) { [200, {}, []] }
builder = Rack::Builder.new
condition = ->(env) { env['PATH_INFO'] == '/match' }
builder.use_when condition, TestMiddleware, { "Foo" => "Bar" }
builder.run target_app
builder.to_app
end

context "when the condition matches" do
subject { get '/match' }

it "uses the middleware" do
expect(subject.headers).to include "Foo" => "Bar"
end
end

context "when the condition does not match" do
subject { get '/no-match' }

it "does not use the middleware" do
expect(subject.headers.keys).to_not include "Foo"
end
end
end
end
end

0 comments on commit fd2e81f

Please sign in to comment.