class SecureHeaders::Configuration

Constants

CONFIG_ATTRIBUTES
CONFIG_ATTRIBUTES_TO_HEADER_CLASSES
DEFAULT_CONFIG
HASH_CONFIG_FILE
HEADERABLE_ATTRIBUTES

The list of attributes that must respond to a `make_header` method

NOOP_OVERRIDE
VALIDATABLE_ATTRIBUTES

The list of attributes that must respond to a `validate_config!` method

Public Class Methods

configure(&block)
Alias for: default
default(&block) click to toggle source

Public: Set the global default configuration.

Optionally supply a block to override the defaults set by this library.

Returns the newly created config.

# File lib/secure_headers/configuration.rb, line 17
def default(&block)
  if defined?(@default_config)
    raise AlreadyConfiguredError, "Policy already configured"
  end

  # Define a built-in override that clears all configuration options and
  # results in no security headers being set.
  override(NOOP_OVERRIDE) do |config|
    CONFIG_ATTRIBUTES.each do |attr|
      config.instance_variable_set("@#{attr}", OPT_OUT)
    end
  end

  new_config = new(&block).freeze
  new_config.validate_config!
  @default_config = new_config
end
Also aliased as: configure
dup() click to toggle source
# File lib/secure_headers/configuration.rb, line 71
def dup
  default_config.dup
end
named_append(name, &block) click to toggle source
# File lib/secure_headers/configuration.rb, line 62
def named_append(name, &block)
  @appends ||= {}
  raise "Provide a configuration block" unless block_given?
  if named_append_or_override_exists?(name)
    raise AlreadyConfiguredError, "Configuration already exists"
  end
  @appends[name] = block
end
named_appends(name) click to toggle source
# File lib/secure_headers/configuration.rb, line 57
def named_appends(name)
  @appends ||= {}
  @appends[name]
end
new(&block) click to toggle source
# File lib/secure_headers/configuration.rb, line 155
def initialize(&block)
  @cookies = self.class.send(:deep_copy_if_hash, Cookie::COOKIE_DEFAULTS)
  @clear_site_data = nil
  @csp = nil
  @csp_report_only = nil
  @hsts = nil
  @x_content_type_options = nil
  @x_download_options = nil
  @x_frame_options = nil
  @x_permitted_cross_domain_policies = nil
  @x_xss_protection = nil
  @expect_certificate_transparency = nil

  self.referrer_policy = OPT_OUT
  self.csp = ContentSecurityPolicyConfig.new(ContentSecurityPolicyConfig::DEFAULT)
  self.csp_report_only = OPT_OUT

  instance_eval(&block) if block_given?
end
override(name, &block) click to toggle source

Public: create a named configuration that overrides the default config.

name - use an idenfier for the override config. base - override another existing config, or override the default config if no value is supplied.

Returns: the newly created config

# File lib/secure_headers/configuration.rb, line 43
def override(name, &block)
  @overrides ||= {}
  raise "Provide a configuration block" unless block_given?
  if named_append_or_override_exists?(name)
    raise AlreadyConfiguredError, "Configuration already exists"
  end
  @overrides[name] = block
end
overrides(name) click to toggle source
# File lib/secure_headers/configuration.rb, line 52
def overrides(name)
  @overrides ||= {}
  @overrides[name]
end

Private Class Methods

deep_copy(config) click to toggle source

Public: perform a basic deep dup. The shallow copy provided by dup/clone can lead to modifying parent objects.

# File lib/secure_headers/configuration.rb, line 84
def deep_copy(config)
  return unless config
  config.each_with_object({}) do |(key, value), hash|
    hash[key] =
      if value.is_a?(Array)
        value.dup
      else
        value
      end
  end
end
deep_copy_if_hash(value) click to toggle source

Private: convenience method purely DRY things up. The value may not be a hash (e.g. OPT_OUT, nil)

# File lib/secure_headers/configuration.rb, line 109
def deep_copy_if_hash(value)
  if value.is_a?(Hash)
    deep_copy(value)
  else
    value
  end
end
default_config() click to toggle source

Private: Returns the internal default configuration. This should only ever be called by internal callers (or tests) that know the semantics of ensuring that the default config is never mutated and is dup(ed) before it is used in a request.

# File lib/secure_headers/configuration.rb, line 100
def default_config
  unless defined?(@default_config)
    raise NotYetConfiguredError, "Default policy not yet configured"
  end
  @default_config
