secure_headers 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ module SecureHeaders
2
+ module DynamicConfig
3
+ def self.included(base)
4
+ base.send(:attr_writer, :modified)
5
+ base.send(:attr_reader, *base.attrs)
6
+ base.attrs.each do |attr|
7
+ base.send(:define_method, "#{attr}=") do |value|
8
+ if self.class.attrs.include?(attr)
9
+ value = value.dup if PolicyManagement::DIRECTIVE_VALUE_TYPES[attr] == :source_list
10
+ prev_value = self.instance_variable_get("@#{attr}")
11
+ self.instance_variable_set("@#{attr}", value)
12
+ if prev_value != self.instance_variable_get("@#{attr}")
13
+ @modified = true
14
+ end
15
+ else
16
+ raise ContentSecurityPolicyConfigError, "Unknown config directive: #{attr}=#{value}"
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize(hash)
23
+ from_hash(hash)
24
+ @modified = false
25
+ end
26
+
27
+ def update_directive(directive, value)
28
+ self.send("#{directive}=", value)
29
+ end
30
+
31
+ def directive_value(directive)
32
+ if self.class.attrs.include?(directive)
33
+ self.send(directive)
34
+ end
35
+ end
36
+
37
+ def modified?
38
+ @modified
39
+ end
40
+
41
+ def merge(new_hash)
42
+ ContentSecurityPolicy.combine_policies(self.to_h, new_hash)
43
+ end
44
+
45
+ def merge!(new_hash)
46
+ from_hash(new_hash)
47
+ end
48
+
49
+ def append(new_hash)
50
+ from_hash(ContentSecurityPolicy.combine_policies(self.to_h, new_hash))
51
+ end
52
+
53
+ def to_h
54
+ self.class.attrs.each_with_object({}) do |key, hash|
55
+ hash[key] = self.send(key)
56
+ end.reject { |_, v| v.nil? }
57
+ end
58
+
59
+ def dup
60
+ self.class.new(self.to_h)
61
+ end
62
+
63
+ def opt_out?
64
+ false
65
+ end
66
+
67
+ def ==(o)
68
+ self.class == o.class && self.to_h == o.to_h
69
+ end
70
+
71
+ alias_method :[], :directive_value
72
+ alias_method :[]=, :update_directive
73
+
74
+ private
75
+ def from_hash(hash)
76
+ hash.keys.reject { |k| hash[k].nil? }.map do |k|
77
+ if self.class.attrs.include?(k)
78
+ self.send("#{k}=", hash[k])
79
+ else
80
+ raise ContentSecurityPolicyConfigError, "Unknown config directive: #{k}=#{hash[k]}"
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ class ContentSecurityPolicyConfigError < StandardError; end
87
+ class ContentSecurityPolicyConfig
88
+ CONFIG_KEY = :csp
89
+ HEADER_NAME = "Content-Security-Policy".freeze
90
+
91
+ def self.attrs
92
+ PolicyManagement::ALL_DIRECTIVES + PolicyManagement::META_CONFIGS + PolicyManagement::NONCES
93
+ end
94
+
95
+ include DynamicConfig
96
+
97
+ # based on what was suggested in https://github.com/rails/rails/pull/24961/files
98
+ DEFAULT = {
99
+ default_src: %w('self' https:),
100
+ font_src: %w('self' https: data:),
101
+ img_src: %w('self' https: data:),
102
+ object_src: %w('none'),
103
+ script_src: %w(https:),
104
+ style_src: %w('self' https: 'unsafe-inline')
105
+ }
106
+
107
+ def report_only?
108
+ false
109
+ end
110
+
111
+ def make_report_only
112
+ ContentSecurityPolicyReportOnlyConfig.new(self.to_h)
113
+ end
114
+ end
115
+
116
+ class ContentSecurityPolicyReportOnlyConfig < ContentSecurityPolicyConfig
117
+ CONFIG_KEY = :csp_report_only
118
+ HEADER_NAME = "Content-Security-Policy-Report-Only".freeze
119
+
120
+ def report_only?
121
+ true
122
+ end
123
+
124
+ def make_report_only
125
+ self
126
+ end
127
+ end
128
+ end
@@ -7,9 +7,6 @@ module SecureHeaders
7
7
  MODERN_BROWSERS = %w(Chrome Opera Firefox)
