rodauth 2.18.0 → 2.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/README.rdoc +6 -1
- data/doc/error_reasons.rdoc +3 -0
- data/doc/guides/change_table_and_column_names.rdoc +19 -0
- data/doc/guides/share_configuration.rdoc +34 -0
- data/doc/login_password_requirements_base.rdoc +9 -3
- data/doc/release_notes/2.19.0.txt +61 -0
- data/doc/release_notes/2.20.0.txt +10 -0
- data/doc/release_notes/2.21.0.txt +28 -0
- data/lib/rodauth/features/active_sessions.rb +2 -1
- data/lib/rodauth/features/base.rb +6 -6
- data/lib/rodauth/features/internal_request.rb +4 -8
- data/lib/rodauth/features/login_password_requirements_base.rb +33 -3
- data/lib/rodauth/features/verify_account_grace_period.rb +13 -1
- data/lib/rodauth/features/webauthn.rb +1 -1
- data/lib/rodauth/version.rb +1 -1
- data/lib/rodauth.rb +41 -33
- data/templates/webauthn-remove.str +1 -0
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb1777533bb6a941212c0e6d5be00fc393b95c3d22e7af40542d616cdd68d139
|
4
|
+
data.tar.gz: de6a798803940fb94ff1d44bc2d148e45b1adc8e532cb44db4602b974a1b6b19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 830b574f78cba6d5e103306f3709e2ae92e99af0cb0b02c8276699c048cd799cad58cf28d521980e43c0023aadc8934705ad45ff48819c316b3c6d3b5554f189
|
7
|
+
data.tar.gz: d4127705f604ac89b35f17d795c07bd54bed86b6c9c784e04578f047a3b1d2e34689c0320c35ffe9f7640e7870197c6563c4c57c0867ca5d2d257d23a143ce1a
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,35 @@
|
|
1
|
+
=== 2.21.0 (2022-02-23)
|
2
|
+
|
3
|
+
* Avoid extra bcrypt hashing on account verification when using account_password_hash_column (janko) (#217)
|
4
|
+
|
5
|
+
* Make require_account public (janko) (#212)
|
6
|
+
|
7
|
+
* Force specific date/time format when displaying webauthn last use time (jeremyevans)
|
8
|
+
|
9
|
+
* Automatically clear the session in require_login if users go beyond verify account grace period (janko) (#211)
|
10
|
+
|
11
|
+
* Fix typo in default value of global_logout_label in active_sessions plugin (sterlzbd) (#209)
|
12
|
+
|
13
|
+
=== 2.20.0 (2022-01-24)
|
14
|
+
|
15
|
+
* Change the default implementation of webauth_rp_id to not include the port (jeremyevans) (#203)
|
16
|
+
|
17
|
+
* Make logout of all sessions in active_sessions plugin also remove remember key if using remember plugin (jeremyevans)
|
18
|
+
|
19
|
+
=== 2.19.0 (2021-12-22)
|
20
|
+
|
21
|
+
* Add login_maximum_bytes, setting the maximum number of bytes in a login, 255 by default (jeremyevans)
|
22
|
+
|
23
|
+
* Add password_maximum_bytes, setting the maximum number of bytes in a password, nil by default for no limit (jeremyevans)
|
24
|
+
|
25
|
+
* Add password_maximum_length, setting the maximum number of characters in a password, nil by default for no limit (jeremyevans)
|
26
|
+
|
27
|
+
* Support multi-level inheritance of Rodauth::Auth (janko) (#191)
|
28
|
+
|
29
|
+
* Allow internal_request feature to work correctly when loaded into custom Rodauth::Auth subclasses before loading into a Roda application (janko) (#190)
|
30
|
+
|
31
|
+
* Assign internal subclass created by internal_request feature to the InternalRequest constant (janko) (#187)
|
32
|
+
|
1
33
|
=== 2.18.0 (2021-11-23)
|
2
34
|
|
3
35
|
* Allow JSON API access to /multifactor-manage to get links to setup/disable multifactor authentication endpoints (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
|
|
@@ -989,6 +990,10 @@ require_authentication :: Similar to +require_login+, but also requires
|
|
989
990
|
two factor authentication. Redirects the request to
|
990
991
|
the two factor authentication page if logged in but not
|
991
992
|
authenticated via two factors.
|
993
|
+
require_account :: Similar to +require_authentication+, but also loads the logged
|
994
|
+
in account to ensure it exists in the database. If the account
|
995
|
+
doesn't exist, or if it exists but isn't verified, the session
|
996
|
+
is cleared and the request redirected to the login page.
|
992
997
|
logged_in? :: Whether the session has been logged in.
|
993
998
|
authenticated? :: Similar to +logged_in?+, but if the account has setup two
|
994
999
|
factor authentication, whether the session has authenticated
|
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].
|
@@ -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,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.
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* When using the active_sessions and remember features together,
|
4
|
+
doing a global logout will automatically remove the remember key for
|
5
|
+
the account, so the account will no longer be able to automatically
|
6
|
+
create new sessions using the remember key.
|
7
|
+
|
8
|
+
* The default value of webauthn_rp_id now removes the port from the
|
9
|
+
origin if it exists, since the WebAuthn spec does not allow ports
|
10
|
+
in the relying party identifier.
|
@@ -0,0 +1,28 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* When using the verify_account_grace_period feature, if the grace
|
4
|
+
period has expired for currently logged in session, require_login
|
5
|
+
will clear the session and redirect to the login page. This is
|
6
|
+
implemented by having the unverified_account_session_key store the
|
7
|
+
time of expiration, as an integer.
|
8
|
+
|
9
|
+
* The previously private require_account method is now public. The
|
10
|
+
method is used internally by Rodauth to check that not only is the
|
11
|
+
current session logged in, but also that the account related to the
|
12
|
+
currently logged in session still exists in the database. The only
|
13
|
+
reason you would want to call require_account instead of
|
14
|
+
require_authentication is if you want to handle cases where there
|
15
|
+
can be logged in sessions for accounts that have been deleted.
|
16
|
+
|
17
|
+
* Rodauth now avoids an unnecessary bcrypt hash calculation when
|
18
|
+
updating accounts when using the account_password_hash_column
|
19
|
+
configuration method.
|
20
|
+
|
21
|
+
* When WebAuthn token last use times are displayed, Rodauth now uses a
|
22
|
+
fixed format of YYYY-MM-DD HH:MM:SS, instead of relying on
|
23
|
+
Time#to_s. If this presents an problem for your application, please
|
24
|
+
open an issue and we can add a configuration method to control
|
25
|
+
the behavior.
|
26
|
+
|
27
|
+
* A typo in the default value of global_logout_label in the
|
28
|
+
active_sessions feature has been fixed.
|
@@ -13,7 +13,7 @@ module Rodauth
|
|
13
13
|
auth_value_method :active_sessions_last_use_column, :last_use
|
14
14
|
auth_value_method :active_sessions_session_id_column, :session_id
|
15
15
|
auth_value_method :active_sessions_table, :account_active_session_keys
|
16
|
-
translatable_method :global_logout_label, 'Logout all Logged In
|
16
|
+
translatable_method :global_logout_label, 'Logout all Logged In Sessions?'
|
17
17
|
auth_value_method :global_logout_param, 'global_logout'
|
18
18
|
auth_value_method :inactive_session_error_status, 401
|
19
19
|
auth_value_method :session_inactivity_deadline, 86400
|
@@ -123,6 +123,7 @@ module Rodauth
|
|
123
123
|
|
124
124
|
def before_logout
|
125
125
|
if param_or_nil(global_logout_param)
|
126
|
+
remove_remember_key(session_value) if respond_to?(:remove_remember_key)
|
126
127
|
remove_all_active_sessions
|
127
128
|
else
|
128
129
|
remove_current_session
|
@@ -338,6 +338,11 @@ module Rodauth
|
|
338
338
|
require_login
|
339
339
|
end
|
340
340
|
|
341
|
+
def require_account
|
342
|
+
require_authentication
|
343
|
+
require_account_session
|
344
|
+
end
|
345
|
+
|
341
346
|
def account_initial_status_value
|
342
347
|
account_open_status_value
|
343
348
|
end
|
@@ -524,11 +529,6 @@ module Rodauth
|
|
524
529
|
Rack::Utils.secure_compare(provided.ljust(actual.length), actual) && provided.length == actual.length
|
525
530
|
end
|
526
531
|
|
527
|
-
def require_account
|
528
|
-
require_authentication
|
529
|
-
require_account_session
|
530
|
-
end
|
531
|
-
|
532
532
|
def require_account_session
|
533
533
|
unless account_from_session
|
534
534
|
clear_session
|
@@ -756,7 +756,7 @@ module Rodauth
|
|
756
756
|
num = ds.update(values)
|
757
757
|
if num == 1
|
758
758
|
values.each do |k, v|
|
759
|
-
account[k] =
|
759
|
+
account[k] = Sequel::CURRENT_TIMESTAMP == v ? Time.now : v
|
760
760
|
end
|
761
761
|
end
|
762
762
|
num
|
@@ -339,14 +339,7 @@ module Rodauth
|
|
339
339
|
return if is_a?(InternalRequestMethods)
|
340
340
|
|
341
341
|
klass = self.class
|
342
|
-
internal_class = Class.new(klass)
|
343
|
-
@roda_class = klass.roda_class
|
344
|
-
@features = klass.features.clone
|
345
|
-
@routes = klass.routes.clone
|
346
|
-
@route_hash = klass.route_hash.clone
|
347
|
-
@configuration = klass.configuration.clone
|
348
|
-
@configuration.instance_variable_set(:@auth, self)
|
349
|
-
end
|
342
|
+
internal_class = Class.new(klass)
|
350
343
|
|
351
344
|
if blocks = klass.instance_variable_get(:@internal_request_configuration_blocks)
|
352
345
|
configuration = internal_class.configuration
|
@@ -366,6 +359,9 @@ module Rodauth
|
|
366
359
|
end
|
367
360
|
end
|
368
361
|
end
|
362
|
+
|
363
|
+
klass.const_set(:InternalRequest, internal_class)
|
364
|
+
klass.private_constant :InternalRequest
|
369
365
|
end
|
370
366
|
end
|
371
367
|
end
|
@@ -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)
|
@@ -30,10 +30,17 @@ module Rodauth
|
|
30
30
|
false
|
31
31
|
end
|
32
32
|
|
33
|
+
def require_login
|
34
|
+
if unverified_grace_period_expired?
|
35
|
+
clear_session
|
36
|
+
end
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
33
40
|
def update_session
|
34
41
|
super
|
35
42
|
if account_in_unverified_grace_period?
|
36
|
-
set_session_value(unverified_account_session_key,
|
43
|
+
set_session_value(unverified_account_session_key, Time.now.to_i + verify_account_grace_period)
|
37
44
|
end
|
38
45
|
end
|
39
46
|
|
@@ -78,6 +85,11 @@ module Rodauth
|
|
78
85
|
!verify_account_ds.where(Sequel.date_add(verification_requested_at_column, :seconds=>verify_account_grace_period) > Sequel::CURRENT_TIMESTAMP).empty?
|
79
86
|
end
|
80
87
|
|
88
|
+
def unverified_grace_period_expired?
|
89
|
+
return false unless expires_at = session[unverified_account_session_key]
|
90
|
+
expires_at.is_a?(Integer) && Time.now.to_i > expires_at
|
91
|
+
end
|
92
|
+
|
81
93
|
def use_date_arithmetic?
|
82
94
|
true
|
83
95
|
end
|
data/lib/rodauth/version.rb
CHANGED
data/lib/rodauth.rb
CHANGED
@@ -59,6 +59,7 @@ module Rodauth
|
|
59
59
|
end
|
60
60
|
auth_class.class_eval{@configuration_name = opts[:name] unless defined?(@configuration_name)}
|
61
61
|
auth_class.configure(&block) if block
|
62
|
+
auth_class.allocate.post_configure if auth_class.method_defined?(:post_configure)
|
62
63
|
end
|
63
64
|
|
64
65
|
FEATURES = {}
|
@@ -271,38 +272,6 @@ module Rodauth
|
|
271
272
|
end
|
272
273
|
end
|
273
274
|
|
274
|
-
class Auth
|
275
|
-
class << self
|
276
|
-
attr_accessor :roda_class
|
277
|
-
attr_reader :features
|
278
|
-
attr_reader :routes
|
279
|
-
attr_accessor :route_hash
|
280
|
-
attr_reader :configuration_name
|
281
|
-
attr_reader :configuration
|
282
|
-
end
|
283
|
-
|
284
|
-
def self.inherited(subclass)
|
285
|
-
super
|
286
|
-
subclass.instance_exec do
|
287
|
-
@features = []
|
288
|
-
@routes = []
|
289
|
-
@route_hash = {}
|
290
|
-
@configuration = Configuration.new(self)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def self.configure(&block)
|
295
|
-
@configuration.apply(&block)
|
296
|
-
end
|
297
|
-
|
298
|
-
def self.freeze
|
299
|
-
@features.freeze
|
300
|
-
@routes.freeze
|
301
|
-
@route_hash.freeze
|
302
|
-
super
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
275
|
class Configuration
|
307
276
|
attr_reader :auth
|
308
277
|
|
@@ -318,7 +287,6 @@ module Rodauth
|
|
318
287
|
def apply(&block)
|
319
288
|
load_feature(:base)
|
320
289
|
instance_exec(&block)
|
321
|
-
auth.allocate.post_configure
|
322
290
|
end
|
323
291
|
|
324
292
|
def enable(*features)
|
@@ -342,6 +310,46 @@ module Rodauth
|
|
342
310
|
end
|
343
311
|
end
|
344
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
|
+
|
345
353
|
module InstanceMethods
|
346
354
|
def rodauth(name=nil)
|
347
355
|
if name
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#{rodauth.render('password-field') if rodauth.two_factor_modifications_require_password?}
|
5
5
|
<fieldset class="form-group mb-3">
|
6
6
|
#{(usage = rodauth.account_webauthn_usage; last_id = usage.keys.last; usage;).map do |id, last_use|
|
7
|
+
last_use = last_use.strftime("%F %T") if last_use.is_a?(Time)
|
7
8
|
input = rodauth.input_field_string(rodauth.webauthn_remove_param, "webauthn-remove-#{h id}", :type=>'radio', :class=>"form-check-input", :skip_error_message=>true, :value=>id, :required=>false)
|
8
9
|
label = "<label class=\"rodauth-webauthn-id form-check-label\" for=\"webauthn-remove-#{h id}\">Last Use: #{last_use}</label>"
|
9
10
|
error = rodauth.formatted_field_error(rodauth.webauthn_remove_param) if id == last_id
|
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.21.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:
|
11
|
+
date: 2022-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -332,7 +332,10 @@ extra_rdoc_files:
|
|
332
332
|
- doc/release_notes/2.16.0.txt
|
333
333
|
- doc/release_notes/2.17.0.txt
|
334
334
|
- doc/release_notes/2.18.0.txt
|
335
|
+
- doc/release_notes/2.19.0.txt
|
335
336
|
- doc/release_notes/2.2.0.txt
|
337
|
+
- doc/release_notes/2.20.0.txt
|
338
|
+
- doc/release_notes/2.21.0.txt
|
336
339
|
- doc/release_notes/2.3.0.txt
|
337
340
|
- doc/release_notes/2.4.0.txt
|
338
341
|
- doc/release_notes/2.5.0.txt
|
@@ -364,6 +367,7 @@ files:
|
|
364
367
|
- doc/guides/admin_activation.rdoc
|
365
368
|
- doc/guides/already_authenticated.rdoc
|
366
369
|
- doc/guides/alternative_login.rdoc
|
370
|
+
- doc/guides/change_table_and_column_names.rdoc
|
367
371
|
- doc/guides/create_account_programmatically.rdoc
|
368
372
|
- doc/guides/delay_password.rdoc
|
369
373
|
- doc/guides/email_only.rdoc
|
@@ -381,6 +385,7 @@ files:
|
|
381
385
|
- doc/guides/registration_field.rdoc
|
382
386
|
- doc/guides/require_mfa.rdoc
|
383
387
|
- doc/guides/reset_password_autologin.rdoc
|
388
|
+
- doc/guides/share_configuration.rdoc
|
384
389
|
- doc/guides/status_column.rdoc
|
385
390
|
- doc/guides/totp_or_recovery.rdoc
|
386
391
|
- doc/http_basic_auth.rdoc
|
@@ -435,7 +440,10 @@ files:
|
|
435
440
|
- doc/release_notes/2.16.0.txt
|
436
441
|
- doc/release_notes/2.17.0.txt
|
437
442
|
- doc/release_notes/2.18.0.txt
|
443
|
+
- doc/release_notes/2.19.0.txt
|
438
444
|
- doc/release_notes/2.2.0.txt
|
445
|
+
- doc/release_notes/2.20.0.txt
|
446
|
+
- doc/release_notes/2.21.0.txt
|
439
447
|
- doc/release_notes/2.3.0.txt
|
440
448
|
- doc/release_notes/2.4.0.txt
|
441
449
|
- doc/release_notes/2.5.0.txt
|
@@ -566,7 +574,7 @@ metadata:
|
|
566
574
|
bug_tracker_uri: https://github.com/jeremyevans/rodauth/issues
|
567
575
|
changelog_uri: http://rodauth.jeremyevans.net/rdoc/files/CHANGELOG.html
|
568
576
|
documentation_uri: http://rodauth.jeremyevans.net/documentation.html
|
569
|
-
mailing_list_uri: https://
|
577
|
+
mailing_list_uri: https://github.com/jeremyevans/rodauth/discussions
|
570
578
|
source_code_uri: https://github.com/jeremyevans/rodauth
|
571
579
|
post_install_message:
|
572
580
|
rdoc_options:
|
@@ -590,7 +598,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
590
598
|
- !ruby/object:Gem::Version
|
591
599
|
version: '0'
|
592
600
|
requirements: []
|
593
|
-
rubygems_version: 3.
|
601
|
+
rubygems_version: 3.3.7
|
594
602
|
signing_key:
|
595
603
|
specification_version: 4
|
596
604
|
summary: Authentication and Account Management Framework for Rack Applications
|