rodauth 1.21.0 → 1.22.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2660e5b2f14afadab7d56a0a7329ff3f22cea0bb800fa952b3b40c3dcfbcb29
4
- data.tar.gz: 34b96d4d8bc26d641288af6bced9a42b9a895790b019a03b00c3f0e55b67843b
3
+ metadata.gz: 3379479fde31b70cd341f7d862088a1c29f850a4293bbf08a4ddced9f152a026
4
+ data.tar.gz: 3ec8abcd54a4da0a230d8d5a064d75febc247ee6ed35e3282b9b3ab2e1dde21d
5
5
  SHA512:
6
- metadata.gz: c1f90ea3269e61b7de2e336bbe08ccde86b9d343d4b773971fcda7c4f3294804d9b251087978a57ae6eb0fea0a435fd16f0dd239ae524c465739fa6a129b3584
7
- data.tar.gz: 6d8b86790ac1214bd48fffea3aaeffdce63351b8bf6fc40dce6ca96fa471f84a2d08be525d804f5138ba5664ac73bbc68bfda6f279ef17655fc4f24e64bd23d0
6
+ metadata.gz: 6617d309568f8292c01d00343fdea602692fc6ca0be38d9846f0e8415a6da13cee10007e3286e03e2eb9170f693d4b2420861167225aab35ebea87b111627819
7
+ data.tar.gz: 30efd30667ccb724c0796aa58123beb4d2711ac92a032be21d900ae74391901521d60b6b4806463494fc748461ecac3adb28ce3bf7c1956e6dcd4b72b0fea963
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ === 1.22.0 (2019-10-29)
2
+
3
+ * Add jwt_cors feature to handle Cross-Origin Resource Sharing when using the jwt feature (jeremyevans)
4
+
5
+ * Add space before newline after links in email, fixing issues with some webmail providers with broken autolinkers (jeremyevans)
6
+
1
7
  === 1.21.0 (2019-07-24)
2
8
 
3
9
  * Support rotp 5.1 in the otp feature (jeremyevans)
data/README.rdoc CHANGED
@@ -42,6 +42,7 @@ hashes by protecting access via database functions.
42
42
  * Single Session (Only one active session per account)
43
43
  * JWT (JSON API support for all other features)
44
44
  * JWT Refresh (Access & Refresh Token)
45
+ * JWT CORS (Cross-Origin Resource Sharing)
45
46
  * Update Password Hash (when hash cost changes)
46
47
  * HTTP Basic Auth
47
48
  * Change Password Notify
@@ -811,7 +812,8 @@ view the appropriate file in the doc directory.
811
812
  * {Session Expiration}[rdoc-ref:doc/session_expiration.rdoc]
812
813
  * {Single Session}[rdoc-ref:doc/single_session.rdoc]
813
814
  * {JWT}[rdoc-ref:doc/jwt.rdoc]
814
- * {JWT}[rdoc-ref:doc/jwt_refresh.rdoc]
815
+ * {JWT Refresh}[rdoc-ref:doc/jwt_refresh.rdoc]
816
+ * {JWT CORS}[rdoc-ref:doc/jwt_cors.rdoc]
815
817
  * {HTTP Basic Auth}[rdoc-ref:doc/http_basic_auth.rdoc]
816
818
 
817
819
  === Calling Rodauth in the Routing Tree
data/doc/base.rdoc CHANGED
@@ -64,7 +64,7 @@ input_field_label_suffix :: The suffix to use for all labels. Useful for noting
64
64
  input_field_error_class :: The CSS class to use for input fields with errors. Can be a
65
65
  space separated string for multiple CSS classes.
66
66
  input_field_error_message_class :: The CSS class to use for error messages. Can be a
67
- space separated string for multiple CSS classes.
67
+ space separated string for multiple CSS classes.
68
68
  invalid_field_error_status :: The response status to use for invalid field
69
69
  value errors, 422 by default.
70
70
  invalid_key_error_status :: The response status to use for invalid key codes,
