Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
inherit_gem:
rubocop-github:
- config/default.yml
require: rubocop-performance
plugins:
- rubocop-performance
2 changes: 1 addition & 1 deletion lib/secure_headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def raise_on_unknown_target(target)

def config_and_target(request, target)
config = config_for(request)
target = guess_target(config) unless target
target ||= guess_target(config)
raise_on_unknown_target(target)
[config, target]
end
Expand Down
62 changes: 30 additions & 32 deletions lib/secure_headers/headers/clear_site_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,43 +11,41 @@ class ClearSiteData
EXECUTION_CONTEXTS = "executionContexts".freeze
ALL_TYPES = [CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS]

class << self
# Public: make an clear-site-data header name, value pair
#
# Returns nil if not configured, returns header name and value if configured.
def make_header(config = nil, user_agent = nil)
case config
when nil, OPT_OUT, []
# noop
when Array
[HEADER_NAME, make_header_value(config)]
when true
[HEADER_NAME, make_header_value(ALL_TYPES)]
end
# Public: make an clear-site-data header name, value pair
#
# Returns nil if not configured, returns header name and value if configured.
def self.make_header(config = nil, user_agent = nil)
case config
when nil, OPT_OUT, []
# noop
when Array
[HEADER_NAME, make_header_value(config)]
when true
[HEADER_NAME, make_header_value(ALL_TYPES)]
end
end

def validate_config!(config)
case config
when nil, OPT_OUT, true
# valid
when Array
unless config.all? { |t| t.is_a?(String) }
raise ClearSiteDataConfigError.new("types must be Strings")
end
else
raise ClearSiteDataConfigError.new("config must be an Array of Strings or `true`")
def self.validate_config!(config)
case config
when nil, OPT_OUT, true
# valid
when Array
unless config.all? { |t| t.is_a?(String) }
raise ClearSiteDataConfigError.new("types must be Strings")
end
else
raise ClearSiteDataConfigError.new("config must be an Array of Strings or `true`")
end
end

# Public: Transform a clear-site-data config (an Array of Strings) into a
# String that can be used as the value for the clear-site-data header.
#
# types - An Array of String of types of data to clear.
#
# Returns a String of quoted values that are comma separated.
def make_header_value(types)
types.map { |t| %("#{t}") }.join(", ")
end
# Public: Transform a clear-site-data config (an Array of Strings) into a
# String that can be used as the value for the clear-site-data header.
#
# types - An Array of String of types of data to clear.
#
# Returns a String of quoted values that are comma separated.
def self.make_header_value(types)
types.map { |t| %("#{t}") }.join(", ")
end
end
end
6 changes: 2 additions & 4 deletions lib/secure_headers/headers/cookie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ module SecureHeaders
class CookiesConfigError < StandardError; end
class Cookie

class << self
def validate_config!(config)
CookiesConfig.new(config).validate!
end
def self.validate_config!(config)
CookiesConfig.new(config).validate!
end

attr_reader :raw_cookie, :config
Expand Down
40 changes: 19 additions & 21 deletions lib/secure_headers/headers/expect_certificate_transparency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,29 @@ class ExpectCertificateTransparency
REQUIRED_MAX_AGE_ERROR = "max-age is a required directive.".freeze
INVALID_MAX_AGE_ERROR = "max-age must be a number.".freeze

class << self
# Public: Generate a expect-ct header.
#
# Returns nil if not configured, returns header name and value if
# configured.
def make_header(config, use_agent = nil)
return if config.nil? || config == OPT_OUT
# Public: Generate a expect-ct header.
#
# Returns nil if not configured, returns header name and value if
# configured.
def self.make_header(config, use_agent = nil)
return if config.nil? || config == OPT_OUT

header = new(config)
[HEADER_NAME, header.value]
end
header = new(config)
[HEADER_NAME, header.value]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise ExpectCertificateTransparencyConfigError.new(INVALID_CONFIGURATION_ERROR) unless config.is_a? Hash
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise ExpectCertificateTransparencyConfigError.new(INVALID_CONFIGURATION_ERROR) unless config.is_a? Hash

unless [true, false, nil].include?(config[:enforce])
raise ExpectCertificateTransparencyConfigError.new(INVALID_ENFORCE_VALUE_ERROR)
end
unless [true, false, nil].include?(config[:enforce])
raise ExpectCertificateTransparencyConfigError.new(INVALID_ENFORCE_VALUE_ERROR)
end

if !config[:max_age]
raise ExpectCertificateTransparencyConfigError.new(REQUIRED_MAX_AGE_ERROR)
elsif config[:max_age].to_s !~ /\A\d+\z/
raise ExpectCertificateTransparencyConfigError.new(INVALID_MAX_AGE_ERROR)
end
if !config[:max_age]
raise ExpectCertificateTransparencyConfigError.new(REQUIRED_MAX_AGE_ERROR)
elsif config[:max_age].to_s !~ /\A\d+\z/
raise ExpectCertificateTransparencyConfigError.new(INVALID_MAX_AGE_ERROR)
end
end

Expand Down
40 changes: 19 additions & 21 deletions lib/secure_headers/headers/referrer_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,27 @@ class ReferrerPolicy
unsafe-url
)

