secure_headers 7.0.0 → 7.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -13
  3. data/lib/secure_headers/configuration.rb +1 -1
  4. data/lib/secure_headers/headers/clear_site_data.rb +4 -4
  5. data/lib/secure_headers/headers/content_security_policy.rb +2 -2
  6. data/lib/secure_headers/headers/content_security_policy_config.rb +2 -2
  7. data/lib/secure_headers/headers/expect_certificate_transparency.rb +2 -2
  8. data/lib/secure_headers/headers/policy_management.rb +2 -2
  9. data/lib/secure_headers/headers/referrer_policy.rb +1 -1
  10. data/lib/secure_headers/headers/strict_transport_security.rb +1 -1
  11. data/lib/secure_headers/headers/x_content_type_options.rb +1 -1
  12. data/lib/secure_headers/headers/x_download_options.rb +2 -2
  13. data/lib/secure_headers/headers/x_frame_options.rb +1 -1
  14. data/lib/secure_headers/headers/x_permitted_cross_domain_policies.rb +2 -2
  15. data/lib/secure_headers/headers/x_xss_protection.rb +1 -1
  16. data/lib/secure_headers/railtie.rb +5 -5
  17. data/lib/secure_headers/version.rb +1 -1
  18. data/secure_headers.gemspec +13 -3
  19. metadata +14 -63
  20. data/.github/ISSUE_TEMPLATE.md +0 -41
  21. data/.github/PULL_REQUEST_TEMPLATE.md +0 -20
  22. data/.github/dependabot.yml +0 -6
  23. data/.github/workflows/build.yml +0 -25
  24. data/.github/workflows/github-release.yml +0 -28
  25. data/.gitignore +0 -13
  26. data/.rspec +0 -3
  27. data/.rubocop.yml +0 -4
  28. data/.ruby-gemset +0 -1
  29. data/.ruby-version +0 -1
  30. data/CODE_OF_CONDUCT.md +0 -46
  31. data/CONTRIBUTING.md +0 -41
  32. data/Guardfile +0 -13
  33. data/Rakefile +0 -32
  34. data/docs/cookies.md +0 -65
  35. data/docs/hashes.md +0 -64
  36. data/docs/named_overrides_and_appends.md +0 -104
  37. data/docs/per_action_configuration.md +0 -139
  38. data/docs/sinatra.md +0 -25
  39. data/docs/upgrading-to-3-0.md +0 -42
  40. data/docs/upgrading-to-4-0.md +0 -35
  41. data/docs/upgrading-to-5-0.md +0 -15
  42. data/docs/upgrading-to-6-0.md +0 -50
  43. data/docs/upgrading-to-7-0.md +0 -12
  44. data/spec/lib/secure_headers/configuration_spec.rb +0 -121
  45. data/spec/lib/secure_headers/headers/clear_site_data_spec.rb +0 -87
  46. data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +0 -215
  47. data/spec/lib/secure_headers/headers/cookie_spec.rb +0 -179
  48. data/spec/lib/secure_headers/headers/expect_certificate_transparency_spec.rb +0 -42
  49. data/spec/lib/secure_headers/headers/policy_management_spec.rb +0 -265
  50. data/spec/lib/secure_headers/headers/referrer_policy_spec.rb +0 -91
  51. data/spec/lib/secure_headers/headers/strict_transport_security_spec.rb +0 -33
  52. data/spec/lib/secure_headers/headers/x_content_type_options_spec.rb +0 -31
  53. data/spec/lib/secure_headers/headers/x_download_options_spec.rb +0 -29
  54. data/spec/lib/secure_headers/headers/x_frame_options_spec.rb +0 -36
  55. data/spec/lib/secure_headers/headers/x_permitted_cross_domain_policies_spec.rb +0 -48
  56. data/spec/lib/secure_headers/headers/x_xss_protection_spec.rb +0 -47
  57. data/spec/lib/secure_headers/middleware_spec.rb +0 -117
  58. data/spec/lib/secure_headers/view_helpers_spec.rb +0 -192
  59. data/spec/lib/secure_headers_spec.rb +0 -516
  60. data/spec/spec_helper.rb +0 -64
