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 +4 -4
- data/CHANGELOG +6 -0
- data/README.rdoc +3 -1
- data/doc/base.rdoc +1 -1
- data/doc/jwt_cors.rdoc +23 -0
- data/doc/release_notes/1.22.0.txt +11 -0
- data/lib/rodauth/features/jwt_cors.rb +53 -0
- data/lib/rodauth/version.rb +1 -1
- data/spec/disallow_common_passwords_spec.rb +1 -1
- data/spec/jwt_cors_spec.rb +57 -0
- data/spec/spec_helper.rb +2 -2
- data/templates/email-auth-email.str +1 -1
- data/templates/reset-password-email.str +1 -1
- data/templates/unlock-account-email.str +1 -1
- data/templates/verify-account-email.str +1 -1
- data/templates/verify-login-change-email.str +2 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3379479fde31b70cd341f7d862088a1c29f850a4293bbf08a4ddced9f152a026
|
4
|
+
data.tar.gz: 3ec8abcd54a4da0a230d8d5a064d75febc247ee6ed35e3282b9b3ab2e1dde21d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
data/lib/rodauth/version.rb
CHANGED
@@ -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,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.
|
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-
|
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
|