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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60f279e15751f9a0915c72e919726cae392844137ddabd98cb5a973815ada935
4
- data.tar.gz: ae841728e69f0fdf1d2c67de55f52ed535971a349ecc6dbddeaf6250e573515f
3
+ metadata.gz: bb1777533bb6a941212c0e6d5be00fc393b95c3d22e7af40542d616cdd68d139
4
+ data.tar.gz: de6a798803940fb94ff1d44bc2d148e45b1adc8e532cb44db4602b974a1b6b19
5
5
  SHA512:
6
- metadata.gz: 7490aded0f6e506fff03b445d569709ec77d1dc7e36193d8939c36d706a95f4b9bbd2ad0a05feaa7f4e2c309ce03ceeff302de81546a23f8c26bbd1c62f12c88
7
- data.tar.gz: bb437de6fd56ee88a2acdccc6058eefe05c856d3bc0569b473d968aa7c8c2eae64817944dade3987b612322e61c7351808765e7dfa897267e4966a7b4c8c4206
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
- Google Group :: https://groups.google.com/forum/#!forum/rodauth
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
@@ -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
- login_maximum_length :: The maximum length for logins, 255 by default.
15
- login_minimum_length :: The minimum length for logins, 3 by default.
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
- password_minimum_length :: The minimum length for passwords, 6 by default.
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 Sessons?'
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] = v == Sequel::CURRENT_TIMESTAMP ? Time.now : v
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) do
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
- return true if password_minimum_length <= password.length
132
- set_password_requirement_error_message(:password_too_short, password_too_short_message)
133
- false
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, true)
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
@@ -334,7 +334,7 @@ module Rodauth
334
334
  end
335
335
 
336
336
  def webauthn_rp_id
337
- webauthn_origin.sub(/\Ahttps?:\/\//, '')
337
+ webauthn_origin.sub(/\Ahttps?:\/\//, '').sub(/:\d+\z/, '')
338
338
  end
339
339
 
340
340
  def webauthn_rp_name
@@ -6,7 +6,7 @@ module Rodauth
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 18
9
+ MINOR = 21
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
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.18.0
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: 2021-11-23 00:00:00.000000000 Z
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://groups.google.com/forum/#!forum/rodauth
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.2.22
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