end
named_append_or_override_exists?(name) click to toggle source
# File lib/secure_headers/configuration.rb, line 77
def named_append_or_override_exists?(name)
  (defined?(@appends) && @appends.key?(name)) ||
    (defined?(@overrides) && @overrides.key?(name))
end

Public Instance Methods

csp=(new_csp) click to toggle source
# File lib/secure_headers/configuration.rb, line 243
def csp=(new_csp)
  case new_csp
  when OPT_OUT
    @csp = new_csp
  when ContentSecurityPolicyConfig
    @csp = new_csp
  when Hash
    @csp = ContentSecurityPolicyConfig.new(new_csp)
  else
    raise ArgumentError, "Must provide either an existing CSP config or a CSP config hash"
  end
end
csp_report_only=(new_csp) click to toggle source

Configures the Content-Security-Policy-Report-Only header. `new_csp` cannot contain `report_only: false` or an error will be raised.

NOTE: if csp has not been configured/has the default value when configuring csp_report_only, the code will assume you mean to only use report-only mode and you will be opted-out of enforce mode.

# File lib/secure_headers/configuration.rb, line 262
def csp_report_only=(new_csp)
  case new_csp
  when OPT_OUT
    @csp_report_only = new_csp
  when ContentSecurityPolicyReportOnlyConfig
    @csp_report_only = new_csp.dup
  when ContentSecurityPolicyConfig
    @csp_report_only = new_csp.make_report_only
  when Hash
    @csp_report_only = ContentSecurityPolicyReportOnlyConfig.new(new_csp)
  else
    raise ArgumentError, "Must provide either an existing CSP config or a CSP config hash"
  end
end
dup() click to toggle source

Public: copy everything

Returns a deep-dup'd copy of this configuration.

# File lib/secure_headers/configuration.rb, line 178
def dup
  copy = self.class.new
  copy.cookies = self.class.send(:deep_copy_if_hash, @cookies)
  copy.csp = @csp.dup if @csp
  copy.csp_report_only = @csp_report_only.dup if @csp_report_only
  copy.x_content_type_options = @x_content_type_options
  copy.hsts = @hsts
  copy.x_frame_options = @x_frame_options
  copy.x_xss_protection = @x_xss_protection
  copy.x_download_options = @x_download_options
  copy.x_permitted_cross_domain_policies = @x_permitted_cross_domain_policies
  copy.clear_site_data = @clear_site_data
  copy.expect_certificate_transparency = @expect_certificate_transparency
  copy.referrer_policy = @referrer_policy
  copy
end
generate_headers() click to toggle source
# File lib/secure_headers/configuration.rb, line 207
def generate_headers
  headers = {}
  HEADERABLE_ATTRIBUTES.each do |attr|
    klass = CONFIG_ATTRIBUTES_TO_HEADER_CLASSES[attr]
    header_name, value = klass.make_header(instance_variable_get("@#{attr}"))
    if header_name && value
      headers[header_name] = value
    end
  end
  headers
end
opt_out(header) click to toggle source
# File lib/secure_headers/configuration.rb, line 219
def opt_out(header)
  send("#{header}=", OPT_OUT)
end
override(name = nil, &block) click to toggle source

Public: Apply a named override to the current config

Returns self

# File lib/secure_headers/configuration.rb, line 198
def override(name = nil, &block)
  if override = self.class.overrides(name)
    instance_eval(&override)
  else
    raise ArgumentError.new("no override by the name of #{name} has been configured")
  end
  self
end
secure_cookies=(secure_cookies) click to toggle source
# File lib/secure_headers/configuration.rb, line 239
def secure_cookies=(secure_cookies)
  raise ArgumentError, "#{Kernel.caller.first}: `#secure_cookies=` is no longer supported. Please use `#cookies=` to configure secure cookies instead."
end
update_x_frame_options(value) click to toggle source
# File lib/secure_headers/configuration.rb, line 223
def update_x_frame_options(value)
  @x_frame_options = value
end
validate_config!() click to toggle source

Public: validates all configurations values.

Raises various configuration errors if any invalid config is detected.

Returns nothing

# File lib/secure_headers/configuration.rb, line 232
def validate_config!
  VALIDATABLE_ATTRIBUTES.each do |attr|
    klass = CONFIG_ATTRIBUTES_TO_HEADER_CLASSES[attr]
    klass.validate_config!(instance_variable_get("@#{attr}"))
  end
end