secure_headers 3.0.3 → 3.1.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.
Potentially problematic release.
This version of secure_headers might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +0 -9
- data/.travis.yml +13 -5
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -2
- data/README.md +7 -42
- data/lib/secure_headers.rb +37 -63
- data/lib/secure_headers/configuration.rb +85 -54
- data/lib/secure_headers/headers/content_security_policy.rb +31 -309
- data/lib/secure_headers/headers/policy_management.rb +319 -0
- data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
- data/lib/secure_headers/middleware.rb +23 -0
- data/lib/secure_headers/railtie.rb +1 -1
- data/secure_headers.gemspec +1 -1
- data/spec/lib/secure_headers/configuration_spec.rb +2 -4
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +0 -175
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +190 -0
- data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +1 -1
- data/spec/lib/secure_headers/middleware_spec.rb +23 -4
- data/spec/lib/secure_headers_spec.rb +100 -41
- data/spec/spec_helper.rb +4 -1
- metadata +5 -4
- data/lib/secure_headers/padrino.rb +0 -13
- data/travis.sh +0 -10
@@ -1,5 +1,7 @@
|
|
1
1
|
module SecureHeaders
|
2
2
|
class Middleware
|
3
|
+
SECURE_COOKIE_REGEXP = /;\s*secure\s*(;|$)/i.freeze
|
4
|
+
|
3
5
|
def initialize(app)
|
4
6
|
@app = app
|
5
7
|
end
|
@@ -8,8 +10,29 @@ module SecureHeaders
|
|
8
10
|
def call(env)
|
9
11
|
req = Rack::Request.new(env)
|
10
12
|
status, headers, response = @app.call(env)
|
13
|
+
|
14
|
+
config = SecureHeaders.config_for(req)
|
15
|
+
flag_cookies_as_secure!(headers) if config.secure_cookies
|
11
16
|
headers.merge!(SecureHeaders.header_hash_for(req))
|
12
17
|
[status, headers, response]
|
13
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# inspired by https://github.com/tobmatth/rack-ssl-enforcer/blob/6c014/lib/rack/ssl-enforcer.rb#L183-L194
|
23
|
+
def flag_cookies_as_secure!(headers)
|
24
|
+
if cookies = headers['Set-Cookie']
|
25
|
+
# Support Rails 2.3 / Rack 1.1 arrays as headers
|
26
|
+
cookies = cookies.split("\n") unless cookies.is_a?(Array)
|
27
|
+
|
28
|
+
headers['Set-Cookie'] = cookies.map do |cookie|
|
29
|
+
if cookie !~ SECURE_COOKIE_REGEXP
|
30
|
+
"#{cookie}; secure"
|
31
|
+
else
|
32
|
+
cookie
|
33
|
+
end
|
34
|
+
end.join("\n")
|
35
|
+
end
|
36
|
+
end
|
14
37
|
end
|
15
38
|
end
|
@@ -10,7 +10,7 @@ if defined?(Rails::Railtie)
|
|
10
10
|
'Public-Key-Pins', 'Public-Key-Pins-Report-Only']
|
11
11
|
|
12
12
|
initializer "secure_headers.middleware" do
|
13
|
-
Rails.application.config.middleware.
|
13
|
+
Rails.application.config.middleware.insert_before 0, SecureHeaders::Middleware
|
14
14
|
end
|
15
15
|
|
16
16
|
initializer "secure_headers.action_controller" do
|
data/secure_headers.gemspec
CHANGED
@@ -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.0
|
4
|
+
gem.version = "3.1.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.'
|
@@ -29,16 +29,14 @@ module SecureHeaders
|
|
29
29
|
expect_default_values(header_hash)
|
30
30
|
end
|
31
31
|
|
32
|
-
it "copies
|
32
|
+
it "copies config values when duping" do
|
33
33
|
Configuration.override(:test_override, Configuration::NOOP_CONFIGURATION) do
|
34
34
|
# do nothing, just copy it
|
35
35
|
end
|
36
36
|
|
37
37
|
config = Configuration.get(:test_override)
|
38
38
|
noop = Configuration.get(Configuration::NOOP_CONFIGURATION)
|
39
|
-
[:
|
40
|
-
:x_download_options, :x_permitted_cross_domain_policies, :hpkp, :csp].each do |key|
|
41
|
-
|
39
|
+
[:csp, :dynamic_csp, :secure_cookies].each do |key|
|
42
40
|
expect(config.send(key)).to eq(noop.send(key)), "Value not copied: #{key}."
|
43
41
|
end
|
44
42
|
end
|
@@ -22,181 +22,6 @@ module SecureHeaders
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
describe "#validate_config!" do
|
26
|
-
it "accepts all keys" do
|
27
|
-
# (pulled from README)
|
28
|
-
config = {
|
29
|
-
# "meta" values. these will shaped the header, but the values are not included in the header.
|
30
|
-
report_only: true, # default: false
|
31
|
-
preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
|
32
|
-
|
33
|
-
# directive values: these values will directly translate into source directives
|
34
|
-
default_src: %w(https: 'self'),
|
35
|
-
frame_src: %w('self' *.twimg.com itunes.apple.com),
|
36
|
-
connect_src: %w(wws:),
|
37
|
-
font_src: %w('self' data:),
|
38
|
-
img_src: %w(mycdn.com data:),
|
39
|
-
media_src: %w(utoob.com),
|
40
|
-
object_src: %w('self'),
|
41
|
-
script_src: %w('self'),
|
42
|
-
style_src: %w('unsafe-inline'),
|
43
|
-
base_uri: %w('self'),
|
44
|
-
child_src: %w('self'),
|
45
|
-
form_action: %w('self' github.com),
|
46
|
-
frame_ancestors: %w('none'),
|
47
|
-
plugin_types: %w(application/x-shockwave-flash),
|
48
|
-
block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
|
49
|
-
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
|
50
|
-
report_uri: %w(https://example.com/uri-directive)
|
51
|
-
}
|
52
|
-
|
53
|
-
CSP.validate_config!(config)
|
54
|
-
end
|
55
|
-
|
56
|
-
it "requires a :default_src value" do
|
57
|
-
expect do
|
58
|
-
CSP.validate_config!(script_src: %('self'))
|
59
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
60
|
-
end
|
61
|
-
|
62
|
-
it "requires :report_only to be a truthy value" do
|
63
|
-
expect do
|
64
|
-
CSP.validate_config!(default_opts.merge(report_only: "steve"))
|
65
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "requires :preserve_schemes to be a truthy value" do
|
69
|
-
expect do
|
70
|
-
CSP.validate_config!(default_opts.merge(preserve_schemes: "steve"))
|
71
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
72
|
-
end
|
73
|
-
|
74
|
-
it "requires :block_all_mixed_content to be a boolean value" do
|
75
|
-
expect do
|
76
|
-
CSP.validate_config!(default_opts.merge(block_all_mixed_content: "steve"))
|
77
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "requires :upgrade_insecure_requests to be a boolean value" do
|
81
|
-
expect do
|
82
|
-
CSP.validate_config!(default_opts.merge(upgrade_insecure_requests: "steve"))
|
83
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
84
|
-
end
|
85
|
-
|
86
|
-
it "requires all source lists to be an array of strings" do
|
87
|
-
expect do
|
88
|
-
CSP.validate_config!(default_src: "steve")
|
89
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
90
|
-
end
|
91
|
-
|
92
|
-
it "allows nil values" do
|
93
|
-
expect do
|
94
|
-
CSP.validate_config!(default_src: %w('self'), script_src: ["https:", nil])
|
95
|
-
end.to_not raise_error
|
96
|
-
end
|
97
|
-
|
98
|
-
it "rejects unknown directives / config" do
|
99
|
-
expect do
|
100
|
-
CSP.validate_config!(default_src: %w('self'), default_src_totally_mispelled: "steve")
|
101
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
102
|
-
end
|
103
|
-
|
104
|
-
# this is mostly to ensure people don't use the antiquated shorthands common in other configs
|
105
|
-
it "performs light validation on source lists" do
|
106
|
-
expect do
|
107
|
-
CSP.validate_config!(default_src: %w(self none inline eval))
|
108
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe "#combine_policies" do
|
113
|
-
it "combines the default-src value with the override if the directive was unconfigured" do
|
114
|
-
combined_config = CSP.combine_policies(Configuration.default.csp, script_src: %w(anothercdn.com))
|
115
|
-
csp = ContentSecurityPolicy.new(combined_config)
|
116
|
-
expect(csp.name).to eq(CSP::HEADER_NAME)
|
117
|
-
expect(csp.value).to eq("default-src https:; script-src https: anothercdn.com")
|
118
|
-
end
|
119
|
-
|
120
|
-
it "combines directives where the original value is nil and the hash is frozen" do
|
121
|
-
Configuration.default do |config|
|
122
|
-
config.csp = {
|
123
|
-
default_src: %w('self'),
|
124
|
-
report_only: false
|
125
|
-
}.freeze
|
126
|
-
end
|
127
|
-
report_uri = "https://report-uri.io/asdf"
|
128
|
-
combined_config = CSP.combine_policies(Configuration.get.csp, report_uri: [report_uri])
|
129
|
-
csp = ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox])
|
130
|
-
expect(csp.value).to include("report-uri #{report_uri}")
|
131
|
-
end
|
132
|
-
|
133
|
-
it "does not combine the default-src value for directives that don't fall back to default sources" do
|
134
|
-
Configuration.default do |config|
|
135
|
-
config.csp = {
|
136
|
-
default_src: %w('self'),
|
137
|
-
report_only: false
|
138
|
-
}.freeze
|
139
|
-
end
|
140
|
-
non_default_source_additions = CSP::NON_DEFAULT_SOURCES.each_with_object({}) do |directive, hash|
|
141
|
-
hash[directive] = %w("http://example.org)
|
142
|
-
end
|
143
|
-
combined_config = CSP.combine_policies(Configuration.get.csp, non_default_source_additions)
|
144
|
-
|
145
|
-
CSP::NON_DEFAULT_SOURCES.each do |directive|
|
146
|
-
expect(combined_config[directive]).to eq(%w("http://example.org))
|
147
|
-
end
|
148
|
-
|
149
|
-
ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox]).value
|
150
|
-
end
|
151
|
-
|
152
|
-
it "overrides the report_only flag" do
|
153
|
-
Configuration.default do |config|
|
154
|
-
config.csp = {
|
155
|
-
default_src: %w('self'),
|
156
|
-
report_only: false
|
157
|
-
}
|
158
|
-
end
|
159
|
-
combined_config = CSP.combine_policies(Configuration.get.csp, report_only: true)
|
160
|
-
csp = ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox])
|
161
|
-
expect(csp.name).to eq(CSP::REPORT_ONLY)
|
162
|
-
end
|
163
|
-
|
164
|
-
it "overrides the :block_all_mixed_content flag" do
|
165
|
-
Configuration.default do |config|
|
166
|
-
config.csp = {
|
167
|
-
default_src: %w(https:),
|
168
|
-
block_all_mixed_content: false
|
169
|
-
}
|
170
|
-
end
|
171
|
-
combined_config = CSP.combine_policies(Configuration.get.csp, block_all_mixed_content: true)
|
172
|
-
csp = ContentSecurityPolicy.new(combined_config)
|
173
|
-
expect(csp.value).to eq("default-src https:; block-all-mixed-content")
|
174
|
-
end
|
175
|
-
|
176
|
-
it "raises an error if appending to a OPT_OUT policy" do
|
177
|
-
Configuration.default do |config|
|
178
|
-
config.csp = OPT_OUT
|
179
|
-
end
|
180
|
-
expect do
|
181
|
-
CSP.combine_policies(Configuration.get.csp, script_src: %w(anothercdn.com))
|
182
|
-
end.to raise_error(ContentSecurityPolicyConfigError)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
describe "#idempotent_additions?" do
|
187
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?(OPT_OUT, script_src: %w(b.com))).to be false }
|
188
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(c.com))).to be false }
|
189
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: %w(b.com))).to be false }
|
190
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(a.com b.com c.com))).to be false }
|
191
|
-
|
192
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com))).to be true }
|
193
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com a.com))).to be true }
|
194
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w())).to be true }
|
195
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: [nil])).to be true }
|
196
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: [nil])).to be true }
|
197
|
-
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: nil)).to be true }
|
198
|
-
end
|
199
|
-
|
200
25
|
describe "#value" do
|
201
26
|
it "discards 'none' values if any other source expressions are present" do
|
202
27
|
csp = ContentSecurityPolicy.new(default_opts.merge(frame_src: %w('self' 'none')))
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module SecureHeaders
|
4
|
+
describe PolicyManagement do
|
5
|
+
let (:default_opts) do
|
6
|
+
{
|
7
|
+
default_src: %w(https:),
|
8
|
+
img_src: %w(https: data:),
|
9
|
+
script_src: %w('unsafe-inline' 'unsafe-eval' https: data:),
|
10
|
+
style_src: %w('unsafe-inline' https: about:),
|
11
|
+
report_uri: %w(/csp_report)
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#validate_config!" do
|
16
|
+
it "accepts all keys" do
|
17
|
+
# (pulled from README)
|
18
|
+
config = {
|
19
|
+
# "meta" values. these will shaped the header, but the values are not included in the header.
|
20
|
+
report_only: true, # default: false
|
21
|
+
preserve_schemes: true, # default: false. Schemes are removed from host sources to save bytes and discourage mixed content.
|
22
|
+
|
23
|
+
# directive values: these values will directly translate into source directives
|
24
|
+
default_src: %w(https: 'self'),
|
25
|
+
frame_src: %w('self' *.twimg.com itunes.apple.com),
|
26
|
+
connect_src: %w(wws:),
|
27
|
+
font_src: %w('self' data:),
|
28
|
+
img_src: %w(mycdn.com data:),
|
29
|
+
media_src: %w(utoob.com),
|
30
|
+
object_src: %w('self'),
|
31
|
+
script_src: %w('self'),
|
32
|
+
style_src: %w('unsafe-inline'),
|
33
|
+
base_uri: %w('self'),
|
34
|
+
child_src: %w('self'),
|
35
|
+
form_action: %w('self' github.com),
|
36
|
+
frame_ancestors: %w('none'),
|
37
|
+
plugin_types: %w(application/x-shockwave-flash),
|
38
|
+
block_all_mixed_content: true, # see [http://www.w3.org/TR/mixed-content/](http://www.w3.org/TR/mixed-content/)
|
39
|
+
upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
|
40
|
+
report_uri: %w(https://example.com/uri-directive)
|
41
|
+
}
|
42
|
+
|
43
|
+
CSP.validate_config!(config)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "requires a :default_src value" do
|
47
|
+
expect do
|
48
|
+
CSP.validate_config!(script_src: %('self'))
|
49
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "requires :report_only to be a truthy value" do
|
53
|
+
expect do
|
54
|
+
CSP.validate_config!(default_opts.merge(report_only: "steve"))
|
55
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "requires :preserve_schemes to be a truthy value" do
|
59
|
+
expect do
|
60
|
+
CSP.validate_config!(default_opts.merge(preserve_schemes: "steve"))
|
61
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "requires :block_all_mixed_content to be a boolean value" do
|
65
|
+
expect do
|
66
|
+
CSP.validate_config!(default_opts.merge(block_all_mixed_content: "steve"))
|
67
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "requires :upgrade_insecure_requests to be a boolean value" do
|
71
|
+
expect do
|
72
|
+
CSP.validate_config!(default_opts.merge(upgrade_insecure_requests: "steve"))
|
73
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "requires all source lists to be an array of strings" do
|
77
|
+
expect do
|
78
|
+
CSP.validate_config!(default_src: "steve")
|
79
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "allows nil values" do
|
83
|
+
expect do
|
84
|
+
CSP.validate_config!(default_src: %w('self'), script_src: ["https:", nil])
|
85
|
+
end.to_not raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it "rejects unknown directives / config" do
|
89
|
+
expect do
|
90
|
+
CSP.validate_config!(default_src: %w('self'), default_src_totally_mispelled: "steve")
|
91
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
92
|
+
end
|
93
|
+
|
94
|
+
# this is mostly to ensure people don't use the antiquated shorthands common in other configs
|
95
|
+
it "performs light validation on source lists" do
|
96
|
+
expect do
|
97
|
+
CSP.validate_config!(default_src: %w(self none inline eval))
|
98
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#combine_policies" do
|
103
|
+
it "combines the default-src value with the override if the directive was unconfigured" do
|
104
|
+
combined_config = CSP.combine_policies(Configuration.default.csp, script_src: %w(anothercdn.com))
|
105
|
+
csp = ContentSecurityPolicy.new(combined_config)
|
106
|
+
expect(csp.name).to eq(CSP::HEADER_NAME)
|
107
|
+
expect(csp.value).to eq("default-src https:; script-src https: anothercdn.com")
|
108
|
+
end
|
109
|
+
|
110
|
+
it "combines directives where the original value is nil and the hash is frozen" do
|
111
|
+
Configuration.default do |config|
|
112
|
+
config.csp = {
|
113
|
+
default_src: %w('self'),
|
114
|
+
report_only: false
|
115
|
+
}.freeze
|
116
|
+
end
|
117
|
+
report_uri = "https://report-uri.io/asdf"
|
118
|
+
combined_config = CSP.combine_policies(Configuration.get.csp, report_uri: [report_uri])
|
119
|
+
csp = ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox])
|
120
|
+
expect(csp.value).to include("report-uri #{report_uri}")
|
121
|
+
end
|
122
|
+
|
123
|
+
it "does not combine the default-src value for directives that don't fall back to default sources" do
|
124
|
+
Configuration.default do |config|
|
125
|
+
config.csp = {
|
126
|
+
default_src: %w('self'),
|
127
|
+
report_only: false
|
128
|
+
}.freeze
|
129
|
+
end
|
130
|
+
non_default_source_additions = CSP::NON_FETCH_SOURCES.each_with_object({}) do |directive, hash|
|
131
|
+
hash[directive] = %w("http://example.org)
|
132
|
+
end
|
133
|
+
combined_config = CSP.combine_policies(Configuration.get.csp, non_default_source_additions)
|
134
|
+
|
135
|
+
CSP::NON_FETCH_SOURCES.each do |directive|
|
136
|
+
expect(combined_config[directive]).to eq(%w("http://example.org))
|
137
|
+
end
|
138
|
+
|
139
|
+
ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox]).value
|
140
|
+
end
|
141
|
+
|
142
|
+
it "overrides the report_only flag" do
|
143
|
+
Configuration.default do |config|
|
144
|
+
config.csp = {
|
145
|
+
default_src: %w('self'),
|
146
|
+
report_only: false
|
147
|
+
}
|
148
|
+
end
|
149
|
+
combined_config = CSP.combine_policies(Configuration.get.csp, report_only: true)
|
150
|
+
csp = ContentSecurityPolicy.new(combined_config, USER_AGENTS[:firefox])
|
151
|
+
expect(csp.name).to eq(CSP::REPORT_ONLY)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "overrides the :block_all_mixed_content flag" do
|
155
|
+
Configuration.default do |config|
|
156
|
+
config.csp = {
|
157
|
+
default_src: %w(https:),
|
158
|
+
block_all_mixed_content: false
|
159
|
+
}
|
160
|
+
end
|
161
|
+
combined_config = CSP.combine_policies(Configuration.get.csp, block_all_mixed_content: true)
|
162
|
+
csp = ContentSecurityPolicy.new(combined_config)
|
163
|
+
expect(csp.value).to eq("default-src https:; block-all-mixed-content")
|
164
|
+
end
|
165
|
+
|
166
|
+
it "raises an error if appending to a OPT_OUT policy" do
|
167
|
+
Configuration.default do |config|
|
168
|
+
config.csp = OPT_OUT
|
169
|
+
end
|
170
|
+
expect do
|
171
|
+
CSP.combine_policies(Configuration.get.csp, script_src: %w(anothercdn.com))
|
172
|
+
end.to raise_error(ContentSecurityPolicyConfigError)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "#idempotent_additions?" do
|
177
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?(OPT_OUT, script_src: %w(b.com))).to be false }
|
178
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(c.com))).to be false }
|
179
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: %w(b.com))).to be false }
|
180
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(a.com b.com c.com))).to be false }
|
181
|
+
|
182
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com))).to be true }
|
183
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w(b.com a.com))).to be true }
|
184
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: %w())).to be true }
|
185
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, script_src: [nil])).to be true }
|
186
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: [nil])).to be true }
|
187
|
+
specify { expect(ContentSecurityPolicy.idempotent_additions?({script_src: %w(a.com b.com)}, style_src: nil)).to be true }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|