class << self
# Public: generate an Referrer Policy header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
config ||= DEFAULT_VALUE
[HEADER_NAME, Array(config).join(", ")]
end
# Public: generate an Referrer Policy header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
config ||= DEFAULT_VALUE
[HEADER_NAME, Array(config).join(", ")]
end

def validate_config!(config)
case config
when nil, OPT_OUT
# valid
when String, Array
config = Array(config)
unless config.all? { |t| t.is_a?(String) && VALID_POLICIES.include?(t.downcase) }
raise ReferrerPolicyConfigError.new("Value can only be one or more of #{VALID_POLICIES.join(", ")}")
end
else
raise TypeError.new("Must be a string or array of strings. Found #{config.class}: #{config}")
def self.validate_config!(config)
case config
when nil, OPT_OUT
# valid
when String, Array
config = Array(config)
unless config.all? { |t| t.is_a?(String) && VALID_POLICIES.include?(t.downcase) }
raise ReferrerPolicyConfigError.new("Value can only be one or more of #{VALID_POLICIES.join(", ")}")
end
else
raise TypeError.new("Must be a string or array of strings. Found #{config.class}: #{config}")
end
end
end
Expand Down
26 changes: 12 additions & 14 deletions lib/secure_headers/headers/strict_transport_security.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,19 @@ class StrictTransportSecurity
VALID_STS_HEADER = /\Amax-age=\d+(; includeSubdomains)?(; preload)?\z/i
MESSAGE = "The config value supplied for the HSTS header was invalid. Must match #{VALID_STS_HEADER}"

class << self
# Public: generate an hsts header name, value pair.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end
# Public: generate an hsts header name, value pair.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config} #{config.class}") unless config.is_a?(String)
raise STSConfigError.new(MESSAGE) unless config =~ VALID_STS_HEADER
end
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config} #{config.class}") unless config.is_a?(String)
raise STSConfigError.new(MESSAGE) unless config =~ VALID_STS_HEADER
end
end
end
28 changes: 13 additions & 15 deletions lib/secure_headers/headers/x_content_type_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@ class XContentTypeOptions
HEADER_NAME = "x-content-type-options".freeze
DEFAULT_VALUE = "nosniff"

class << self
# Public: generate an X-Content-Type-Options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end
# Public: generate an X-Content-Type-Options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config.casecmp(DEFAULT_VALUE) == 0
raise XContentTypeOptionsConfigError.new("Value can only be nil or 'nosniff'")
end
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config.casecmp(DEFAULT_VALUE) == 0
raise XContentTypeOptionsConfigError.new("Value can only be nil or 'nosniff'")
end
end
end
Expand Down
28 changes: 13 additions & 15 deletions lib/secure_headers/headers/x_download_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ class XDownloadOptions
HEADER_NAME = "x-download-options".freeze
DEFAULT_VALUE = "noopen"

class << self
# Public: generate an x-download-options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end
# Public: generate an x-download-options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config.casecmp(DEFAULT_VALUE) == 0
raise XDOConfigError.new("Value can only be nil or 'noopen'")
end
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config.casecmp(DEFAULT_VALUE) == 0
raise XDOConfigError.new("Value can only be nil or 'noopen'")
end
end
end
Expand Down
28 changes: 13 additions & 15 deletions lib/secure_headers/headers/x_frame_options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,20 @@ class XFrameOptions
DEFAULT_VALUE = SAMEORIGIN
VALID_XFO_HEADER = /\A(#{SAMEORIGIN}\z|#{DENY}\z|#{ALLOW_ALL}\z|#{ALLOW_FROM}[:\s])/i

class << self
# Public: generate an X-Frame-Options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end
# Public: generate an X-Frame-Options header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config =~ VALID_XFO_HEADER
raise XFOConfigError.new("Value must be SAMEORIGIN|DENY|ALLOW-FROM:|ALLOWALL")
end
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless config =~ VALID_XFO_HEADER
raise XFOConfigError.new("Value must be SAMEORIGIN|DENY|ALLOW-FROM:|ALLOWALL")
end
end
end
Expand Down
28 changes: 13 additions & 15 deletions lib/secure_headers/headers/x_permitted_cross_domain_policies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@ class XPermittedCrossDomainPolicies
DEFAULT_VALUE = "none"
VALID_POLICIES = %w(all none master-only by-content-type by-ftp-filename)

class << self
# Public: generate an x-permitted-cross-domain-policies header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end
# Public: generate an x-permitted-cross-domain-policies header.
#
# Returns a default header if no configuration is provided, or a
# header name and value based on the config.
def self.make_header(config = nil, user_agent = nil)
return if config == OPT_OUT
[HEADER_NAME, config || DEFAULT_VALUE]
end

def validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless VALID_POLICIES.include?(config.downcase)
raise XPCDPConfigError.new("Value can only be one of #{VALID_POLICIES.join(', ')}")
end
def self.validate_config!(config)
return if config.nil? || config == OPT_OUT
raise TypeError.new("Must be a string. Found #{config.class}: #{config}") unless config.is_a?(String)
unless VALID_POLICIES.include?(config.downcase)
raise XPCDPConfigError.new("Value can only be one of #{VALID_POLICIES.join(', ')}")
end
end
end
Expand Down
Loading