secure_headers 3.0.3 → 3.1.0
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/.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
|