data/doc/jwt_cors.rdoc ADDED
@@ -0,0 +1,23 @@
1
+ = Documentation for JWT CORS Feature
2
+
3
+ The jwt_cors feature adds support for Cross-Origin Resource Sharing
4
+ to Rodauth's JSON API.
5
+
6
+ When this feature is used, CORS requests are handled. This includes
7
+ CORS preflight requests, which are required since Rodauth's JSON API
8
+ uses the application/json request content type.
9
+
10
+ This feature depends on the jwt feature.
11
+
12
+ == Auth Value Methods
13
+
14
+ jwt_cors_allow_origin :: Which origins are allowed to perform CORS requests. The default is +false+. This can be a String, Array of Strings, Regexp, or +true+ to allow CORS requests from any domain.
15
+ jwt_cors_allow_methods :: For allowed CORS-preflight requests, the value returned in the Access-Control-Allow-Methods header (default: 'POST'). This specifies which methods are allowed in CORS requests.
16
+ jwt_cors_allow_headers :: For allowed CORS-preflight requests, the value returned in the Access-Control-Allow-Headers header (default: 'Content-Type, Authorization, Accept'). This specifies which headers can be included in CORS requests.
17
+ jwt_cors_expose_headers :: For allowed CORS requests, the value returned in the Access-Control-Expose-Headers header (default: 'Authorization'). This specifies which headers the browser is allowed to access from a response to a CORS request.
18
+ jwt_cors_max_age :: For allowed CORS-preflight requests, the value returned in the Access-Control-Max-Age header (default: 86400). This specifies how long before the information returned should be considered stale and another CORS preflight request made.
19
+
20
+ == Auth Methods
21
+
22
+ jwt_cors_allow? :: Whether the request should be allowed. This is called for all requests for a Rodauth route that include an Origin header. It should return true or false for whether to specially handle the cross-origin request. By default, uses the +jwt_cors_allow_origin+ setting to check the origin.
23
+
@@ -0,0 +1,11 @@
1
+ = New Features
2
+
3
+ * A jwt_cors feature has been added, handling Cross-Origin Resource
4
+ Sharing when using the jwt feature, including supporting CORS
5
+ preflight requests.
6
+
7
+ = Other Improvements
8
+
9
+ * Mail templates that include links (e.g. for verifying accounts),
10
+ now add a space after the link and before the newline, fixing
11
+ issues with some web mail providers that have broken auto-linkers.
@@ -0,0 +1,53 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Rodauth
4
+ Feature.define(:jwt_cors, :JwtCors) do
5
+ depends :jwt
6
+
7
+ auth_value_method :jwt_cors_allow_origin, false
8
+ auth_value_method :jwt_cors_allow_methods, 'POST'
9
+ auth_value_method :jwt_cors_allow_headers, 'Content-Type, Authorization, Accept'
10
+ auth_value_method :jwt_cors_expose_headers, 'Authorization'
11
+ auth_value_method :jwt_cors_max_age, 86400
12
+
13
+ auth_methods(:jwt_cors_allow?)
14
+
15
+ def jwt_cors_allow?
16
+ if origin = request.env['HTTP_ORIGIN']
17
+ case allowed = jwt_cors_allow_origin
18
+ when String
19
+ timing_safe_eql?(origin, allowed)
20
+ when Array
21
+ allowed.any?{|s| timing_safe_eql?(origin, s)}
22
+ when Regexp
23
+ allowed =~ origin
24
+ when true
25
+ true
26
+ else
27
+ false
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def before_rodauth
35
+ if (origin = request.env['HTTP_ORIGIN']) && jwt_cors_allow?
36
+ response['Access-Control-Allow-Origin'] = origin
37
+
38
+ # Handle CORS preflight request
39
+ if request.request_method == 'OPTIONS'
40
+ response['Access-Control-Allow-Methods'] = jwt_cors_allow_methods
41
+ response['Access-Control-Allow-Headers'] = jwt_cors_allow_headers
42
+ response['Access-Control-Max-Age'] = jwt_cors_max_age.to_s
43
+ response.status = 204
44
+ request.halt(response.finish)
45
+ end
46
+
47
+ response['Access-Control-Expose-Headers'] = jwt_cors_expose_headers
48
+ end
49
+
50
+ super
51
+ end
52
+ end
53
+ end
@@ -6,7 +6,7 @@ module Rodauth
6
6
  MAJOR = 1
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 21
9
+ MINOR = 22
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
@@ -18,7 +18,7 @@ describe 'Rodauth disallow common passwords feature' do
18
18
  visit '/change-password'
19
19
 
20
20
  bad_password_file = File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'dict', 'top-10_000-passwords.txt')
