roda 3.74.0 → 3.75.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae3f95331c6c3d69453feb96a7dbd3629a6d5f52bd9d1862edecab893d95a36f
4
- data.tar.gz: c5457f54b2ca5a9971f93a23db10abe3b6fd16a743e2651749ec14c480c248a3
3
+ metadata.gz: 4ebdbc5b5707ba21044b5f4c83445ff8fca6a3925488c72a5176cc662c2ad15b
4
+ data.tar.gz: ac528e50bfe1e778b5b4d32d16d12e117e87dc55b2f7cad1170b682e2f979586
5
5
  SHA512:
6
- metadata.gz: f314713b33ec4400e5ef8849c6a3e30f1b5956b428dea55a5bf45855fef4a965f9b417063182cc4412effa592a7d311715cf4541826781675ca26bd20f202ca3
7
- data.tar.gz: 735cb4cf3e5480be4462d88ccb0090001e7eca27bfe7338a923f5f190730095037ff0c77e1cbe3c875b137175bc7022b8d0611ccbf8b82426cbbaec5b7802149
6
+ metadata.gz: b7d13975d6c7705f1d7b184f27430320e1dfd5fea96e532f119f86b4c09fdb5c7e460107033d8d099c6ef8da354a514289981163d74cdb293b89074299a57eda
7
+ data.tar.gz: d16c1b3a2edd401a73b104bf9458fcb865e441f4de649dcfcb8144eb3102abcd6abee741ecbbbf1cad3b13d8efca7260d7785b7e5a2505f29541ad001de9b1e4
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ = 3.75.0 (2023-12-14)
2
+
3
+ * Add cookie_flags plugin, for overriding, warning, or raising for incorrect cookie flags (jeremyevans)
4
+
1
5
  = 3.74.0 (2023-11-13)
2
6
 
3
7
  * Add redirect_http_to_https plugin, helping to ensure future requests from the browser are submitted via HTTPS (jeremyevans)
