Class: SecureHeaders::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/secure_headers/configuration.rb

Defined Under Namespace

Classes: NotYetConfiguredError

Constant Summary collapse

DEFAULT_CONFIG =
:default
NOOP_CONFIGURATION =
"secure_headers_noop_config"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ Configuration

Returns a new instance of Configuration.



96
97
98
99
100
# File 'lib/secure_headers/configuration.rb', line 96

def initialize(&block)
  self.hpkp = OPT_OUT
  self.csp = self.class.deep_copy(CSP::DEFAULT_CONFIG)
  instance_eval &block if block_given?
end

Instance Attribute Details

#cached_headers ⇒ Object (readonly)

Returns the value of attribute cached_headers.



94
95
96
# File 'lib/secure_headers/configuration.rb', line 94

def cached_headers
  @cached_headers
end

#csp ⇒ Object

Returns the value of attribute csp.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def csp
  @csp
end

#hpkp ⇒ Object

Returns the value of attribute hpkp.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def hpkp
  @hpkp
end

#hsts ⇒ Object

Returns the value of attribute hsts.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def hsts
  @hsts
end

#x_content_type_options ⇒ Object

Returns the value of attribute x_content_type_options.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def x_content_type_options
  @x_content_type_options
end

#x_download_options ⇒ Object

Returns the value of attribute x_download_options.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def x_download_options
  @x_download_options
end

#x_frame_options ⇒ Object

Returns the value of attribute x_frame_options.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def x_frame_options
  @x_frame_options
end

#x_permitted_cross_domain_policies ⇒ Object

Returns the value of attribute x_permitted_cross_domain_policies.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def x_permitted_cross_domain_policies
  @x_permitted_cross_domain_policies
end

#x_xss_protection ⇒ Object

Returns the value of attribute x_xss_protection.



91
92
93
# File 'lib/secure_headers/configuration.rb', line 91

def x_xss_protection
  @x_xss_protection
end

Class Method Details

.deep_copy(config) ⇒ Object

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



48
49
50
51
52
53
54
55
56
# File 'lib/secure_headers/configuration.rb', line 48

def deep_copy(config)
  config.each_with_object({}) do |(key, value), hash|
    hash[key] = if value.is_a?(Array)
      value.dup
    else
      value
    end
  end
end

.default(&block) ⇒ Object Also known as: configure

Public: Set the global default configuration.

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

Returns the newly created config.



12
13
14
15
16
# File 'lib/secure_headers/configuration.rb', line 12

def default(&block)
  config = new(&block)
  add_noop_configuration
  add_configuration(DEFAULT_CONFIG, config)
end

.get(name = DEFAULT_CONFIG) ⇒ Object

Public: retrieve a global configuration object

Returns the configuration with a given name or raises a NotYetConfiguredError if default has not been called.



39
40
41
42
43
44
# File 'lib/secure_headers/configuration.rb', line 39

def get(name = DEFAULT_CONFIG)
  if @configurations.nil?
    raise NotYetConfiguredError, "Default policy not yet supplied"
  end
  @configurations[name]
end

.override(name, base = DEFAULT_CONFIG) {|override| ... } ⇒ Object

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

Yields:



26
27
28
29
30
31
32
33
# File 'lib/secure_headers/configuration.rb', line 26

def override(name, base = DEFAULT_CONFIG)
  unless get(base)
    raise NotYetConfiguredError, "#{base} policy not yet supplied"
  end
  override = @configurations[base].dup
  yield(override)
  add_configuration(name, override)
end

Instance Method Details

#cache_headers! ⇒ Object

Public: Precompute the header names and values for this configuraiton. Ensures that headers generated at configure time, not on demand.

Returns the cached headers



156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/secure_headers/configuration.rb', line 156

def cache_headers!
  # generate defaults for the "easy" headers
  headers = (ALL_HEADERS_BESIDES_CSP).each_with_object({}) do |klass, hash|
    config = fetch(klass::CONFIG_KEY)
    unless config == OPT_OUT
      hash[klass::CONFIG_KEY] = klass.make_header(config).freeze
    end
  end

  generate_csp_headers(headers)

  headers.freeze
  @cached_headers = headers
end

#dup ⇒ Object

Public: copy everything but the cached headers

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



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/secure_headers/configuration.rb', line 105

def dup
  copy = self.class.new
  copy.hsts = hsts
  copy.x_frame_options = x_frame_options
  copy.x_content_type_options = x_content_type_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.csp = if csp.is_a?(Hash)
    self.class.deep_copy(csp)
  else
    csp
  end

  copy.hpkp = if hpkp.is_a?(Hash)
    self.class.deep_copy(hpkp)
  else
    hpkp
  end
  copy
end

#fetch(key) ⇒ Object

Public: Retrieve a config based on the CONFIG_KEY for a class

Returns the value if available, and returns a dup of any hash values.



130
131
132
133
134
# File 'lib/secure_headers/configuration.rb', line 130

def fetch(key)
  config = send(key)
  config = self.class.deep_copy(config) if config.is_a?(Hash)
  config
end

#generate_csp_headers(headers) ⇒ Object

Private: adds CSP headers for each variation of CSP support.

headers - generated headers are added to this hash namespaced by The different variations

Returns nothing



177
178
179
180
181
182
183
184
185
186
187
# File 'lib/secure_headers/configuration.rb', line 177

def generate_csp_headers(headers)
  unless csp == OPT_OUT
    headers[CSP::CONFIG_KEY] = {}

    CSP::VARIATIONS.each do |name, _|
      csp_config = fetch(CSP::CONFIG_KEY)
      csp = CSP.make_header(csp_config, UserAgent.parse(name))
      headers[CSP::CONFIG_KEY][name] = csp.freeze
    end
  end
end

#validate_config! ⇒ Object

Public: validates all configurations values.

Raises various configuration errors if any invalid config is detected.

Returns nothing



141
142
143
144
145
146
147
148
149
150
# File 'lib/secure_headers/configuration.rb', line 141

def validate_config!
  StrictTransportSecurity.validate_config!(hsts)
  ContentSecurityPolicy.validate_config!(csp)
  XFrameOptions.validate_config!(x_frame_options)
  XContentTypeOptions.validate_config!(x_content_type_options)
  XXssProtection.validate_config!(x_xss_protection)
  XDownloadOptions.validate_config!(x_download_options)
  XPermittedCrossDomainPolicies.validate_config!(x_permitted_cross_domain_policies)
  PublicKeyPins.validate_config!(hpkp)
end