@@ -1,121 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe Configuration do
6
- before(:each) do
7
- reset_config
8
- end
9
-
10
- it "has a default config" do
11
- expect(Configuration.default).to_not be_nil
12
- end
13
-
14
- it "has an 'noop' override" do
15
- Configuration.default
16
- expect(Configuration.overrides(Configuration::NOOP_OVERRIDE)).to_not be_nil
17
- end
18
-
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))
26
- end
27
- end
28
-
29
- it "stores an override" do
30
- Configuration.override(:test_override) do |config|
31
- config.x_frame_options = "DENY"
32
- end
33
-
34
- expect(Configuration.overrides(:test_override)).to_not be_nil
35
- end
36
-
37
- describe "#override" do
38
- it "raises on configuring an existing override" do
39
- set_override = Proc.new {
40
- Configuration.override(:test_override) do |config|
41
- config.x_frame_options = "DENY"
42
- end
43
- }
44
-
45
- set_override.call
46
-
47
- expect { set_override.call }
48
- .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
49
- end
50
-
51
- it "raises when a named append with the given name exists" do
52
- Configuration.named_append(:test_override) do |config|
53
- config.x_frame_options = "DENY"
54
- end
55
-
56
- expect do
57
- Configuration.override(:test_override) do |config|
58
- config.x_frame_options = "SAMEORIGIN"
59
- end
60
- end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
61
- end
62
- end
63
-
64
- describe "#named_append" do
65
- it "raises on configuring an existing append" do
66
- set_override = Proc.new {
67
- Configuration.named_append(:test_override) do |config|
68
- config.x_frame_options = "DENY"
69
- end
70
- }
71
-
72
- set_override.call
73
-
74
- expect { set_override.call }
75
- .to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
76
- end
77
-
78
- it "raises when an override with the given name exists" do
79
- Configuration.override(:test_override) do |config|
80
- config.x_frame_options = "DENY"
81
- end
82
-
83
- expect do
84
- Configuration.named_append(:test_override) do |config|
85
- config.x_frame_options = "SAMEORIGIN"
86
- end
87
- end.to raise_error(Configuration::AlreadyConfiguredError, "Configuration already exists")
88
- end
89
- end
90
-
91
- it "deprecates the secure_cookies configuration" do
92
- expect {
93
- Configuration.default do |config|
94
- config.secure_cookies = true
95
- end
96
- }.to raise_error(ArgumentError)
97
- end
98
-
99
- it "gives cookies a default config" do
100
- expect(Configuration.default.cookies).to eq({httponly: true, secure: true, samesite: {lax: true}})
101
- end
102
-
103
- it "allows OPT_OUT" do
104
- Configuration.default do |config|
105
- config.cookies = OPT_OUT
106
- end
107
-
108
- config = Configuration.dup
109
- expect(config.cookies).to eq(OPT_OUT)
110
- end
111
-
112
- it "allows me to be explicit too" do
113
- Configuration.default do |config|
114
- config.cookies = {httponly: true, secure: true, samesite: {lax: false}}
115
- end
116
-
117
- config = Configuration.dup
118
- expect(config.cookies).to eq({httponly: true, secure: true, samesite: {lax: false}})
119
- end
120
- end
121
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe ClearSiteData do
6
- describe "make_header" do
7
- it "returns nil with nil config" do
8
- expect(described_class.make_header).to be_nil
9
- end
10
-
11
- it "returns nil with empty config" do
12
- expect(described_class.make_header([])).to be_nil
13
- end
14
-
15
- it "returns nil with opt-out config" do
16
- expect(described_class.make_header(OPT_OUT)).to be_nil
17
- end
18
-
19
- it "returns all types with `true` config" do
20
- name, value = described_class.make_header(true)
21
-
22
- expect(name).to eq(ClearSiteData::HEADER_NAME)
23
- expect(value).to eq(
24
- %("cache", "cookies", "storage", "executionContexts")
25
- )
26
- end
27
-
28
- it "returns specified types" do
29
- name, value = described_class.make_header(["foo", "bar"])
30
-
31
- expect(name).to eq(ClearSiteData::HEADER_NAME)
32
- expect(value).to eq(%("foo", "bar"))
33
- end
34
- end
35
-
36
- describe "validate_config!" do
37
- it "succeeds for `true` config" do
38
- expect do
39
- described_class.validate_config!(true)
40
- end.not_to raise_error
41
- end
42
-
43
- it "succeeds for `nil` config" do
44
- expect do
45
- described_class.validate_config!(nil)
46
- end.not_to raise_error
47
- end
48
-
49
- it "succeeds for opt-out config" do
50
- expect do
51
- described_class.validate_config!(OPT_OUT)
52
- end.not_to raise_error
53
- end
54
-
55
- it "succeeds for empty config" do
56
- expect do
57
- described_class.validate_config!([])
58
- end.not_to raise_error
59
- end
60
-
61
- it "succeeds for Array of Strings config" do
62
- expect do
63
- described_class.validate_config!(["foo"])
64
- end.not_to raise_error
65
- end
66
-
67
- it "fails for Array of non-String config" do
68
- expect do
69
- described_class.validate_config!([1])
70
- end.to raise_error(ClearSiteDataConfigError)
71
- end
72
-
73
- it "fails for other types of config" do
74
- expect do
75
- described_class.validate_config!(:cookies)
76
- end.to raise_error(ClearSiteDataConfigError)
77
- end
78
- end
79
-
80
- describe "make_header_value" do
81
- it "returns a string of quoted values that are comma separated" do
82
- value = described_class.make_header_value(["foo", "bar"])
83
- expect(value).to eq(%("foo", "bar"))
84
- end
85
- end
86
- end
87
- end
@@ -1,215 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe ContentSecurityPolicy do
6
- let (:default_opts) do
7
- {
8
- default_src: %w(https:),
9
- img_src: %w(https: data:),
10
- script_src: %w('unsafe-inline' 'unsafe-eval' https: data:),
11
- style_src: %w('unsafe-inline' https: about:),
12
- report_uri: %w(/csp_report)
13
- }
14
- end
15
-
16
- describe "#name" do
17
- context "when in report-only mode" do
18
- specify { expect(ContentSecurityPolicy.new(default_opts.merge(report_only: true)).name).to eq(ContentSecurityPolicyReportOnlyConfig::HEADER_NAME) }
19
- end
20
-
21
- context "when in enforce mode" do
22
- specify { expect(ContentSecurityPolicy.new(default_opts).name).to eq(ContentSecurityPolicyConfig::HEADER_NAME) }
23
- end
24
- end
25
-
26
- describe "#value" do
27
- it "uses a safe but non-breaking default value" do
28
- expect(ContentSecurityPolicy.new.value).to eq("default-src https:; form-action 'self'; img-src https: data: 'self'; object-src 'none'; script-src https:; style-src 'self' 'unsafe-inline' https:")
29
- end
30
-
31
- it "deprecates and escapes semicolons in directive source lists" do
32
- expect(Kernel).to receive(:warn).with(%(frame_ancestors contains a ; in "google.com;script-src *;.;" which will raise an error in future versions. It has been replaced with a blank space.))
33
- expect(ContentSecurityPolicy.new(frame_ancestors: %w(https://google.com;script-src https://*;.;)).value).to eq("frame-ancestors google.com script-src * .")
34
- end
35
-
36
- it "deprecates and escapes semicolons in directive source lists" do
37
- expect(Kernel).to receive(:warn).with(%(frame_ancestors contains a \n in "\\nfoo.com\\nhacked" which will raise an error in future versions. It has been replaced with a blank space.))
38
- expect(ContentSecurityPolicy.new(frame_ancestors: ["\nfoo.com\nhacked"]).value).to eq("frame-ancestors foo.com hacked")
39
- end
40
-
41
- it "discards 'none' values if any other source expressions are present" do
42
- csp = ContentSecurityPolicy.new(default_opts.merge(child_src: %w('self' 'none')))
43
- expect(csp.value).not_to include("'none'")
44
- end
45
-
46
- it "discards source expressions (besides unsafe-* and non-host source values) when * is present" do
47
- csp = ContentSecurityPolicy.new(default_src: %w(* 'unsafe-inline' 'unsafe-eval' http: https: example.org data: blob:))
48
- expect(csp.value).to eq("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:")
49
- end
50
-
51
- it "does not minify source expressions based on overlapping wildcards" do
52
- config = {
53
- default_src: %w(a.example.org b.example.org *.example.org https://*.example.org)
54
- }
55
- csp = ContentSecurityPolicy.new(config)
56
- expect(csp.value).to eq("default-src a.example.org b.example.org *.example.org")
57
- end
58
-
59
- it "removes http/s schemes from hosts" do
60
- csp = ContentSecurityPolicy.new(default_src: %w(https://example.org))
61
- expect(csp.value).to eq("default-src example.org")
62
- end
63
-
64
- it "does not build directives with a value of OPT_OUT (and bypasses directive requirements)" do
65
- csp = ContentSecurityPolicy.new(default_src: %w(https://example.org), script_src: OPT_OUT)
66
- expect(csp.value).to eq("default-src example.org")
67
- end
68
-
69
- it "does not remove schemes from report-uri values" do
70
- csp = ContentSecurityPolicy.new(default_src: %w(https:), report_uri: %w(https://example.org))
71
- expect(csp.value).to eq("default-src https:; report-uri https://example.org")
72
- end
73
-
74
- it "does not remove schemes when :preserve_schemes is true" do
75
- csp = ContentSecurityPolicy.new(default_src: %w(https://example.org), preserve_schemes: true)
76
- expect(csp.value).to eq("default-src https://example.org")
77
- end
78
-
79
- it "removes nil from source lists" do
80
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org", nil])
81
- expect(csp.value).to eq("default-src example.org")
82
- end
83
-
84
- it "does not add a directive if the value is an empty array (or all nil)" do
85
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], script_src: [nil])
86
- expect(csp.value).to eq("default-src example.org")
87
- end
88
-
89
- it "does not add a directive if the value is nil" do
90
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], script_src: nil)
91
- expect(csp.value).to eq("default-src example.org")
92
- end
93
-
94
- it "does add a boolean directive if the value is true" do
95
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], upgrade_insecure_requests: true)
96
- expect(csp.value).to eq("default-src example.org; upgrade-insecure-requests")
97
- end
98
-
99
- it "does not add a boolean directive if the value is false" do
100
- csp = ContentSecurityPolicy.new(default_src: ["https://example.org"], upgrade_insecure_requests: false)
101
- expect(csp.value).to eq("default-src example.org")
102
- end
103
-
104
- it "handles wildcard subdomain with wildcard port" do
105
- csp = ContentSecurityPolicy.new(default_src: %w(https://*.example.org:*))
106
- expect(csp.value).to eq("default-src *.example.org:*")
107
- end
108
-
109
- it "deduplicates source expressions that match exactly (after scheme stripping)" do
110
- csp = ContentSecurityPolicy.new(default_src: %w(example.org https://example.org example.org))
111
- expect(csp.value).to eq("default-src example.org")
112
- end
113
-
114
- it "does not deduplicate non-matching schema source expressions" do
115
- csp = ContentSecurityPolicy.new(default_src: %w(*.example.org wss://example.example.org))
116
- expect(csp.value).to eq("default-src *.example.org wss://example.example.org")
117
- end
118
-
119
- it "creates maximally strict sandbox policy when passed no sandbox token values" do
120
- csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: [])
121
- expect(csp.value).to eq("default-src example.org; sandbox")
122
- end
123
-
124
- it "creates maximally strict sandbox policy when passed true" do
125
- csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: true)
126
- expect(csp.value).to eq("default-src example.org; sandbox")
127
- end
128
-
129
- it "creates sandbox policy when passed valid sandbox token values" do
130
- csp = ContentSecurityPolicy.new(default_src: %w(example.org), sandbox: %w(allow-forms allow-scripts))
131
- expect(csp.value).to eq("default-src example.org; sandbox allow-forms allow-scripts")
132
- end
133
-
134
- it "does not emit a warning when using frame-src" do
135
- expect(Kernel).to_not receive(:warn)
136
- ContentSecurityPolicy.new(default_src: %w('self'), frame_src: %w('self')).value
137
- end
138
-
139
- it "allows script as a require-sri-src" do
140
- csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(script))
141
- expect(csp.value).to eq("default-src 'self'; require-sri-for script")
142
- end
143
-
144
- it "allows style as a require-sri-src" do
145
- csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(style))
146
- expect(csp.value).to eq("default-src 'self'; require-sri-for style")
147
- end
148
-
149
- it "allows script and style as a require-sri-src" do
150
- csp = ContentSecurityPolicy.new(default_src: %w('self'), require_sri_for: %w(script style))
151
- expect(csp.value).to eq("default-src 'self'; require-sri-for script style")
152
- end
153
-
154
- it "allows style as a require-trusted-types-for source" do
155
- csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script))
156
- expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script")
157
- end
158
-
159
- it "includes prefetch-src" do
160
- csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com))
161
- expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com")
162
- end
163
-
164
- it "includes navigate-to" do
165
- csp = ContentSecurityPolicy.new(default_src: %w('self'), navigate_to: %w(foo.com))
166
- expect(csp.value).to eq("default-src 'self'; navigate-to foo.com")
167
- end
168
-
169
- it "supports strict-dynamic" do
170
- csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456})
171
- expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456' 'unsafe-inline'")
172
- end
173
-
174
- it "supports strict-dynamic and opting out of the appended 'unsafe-inline'" do
175
- csp = ContentSecurityPolicy.new({default_src: %w('self'), script_src: [ContentSecurityPolicy::STRICT_DYNAMIC], script_nonce: 123456, disable_nonce_backwards_compatibility: true })
176
- expect(csp.value).to eq("default-src 'self'; script-src 'strict-dynamic' 'nonce-123456'")
177
- end
178
-
179
- it "supports script-src-elem directive" do
180
- csp = ContentSecurityPolicy.new({script_src: %w('self'), script_src_elem: %w('self')})
181
- expect(csp.value).to eq("script-src 'self'; script-src-elem 'self'")
182
- end
183
-
184
- it "supports script-src-attr directive" do
185
- csp = ContentSecurityPolicy.new({script_src: %w('self'), script_src_attr: %w('self')})
186
- expect(csp.value).to eq("script-src 'self'; script-src-attr 'self'")
187
- end
188
-
189
- it "supports style-src-elem directive" do
190
- csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_elem: %w('self')})
191
- expect(csp.value).to eq("style-src 'self'; style-src-elem 'self'")
192
- end
193
-
194
- it "supports style-src-attr directive" do
195
- csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')})
196
- expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'")
197
- end
198
-
199
- it "supports trusted-types directive" do
200
- csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)})
201
- expect(csp.value).to eq("trusted-types blahblahpolicy")
202
- end
203
-
204
- it "supports trusted-types directive with 'none'" do
205
- csp = ContentSecurityPolicy.new({trusted_types: %w('none')})
206
- expect(csp.value).to eq("trusted-types 'none'")
207
- end
208
-
209
- it "allows duplicate policy names in trusted-types directive" do
210
- csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')})
211
- expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'")
212
- end
213
- end
214
- end
215
- end
@@ -1,179 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe Cookie do
6
- let(:raw_cookie) { "_session=thisisatest" }
7
-
8
- it "does not tamper with cookies when using OPT_OUT is used" do
9
- cookie = Cookie.new(raw_cookie, OPT_OUT)
10
- expect(cookie.to_s).to eq(raw_cookie)
11
- end
12
-
13
- it "applies httponly, secure, and samesite by default" do
14
- cookie = Cookie.new(raw_cookie, nil)
15
- expect(cookie.to_s).to eq("_session=thisisatest; secure; HttpOnly; SameSite=Lax")
16
- end
17
-
18
- it "preserves existing attributes" do
19
- cookie = Cookie.new("_session=thisisatest; secure", secure: true, httponly: OPT_OUT, samesite: OPT_OUT)
20
- expect(cookie.to_s).to eq("_session=thisisatest; secure")
21
- end
22
-
23
- it "prevents duplicate flagging of attributes" do
24
- cookie = Cookie.new("_session=thisisatest; secure", secure: true, httponly: OPT_OUT)
25
- expect(cookie.to_s.scan(/secure/i).count).to eq(1)
26
- end
27
-
28
- context "Secure cookies" do
29
- context "when configured with a boolean" do
30
- it "flags cookies as Secure" do
31
- cookie = Cookie.new(raw_cookie, secure: true, httponly: OPT_OUT, samesite: OPT_OUT)
32
- expect(cookie.to_s).to eq("_session=thisisatest; secure")
33
- end
34
- end
35
-
36
- context "when configured with a Hash" do
37
- it "flags cookies as Secure when whitelisted" do
38
- cookie = Cookie.new(raw_cookie, secure: { only: ["_session"]}, httponly: OPT_OUT, samesite: OPT_OUT)
39
- expect(cookie.to_s).to eq("_session=thisisatest; secure")
40
- end
41
-
42
- it "does not flag cookies as Secure when excluded" do
43
- cookie = Cookie.new(raw_cookie, secure: { except: ["_session"] }, httponly: OPT_OUT, samesite: OPT_OUT)
44
- expect(cookie.to_s).to eq("_session=thisisatest")
45
- end
46
- end
47
- end
48
-
49
- context "HttpOnly cookies" do
50
- context "when configured with a boolean" do
51
- it "flags cookies as HttpOnly" do
52
- cookie = Cookie.new(raw_cookie, httponly: true, secure: OPT_OUT, samesite: OPT_OUT)
53
- expect(cookie.to_s).to eq("_session=thisisatest; HttpOnly")
54
- end
55
- end
56
-
57
- context "when configured with a Hash" do
58
- it "flags cookies as HttpOnly when whitelisted" do
59
- cookie = Cookie.new(raw_cookie, httponly: { only: ["_session"]}, secure: OPT_OUT, samesite: OPT_OUT)
60
- expect(cookie.to_s).to eq("_session=thisisatest; HttpOnly")
61
- end
62
-
63
- it "does not flag cookies as HttpOnly when excluded" do
64
- cookie = Cookie.new(raw_cookie, httponly: { except: ["_session"] }, secure: OPT_OUT, samesite: OPT_OUT)
65
- expect(cookie.to_s).to eq("_session=thisisatest")
66
- end
67
- end
68
- end
69
-
70
- context "SameSite cookies" do
71
- %w(None Lax Strict).each do |flag|
72
- it "flags SameSite=#{flag}" do
73
- cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => { only: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
74
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=#{flag}")
75
- end
76
-
77
- it "flags SameSite=#{flag} when configured with a boolean" do
78
- cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => true}, secure: OPT_OUT, httponly: OPT_OUT)
79
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=#{flag}")
80
- end
81
-
82
- it "does not flag cookies as SameSite=#{flag} when excluded" do
83
- cookie = Cookie.new(raw_cookie, samesite: { flag.downcase.to_sym => { except: ["_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
84
- expect(cookie.to_s).to eq("_session=thisisatest")
85
- end
86
- end
87
-
88
- it "flags SameSite=Strict when configured with a boolean" do
89
- cookie = Cookie.new(raw_cookie, {samesite: { strict: true}, secure: OPT_OUT, httponly: OPT_OUT})
90
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
91
- end
92
-
93
- it "flags properly when both lax and strict are configured" do
94
- raw_cookie = "_session=thisisatest"
95
- cookie = Cookie.new(raw_cookie, samesite: { strict: { only: ["_session"] }, lax: { only: ["_additional_session"] } }, secure: OPT_OUT, httponly: OPT_OUT)
96
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Strict")
97
- end
98
-
99
- it "ignores configuration if the cookie is already flagged" do
100
- raw_cookie = "_session=thisisatest; SameSite=Strict"
101
- cookie = Cookie.new(raw_cookie, samesite: { lax: true }, secure: OPT_OUT, httponly: OPT_OUT)
102
- expect(cookie.to_s).to eq(raw_cookie)
103
- end
104
-
105
- it "samesite: true sets all cookies to samesite=lax" do
106
- raw_cookie = "_session=thisisatest"
107
- cookie = Cookie.new(raw_cookie, samesite: true, secure: OPT_OUT, httponly: OPT_OUT)
108
- expect(cookie.to_s).to eq("_session=thisisatest; SameSite=Lax")
109
- end
110
- end
111
- end
112
-
113
- context "with an invalid configuration" do
114
- it "raises an exception when not configured with a Hash" do
115
- expect do
116
- Cookie.validate_config!("configuration")
117
- end.to raise_error(CookiesConfigError)
118
- end
119
-
120
- it "raises an exception when configured without a boolean(true or OPT_OUT)/Hash" do
121
- expect do
122
- Cookie.validate_config!(secure: "true")
123
- end.to raise_error(CookiesConfigError)
124
- end
125
-
126
- it "raises an exception when configured with false" do
127
- expect do
128
- Cookie.validate_config!(secure: false)
129
- end.to raise_error(CookiesConfigError)
130
- end
131
-
132
- it "raises an exception when both only and except filters are provided" do
133
- expect do
134
- Cookie.validate_config!(secure: { only: [], except: [] })
135
- end.to raise_error(CookiesConfigError)
136
- end
137
-
138
- it "raises an exception when SameSite is not configured with a Hash" do
139
- expect do
140
- Cookie.validate_config!(samesite: true)
141
- end.to raise_error(CookiesConfigError)
142
- end
143
-
144
- cookie_options = %i(none lax strict)
145
- cookie_options.each do |flag|
146
- (cookie_options - [flag]).each do |other_flag|
147
- it "raises an exception when SameSite #{flag} and #{other_flag} enforcement modes are configured with booleans" do
148
- expect do
149
- Cookie.validate_config!(samesite: { flag => true, other_flag => true})
150
- end.to raise_error(CookiesConfigError)
151
- end
152
- end
153
- end
154
-
155
- it "raises an exception when SameSite lax and strict enforcement modes are configured with booleans" do
156
- expect do
157
- Cookie.validate_config!(samesite: { lax: true, strict: { only: ["_anything"] } })
158
- end.to raise_error(CookiesConfigError)
159
- end
160
-
161
- it "raises an exception when both only and except filters are provided to SameSite configurations" do
162
- expect do
163
- Cookie.validate_config!(samesite: { lax: { only: ["_anything"], except: ["_anythingelse"] } })
164
- end.to raise_error(CookiesConfigError)
165
- end
166
-
167
- it "raises an exception when both lax and strict only filters are provided to SameSite configurations" do
168
- expect do
169
- Cookie.validate_config!(samesite: { lax: { only: ["_anything"] }, strict: { only: ["_anything"] } })
170
- end.to raise_error(CookiesConfigError)
171
- end
172
-
173
- it "raises an exception when both lax and strict only filters are provided to SameSite configurations" do
174
- expect do
175
- Cookie.validate_config!(samesite: { lax: { except: ["_anything"] }, strict: { except: ["_anything"] } })
176
- end.to raise_error(CookiesConfigError)
177
- end
178
- end
179
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
- require "spec_helper"
3
-
4
- module SecureHeaders
5
- describe ExpectCertificateTransparency do
6
- specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: true).value).to eq("enforce, max-age=1234") }
7
- specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: false).value).to eq("max-age=1234") }
8
- specify { expect(ExpectCertificateTransparency.new(max_age: 1234, enforce: "yolocopter").value).to eq("max-age=1234") }
9
- specify { expect(ExpectCertificateTransparency.new(max_age: 1234, report_uri: "https://report-uri.io/expect-ct").value).to eq("max-age=1234, report-uri=\"https://report-uri.io/expect-ct\"") }
10
- specify do
11
- config = { enforce: true, max_age: 1234, report_uri: "https://report-uri.io/expect-ct" }
12
- header_value = "enforce, max-age=1234, report-uri=\"https://report-uri.io/expect-ct\""
13
- expect(ExpectCertificateTransparency.new(config).value).to eq(header_value)
14
- end
15
-
16
- context "with an invalid configuration" do
17
- it "raises an exception when configuration isn't a hash" do
18
- expect do
19
- ExpectCertificateTransparency.validate_config!(%w(a))
20
- end.to raise_error(ExpectCertificateTransparencyConfigError)
21
- end
22
-
23
- it "raises an exception when max-age is not provided" do
24
- expect do
25
- ExpectCertificateTransparency.validate_config!(foo: "bar")
26
- end.to raise_error(ExpectCertificateTransparencyConfigError)
27
- end
28
-
29
- it "raises an exception with an invalid max-age" do
30
- expect do
31
- ExpectCertificateTransparency.validate_config!(max_age: "abc123")
32
- end.to raise_error(ExpectCertificateTransparencyConfigError)
33
- end
34
-
35
- it "raises an exception with an invalid enforce value" do
36
- expect do
37
- ExpectCertificateTransparency.validate_config!(enforce: "brokenstring")
38
- end.to raise_error(ExpectCertificateTransparencyConfigError)
39
- end
40
- end
41
- end
42
- end