rodauth 2.15.0 → 2.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +38 -0
- data/README.rdoc +27 -2
- data/doc/error_reasons.rdoc +3 -0
- data/doc/guides/change_table_and_column_names.rdoc +19 -0
- data/doc/guides/i18n.rdoc +3 -0
- data/doc/guides/share_configuration.rdoc +34 -0
- data/doc/login_password_requirements_base.rdoc +9 -3
- data/doc/release_notes/2.16.0.txt +20 -0
- data/doc/release_notes/2.17.0.txt +10 -0
- data/doc/release_notes/2.18.0.txt +27 -0
- data/doc/release_notes/2.19.0.txt +61 -0
- data/lib/rodauth/features/argon2.rb +13 -1
- data/lib/rodauth/features/internal_request.rb +8 -8
- data/lib/rodauth/features/json.rb +19 -0
- data/lib/rodauth/features/jwt_refresh.rb +2 -2
- data/lib/rodauth/features/login_password_requirements_base.rb +33 -3
- data/lib/rodauth/features/otp.rb +1 -1
- data/lib/rodauth/features/verify_account.rb +2 -4
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +55 -35
- metadata +14 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0defa94cb0c58b317997853eda1775694a8b0bb89e3bb75f8de50af57a2223fe
|
4
|
+
data.tar.gz: 977738446cb7d8ac53a7edeab2587c07e7a9b9407d2584daa80fe6d47147f395
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e8833fc2ac01f3a917b8c267642b92472969531df33dc90dcae6e90d5b62befbf2f948ca75cafcd84353b4b9d629f1dec8d70e3e77cc2387cc0791cee551773
|
7
|
+
data.tar.gz: 03ff22811e9679b26f1dc83c676ca19145c762d26c216a9aafae816d3bad67cd39a68430fbd72c55f17e77117fbcd65690eb6d71f3b05f72860833a2205f2fe7
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
=== 2.19.0 (2021-12-22)
|
2
|
+
|
3
|
+
* Add login_maximum_bytes, setting the maximum number of bytes in a login, 255 by default (jeremyevans)
|
4
|
+
|
5
|
+
* Add password_maximum_bytes, setting the maximum number of bytes in a password, nil by default for no limit (jeremyevans)
|
6
|
+
|
7
|
+
* Add password_maximum_length, setting the maximum number of characters in a password, nil by default for no limit (jeremyevans)
|
8
|
+
|
9
|
+
* Support multi-level inheritance of Rodauth::Auth (janko) (#191)
|
10
|
+
|
11
|
+
* Allow internal_request feature to work correctly when loaded into custom Rodauth::Auth subclasses before loading into a Roda application (janko) (#190)
|
12
|
+
|
13
|
+
* Assign internal subclass created by internal_request feature to the InternalRequest constant (janko) (#187)
|
14
|
+
|
15
|
+
=== 2.18.0 (2021-11-23)
|
16
|
+
|
17
|
+
* Allow JSON API access to /multifactor-manage to get links to setup/disable multifactor authentication endpoints (jeremyevans)
|
18
|
+
|
19
|
+
* Allow JSON API access to /multifactor-auth to get links to possible multifactor authentication endpoints (jeremyevans)
|
20
|
+
|
21
|
+
* Set configuration_name on class passed via :auth_class option if not already set (janko, jeremyevans) (#181)
|
22
|
+
|
23
|
+
* Use viewbox: true option when creating QR code in otp feature, displays better and easier to style when using rqrcode 2+ (jeremyevans)
|
24
|
+
|
25
|
+
* Make argon2 feature work with argon2 2.1.0 (jeremyevans)
|
26
|
+
|
27
|
+
=== 2.17.0 (2021-09-24)
|
28
|
+
|
29
|
+
* Make jwt_refresh work correctly with verify_account_grace_period (jeremyevans)
|
30
|
+
|
31
|
+
* Use 4xx status code when attempting to login to or create an unverified account (janko) (#177, #178)
|
32
|
+
|
33
|
+
=== 2.16.0 (2021-08-23)
|
34
|
+
|
35
|
+
* Add Rodauth.lib for using Rodauth as a library (jeremyevans)
|
36
|
+
|
37
|
+
* Make internal_request feature work if the configuration uses only_json? true (janko) (#176)
|
38
|
+
|
1
39
|
=== 2.15.0 (2021-07-27)
|
2
40
|
|
3
41
|
* Add path_class_methods feature, for getting paths/URLs using class methods (jeremyevans)
|
data/README.rdoc
CHANGED
@@ -69,7 +69,8 @@ Website :: http://rodauth.jeremyevans.net
|
|
69
69
|
Demo Site :: http://rodauth-demo.jeremyevans.net
|
70
70
|
Source :: http://github.com/jeremyevans/rodauth
|
71
71
|
Bugs :: http://github.com/jeremyevans/rodauth/issues
|
72
|
-
|
72
|
+
Discussion Forum (GitHub Discussions) :: https://github.com/jeremyevans/rodauth/discussions
|
73
|
+
Alternate Discussion Forum (Google Groups) :: https://groups.google.com/forum/#!forum/rodauth
|
73
74
|
|
74
75
|
== Dependencies
|
75
76
|
|
@@ -422,9 +423,12 @@ Note that these migrations require Sequel 4.35.0+.
|
|
422
423
|
if db.database_type == :postgres
|
423
424
|
citext :email, :null=>false
|
424
425
|
constraint :valid_email, :email=>/^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
|
425
|
-
index :email, :unique=>true, :where=>{:status_id=>[1, 2]}
|
426
426
|
else
|
427
427
|
String :email, :null=>false
|
428
|
+
end
|
429
|
+
if db.supports_partial_indexes?
|
430
|
+
index :email, :unique=>true, :where=>{:status_id=>[1, 2]}
|
431
|
+
else
|
428
432
|
index :email, :unique=>true
|
429
433
|
end
|
430
434
|
end
|
@@ -1073,6 +1077,27 @@ methods on that class to perform actions on behalf of a user. See the
|
|
1073
1077
|
{internal request feature documentation}[rdoc-ref:doc/internal_request.rdoc]
|
1074
1078
|
for details.
|
1075
1079
|
|
1080
|
+
== Using Rodauth as a Library
|
1081
|
+
|
1082
|
+
Rodauth was designed to serve as an authentication framework for Rack applications.
|
1083
|
+
However, Rodauth can be used purely as a library outside of a web application. You
|
1084
|
+
can do this by requiring +rodauth+, and using the +Rodauth.lib+ method to return
|
1085
|
+
a <tt>Rodauth::Auth</tt> subclass, which you can call methods on. You pass the
|
1086
|
+
+Rodauth.lib+ method an optional hash of Rodauth plugin options and a Rodauth
|
1087
|
+
configuration block:
|
1088
|
+
|
1089
|
+
require 'rodauth'
|
1090
|
+
rodauth = Rodauth.lib do
|
1091
|
+
enable :create_account, :change_password
|
1092
|
+
end
|
1093
|
+
rodauth.create_account(login: 'foo@example.com', password: '...')
|
1094
|
+
rodauth.change_password(account_id: 24601, password: '...')
|
1095
|
+
|
1096
|
+
This supports builds on top of the internal_request support (it implicitly loads
|
1097
|
+
the internal_request feature before processing the configuration block), and
|
1098
|
+
allows the use of Rodauth in non-web applications. Note that you still have to
|
1099
|
+
setup a Sequel::Database connection for Rodauth to use for data storage.
|
1100
|
+
|
1076
1101
|
=== With Multiple Configurations
|
1077
1102
|
|
1078
1103
|
Rodauth supports using multiple rodauth configurations in the same
|
data/doc/error_reasons.rdoc
CHANGED
@@ -44,6 +44,7 @@ Rodauth will call +set_error_reason+ with:
|
|
44
44
|
* :login_not_valid_email
|
45
45
|
* :login_required
|
46
46
|
* :login_too_long
|
47
|
+
* :login_too_many_bytes
|
47
48
|
* :login_too_short
|
48
49
|
* :logins_do_not_match
|
49
50
|
* :no_current_sms_code
|
@@ -56,6 +57,8 @@ Rodauth will call +set_error_reason+ with:
|
|
56
57
|
* :password_in_dictionary
|
57
58
|
* :password_is_one_of_the_most_common
|
58
59
|
* :password_same_as_previous_password
|
60
|
+
* :password_too_long
|
61
|
+
* :password_too_many_bytes
|
59
62
|
* :password_too_short
|
60
63
|
* :passwords_do_not_match
|
61
64
|
* :same_as_current_login
|
@@ -0,0 +1,19 @@
|
|
1
|
+
= Change table and column names
|
2
|
+
|
3
|
+
All tables that Rodauth uses will have a configuration method that ends with
|
4
|
+
+_table+ for configuring the table name. For example, if you store user accounts
|
5
|
+
in the +users+ table instead of +accounts+ table, you can use the following
|
6
|
+
in your configuration:
|
7
|
+
|
8
|
+
accounts_table :users
|
9
|
+
|
10
|
+
All columns that Rodauth uses will have a configuration method that ends with
|
11
|
+
+_column+ for configuring the column name. For example, if you are storing the
|
12
|
+
login for accounts in the +login+ column instead of the +email+ column, you
|
13
|
+
can use the following in your configuration:
|
14
|
+
|
15
|
+
login_column :login
|
16
|
+
|
17
|
+
Please see the documentation for Rodauth features for the names of the
|
18
|
+
configuration methods that you can use. You can see the default values for
|
19
|
+
the tables and columns in the {"Creating tables" section of the README}[rdoc-ref:README.rdoc].
|
data/doc/guides/i18n.rdoc
CHANGED
@@ -24,3 +24,6 @@ Your translation file may then look something like this:
|
|
24
24
|
require_login_error_flash: "Login is required for accessing this page"
|
25
25
|
no_matching_login_message: "user with this email address doesn't exist"
|
26
26
|
reset_password_email_subject: "Password Reset Instructions"
|
27
|
+
|
28
|
+
Alternatively, you can use the
|
29
|
+
{rodauth-i18n}[https://github.com/janko/rodauth-i18n] gem.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
= Share configuration via inheritance
|
2
|
+
|
3
|
+
If you have multiple configurations that needs to share some amount of
|
4
|
+
authentication behaviour, you can do so through inheritance. For example:
|
5
|
+
|
6
|
+
require "rodauth"
|
7
|
+
|
8
|
+
class RodauthBase < Rodauth::Auth
|
9
|
+
configure do
|
10
|
+
# common authentication configuration
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class RodauthMain < RodauthBase # inherit common configuration
|
15
|
+
configure do
|
16
|
+
# main-specific authentication configuration
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class RodauthAdmin < RodauthBase # inherit common configuration
|
21
|
+
configure do
|
22
|
+
# admin-specific authentication configuration
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RodauthApp < Roda
|
27
|
+
plugin :rodauth, auth_class: RodauthMain
|
28
|
+
plugin :rodauth, auth_class: RodauthAdmin, name: :admin
|
29
|
+
# ...
|
30
|
+
end
|
31
|
+
|
32
|
+
However, when doing this, you need to be careful that you do not use a
|
33
|
+
configuration method in a superclass, and then load a feature in a subclass
|
34
|
+
that overrides the configuration you set in the superclass.
|
@@ -11,17 +11,23 @@ login_confirm_label :: The label to use for login confirmations.
|
|
11
11
|
login_confirm_param :: The parameter name to use for login confirmations.
|
12
12
|
login_does_not_meet_requirements_message :: The error message to display when the login does not meet the requirements you have set.
|
13
13
|
login_email_regexp :: The regular expression used to validate whether login is a valid email address.
|
14
|
-
|
15
|
-
|
14
|
+
login_maximum_bytes :: The maximum length for logins in bytes, 255 by default.
|
15
|
+
login_maximum_length :: The maximum length for logins in characters, 255 by default.
|
16
|
+
login_minimum_length :: The minimum length for logins in characters, 3 by default.
|
16
17
|
login_not_valid_email_message :: The error message to display when login is not a valid email address.
|
17
18
|
login_too_long_message :: The error message fragment to show if the login is too long.
|
19
|
+
login_too_many_bytes_message :: The error message fragment to show if the login has too many bytes.
|
18
20
|
login_too_short_message :: The error message fragment to show if the login is too short.
|
19
21
|
logins_do_not_match_message :: The error message to display when login and login confirmation do not match.
|
20
22
|
password_confirm_label :: The label to use for password confirmations.
|
21
23
|
password_confirm_param :: The parameter name to use for password confirmations.
|
22
24
|
password_does_not_meet_requirements_message :: The error message to display when the password does not meet the requirements you have set.
|
23
25
|
password_hash_cost :: The cost to use for the password hash algorithm. This should be an integer when using bcrypt (the default), and a hash if using argon2 (supported by the argon2 feature).
|
24
|
-
|
26
|
+
password_maximum_bytes :: The maximum length for passwords in bytes, nil by default for no limit. bcrypt only uses the first 72 bytes of the password when creating the password hash, so if you are using bcrypt as the password hash function, you may want to set this to 72.
|
27
|
+
password_maximum_length :: The maximum length for passwords in characters, nil by default for no limit.
|
28
|
+
password_minimum_length :: The minimum length for passwords in characters, 6 by default.
|
29
|
+
password_too_long_message :: The error message fragment to show if the password is too long.
|
30
|
+
password_too_many_bytes_message :: The error message fragment to show if the password is has too many bytes.
|
25
31
|
password_too_short_message :: The error message fragment to show if the password is too short.
|
26
32
|
passwords_do_not_match_message :: The error message to display when password and password confirmation do not match.
|
27
33
|
require_email_address_logins? :: Whether logins need to be valid email addresses, true by default.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* Rodauth.lib has been added for using Rodauth purely as a library,
|
4
|
+
useful in non-web applications:
|
5
|
+
|
6
|
+
require 'rodauth'
|
7
|
+
rodauth = Rodauth.lib do
|
8
|
+
enable :create_account, :change_password
|
9
|
+
end
|
10
|
+
rodauth.create_account(login: 'foo@example.com', password: '...')
|
11
|
+
rodauth.change_password(account_id: 24601, password: '...')
|
12
|
+
|
13
|
+
This is built on top of the internal_request feature, and works by
|
14
|
+
creating a Roda application with the rodauth plugin, and returning
|
15
|
+
the related Rodauth::Auth class.
|
16
|
+
|
17
|
+
= Other Improvements
|
18
|
+
|
19
|
+
* The internal_request feature now works correctly for configurations
|
20
|
+
where only_json? is set to true.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The jwt_refresh feature now works for unverified accounts when using
|
4
|
+
the verify_account_grace_period feature.
|
5
|
+
|
6
|
+
* When trying to create an account that already exists but is
|
7
|
+
unverified, Rodauth now returns a 4xx response.
|
8
|
+
|
9
|
+
* When trying to login to an unverified account, Rodauth now returns a
|
10
|
+
4xx response.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* When using the json and multifactor auth features, the JSON API can
|
4
|
+
now access the multifactor-manage route to get lists of endpoints
|
5
|
+
for setting up and disabling supported multifactor authentication
|
6
|
+
methods. The JSON API can now also access the multifactor-auth
|
7
|
+
route to get a list of endpoints for multifactor authentication for
|
8
|
+
the currently logged in account.
|
9
|
+
|
10
|
+
= Other Improvements
|
11
|
+
|
12
|
+
* In the otp feature, the viewbox: true rqrcode option is now used
|
13
|
+
when creating the QR code. This results in a QR code that is
|
14
|
+
displayed better and is easier to style. This option only has
|
15
|
+
an effect when using rqrcode 2+.
|
16
|
+
|
17
|
+
* When using the :auth_class option when loading the rodauth plugin,
|
18
|
+
the configuration name is set in the provided auth class, unless the
|
19
|
+
auth class already has a configuration name set.
|
20
|
+
|
21
|
+
* The example migration now recommends using a partial index on the
|
22
|
+
email column in cases where the database supports partial indexes.
|
23
|
+
Previously, it only recommended it on PostgreSQL.
|
24
|
+
|
25
|
+
* The argon2 feature now works with argon2 2.1.0. Older versions of
|
26
|
+
Rodauth work with both earlier and later versions of argon2, but
|
27
|
+
not 2.1.0.
|
@@ -0,0 +1,61 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A login_maximum_bytes configuration method has been added, setting
|
4
|
+
the maximum bytes allowed in a login. This was added as
|
5
|
+
login_maximum_length sets the maximum length in characters. It's
|
6
|
+
possible a different number of maximum bytes than maximum
|
7
|
+
characters is desired by some applications, and since the database
|
8
|
+
column size may be enforced in bytes, it's useful to have a check
|
9
|
+
before trying a database query that would raise an exception. This
|
10
|
+
default value for login_maximum_bytes is 255, the same as the
|
11
|
+
default value for login_maximum_length.
|
12
|
+
|
13
|
+
A login_too_many_bytes_message configuration method has been added
|
14
|
+
for customizing the error message if a login has too many bytes.
|
15
|
+
|
16
|
+
* password_maximum_length and password_maximum_bytes configuration
|
17
|
+
methods have been added, specifying the maximum size of passwords
|
18
|
+
in characters and bytes, respectively. Both configurations default
|
19
|
+
to nil, meaning no limit, so there is no change in default behavior.
|
20
|
+
|
21
|
+
The bcrypt algorithm only uses the first 72 bytes of a password, and
|
22
|
+
in some environments it may be desirable to reject passwords over
|
23
|
+
that limit. password_too_long_message and
|
24
|
+
password_too_many_bytes_message configuration methods have been
|
25
|
+
added for customizing the error messages used for passwords that are
|
26
|
+
too long.
|
27
|
+
|
28
|
+
Note that in most environments, if you want to support passwords
|
29
|
+
over 72 bytes and have the entire password be considered, you should
|
30
|
+
probably use the argon2 feature.
|
31
|
+
|
32
|
+
= Other Improvements
|
33
|
+
|
34
|
+
* The subclass created by the internal_request feature is now set
|
35
|
+
to the InternalRequest constant on the superclass, mostly to
|
36
|
+
make identifying it easier in inspect output.
|
37
|
+
|
38
|
+
* Support has been improved for custom Rodauth::Auth subclasses that
|
39
|
+
load features before the subclass is loaded into Roda, by delaying
|
40
|
+
the call to post_configure until the subclass is loaded into Roda.
|
41
|
+
Among other things, this fixes the use of the internal_request
|
42
|
+
feature in such classes.
|
43
|
+
|
44
|
+
* Multi-level inheritance of Rodauth::Auth is now supported. This can
|
45
|
+
be useful as a way to share custom authentication settings between
|
46
|
+
multiple Rodauth configurations. However, users of multi-level
|
47
|
+
inheritance should be careful not to load features in subclasses
|
48
|
+
that override custom settings in superclasses.
|
49
|
+
|
50
|
+
= Other
|
51
|
+
|
52
|
+
* Rodauth's primary discussion forum is now GitHub Discussions. The
|
53
|
+
rodauth Google Group is still available for users who would prefer
|
54
|
+
to use that instead.
|
55
|
+
|
56
|
+
= Backwards Compatibility
|
57
|
+
|
58
|
+
* The addition of login_maximum_bytes with a default value of 255 is
|
59
|
+
backwards incompatible for applications that want to support logins
|
60
|
+
with multibyte characters where the number of characters in the
|
61
|
+
login is at or below 255, but the number of bytes is above 255.
|
@@ -16,6 +16,18 @@ module Rodauth
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
+
if Argon2::VERSION != '2.1.0'
|
20
|
+
def argon2_salt_option
|
21
|
+
:salt_do_not_supply
|
22
|
+
end
|
23
|
+
# :nocov:
|
24
|
+
else
|
25
|
+
def argon2_salt_option
|
26
|
+
:salt_for_testing_purposes_only
|
27
|
+
end
|
28
|
+
# :nocov:
|
29
|
+
end
|
30
|
+
|
19
31
|
def password_hash_cost
|
20
32
|
return super unless use_argon2?
|
21
33
|
argon2_hash_cost
|
@@ -35,7 +47,7 @@ module Rodauth
|
|
35
47
|
return super unless argon2_hash_algorithm?(salt)
|
36
48
|
|
37
49
|
argon2_params = Hash[extract_password_hash_cost(salt)]
|
38
|
-
argon2_params[
|
50
|
+
argon2_params[argon2_salt_option] = Base64.decode64(salt.split('$').last)
|
39
51
|
::Argon2::Password.new(argon2_params).create(password)
|
40
52
|
end
|
41
53
|
|
@@ -92,6 +92,10 @@ module Rodauth
|
|
92
92
|
@internal_request_return_value
|
93
93
|
end
|
94
94
|
|
95
|
+
def only_json?
|
96
|
+
false
|
97
|
+
end
|
98
|
+
|
95
99
|
private
|
96
100
|
|
97
101
|
def internal_request?
|
@@ -335,14 +339,7 @@ module Rodauth
|
|
335
339
|
return if is_a?(InternalRequestMethods)
|
336
340
|
|
337
341
|
klass = self.class
|
338
|
-
internal_class = Class.new(klass)
|
339
|
-
@roda_class = klass.roda_class
|
340
|
-
@features = klass.features.clone
|
341
|
-
@routes = klass.routes.clone
|
342
|
-
@route_hash = klass.route_hash.clone
|
343
|
-
@configuration = klass.configuration.clone
|
344
|
-
@configuration.instance_variable_set(:@auth, self)
|
345
|
-
end
|
342
|
+
internal_class = Class.new(klass)
|
346
343
|
|
347
344
|
if blocks = klass.instance_variable_get(:@internal_request_configuration_blocks)
|
348
345
|
configuration = internal_class.configuration
|
@@ -362,6 +359,9 @@ module Rodauth
|
|
362
359
|
end
|
363
360
|
end
|
364
361
|
end
|
362
|
+
|
363
|
+
klass.const_set(:InternalRequest, internal_class)
|
364
|
+
klass.private_constant :InternalRequest
|
365
365
|
end
|
366
366
|
end
|
367
367
|
end
|
@@ -67,6 +67,25 @@ module Rodauth
|
|
67
67
|
|
68
68
|
private
|
69
69
|
|
70
|
+
def before_two_factor_manage_route
|
71
|
+
super if defined?(super)
|
72
|
+
if use_json?
|
73
|
+
json_response[:setup_links] = two_factor_setup_links.sort.map{|_,link| link}
|
74
|
+
json_response[:remove_links] = two_factor_remove_links.sort.map{|_,link| link}
|
75
|
+
json_response[json_response_success_key] ||= "" if include_success_messages?
|
76
|
+
return_json_response
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def before_two_factor_auth_route
|
81
|
+
super if defined?(super)
|
82
|
+
if use_json?
|
83
|
+
json_response[:auth_links] = two_factor_auth_links.sort.map{|_,link| link}
|
84
|
+
json_response[json_response_success_key] ||= "" if include_success_messages?
|
85
|
+
return_json_response
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
70
89
|
def before_view_recovery_codes
|
71
90
|
super if defined?(super)
|
72
91
|
if use_json?
|
@@ -98,7 +98,7 @@ module Rodauth
|
|
98
98
|
# JWT is invalid for other reasons. Make sure the expiration is the
|
99
99
|
# only reason the JWT isn't valid before treating this as an expired token.
|
100
100
|
JWT.decode(jwt_token, jwt_secret, true, Hash[jwt_decode_opts].merge!(:verify_expiration=>false, :algorithm=>jwt_algorithm))[0]
|
101
|
-
rescue
|
101
|
+
rescue
|
102
102
|
else
|
103
103
|
json_response[json_response_error_key] = expired_jwt_access_token_message
|
104
104
|
response.status ||= expired_jwt_access_token_status
|
@@ -120,7 +120,7 @@ module Rodauth
|
|
120
120
|
end
|
121
121
|
|
122
122
|
ds = account_ds(id)
|
123
|
-
ds = ds.where(
|
123
|
+
ds = ds.where(account_session_status_filter) unless skip_status_checks?
|
124
124
|
ds.first
|
125
125
|
end
|
126
126
|
|
@@ -7,10 +7,13 @@ module Rodauth
|
|
7
7
|
auth_value_method :login_email_regexp, /\A[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+\z/
|
8
8
|
auth_value_method :login_minimum_length, 3
|
9
9
|
auth_value_method :login_maximum_length, 255
|
10
|
+
auth_value_method :login_maximum_bytes, 255
|
10
11
|
translatable_method :login_not_valid_email_message, 'not a valid email address'
|
11
12
|
translatable_method :logins_do_not_match_message, 'logins do not match'
|
12
13
|
auth_value_method :password_confirm_param, 'password-confirm'
|
13
14
|
auth_value_method :password_minimum_length, 6
|
15
|
+
auth_value_method :password_maximum_bytes, nil
|
16
|
+
auth_value_method :password_maximum_length, nil
|
14
17
|
translatable_method :passwords_do_not_match_message, 'passwords do not match'
|
15
18
|
auth_value_method :require_email_address_logins?, true
|
16
19
|
auth_value_method :require_login_confirmation?, true
|
@@ -22,10 +25,13 @@ module Rodauth
|
|
22
25
|
:login_confirm_label,
|
23
26
|
:login_does_not_meet_requirements_message,
|
24
27
|
:login_too_long_message,
|
28
|
+
:login_too_many_bytes_message,
|
25
29
|
:login_too_short_message,
|
26
30
|
:password_confirm_label,
|
27
31
|
:password_does_not_meet_requirements_message,
|
28
32
|
:password_hash_cost,
|
33
|
+
:password_too_long_message,
|
34
|
+
:password_too_many_bytes_message,
|
29
35
|
:password_too_short_message
|
30
36
|
)
|
31
37
|
|
@@ -78,6 +84,14 @@ module Rodauth
|
|
78
84
|
"invalid password, does not meet requirements#{" (#{password_requirement_message})" if password_requirement_message}"
|
79
85
|
end
|
80
86
|
|
87
|
+
def password_too_long_message
|
88
|
+
"maximum #{password_maximum_length} characters"
|
89
|
+
end
|
90
|
+
|
91
|
+
def password_too_many_bytes_message
|
92
|
+
"maximum #{password_maximum_bytes} bytes"
|
93
|
+
end
|
94
|
+
|
81
95
|
def password_too_short_message
|
82
96
|
"minimum #{password_minimum_length} characters"
|
83
97
|
end
|
@@ -95,6 +109,10 @@ module Rodauth
|
|
95
109
|
"maximum #{login_maximum_length} characters"
|
96
110
|
end
|
97
111
|
|
112
|
+
def login_too_many_bytes_message
|
113
|
+
"maximum #{login_maximum_bytes} bytes"
|
114
|
+
end
|
115
|
+
|
98
116
|
def login_too_short_message
|
99
117
|
"minimum #{login_minimum_length} characters"
|
100
118
|
end
|
@@ -111,6 +129,9 @@ module Rodauth
|
|
111
129
|
elsif login_maximum_length < login.length
|
112
130
|
set_login_requirement_error_message(:login_too_long, login_too_long_message)
|
113
131
|
false
|
132
|
+
elsif login_maximum_bytes < login.bytesize
|
133
|
+
set_login_requirement_error_message(:login_too_many_bytes, login_too_many_bytes_message)
|
134
|
+
false
|
114
135
|
else
|
115
136
|
true
|
116
137
|
end
|
@@ -128,9 +149,18 @@ module Rodauth
|
|
128
149
|
end
|
129
150
|
|
130
151
|
def password_meets_length_requirements?(password)
|
131
|
-
|
132
|
-
|
133
|
-
|
152
|
+
if password_minimum_length > password.length
|
153
|
+
set_password_requirement_error_message(:password_too_short, password_too_short_message)
|
154
|
+
false
|
155
|
+
elsif password_maximum_length && password_maximum_length < password.length
|
156
|
+
set_password_requirement_error_message(:password_too_long, password_too_long_message)
|
157
|
+
false
|
158
|
+
elsif password_maximum_bytes && password_maximum_bytes < password.bytesize
|
159
|
+
set_password_requirement_error_message(:password_too_many_bytes, password_too_many_bytes_message)
|
160
|
+
false
|
161
|
+
else
|
162
|
+
true
|
163
|
+
end
|
134
164
|
end
|
135
165
|
|
136
166
|
def password_does_not_contain_null_byte?(password)
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -196,8 +196,7 @@ module Rodauth
|
|
196
196
|
|
197
197
|
def new_account(login)
|
198
198
|
if account_from_login(login) && allow_resending_verify_account_email?
|
199
|
-
|
200
|
-
set_error_reason :already_an_unverified_account_with_this_login
|
199
|
+
set_response_error_reason_status(:already_an_unverified_account_with_this_login, unopen_account_error_status)
|
201
200
|
set_error_flash attempt_to_create_unverified_account_error_flash
|
202
201
|
response.write resend_verify_account_view
|
203
202
|
request.halt
|
@@ -274,8 +273,7 @@ module Rodauth
|
|
274
273
|
|
275
274
|
def before_login_attempt
|
276
275
|
unless open_account?
|
277
|
-
|
278
|
-
set_error_reason :unverified_account
|
276
|
+
set_response_error_reason_status(:unverified_account, unopen_account_error_status)
|
279
277
|
set_error_flash attempt_to_login_to_unverified_account_error_flash
|
280
278
|
response.write resend_verify_account_view
|
281
279
|
request.halt
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
@@ -3,6 +3,17 @@
|
|
3
3
|
require 'securerandom'
|
4
4
|
|
5
5
|
module Rodauth
|
6
|
+
def self.lib(opts={}, &block)
|
7
|
+
require 'roda'
|
8
|
+
c = Class.new(Roda)
|
9
|
+
c.plugin(:rodauth, opts) do
|
10
|
+
enable :internal_request
|
11
|
+
instance_exec(&block)
|
12
|
+
end
|
13
|
+
c.freeze
|
14
|
+
c.rodauth
|
15
|
+
end
|
16
|
+
|
6
17
|
def self.load_dependencies(app, opts={})
|
7
18
|
json_opt = opts.fetch(:json, app.opts[:rodauth_json])
|
8
19
|
if json_opt
|
@@ -39,14 +50,16 @@ module Rodauth
|
|
39
50
|
else
|
40
51
|
json_opt != :only
|
41
52
|
end
|
42
|
-
auth_class = (app.opts[:rodauths] ||= {})[opts[:name]] ||= opts[:auth_class] || Class.new(Auth)
|
53
|
+
auth_class = (app.opts[:rodauths] ||= {})[opts[:name]] ||= opts[:auth_class] || Class.new(Auth)
|
43
54
|
if !auth_class.roda_class
|
44
55
|
auth_class.roda_class = app
|
45
56
|
elsif auth_class.roda_class != app
|
46
|
-
auth_class = app.opts[:rodauths][opts[:name]] = Class.new(auth_class)
|
57
|
+
auth_class = app.opts[:rodauths][opts[:name]] = Class.new(auth_class)
|
47
58
|
auth_class.roda_class = app
|
48
59
|
end
|
60
|
+
auth_class.class_eval{@configuration_name = opts[:name] unless defined?(@configuration_name)}
|
49
61
|
auth_class.configure(&block) if block
|
62
|
+
auth_class.allocate.post_configure if auth_class.method_defined?(:post_configure)
|
50
63
|
end
|
51
64
|
|
52
65
|
FEATURES = {}
|
@@ -259,38 +272,6 @@ module Rodauth
|
|
259
272
|
end
|
260
273
|
end
|
261
274
|
|
262
|
-
class Auth
|
263
|
-
class << self
|
264
|
-
attr_accessor :roda_class
|
265
|
-
attr_reader :features
|
266
|
-
attr_reader :routes
|
267
|
-
attr_accessor :route_hash
|
268
|
-
attr_reader :configuration_name
|
269
|
-
attr_reader :configuration
|
270
|
-
end
|
271
|
-
|
272
|
-
def self.inherited(subclass)
|
273
|
-
super
|
274
|
-
subclass.instance_exec do
|
275
|
-
@features = []
|
276
|
-
@routes = []
|
277
|
-
@route_hash = {}
|
278
|
-
@configuration = Configuration.new(self)
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
def self.configure(&block)
|
283
|
-
@configuration.apply(&block)
|
284
|
-
end
|
285
|
-
|
286
|
-
def self.freeze
|
287
|
-
@features.freeze
|
288
|
-
@routes.freeze
|
289
|
-
@route_hash.freeze
|
290
|
-
super
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
275
|
class Configuration
|
295
276
|
attr_reader :auth
|
296
277
|
|
@@ -306,7 +287,6 @@ module Rodauth
|
|
306
287
|
def apply(&block)
|
307
288
|
load_feature(:base)
|
308
289
|
instance_exec(&block)
|
309
|
-
auth.allocate.post_configure
|
310
290
|
end
|
311
291
|
|
312
292
|
def enable(*features)
|
@@ -330,6 +310,46 @@ module Rodauth
|
|
330
310
|
end
|
331
311
|
end
|
332
312
|
|
313
|
+
class Auth
|
314
|
+
@features = []
|
315
|
+
@routes = []
|
316
|
+
@route_hash = {}
|
317
|
+
@configuration = Configuration.new(self)
|
318
|
+
|
319
|
+
class << self
|
320
|
+
attr_accessor :roda_class
|
321
|
+
attr_reader :features
|
322
|
+
attr_reader :routes
|
323
|
+
attr_accessor :route_hash
|
324
|
+
attr_reader :configuration_name
|
325
|
+
attr_reader :configuration
|
326
|
+
end
|
327
|
+
|
328
|
+
def self.inherited(subclass)
|
329
|
+
super
|
330
|
+
superclass = self
|
331
|
+
subclass.instance_exec do
|
332
|
+
@roda_class = superclass.roda_class
|
333
|
+
@features = superclass.features.clone
|
334
|
+
@routes = superclass.routes.clone
|
335
|
+
@route_hash = superclass.route_hash.clone
|
336
|
+
@configuration = superclass.configuration.clone
|
337
|
+
@configuration.instance_variable_set(:@auth, self)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def self.configure(&block)
|
342
|
+
@configuration.apply(&block)
|
343
|
+
end
|
344
|
+
|
345
|
+
def self.freeze
|
346
|
+
@features.freeze
|
347
|
+
@routes.freeze
|
348
|
+
@route_hash.freeze
|
349
|
+
super
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
333
353
|
module InstanceMethods
|
334
354
|
def rodauth(name=nil)
|
335
355
|
if name
|
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: 2.
|
4
|
+
version: 2.19.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: 2021-
|
11
|
+
date: 2021-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -329,6 +329,10 @@ extra_rdoc_files:
|
|
329
329
|
- doc/release_notes/2.13.0.txt
|
330
330
|
- doc/release_notes/2.14.0.txt
|
331
331
|
- doc/release_notes/2.15.0.txt
|
332
|
+
- doc/release_notes/2.16.0.txt
|
333
|
+
- doc/release_notes/2.17.0.txt
|
334
|
+
- doc/release_notes/2.18.0.txt
|
335
|
+
- doc/release_notes/2.19.0.txt
|
332
336
|
- doc/release_notes/2.2.0.txt
|
333
337
|
- doc/release_notes/2.3.0.txt
|
334
338
|
- doc/release_notes/2.4.0.txt
|
@@ -361,6 +365,7 @@ files:
|
|
361
365
|
- doc/guides/admin_activation.rdoc
|
362
366
|
- doc/guides/already_authenticated.rdoc
|
363
367
|
- doc/guides/alternative_login.rdoc
|
368
|
+
- doc/guides/change_table_and_column_names.rdoc
|
364
369
|
- doc/guides/create_account_programmatically.rdoc
|
365
370
|
- doc/guides/delay_password.rdoc
|
366
371
|
- doc/guides/email_only.rdoc
|
@@ -378,6 +383,7 @@ files:
|
|
378
383
|
- doc/guides/registration_field.rdoc
|
379
384
|
- doc/guides/require_mfa.rdoc
|
380
385
|
- doc/guides/reset_password_autologin.rdoc
|
386
|
+
- doc/guides/share_configuration.rdoc
|
381
387
|
- doc/guides/status_column.rdoc
|
382
388
|
- doc/guides/totp_or_recovery.rdoc
|
383
389
|
- doc/http_basic_auth.rdoc
|
@@ -429,6 +435,10 @@ files:
|
|
429
435
|
- doc/release_notes/2.13.0.txt
|
430
436
|
- doc/release_notes/2.14.0.txt
|
431
437
|
- doc/release_notes/2.15.0.txt
|
438
|
+
- doc/release_notes/2.16.0.txt
|
439
|
+
- doc/release_notes/2.17.0.txt
|
440
|
+
- doc/release_notes/2.18.0.txt
|
441
|
+
- doc/release_notes/2.19.0.txt
|
432
442
|
- doc/release_notes/2.2.0.txt
|
433
443
|
- doc/release_notes/2.3.0.txt
|
434
444
|
- doc/release_notes/2.4.0.txt
|
@@ -560,7 +570,7 @@ metadata:
|
|
560
570
|
bug_tracker_uri: https://github.com/jeremyevans/rodauth/issues
|
561
571
|
changelog_uri: http://rodauth.jeremyevans.net/rdoc/files/CHANGELOG.html
|
562
572
|
documentation_uri: http://rodauth.jeremyevans.net/documentation.html
|
563
|
-
mailing_list_uri: https://
|
573
|
+
mailing_list_uri: https://github.com/jeremyevans/rodauth/discussions
|
564
574
|
source_code_uri: https://github.com/jeremyevans/rodauth
|
565
575
|
post_install_message:
|
566
576
|
rdoc_options:
|
@@ -584,7 +594,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
584
594
|
- !ruby/object:Gem::Version
|
585
595
|
version: '0'
|
586
596
|
requirements: []
|
587
|
-
rubygems_version: 3.2.
|
597
|
+
rubygems_version: 3.2.32
|
588
598
|
signing_key:
|
589
599
|
specification_version: 4
|
590
600
|
summary: Authentication and Account Management Framework for Rack Applications
|