@@ -0,0 +1,19 @@
1
+ = New Features
2
+
3
+ * A cookie_flags plugin has been added, for overriding, warning, or
4
+ raising for incorrect cookie flags. The plugin by default checks
5
+ whether the secure, httponly, and samesite=strict flags are set.
6
+ The default behavior is to add the appropriate flags if they are
7
+ not set, and change the samesite flag to strict if it is set to
8
+ something else. You can configure the flag checking behavior
9
+ via the :httponly, :same_site, and :secure options.
10
+
11
+ You can configure the action the plugin takes via the :action option.
12
+ The default action is to modify the flags, but the :action option can
13
+ be set to :raise, :warn, or :warn_and_modify to override the behavior.
14
+
15
+ The recommended way to use the plugin is to use it during testing,
16
+ and specify action: :raise, so you can catch places where cookies
17
+ are set with the wrong flags. Then you can fix those places to
18
+ use the correct flags, which is better than relying on the plugin
19
+ at runtime in production to fix incorrect flags.
@@ -0,0 +1,157 @@
1
+ # frozen-string-literal: true
2
+
3
+ #
4
+ class Roda
5
+ module RodaPlugins
6
+ # The cookie_flags plugin allows users to force specific cookie flags for
7
+ # all cookies set by the application. It can also be used to warn or
8
+ # raise for unexpected cookie flags.
9
+ #
10
+ # The cookie_flags plugin deals with the following cookie flags:
11
+ #
12
+ # httponly :: Disallows access to the cookie from client-side scripts.
13
+ # samesite :: Restricts to which domains the cookie is sent.
14
+ # secure :: Instructs the browser to only transmit the cookie over HTTPS.
15
+ #
16
+ # This plugin ships in secure-by-default mode, where it enforces
17
+ # secure, httponly, samesite=strict cookies. You can disable enforcing
18
+ # specific flags using the following options:
19
+ #
20
+ # :httponly :: Set to false to not enforce httponly flag.
21
+ # :same_site :: Set to symbol or string to enforce a different samesite
22
+ # setting, or false to not enforce a specific samesite setting.
23
+ # :secure :: Set to false to not enforce secure flag.
24
+ #
25
+ # For example, to enforce secure cookies and enforce samesite=lax, but not enforce
26
+ # an httponly flag:
27
+ #
28
+ # plugin :cookie_flags, httponly: false, same_site: 'lax'
29
+ #
30
+ # In general, overriding cookie flags using this plugin should be considered a
31
+ # stop-gap solution. Instead of overriding cookie flags, it's better to fix
32
+ # whatever is setting the cookie flags incorrectly. You can use the :action
33
+ # option to modify the behavior:
34
+ #
35
+ # # Issue warnings when modifying cookie flags
36
+ # plugin :cookie_flags, action: :warn_and_modify
37
+ #
38
+ # # Issue warnings for incorrect cookie flags without modifying cookie flags
39
+ # plugin :cookie_flags, action: :warn
40
+ #
41
+ # # Raise errors for incorrect cookie flags
42
+ # plugin :cookie_flags, action: :raise
43
+ #
44
+ # The recommended way to use the plugin is to use it only during testing with
45
+ # <tt>action: :raise</tt>. Then as long as you have fully covering tests, you
46
+ # can be sure the cookies set by your application use the correct flags.
47
+ #
48
+ # Note that this plugin only affects cookies set by the application, and does not
49
+ # affect cookies set by middleware the application is using.
50
+ module CookieFlags
51
+ # :nocov:
52
+ MATCH_METH = RUBY_VERSION >= '2.4' ? :match? : :match
53
+ # :nocov:
54
+ private_constant :MATCH_METH
55
+
56
+ DEFAULTS = {:secure=>true, :httponly=>true, :same_site=>'strict', :action=>:modify}.freeze
57
+ private_constant :DEFAULTS
58
+
59
+ # Error class raised for action: :raise when incorrect cookie flags are used.
60
+ class Error < RodaError
61
+ end
62
+
63
+ def self.configure(app, opts=OPTS)
64
+ previous = app.opts[:cookie_flags] || DEFAULTS
65
+ opts = app.opts[:cookie_flags] = previous.merge(opts)
66
+
67
+ case opts[:same_site]
68
+ when String, Symbol
69
+ opts[:same_site] = opts[:same_site].to_s.downcase.freeze
70
+ opts[:same_site_string] = "; samesite=#{opts[:same_site]}".freeze
71
+ opts[:secure] = true if opts[:same_site] == 'none'
72
+ end
73
+
74
+ opts.freeze
75
+ end
76
+
77
+ module InstanceMethods
78
+ private
79
+
80
+ def _handle_cookie_flags_array(cookies)
81
+ opts = self.class.opts[:cookie_flags]
82
+ needs_secure = opts[:secure]
83
+ needs_httponly = opts[:httponly]
84
+ if needs_same_site = opts[:same_site]
85
+ same_site_string = opts[:same_site_string]
86
+ same_site_regexp = /;\s*samesite\s*=\s*(\S+)\s*(?:\z|;)/i
87
+ end
88
+ action = opts[:action]
89
+
90
+ cookies.map do |cookie|
91
+ if needs_secure
92
+ add_secure = !/;\s*secure\s*(?:\z|;)/i.send(MATCH_METH, cookie)
93
+ end
94
+
95
+ if needs_httponly
96
+ add_httponly = !/;\s*httponly\s*(?:\z|;)/i.send(MATCH_METH, cookie)
97
+ end
98
+
99
+ if needs_same_site
100
+ has_same_site = same_site_regexp.match(cookie)
101
+ unless add_same_site = !has_same_site
102
+ update_same_site = needs_same_site != has_same_site[1].downcase
103
+ end
104
+ end
105
+
106
+ next cookie unless add_secure || add_httponly || add_same_site || update_same_site
107
+
108
+ case action
109
+ when :raise, :warn, :warn_and_modify
110
+ message = "Response contains cookie with unexpected flags: #{cookie.inspect}." \
111
+ "Expecting the following cookie flags: "\
112
+ "#{'secure ' if add_secure}#{'httponly ' if add_httponly}#{same_site_string[2..-1] if add_same_site || update_same_site}"
113
+
114
+ if action == :raise
115
+ raise Error, message
116
+ else
117
+ warn(message)
118
+ next cookie if action == :warn
119
+ end
120
+ end
121
+
122
+ if update_same_site
123
+ cookie = cookie.gsub(same_site_regexp, same_site_string)
124
+ else
125
+ cookie = cookie.dup
126
+ cookie << same_site_string if add_same_site
127
+ end
128
+
129
+ cookie << '; secure' if add_secure
130
+ cookie << '; httponly' if add_httponly
131
+
132
+ cookie
133
+ end
134
+ end
135
+
136
+ if Rack.release >= '3'
137
+ def _handle_cookie_flags(cookies)
138
+ cookies = [cookies] if cookies.is_a?(String)
139
+ _handle_cookie_flags_array(cookies)
140
+ end
141
+ else
142
+ def _handle_cookie_flags(cookie_string)
143
+ _handle_cookie_flags_array(cookie_string.split("\n")).join("\n")
144
+ end
145
+ end
146
+
147
+ # Handle cookie flags in response
148
+ def _roda_after_85__cookie_flags(res)
149
+ return unless res && (headers = res[1]) && (value = headers[RodaResponseHeaders::SET_COOKIE])
150
+ headers[RodaResponseHeaders::SET_COOKIE] = _handle_cookie_flags(value)
151
+ end
152
+ end
153
+ end
154
+
155
+ register_plugin(:cookie_flags, CookieFlags)
156
+ end
157
+ end
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 74
7
+ RodaMinorVersion = 75
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.74.0
4
+ version: 3.75.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-13 00:00:00.000000000 Z
11
+ date: 2023-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -248,6 +248,7 @@ extra_rdoc_files:
248
248
  - doc/release_notes/3.72.0.txt
249
249
  - doc/release_notes/3.73.0.txt
250
250
  - doc/release_notes/3.74.0.txt
251
+ - doc/release_notes/3.75.0.txt
251
252
  - doc/release_notes/3.8.0.txt
252
253
  - doc/release_notes/3.9.0.txt
253
254
  files:
@@ -329,6 +330,7 @@ files:
329
330
  - doc/release_notes/3.72.0.txt
330
331
  - doc/release_notes/3.73.0.txt
331
332
  - doc/release_notes/3.74.0.txt
333
+ - doc/release_notes/3.75.0.txt
332
334
  - doc/release_notes/3.8.0.txt
333
335
  - doc/release_notes/3.9.0.txt
334
336
  - lib/roda.rb
@@ -357,6 +359,7 @@ files:
357
359
  - lib/roda/plugins/common_logger.rb
358
360
  - lib/roda/plugins/content_for.rb
359
361
  - lib/roda/plugins/content_security_policy.rb
362
+ - lib/roda/plugins/cookie_flags.rb
360
363
  - lib/roda/plugins/cookies.rb
361
364
  - lib/roda/plugins/csrf.rb
362
365
  - lib/roda/plugins/custom_block_results.rb