secure_headers 5.2.0 → 6.0.0.alpha01
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of secure_headers might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +8 -4
- data/CHANGELOG.md +3 -7
- data/Gemfile +1 -1
- data/docs/upgrading-to-6-0.md +50 -0
- data/lib/secure_headers.rb +14 -76
- data/lib/secure_headers/configuration.rb +114 -164
- data/lib/secure_headers/headers/clear_site_data.rb +1 -3
- data/lib/secure_headers/headers/content_security_policy.rb +4 -17
- data/lib/secure_headers/headers/content_security_policy_config.rb +3 -13
- data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -3
- data/lib/secure_headers/headers/policy_management.rb +12 -11
- data/lib/secure_headers/headers/public_key_pins.rb +2 -3
- data/lib/secure_headers/headers/referrer_policy.rb +2 -2
- data/lib/secure_headers/headers/strict_transport_security.rb +2 -2
- data/lib/secure_headers/headers/x_content_type_options.rb +2 -2
- data/lib/secure_headers/headers/x_download_options.rb +2 -2
- data/lib/secure_headers/headers/x_frame_options.rb +1 -2
- data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
- data/lib/secure_headers/headers/x_xss_protection.rb +3 -3
- data/secure_headers.gemspec +1 -1
- data/spec/lib/secure_headers/configuration_spec.rb +15 -70
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +12 -22
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +33 -7
- data/spec/lib/secure_headers/middleware_spec.rb +7 -1
- data/spec/lib/secure_headers/view_helpers_spec.rb +1 -0
- data/spec/lib/secure_headers_spec.rb +39 -40
- data/spec/spec_helper.rb +7 -3
- metadata +5 -4
@@ -11,13 +11,11 @@ module SecureHeaders
|
|
11
11
|
EXECUTION_CONTEXTS = "executionContexts".freeze
|
12
12
|
ALL_TYPES = [CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS]
|
13
13
|
|
14
|
-
CONFIG_KEY = :clear_site_data
|
15
|
-
|
16
14
|
class << self
|
17
15
|
# Public: make an Clear-Site-Data header name, value pair
|
18
16
|
#
|
19
17
|
# Returns nil if not configured, returns header name and value if configured.
|
20
|
-
def make_header(config = nil)
|
18
|
+
def make_header(config = nil, user_agent = nil)
|
21
19
|
case config
|
22
20
|
when nil, OPT_OUT, []
|
23
21
|
# noop
|
@@ -13,6 +13,7 @@ module SecureHeaders
|
|
13
13
|
FALLBACK_VERSION = ::UserAgent::Version.new("0")
|
14
14
|
|
15
15
|
def initialize(config = nil, user_agent = OTHER)
|
16
|
+
user_agent ||= OTHER
|
16
17
|
@config = if config.is_a?(Hash)
|
17
18
|
if config[:report_only]
|
18
19
|
ContentSecurityPolicyReportOnlyConfig.new(config || DEFAULT_CONFIG)
|
@@ -138,14 +139,8 @@ module SecureHeaders
|
|
138
139
|
end
|
139
140
|
|
140
141
|
if source_list != OPT_OUT && source_list && source_list.any?
|
141
|
-
|
142
|
-
|
143
|
-
if minified_source_list =~ /(\n|;)/
|
144
|
-
Kernel.warn("#{directive} contains a #{$1} in #{minified_source_list.inspect} which will raise an error in future versions. It has been replaced with a blank space.")
|
145
|
-
end
|
146
|
-
|
147
|
-
escaped_source_list = minified_source_list.gsub(/[\n;]/, " ")
|
148
|
-
[symbol_to_hyphen_case(directive), escaped_source_list].join(" ").strip
|
142
|
+
normalized_source_list = minify_source_list(directive, source_list)
|
143
|
+
[symbol_to_hyphen_case(directive), normalized_source_list].join(" ")
|
149
144
|
end
|
150
145
|
end
|
151
146
|
|
@@ -218,11 +213,7 @@ module SecureHeaders
|
|
218
213
|
# unsafe-inline, this is more concise.
|
219
214
|
def append_nonce(source_list, nonce)
|
220
215
|
if nonce
|
221
|
-
|
222
|
-
source_list << "'nonce-#{nonce}'"
|
223
|
-
else
|
224
|
-
source_list << UNSAFE_INLINE
|
225
|
-
end
|
216
|
+
source_list.push("'nonce-#{nonce}'", UNSAFE_INLINE)
|
226
217
|
end
|
227
218
|
|
228
219
|
source_list
|
@@ -262,10 +253,6 @@ module SecureHeaders
|
|
262
253
|
end
|
263
254
|
end
|
264
255
|
|
265
|
-
def nonces_supported?
|
266
|
-
@nonces_supported ||= self.class.nonces_supported?(@parsed_ua)
|
267
|
-
end
|
268
|
-
|
269
256
|
def symbol_to_hyphen_case(sym)
|
270
257
|
sym.to_s.tr("_", "-")
|
271
258
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
module SecureHeaders
|
3
3
|
module DynamicConfig
|
4
4
|
def self.included(base)
|
5
|
-
base.send(:attr_writer, :modified)
|
6
5
|
base.send(:attr_reader, *base.attrs)
|
7
6
|
base.attrs.each do |attr|
|
8
7
|
base.send(:define_method, "#{attr}=") do |value|
|
@@ -42,7 +41,6 @@ module SecureHeaders
|
|
42
41
|
@upgrade_insecure_requests = nil
|
43
42
|
|
44
43
|
from_hash(hash)
|
45
|
-
@modified = false
|
46
44
|
end
|
47
45
|
|
48
46
|
def update_directive(directive, value)
|
@@ -55,12 +53,10 @@ module SecureHeaders
|
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
58
|
-
def modified?
|
59
|
-
@modified
|
60
|
-
end
|
61
|
-
|
62
56
|
def merge(new_hash)
|
63
|
-
|
57
|
+
new_config = self.dup
|
58
|
+
new_config.send(:from_hash, new_hash)
|
59
|
+
new_config
|
64
60
|
end
|
65
61
|
|
66
62
|
def merge!(new_hash)
|
@@ -109,17 +105,12 @@ module SecureHeaders
|
|
109
105
|
def write_attribute(attr, value)
|
110
106
|
value = value.dup if PolicyManagement::DIRECTIVE_VALUE_TYPES[attr] == :source_list
|
111
107
|
attr_variable = "@#{attr}"
|
112
|
-
prev_value = self.instance_variable_get(attr_variable)
|
113
108
|
self.instance_variable_set(attr_variable, value)
|
114
|
-
if prev_value != value
|
115
|
-
@modified = true
|
116
|
-
end
|
117
109
|
end
|
118
110
|
end
|
119
111
|
|
120
112
|
class ContentSecurityPolicyConfigError < StandardError; end
|
121
113
|
class ContentSecurityPolicyConfig
|
122
|
-
CONFIG_KEY = :csp
|
123
114
|
HEADER_NAME = "Content-Security-Policy".freeze
|
124
115
|
|
125
116
|
ATTRS = PolicyManagement::ALL_DIRECTIVES + PolicyManagement::META_CONFIGS + PolicyManagement::NONCES
|
@@ -149,7 +140,6 @@ module SecureHeaders
|
|
149
140
|
end
|
150
141
|
|
151
142
|
class ContentSecurityPolicyReportOnlyConfig < ContentSecurityPolicyConfig
|
152
|
-
CONFIG_KEY = :csp_report_only
|
153
143
|
HEADER_NAME = "Content-Security-Policy-Report-Only".freeze
|
154
144
|
|
155
145
|
def report_only?
|
@@ -4,7 +4,6 @@ module SecureHeaders
|
|
4
4
|
|
5
5
|
class ExpectCertificateTransparency
|
6
6
|
HEADER_NAME = "Expect-CT".freeze
|
7
|
-
CONFIG_KEY = :expect_certificate_transparency
|
8
7
|
INVALID_CONFIGURATION_ERROR = "config must be a hash.".freeze
|
9
8
|
INVALID_ENFORCE_VALUE_ERROR = "enforce must be a boolean".freeze
|
10
9
|
REQUIRED_MAX_AGE_ERROR = "max-age is a required directive.".freeze
|
@@ -15,8 +14,8 @@ module SecureHeaders
|
|
15
14
|
#
|
16
15
|
# Returns nil if not configured, returns header name and value if
|
17
16
|
# configured.
|
18
|
-
def make_header(config)
|
19
|
-
return if config.nil?
|
17
|
+
def make_header(config, use_agent = nil)
|
18
|
+
return if config.nil? || config == OPT_OUT
|
20
19
|
|
21
20
|
header = new(config)
|
22
21
|
[HEADER_NAME, header.value]
|
@@ -5,7 +5,6 @@ module SecureHeaders
|
|
5
5
|
base.extend(ClassMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
MODERN_BROWSERS = %w(Chrome Opera Firefox)
|
9
8
|
DEFAULT_CONFIG = {
|
10
9
|
default_src: %w(https:),
|
11
10
|
img_src: %w(https: data: 'self'),
|
@@ -200,7 +199,8 @@ module SecureHeaders
|
|
200
199
|
#
|
201
200
|
# Returns a default policy if no configuration is provided, or a
|
202
201
|
# header name and value based on the config.
|
203
|
-
def make_header(config, user_agent)
|
202
|
+
def make_header(config, user_agent = nil)
|
203
|
+
return if config.nil? || config == OPT_OUT
|
204
204
|
header = new(config, user_agent)
|
205
205
|
[header.name, header.value]
|
206
206
|
end
|
@@ -215,27 +215,28 @@ module SecureHeaders
|
|
215
215
|
if config.directive_value(:script_src).nil?
|
216
216
|
raise ContentSecurityPolicyConfigError.new(":script_src is required, falling back to default-src is too dangerous. Use `script_src: OPT_OUT` to override")
|
217
217
|
end
|
218
|
+
if !config.report_only? && config.directive_value(:report_only)
|
219
|
+
raise ContentSecurityPolicyConfigError.new("Only the csp_report_only config should set :report_only to true")
|
220
|
+
end
|
221
|
+
|
222
|
+
if config.report_only? && config.directive_value(:report_only) == false
|
223
|
+
raise ContentSecurityPolicyConfigError.new("csp_report_only config must have :report_only set to true")
|
224
|
+
end
|
218
225
|
|
219
226
|
ContentSecurityPolicyConfig.attrs.each do |key|
|
220
227
|
value = config.directive_value(key)
|
221
228
|
next unless value
|
229
|
+
|
222
230
|
if META_CONFIGS.include?(key)
|
223
231
|
raise ContentSecurityPolicyConfigError.new("#{key} must be a boolean value") unless boolean?(value) || value.nil?
|
232
|
+
elsif NONCES.include?(key)
|
233
|
+
raise ContentSecurityPolicyConfigError.new("#{key} must be a non-nil value") if value.nil?
|
224
234
|
else
|
225
235
|
validate_directive!(key, value)
|
226
236
|
end
|
227
237
|
end
|
228
238
|
end
|
229
239
|
|
230
|
-
# Public: check if a user agent supports CSP nonces
|
231
|
-
#
|
232
|
-
# user_agent - a String or a UserAgent object
|
233
|
-
def nonces_supported?(user_agent)
|
234
|
-
user_agent = UserAgent.parse(user_agent) if user_agent.is_a?(String)
|
235
|
-
MODERN_BROWSERS.include?(user_agent.browser) ||
|
236
|
-
user_agent.browser == "Safari" && (user_agent.version || CSP::FALLBACK_VERSION) >= CSP::VERSION_10
|
237
|
-
end
|
238
|
-
|
239
240
|
# Public: combine the values from two different configs.
|
240
241
|
#
|
241
242
|
# original - the main config
|
@@ -5,15 +5,14 @@ module SecureHeaders
|
|
5
5
|
HEADER_NAME = "Public-Key-Pins".freeze
|
6
6
|
REPORT_ONLY = "Public-Key-Pins-Report-Only".freeze
|
7
7
|
HASH_ALGORITHMS = [:sha256].freeze
|
8
|
-
CONFIG_KEY = :hpkp
|
9
8
|
|
10
9
|
|
11
10
|
class << self
|
12
11
|
# Public: make an hpkp header name, value pair
|
13
12
|
#
|
14
13
|
# Returns nil if not configured, returns header name and value if configured.
|
15
|
-
def make_header(config)
|
16
|
-
return if config.nil?
|
14
|
+
def make_header(config, user_agent = nil)
|
15
|
+
return if config.nil? || config == OPT_OUT
|
17
16
|
header = new(config)
|
18
17
|
[header.name, header.value]
|
19
18
|
end
|
@@ -14,14 +14,14 @@ module SecureHeaders
|
|
14
14
|
origin-when-cross-origin
|
15
15
|
unsafe-url
|
16
16
|
)
|
17
|
-
CONFIG_KEY = :referrer_policy
|
18
17
|
|
19
18
|
class << self
|
20
19
|
# Public: generate an Referrer Policy header.
|
21
20
|
#
|
22
21
|
# Returns a default header if no configuration is provided, or a
|
23
22
|
# header name and value based on the config.
|
24
|
-
def make_header(config = nil)
|
23
|
+
def make_header(config = nil, user_agent = nil)
|
24
|
+
return if config == OPT_OUT
|
25
25
|
config ||= DEFAULT_VALUE
|
26
26
|
[HEADER_NAME, Array(config).join(", ")]
|
27
27
|
end
|
@@ -8,14 +8,14 @@ module SecureHeaders
|
|
8
8
|
DEFAULT_VALUE = "max-age=" + HSTS_MAX_AGE
|
9
9
|
VALID_STS_HEADER = /\Amax-age=\d+(; includeSubdomains)?(; preload)?\z/i
|
10
10
|
MESSAGE = "The config value supplied for the HSTS header was invalid. Must match #{VALID_STS_HEADER}"
|
11
|
-
CONFIG_KEY = :hsts
|
12
11
|
|
13
12
|
class << self
|
14
13
|
# Public: generate an hsts header name, value pair.
|
15
14
|
#
|
16
15
|
# Returns a default header if no configuration is provided, or a
|
17
16
|
# header name and value based on the config.
|
18
|
-
def make_header(config = nil)
|
17
|
+
def make_header(config = nil, user_agent = nil)
|
18
|
+
return if config == OPT_OUT
|
19
19
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
20
20
|
end
|
21
21
|
|
@@ -5,14 +5,14 @@ module SecureHeaders
|
|
5
5
|
class XContentTypeOptions
|
6
6
|
HEADER_NAME = "X-Content-Type-Options".freeze
|
7
7
|
DEFAULT_VALUE = "nosniff"
|
8
|
-
CONFIG_KEY = :x_content_type_options
|
9
8
|
|
10
9
|
class << self
|
11
10
|
# Public: generate an X-Content-Type-Options header.
|
12
11
|
#
|
13
12
|
# Returns a default header if no configuration is provided, or a
|
14
13
|
# header name and value based on the config.
|
15
|
-
def make_header(config = nil)
|
14
|
+
def make_header(config = nil, user_agent = nil)
|
15
|
+
return if config == OPT_OUT
|
16
16
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
17
17
|
end
|
18
18
|
|
@@ -4,14 +4,14 @@ module SecureHeaders
|
|
4
4
|
class XDownloadOptions
|
5
5
|
HEADER_NAME = "X-Download-Options".freeze
|
6
6
|
DEFAULT_VALUE = "noopen"
|
7
|
-
CONFIG_KEY = :x_download_options
|
8
7
|
|
9
8
|
class << self
|
10
9
|
# Public: generate an X-Download-Options header.
|
11
10
|
#
|
12
11
|
# Returns a default header if no configuration is provided, or a
|
13
12
|
# header name and value based on the config.
|
14
|
-
def make_header(config = nil)
|
13
|
+
def make_header(config = nil, user_agent = nil)
|
14
|
+
return if config == OPT_OUT
|
15
15
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
16
16
|
end
|
17
17
|
|
@@ -3,7 +3,6 @@ module SecureHeaders
|
|
3
3
|
class XFOConfigError < StandardError; end
|
4
4
|
class XFrameOptions
|
5
5
|
HEADER_NAME = "X-Frame-Options".freeze
|
6
|
-
CONFIG_KEY = :x_frame_options
|
7
6
|
SAMEORIGIN = "sameorigin"
|
8
7
|
DENY = "deny"
|
9
8
|
ALLOW_FROM = "allow-from"
|
@@ -16,7 +15,7 @@ module SecureHeaders
|
|
16
15
|
#
|
17
16
|
# Returns a default header if no configuration is provided, or a
|
18
17
|
# header name and value based on the config.
|
19
|
-
def make_header(config = nil)
|
18
|
+
def make_header(config = nil, user_agent = nil)
|
20
19
|
return if config == OPT_OUT
|
21
20
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
22
21
|
end
|
@@ -5,14 +5,14 @@ module SecureHeaders
|
|
5
5
|
HEADER_NAME = "X-Permitted-Cross-Domain-Policies".freeze
|
6
6
|
DEFAULT_VALUE = "none"
|
7
7
|
VALID_POLICIES = %w(all none master-only by-content-type by-ftp-filename)
|
8
|
-
CONFIG_KEY = :x_permitted_cross_domain_policies
|
9
8
|
|
10
9
|
class << self
|
11
10
|
# Public: generate an X-Permitted-Cross-Domain-Policies header.
|
12
11
|
#
|
13
12
|
# Returns a default header if no configuration is provided, or a
|
14
13
|
# header name and value based on the config.
|
15
|
-
def make_header(config = nil)
|
14
|
+
def make_header(config = nil, user_agent = nil)
|
15
|
+
return if config == OPT_OUT
|
16
16
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
17
17
|
end
|
18
18
|
|
@@ -4,15 +4,15 @@ module SecureHeaders
|
|
4
4
|
class XXssProtection
|
5
5
|
HEADER_NAME = "X-XSS-Protection".freeze
|
6
6
|
DEFAULT_VALUE = "1; mode=block"
|
7
|
-
VALID_X_XSS_HEADER = /\A[01](; mode=block)?(; report=.*)?\z/
|
8
|
-
CONFIG_KEY = :x_xss_protection
|
7
|
+
VALID_X_XSS_HEADER = /\A[01](; mode=block)?(; report=.*)?\z/
|
9
8
|
|
10
9
|
class << self
|
11
10
|
# Public: generate an X-Xss-Protection header.
|
12
11
|
#
|
13
12
|
# Returns a default header if no configuration is provided, or a
|
14
13
|
# header name and value based on the config.
|
15
|
-
def make_header(config = nil)
|
14
|
+
def make_header(config = nil, user_agent = nil)
|
15
|
+
return if config == OPT_OUT
|
16
16
|
[HEADER_NAME, config || DEFAULT_VALUE]
|
17
17
|
end
|
18
18
|
|
data/secure_headers.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = "secure_headers"
|
5
|
-
gem.version = "
|
5
|
+
gem.version = "6.0.0.alpha01"
|
6
6
|
gem.authors = ["Neil Matatall"]
|
7
7
|
gem.email = ["neil.matatall@gmail.com"]
|
8
8
|
gem.description = "Manages application of security headers with many safe defaults."
|
@@ -5,88 +5,33 @@ module SecureHeaders
|
|
5
5
|
describe Configuration do
|
6
6
|
before(:each) do
|
7
7
|
reset_config
|
8
|
-
Configuration.default
|
9
8
|
end
|
10
9
|
|
11
10
|
it "has a default config" do
|
12
|
-
expect(Configuration.
|
13
|
-
end
|
14
|
-
|
15
|
-
it "warns when using deprecated internal-ish #get API" do
|
16
|
-
expect(Kernel).to receive(:warn).once.with(/`#get` is deprecated/)
|
17
|
-
Configuration.get(Configuration::DEFAULT_CONFIG)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "has an 'noop' config" do
|
21
|
-
expect(Configuration.get(Configuration::NOOP_CONFIGURATION, internal: true)).to_not be_nil
|
22
|
-
end
|
23
|
-
|
24
|
-
it "precomputes headers upon creation" do
|
25
|
-
default_config = Configuration.get(Configuration::DEFAULT_CONFIG, internal: true)
|
26
|
-
header_hash = default_config.cached_headers.each_with_object({}) do |(key, value), hash|
|
27
|
-
header_name, header_value = if key == :csp
|
28
|
-
value["Chrome"]
|
29
|
-
else
|
30
|
-
value
|
31
|
-
end
|
32
|
-
|
33
|
-
hash[header_name] = header_value
|
34
|
-
end
|
35
|
-
expect_default_values(header_hash)
|
11
|
+
expect(Configuration.default).to_not be_nil
|
36
12
|
end
|
37
13
|
|
38
|
-
it "
|
39
|
-
Configuration.
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
config = Configuration.get(:test_override, internal: true)
|
44
|
-
noop = Configuration.get(Configuration::NOOP_CONFIGURATION, internal: true)
|
45
|
-
[:csp, :csp_report_only, :cookies].each do |key|
|
46
|
-
expect(config.send(key)).to eq(noop.send(key))
|
47
|
-
end
|
14
|
+
it "has an 'noop' override" do
|
15
|
+
Configuration.default
|
16
|
+
expect(Configuration.overrides(Configuration::NOOP_OVERRIDE)).to_not be_nil
|
48
17
|
end
|
49
18
|
|
50
|
-
it "
|
51
|
-
Configuration.
|
52
|
-
|
19
|
+
it "dup results in a copy of the default config" do
|
20
|
+
Configuration.default
|
21
|
+
original_configuration = Configuration.send(:default_config)
|
22
|
+
configuration = Configuration.dup
|
23
|
+
expect(original_configuration).not_to be(configuration)
|
24
|
+
Configuration::CONFIG_ATTRIBUTES.each do |attr|
|
25
|
+
expect(original_configuration.send(attr)).to eq(configuration.send(attr))
|
53
26
|
end
|
54
|
-
|
55
|
-
expect(Configuration.get(Configuration::DEFAULT_CONFIG, internal: true).cached_headers).to_not eq(Configuration.get(:test_override, internal: true).cached_headers)
|
56
27
|
end
|
57
28
|
|
58
|
-
it "stores an override
|
29
|
+
it "stores an override" do
|
59
30
|
Configuration.override(:test_override) do |config|
|
60
31
|
config.x_frame_options = "DENY"
|
61
32
|
end
|
62
33
|
|
63
|
-
expect(Configuration.
|
64
|
-
end
|
65
|
-
|
66
|
-
it "deep dup's config values when overriding so the original cannot be modified" do
|
67
|
-
Configuration.override(:override) do |config|
|
68
|
-
config.csp[:default_src] << "'self'"
|
69
|
-
end
|
70
|
-
|
71
|
-
default = Configuration.get(Configuration::DEFAULT_CONFIG, internal: true)
|
72
|
-
override = Configuration.get(:override, internal: true)
|
73
|
-
|
74
|
-
expect(override.csp.directive_value(:default_src)).not_to be(default.csp.directive_value(:default_src))
|
75
|
-
end
|
76
|
-
|
77
|
-
it "allows you to override an override" do
|
78
|
-
Configuration.override(:override) do |config|
|
79
|
-
config.csp = { default_src: %w('self'), script_src: %w('self')}
|
80
|
-
end
|
81
|
-
|
82
|
-
Configuration.override(:second_override, :override) do |config|
|
83
|
-
config.csp = config.csp.merge(script_src: %w(example.org))
|
84
|
-
end
|
85
|
-
|
86
|
-
original_override = Configuration.get(:override, internal: true)
|
87
|
-
expect(original_override.csp.to_h).to eq(default_src: %w('self'), script_src: %w('self'))
|
88
|
-
override_config = Configuration.get(:second_override, internal: true)
|
89
|
-
expect(override_config.csp.to_h).to eq(default_src: %w('self'), script_src: %w('self' example.org))
|
34
|
+
expect(Configuration.overrides(:test_override)).to_not be_nil
|
90
35
|
end
|
91
36
|
|
92
37
|
it "deprecates the secure_cookies configuration" do
|
@@ -106,7 +51,7 @@ module SecureHeaders
|
|
106
51
|
config.cookies = OPT_OUT
|
107
52
|
end
|
108
53
|
|
109
|
-
config = Configuration.
|
54
|
+
config = Configuration.dup
|
110
55
|
expect(config.cookies).to eq(OPT_OUT)
|
111
56
|
end
|
112
57
|
|
@@ -115,7 +60,7 @@ module SecureHeaders
|
|
115
60
|
config.cookies = {httponly: true, secure: true, samesite: {lax: false}}
|
116
61
|
end
|
117
62
|
|
118
|
-
config = Configuration.
|
63
|
+
config = Configuration.dup
|
119
64
|
expect(config.cookies).to eq({httponly: true, secure: true, samesite: {lax: false}})
|
120
65
|
end
|
121
66
|
end
|