8
8
  DEFAULT_VALUE = "default-src https:".freeze
9
9
  DEFAULT_CONFIG = { default_src: %w(https:) }.freeze
10
- HEADER_NAME = "Content-Security-Policy".freeze
11
- REPORT_ONLY = "Content-Security-Policy-Report-Only".freeze
12
- HEADER_NAMES = [HEADER_NAME, REPORT_ONLY]
13
10
  DATA_PROTOCOL = "data:".freeze
14
11
  BLOB_PROTOCOL = "blob:".freeze
15
12
  SELF = "'self'".freeze
@@ -53,16 +50,6 @@ module SecureHeaders
53
50
  FRAME_ANCESTORS = :frame_ancestors
54
51
  PLUGIN_TYPES = :plugin_types
55
52
 
56
- # These are directives that do not inherit the default-src value. This is
57
- # useful when calling #combine_policies.
58
- NON_FETCH_SOURCES = [
59
- BASE_URI,
60
- FORM_ACTION,
61
- FRAME_ANCESTORS,
62
- PLUGIN_TYPES,
63
- REPORT_URI
64
- ]
65
-
66
53
  DIRECTIVES_2_0 = [
67
54
  DIRECTIVES_1_0,
68
55
  BASE_URI,
@@ -127,6 +114,18 @@ module SecureHeaders
127
114
  # everything else is in between.
128
115
  BODY_DIRECTIVES = ALL_DIRECTIVES - [DEFAULT_SRC, REPORT_URI]
129
116
 
117
+ # These are directives that do not inherit the default-src value. This is
118
+ # useful when calling #combine_policies.
119
+ NON_FETCH_SOURCES = [
120
+ BASE_URI,
121
+ FORM_ACTION,
122
+ FRAME_ANCESTORS,
123
+ PLUGIN_TYPES,
124
+ REPORT_URI
125
+ ]
126
+
127
+ FETCH_SOURCES = ALL_DIRECTIVES - NON_FETCH_SOURCES
128
+
130
129
  VARIATIONS = {
131
130
  "Chrome" => CHROME_DIRECTIVES,
132
131
  "Opera" => CHROME_DIRECTIVES,
@@ -156,13 +155,13 @@ module SecureHeaders
156
155
  PLUGIN_TYPES => :source_list,
157
156
  REFLECTED_XSS => :string,
158
157
  REPORT_URI => :source_list,
159
- SANDBOX => :string,
158
+ SANDBOX => :source_list,
160
159
  SCRIPT_SRC => :source_list,
161
160
  STYLE_SRC => :source_list,
162
161
  UPGRADE_INSECURE_REQUESTS => :boolean
163
162
  }.freeze
164
163
 
165
- CONFIG_KEY = :csp
164
+
166
165
  STAR_REGEXP = Regexp.new(Regexp.escape(STAR))
167
166
  HTTP_SCHEME_REGEX = %r{\Ahttps?://}
168
167
 
@@ -179,6 +178,11 @@ module SecureHeaders
179
178
  :preserve_schemes
180
179
  ].freeze
181
180
 
181
+ NONCES = [
182
+ :script_nonce,
183
+ :style_nonce
184
+ ].freeze
185
+
182
186
  module ClassMethods
183
187
  # Public: generate a header name, value array that is user-agent-aware.
184
188
  #
@@ -194,9 +198,11 @@ module SecureHeaders
194
198
  # Does not validate the invididual values of the source expression (e.g.
195
199
  # script_src => h*t*t*p: will not raise an exception)
196
200
  def validate_config!(config)
197
- return if config.nil? || config == OPT_OUT
198
- raise ContentSecurityPolicyConfigError.new(":default_src is required") unless config[:default_src]
199
- config.each do |key, value|
201
+ return if config.nil? || config.opt_out?
202
+ raise ContentSecurityPolicyConfigError.new(":default_src is required") unless config.directive_value(:default_src)
203
+ ContentSecurityPolicyConfig.attrs.each do |key|
204
+ value = config.directive_value(key)
205
+ next unless value
200
206
  if META_CONFIGS.include?(key)
201
207
  raise ContentSecurityPolicyConfigError.new("#{key} must be a boolean value") unless boolean?(value) || value.nil?
202
208
  else
@@ -205,16 +211,13 @@ module SecureHeaders
205
211
  end
206
212
  end
207
213
 
208
- # Public: determine if merging +additions+ will cause a change to the
209
- # actual value of the config.
214
+ # Public: check if a user agent supports CSP nonces
210
215
  #
211
- # e.g. config = { script_src: %w(example.org google.com)} and
212
- # additions = { script_src: %w(google.com)} then idempotent_additions? would return
213
- # because google.com is already in the config.
214
- def idempotent_additions?(config, additions)
215
- return true if config == OPT_OUT && additions == OPT_OUT
216
- return false if config == OPT_OUT
217
- config == combine_policies(config, additions)
216
+ # user_agent - a String or a UserAgent object
217
+ def nonces_supported?(user_agent)
218
+ user_agent = UserAgent.parse(user_agent) if user_agent.is_a?(String)
219
+ MODERN_BROWSERS.include?(user_agent.browser) ||
220
+ user_agent.browser == "Safari" && user_agent.version >= CSP::VERSION_10
218
221
  end
219
222
 
220
223
  # Public: combine the values from two different configs.
@@ -231,7 +234,7 @@ module SecureHeaders
231
234
  # 3. if a value in additions does exist in the original config, the two
232
235
  # values are joined.
233
236
  def combine_policies(original, additions)
234
- if original == OPT_OUT
237
+ if original == {}
235
238
  raise ContentSecurityPolicyConfigError.new("Attempted to override an opt-out CSP config.")
236
239
  end
237
240
 
@@ -268,8 +271,23 @@ module SecureHeaders
268
271
  def populate_fetch_source_with_default!(original, additions)
269
272
  # in case we would be appending to an empty directive, fill it with the default-src value
270
273
  additions.keys.each do |directive|
271
- unless original[directive] || !source_list?(directive) || NON_FETCH_SOURCES.include?(directive)
272
- original[directive] = original[:default_src]
274
+ if !original[directive] && ((source_list?(directive) && FETCH_SOURCES.include?(directive)) || nonce_added?(original, additions))
275
+ if nonce_added?(original, additions)
276
+ inferred_directive = directive.to_s.gsub(/_nonce/, "_src").to_sym
277
+ unless original[inferred_directive] || NON_FETCH_SOURCES.include?(inferred_directive)
278
+ original[inferred_directive] = original[:default_src]
279
+ end
280
+ else
281
+ original[directive] = original[:default_src]
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ def nonce_added?(original, additions)
288
+ [:script_nonce, :style_nonce].each do |nonce|
289
+ if additions[nonce] && !original[nonce]
290
+ return true
273
291
  end
274
292
  end
275
293
  end
@@ -34,6 +34,14 @@ module SecureHeaders
34
34
  end
35
35
  end
36
36
 
37
+ def content_security_policy_script_nonce
38
+ content_security_policy_nonce(:script)
39
+ end
40
+
41
+ def content_security_policy_style_nonce
42
+ content_security_policy_nonce(:style)
43
+ end
44
+
37
45
  ##
38
46
  # Checks to see if the hashed code is expected and adds the hash source
39
47
  # value to the current CSP.
@@ -14,18 +14,44 @@ require "secure_headers/middleware"
14
14
  require "secure_headers/railtie"
15
15
  require "secure_headers/view_helper"
16
16
  require "useragent"
17
+ require "singleton"
17
18
 
18
19
  # All headers (except for hpkp) have a default value. Provide SecureHeaders::OPT_OUT
19
20
  # or ":optout_of_protection" as a config value to disable a given header
20
21
  module SecureHeaders
21
- OPT_OUT = :opt_out_of_protection
22
+ class NoOpHeaderConfig
23
+ include Singleton
24
+
25
+ def boom(arg = nil)
26
+ raise "Illegal State: attempted to modify NoOpHeaderConfig. Create a new config instead."
27
+ end
28
+
29
+ def to_h
30
+ {}
31
+ end
32
+
33
+ def dup
34
+ self.class.instance
35
+ end
36
+
37
+ def opt_out?
38
+ true
39
+ end
40
+
41
+ alias_method :[], :boom
42
+ alias_method :[]=, :boom
43
+ alias_method :keys, :boom
44
+ end
45
+
46
+ OPT_OUT = NoOpHeaderConfig.instance
22
47
  SECURE_HEADERS_CONFIG = "secure_headers_request_config".freeze
23
48
  NONCE_KEY = "secure_headers_content_security_policy_nonce".freeze
24
49
  HTTPS = "https".freeze
25
50
  CSP = ContentSecurityPolicy
26
51
 
27
52
  ALL_HEADER_CLASSES = [
28
- ContentSecurityPolicy,
53
+ ContentSecurityPolicyConfig,
54
+ ContentSecurityPolicyReportOnlyConfig,
29
55
  StrictTransportSecurity,
30
56
  PublicKeyPins,
31
57
  ReferrerPolicy,
@@ -36,7 +62,10 @@ module SecureHeaders
36
62
  XXssProtection
37
63
  ].freeze
38
64
 
39
- ALL_HEADERS_BESIDES_CSP = (ALL_HEADER_CLASSES - [CSP]).freeze
65
+ ALL_HEADERS_BESIDES_CSP = (
66
+ ALL_HEADER_CLASSES -
67
+ [ContentSecurityPolicyConfig, ContentSecurityPolicyReportOnlyConfig]
68
+ ).freeze
40
69
 
41
70
  # Headers set on http requests (excludes STS and HPKP)
42
71
  HTTP_HEADER_CLASSES =
@@ -50,13 +79,25 @@ module SecureHeaders
50
79
  #
51
80
  # additions - a hash containing directives. e.g.
52
81
  # script_src: %w(another-host.com)
53
- def override_content_security_policy_directives(request, additions)
54
- config = config_for(request)
55
- if config.current_csp == OPT_OUT
56
- config.dynamic_csp = {}
82
+ def override_content_security_policy_directives(request, additions, target = nil)
83
+ config, target = config_and_target(request, target)
84
+
85
+ if [:both, :enforced].include?(target)
86
+ if config.csp.opt_out?
87
+ config.csp = ContentSecurityPolicyConfig.new({})
88
+ end
89
+
90
+ config.csp.merge!(additions)
91
+ end
92
+
93
+ if [:both, :report_only].include?(target)
94
+ if config.csp_report_only.opt_out?
95
+ config.csp_report_only = ContentSecurityPolicyReportOnlyConfig.new({})
96
+ end
97
+
98
+ config.csp_report_only.merge!(additions)
57
99
  end
58
100
 
59
- config.dynamic_csp = config.current_csp.merge(additions)
60
101
  override_secure_headers_request_config(request, config)
61
102
  end
62
103
 
@@ -66,12 +107,25 @@ module SecureHeaders
66
107
  #
67
108
  # additions - a hash containing directives. e.g.
68
109
  # script_src: %w(another-host.com)
69
- def append_content_security_policy_directives(request, additions)
70
- config = config_for(request)
71
- config.dynamic_csp = CSP.combine_policies(config.current_csp, additions)
110
+ def append_content_security_policy_directives(request, additions, target = nil)
111
+ config, target = config_and_target(request, target)
112
+
113
+ if [:both, :enforced].include?(target) && !config.csp.opt_out?
114
+ config.csp.append(additions)
115
+ end
116
+
117
+ if [:both, :report_only].include?(target) && !config.csp_report_only.opt_out?
118
+ config.csp_report_only.append(additions)
119
+ end
120
+
72
121
  override_secure_headers_request_config(request, config)
73
122
  end
74
123
 
124
+ def use_content_security_policy_named_append(request, name)
125
+ additions = SecureHeaders::Configuration.named_appends(name).call(request)
126
+ append_content_security_policy_directives(request, additions)
127
+ end
128
+
75
129
  # Public: override X-Frame-Options settings for this request.
76
130
  #
77
131
  # value - deny, sameorigin, or allowall
@@ -107,12 +161,28 @@ module SecureHeaders
107
161
  # returned is meant to be merged into the header value from `@app.call(env)`
108
162
  # in Rack middleware.
109
163
  def header_hash_for(request)
110
- config = config_for(request)
111
- unless ContentSecurityPolicy.idempotent_additions?(config.csp, config.current_csp)
112
- config.rebuild_csp_header_cache!(request.user_agent)
164
+ config = config_for(request, prevent_dup = true)
165
+ headers = config.cached_headers
166
+ user_agent = UserAgent.parse(request.user_agent)
167
+
168
+ if !config.csp.opt_out? && config.csp.modified?
169
+ headers = update_cached_csp(config.csp, headers, user_agent)
113
170
  end
114
171
 
115
- use_cached_headers(config.cached_headers, request)
172
+ if !config.csp_report_only.opt_out? && config.csp_report_only.modified?
173
+ headers = update_cached_csp(config.csp_report_only, headers, user_agent)
174
+ end
175
+
176
+ header_classes_for(request).each_with_object({}) do |klass, hash|
177
+ if header = headers[klass::CONFIG_KEY]
178
+ header_name, value = if [ContentSecurityPolicyConfig, ContentSecurityPolicyReportOnlyConfig].include?(klass)
179
+ csp_header_for_ua(header, user_agent)
180
+ else
181
+ header
182
+ end
183
+ hash[header_name] = value
184
+ end
185
+ end
116
186
  end
117
187
 
118
188
  # Public: specify which named override will be used for this request.
@@ -133,7 +203,7 @@ module SecureHeaders
133
203
  #
134
204
  # Returns the nonce
135
205
  def content_security_policy_script_nonce(request)
136
- content_security_policy_nonce(request, CSP::SCRIPT_SRC)
206
+ content_security_policy_nonce(request, ContentSecurityPolicy::SCRIPT_SRC)
137
207
  end
138
208
 
139
209
  # Public: gets or creates a nonce for CSP.
@@ -142,7 +212,7 @@ module SecureHeaders
142
212
  #
143
213
  # Returns the nonce
144
214
  def content_security_policy_style_nonce(request)
145
- content_security_policy_nonce(request, CSP::STYLE_SRC)
215
+ content_security_policy_nonce(request, ContentSecurityPolicy::STYLE_SRC)
146
216
  end
147
217
 
148
218
  # Public: Retreives the config for a given header type:
@@ -150,11 +220,15 @@ module SecureHeaders
150
220
  # Checks to see if there is an override for this request, then
151
221
  # Checks to see if a named override is used for this request, then
152
222
  # Falls back to the global config
153
- def config_for(request)
223
+ def config_for(request, prevent_dup = false)
154
224
  config = request.env[SECURE_HEADERS_CONFIG] ||
155
225
  Configuration.get(Configuration::DEFAULT_CONFIG)
156
226
 
157
- if config.frozen?
227
+
228
+ # Global configs are frozen, per-request configs are not. When we're not
229
+ # making modifications to the config, prevent_dup ensures we don't dup
230
+ # the object unnecessarily. It's not necessarily frozen to begin with.
231
+ if config.frozen? && !prevent_dup
158
232
  config.dup
159
233
  else
160
234
  config
@@ -162,13 +236,38 @@ module SecureHeaders
162
236
  end
163
237
 
164
238
  private
239
+ TARGETS = [:both, :enforced, :report_only]
240
+ def raise_on_unknown_target(target)
241
+ unless TARGETS.include?(target)
242
+ raise "Unrecognized target: #{target}. Must be [:both, :enforced, :report_only]"
243
+ end
244
+ end
245
+
246
+ def config_and_target(request, target)
247
+ config = config_for(request)
248
+ target = guess_target(config) unless target
249
+ raise_on_unknown_target(target)
250
+ [config, target]
251
+ end
252
+
253
+ def guess_target(config)
254
+ if !config.csp.opt_out? && !config.csp_report_only.opt_out?
255
+ :both
256
+ elsif !config.csp.opt_out?
257
+ :enforced
258
+ elsif !config.csp_report_only.opt_out?
259
+ :report_only
260
+ else
261
+ :both
262
+ end
263
+ end
165
264
 
166
265
  # Private: gets or creates a nonce for CSP.
167
266
  #
168
267
  # Returns the nonce
169
268
  def content_security_policy_nonce(request, script_or_style)
170
269
  request.env[NONCE_KEY] ||= SecureRandom.base64(32).chomp
171
- nonce_key = script_or_style == CSP::SCRIPT_SRC ? :script_nonce : :style_nonce
270
+ nonce_key = script_or_style == ContentSecurityPolicy::SCRIPT_SRC ? :script_nonce : :style_nonce
172
271
  append_content_security_policy_directives(request, nonce_key => request.env[NONCE_KEY])
173
272
  request.env[NONCE_KEY]
174
273
  end
@@ -193,21 +292,12 @@ module SecureHeaders
193
292
  end
194
293
  end
195
294
 
196
- # Private: takes a precomputed hash of headers and returns the Headers
197
- # customized for the request.
198
- #
199
- # Returns a hash of header names / values valid for a given request.
200
- def use_cached_headers(headers, request)
201
- header_classes_for(request).each_with_object({}) do |klass, hash|
202
- if header = headers[klass::CONFIG_KEY]
203
- header_name, value = if klass == CSP
204
- csp_header_for_ua(header, request)
205
- else
206
- header
207
- end
208
- hash[header_name] = value
209
- end
210
- end
295
+ def update_cached_csp(config, headers, user_agent)
296
+ headers = Configuration.send(:deep_copy, headers)
297
+ headers[config.class::CONFIG_KEY] = {}
298
+ variation = ContentSecurityPolicy.ua_to_variation(user_agent)
299
+ headers[config.class::CONFIG_KEY][variation] = ContentSecurityPolicy.make_header(config, user_agent)
300
+ headers
211
301
  end
212
302
 
213
303
  # Private: chooses the applicable CSP header for the provided user agent.
@@ -215,26 +305,8 @@ module SecureHeaders
215
305
  # headers - a hash of header_config_key => [header_name, header_value]
216
306
  #
217
307
  # Returns a CSP [header, value] array
218
- def csp_header_for_ua(headers, request)
219
- headers[CSP.ua_to_variation(UserAgent.parse(request.user_agent))]
220
- end
221
-
222
- # Private: optionally build a header with a given configure
223
- #
224
- # klass - corresponding Class for a given header
225
- # config - A string, symbol, or hash config for the header
226
- # user_agent - A string representing the UA (only used for CSP feature sniffing)
227
- #
228
- # Returns a 2 element array [header_name, header_value] or nil if config
229
- # is OPT_OUT
230
- def make_header(klass, header_config, user_agent = nil)
231
- unless header_config == OPT_OUT
232
- if klass == CSP
233
- klass.make_header(header_config, user_agent)
234
- else
235
- klass.make_header(header_config)
236
- end
237
- end
308
+ def csp_header_for_ua(headers, user_agent)
309
+ headers[ContentSecurityPolicy.ua_to_variation(user_agent)]
238
310
  end
239
311
  end
240
312
 
@@ -267,4 +339,8 @@ module SecureHeaders
267
339
  def override_x_frame_options(value)
268
340
  SecureHeaders.override_x_frame_options(request, value)
269
341
  end
342
+
343
+ def use_content_security_policy_named_append(name)
344
+ SecureHeaders.use_content_security_policy_named_append(request, name)
345
+ end
270
346
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |gem|
3
3
  gem.name = "secure_headers"
4
- gem.version = "3.4.0"
4
+ gem.version = "3.5.0"
5
5
  gem.authors = ["Neil Matatall"]
6
6
  gem.email = ["neil.matatall@gmail.com"]
7
7
  gem.description = 'Security related headers all in one gem.'
@@ -36,8 +36,8 @@ module SecureHeaders
36
36
 
37
37
  config = Configuration.get(:test_override)
38
38
  noop = Configuration.get(Configuration::NOOP_CONFIGURATION)
39
- [:csp, :dynamic_csp, :cookies].each do |key|
40
- expect(config.send(key)).to eq(noop.send(key)), "Value not copied: #{key}."
39
+ [:csp, :csp_report_only, :cookies].each do |key|
40
+ expect(config.send(key)).to eq(noop.send(key))
41
41
  end
42
42
  end
43
43
 
@@ -65,7 +65,7 @@ module SecureHeaders
65
65
  default = Configuration.get
66
66
  override = Configuration.get(:override)
67
67
 
68
- expect(override.csp).not_to eq(default.csp)
68
+ expect(override.csp.directive_value(:default_src)).not_to be(default.csp.directive_value(:default_src))
69
69
  end
70
70
 
71
71
  it "allows you to override an override" do
@@ -78,9 +78,9 @@ module SecureHeaders
78
78
  end
79
79
 
80
80
  original_override = Configuration.get(:override)
81
- expect(original_override.csp).to eq(default_src: %w('self'))
81
+ expect(original_override.csp.to_h).to eq(default_src: %w('self'))
82
82
  override_config = Configuration.get(:second_override)
83
- expect(override_config.csp).to eq(default_src: %w('self'), script_src: %w(example.org))
83
+ expect(override_config.csp.to_h).to eq(default_src: %w('self'), script_src: %w('self' example.org))
84
84
  end
85
85
 
86
86
  it "deprecates the secure_cookies configuration" do
@@ -14,11 +14,11 @@ module SecureHeaders
14
14
 
15
15
  describe "#name" do
16
16
  context "when in report-only mode" do
17
- specify { expect(ContentSecurityPolicy.new(default_opts.merge(report_only: true)).name).to eq(ContentSecurityPolicy::HEADER_NAME + "-Report-Only") }
17
+ specify { expect(ContentSecurityPolicy.new(default_opts.merge(report_only: true)).name).to eq(ContentSecurityPolicyReportOnlyConfig::HEADER_NAME) }
18
18
  end
19
19
 
20
20
  context "when in enforce mode" do
21
- specify { expect(ContentSecurityPolicy.new(default_opts).name).to eq(ContentSecurityPolicy::HEADER_NAME) }
21
+ specify { expect(ContentSecurityPolicy.new(default_opts).name).to eq(ContentSecurityPolicyConfig::HEADER_NAME) }
22
22
  end
23
23
  end
24
24