21
- File.read(bad_password_file).split.shuffle.take(5).each do |pass|
21
+ (File.read(bad_password_file).split.shuffle - ['0123456789']).take(5).each do |pass|
22
22
  fill_in 'New Password', :with=>pass
23
23
  fill_in 'Confirm Password', :with=>pass
24
24
  click_button 'Change Password'
@@ -0,0 +1,57 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ describe 'Rodauth jwt_cors feature' do
4
+ it "should support CORS logins if allowed" do
5
+ origin = false
6
+ rodauth do
7
+ enable :login, :jwt_cors
8
+ jwt_secret '1'
9
+ json_response_success_key 'success'
10
+ jwt_cors_allow_origin{origin}
11
+ end
12
+ roda(:csrf=>false, :json=>true) do |r|
13
+ r.rodauth
14
+ rodauth.require_authentication
15
+ response['Content-Type'] = 'application/json'
16
+ '1'
17
+ end
18
+
19
+ # CORS Preflight Request
20
+ preflight_request = {
21
+ :method=>'OPTIONS',
22
+ :headers=>{
23
+ "HTTP_ACCESS_CONTROL_REQUEST_METHOD"=>"POST",
24
+ "HTTP_ORIGIN"=>"https://foo.example.com",
25
+ "HTTP_ACCESS_CONTROL_REQUEST_HEADERS"=>"content-type",
26
+ "CONTENT_TYPE"=>' application/json'
27
+ }
28
+ }
29
+
30
+ res = json_request("/login", preflight_request.dup)
31
+ res.must_equal [405, ["{\"error\":\"non-POST method used in JSON API\"}"]]
32
+
33
+ origin = Object.new
34
+ res = json_request("/login", preflight_request.dup)
35
+ res.must_equal [405, ["{\"error\":\"non-POST method used in JSON API\"}"]]
36
+
37
+ ["https://foo.example.com", ["https://foo.example.com"], %r{https://foo.example.com}, true].each do |orig|
38
+ origin = orig
39
+
40
+ res = json_request("/login", preflight_request.merge(:include_headers=>true))
41
+ res[0].must_equal 204
42
+ res[1]['Access-Control-Allow-Origin'].must_equal "https://foo.example.com"
43
+ res[1]['Access-Control-Allow-Methods'].must_equal "POST"
44
+ res[1]['Access-Control-Allow-Headers'].must_equal "Content-Type, Authorization, Accept"
45
+ res[1]['Access-Control-Max-Age'].must_equal "86400"
46
+ res[2].must_equal []
47
+
48
+ res = json_request("/login", :login=>'foo@example.com', :password=>'0123456789', :headers=>{"HTTP_ORIGIN"=>"https://foo.example.com"}, :include_headers=>true)
49
+ res[0].must_equal 200
50
+ res[1]['Access-Control-Allow-Origin'].must_equal "https://foo.example.com"
51
+ res[1]['Access-Control-Expose-Headers'].must_equal "Authorization"
52
+ res[2].must_equal("success"=>"You have been logged in")
53
+
54
+ json_request("/foo").must_equal [200, 1]
55
+ end
56
+ end
57
+ end
data/spec/spec_helper.rb CHANGED
@@ -33,7 +33,7 @@ require 'securerandom'
33
33
 
34
34
  ENV['MT_NO_PLUGINS'] = '1' # Work around stupid autoloading of plugins
35
35
  gem 'minitest'
36
- require 'minitest/autorun'
36
+ require 'minitest/global_expectations/autorun'
37
37
  require 'minitest/hooks/default'
38
38
 
39
39
  require 'roda'
@@ -198,7 +198,7 @@ class Minitest::HooksSpec
198
198
  msgs.length.must_equal 1
199
199
  msgs.first.to.first.must_equal to
200
200
 
201
- link = msgs.first.body.to_s[regexp]
201
+ link = msgs.first.body.to_s.gsub(/ $/, '')[regexp]
202
202
  msgs.clear
203
203
  link.must_be_kind_of(String)
204
204
  link
@@ -1,5 +1,5 @@
1
1
  Someone has requested a login link for the account with this email
2
2
  address. If you did not request a login link, please ignore this
3
3
  message. If you requested a login link, please go to
4
- #{rodauth.email_auth_email_link}
4
+ #{rodauth.email_auth_email_link}
5
5
  to login to this account.
@@ -1,5 +1,5 @@
1
1
  Someone has requested a password reset for the account with this email
2
2
  address. If you did not request a password reset, please ignore this
3
3
  message. If you requested a password reset, please go to
4
- #{rodauth.reset_password_email_link}
4
+ #{rodauth.reset_password_email_link}
5
5
  to reset the password for the account.
@@ -1,5 +1,5 @@
1
1
  Someone has requested a that the account with this email be unlocked.
2
2
  If you did not request the unlocking of this account, please ignore this
3
3
  message. If you requested the unlocking of this account, please go to
4
- #{rodauth.unlock_account_email_link}
4
+ #{rodauth.unlock_account_email_link}
5
5
  to unlock this account.
@@ -1,4 +1,4 @@
1
1
  Someone has created an account with this email address. If you did not create
2
2
  this account, please ignore this message. If you created this account, please go to
3
- #{rodauth.verify_account_email_link}
3
+ #{rodauth.verify_account_email_link}
4
4
  to verify the account.
@@ -1,9 +1,10 @@
1
1
  Someone with an account has requested their login be changed to this email address:
2
2
 
3
3
  Old Login: #{rodauth.verify_login_change_old_login}
4
+
4
5
  New Login: #{rodauth.verify_login_change_new_login}
5
6
 
6
7
  If you did not request this login change, please ignore this message. If you
7
8
  requested this login change, please go to
8
- #{rodauth.verify_login_change_email_link}
9
+ #{rodauth.verify_login_change_email_link}
9
10
  to verify the login change.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.21.0
4
+ version: 1.22.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: 2019-07-24 00:00:00.000000000 Z
11
+ date: 2019-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: 5.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: minitest-global_expectations
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: minitest-hooks
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -232,6 +246,7 @@ extra_rdoc_files:
232
246
  - doc/jwt_refresh.rdoc
233
247
  - doc/verify_account_grace_period.rdoc
234
248
  - doc/verify_login_change.rdoc
249
+ - doc/jwt_cors.rdoc
235
250
  - doc/release_notes/1.17.0.txt
236
251
  - doc/release_notes/1.0.0.txt
237
252
  - doc/release_notes/1.1.0.txt
@@ -254,6 +269,7 @@ extra_rdoc_files:
254
269
  - doc/release_notes/1.19.0.txt
255
270
  - doc/release_notes/1.20.0.txt
256
271
  - doc/release_notes/1.21.0.txt
272
+ - doc/release_notes/1.22.0.txt
257
273
  files:
258
274
  - CHANGELOG
259
275
  - MIT-LICENSE
@@ -275,6 +291,7 @@ files:
275
291
  - doc/http_basic_auth.rdoc
276
292
  - doc/internals.rdoc
277
293
  - doc/jwt.rdoc
294
+ - doc/jwt_cors.rdoc
278
295
  - doc/jwt_refresh.rdoc
279
296
  - doc/lockout.rdoc
280
297
  - doc/login.rdoc
@@ -300,6 +317,7 @@ files:
300
317
  - doc/release_notes/1.2.0.txt
301
318
  - doc/release_notes/1.20.0.txt
302
319
  - doc/release_notes/1.21.0.txt
320
+ - doc/release_notes/1.22.0.txt
303
321
  - doc/release_notes/1.3.0.txt
304
322
  - doc/release_notes/1.4.0.txt
305
323
  - doc/release_notes/1.5.0.txt
@@ -334,6 +352,7 @@ files:
334
352
  - lib/rodauth/features/email_base.rb
335
353
  - lib/rodauth/features/http_basic_auth.rb
336
354
  - lib/rodauth/features/jwt.rb
355
+ - lib/rodauth/features/jwt_cors.rb
337
356
  - lib/rodauth/features/jwt_refresh.rb
338
357
  - lib/rodauth/features/lockout.rb
339
358
  - lib/rodauth/features/login.rb
@@ -369,6 +388,7 @@ files:
369
388
  - spec/disallow_password_reuse_spec.rb
370
389
  - spec/email_auth_spec.rb
371
390
  - spec/http_basic_auth_spec.rb
391
+ - spec/jwt_cors_spec.rb
372
392
  - spec/jwt_refresh_spec.rb
373
393
  - spec/jwt_spec.rb
374
394
  - spec/lockout_spec.rb