lib/rspec/webservice_matchers/enforce_https_everywhere.rb
# frozen_string_literal: true
require 'faraday'
require 'web_test/util'
require 'rspec/webservice_matchers/redirect_helpers'
module RSpec
module WebserviceMatchers
module EnforceHttpsEverywhere
# This is a high level matcher which checks three things:
# 1. Permanent redirect
# 2. to an https url
# 3. which is correctly configured
RSpec::Matchers.define :enforce_https_everywhere do
include RedirectHelpers
error_msg = status = final_protocol = has_valid_cert = nil
match do |domain_name_or_url|
begin
status, new_url, final_protocol = get_info(WebTest::Util.make_domain_name(domain_name_or_url))
meets_expectations?(status, final_protocol, WebTest::Util.valid_cert?(new_url))
rescue Faraday::Error::ConnectionFailed
error_msg = 'Connection failed'
false
end
end
def get_info(domain_name)
status, headers = WebTest::Util.head(domain_name)
location = headers['location']
/^(https?)/ =~ location
protocol = Regexp.last_match(1) || nil
[status, location, protocol]
end
def meets_expectations?(status, protocol, valid_cert)
permanent_redirect?(status) && (protocol == 'https') && valid_cert
end
# Create a compound error message listing all of the
# relevant actual values received.
failure_message do
error_msg || higher_level_errors(status, final_protocol, has_valid_cert)
end
def higher_level_errors(status, protocol, cert_is_valid)
errors = []
unless permanent_redirect?(status)
errors << "received status #{status} instead of 301"
end
if protocol && (protocol != 'https')
errors << "destination uses protocol #{protocol.upcase}"
end
errors << "there's no valid SSL certificate" unless cert_is_valid
WebTest::Util.error_message(errors)
end
end
end
end
end