rodauth 2.26.0 → 2.27.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +14 -0
- data/MIT-LICENSE +1 -1
- data/doc/base.rdoc +2 -0
- data/doc/release_notes/2.27.0.txt +35 -0
- data/doc/webauthn.rdoc +1 -1
- data/lib/rodauth/features/base.rb +33 -4
- data/lib/rodauth/features/email_base.rb +9 -8
- data/lib/rodauth/features/json.rb +2 -2
- data/lib/rodauth/features/jwt_refresh.rb +3 -1
- data/lib/rodauth/features/otp.rb +1 -1
- data/lib/rodauth/features/webauthn.rb +4 -2
- data/lib/rodauth/version.rb +1 -1
- data/templates/webauthn-auth.str +2 -2
- data/templates/webauthn-setup.str +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eeb08d35b1a9cf7c0a5393bbcf831d41fa0ff1a9d822761ef63c149723d79db2
|
4
|
+
data.tar.gz: 8a890d1659b1a0634960420ab0546db1e76363dad7c43dc01a0b05dfe4cc85e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e27b99b1fa245aab6c600257fc82fcae6789d31105047d06d39eae185064d08917359ba8eb631b94dcfa7aa6a05be77e700a8935070b8467bcac25bbd3e2cb1
|
7
|
+
data.tar.gz: 71bfbebd641cc594889fa4d82086a17b250388796990d24b8240acb6e668fe41b52f9b1727b4b8b49846cc13574b398da0ae7c4f092436d027a4719df96f0e75
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 2.27.0 (2023-01-24)
|
2
|
+
|
3
|
+
* Rename webauth_credentials_for_get to webauthn_credentials_for_get for consistency (janko) (#295)
|
4
|
+
|
5
|
+
* Hide WebAuthn text inputs by default when using Bootstrap (janko) (#294)
|
6
|
+
|
7
|
+
* Attempt to avoid database errors when invalid tokens are submitted (jeremyevans)
|
8
|
+
|
9
|
+
* Allow button template to be overridden just as other templates can be (jeremyevans) (#280)
|
10
|
+
|
11
|
+
=== 2.26.1 (2022-11-08)
|
12
|
+
|
13
|
+
* Fix regression in QR code generation in otp feature causing all black QR code (janko) (#279)
|
14
|
+
|
1
15
|
=== 2.26.0 (2022-10-21)
|
2
16
|
|
3
17
|
* Raise a more informative error when using a feature requiring hmac_secret but not setting hmac_secret (janko) (#271)
|
data/MIT-LICENSE
CHANGED
data/doc/base.rdoc
CHANGED
@@ -35,6 +35,7 @@ cache_templates :: Whether to cache templates. True by default. It may be worth
|
|
35
35
|
check_csrf? :: Whether Rodauth should use Roda's +check_csrf!+ method for checking CSRF tokens before dispatching to Rodauth routes, true by default.
|
36
36
|
check_csrf_opts :: Options to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
|
37
37
|
check_csrf_block :: Proc for block to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
|
38
|
+
convert_token_id_to_integer? :: Whether token ids should be converted to a valid 64-bit integer value. If not set, defaults to true if +account_id_column+ uses an integer type, and false otherwise.
|
38
39
|
default_field_attributes :: The default attributes to use for input field tags, if field_attributes returns nil for the field.
|
39
40
|
default_redirect :: Where to redirect after most successful actions.
|
40
41
|
field_attributes(field) :: The attributes to use for the input field tags for the given field (parameter name).
|
@@ -96,6 +97,7 @@ before_login_attempt :: Run arbitrary code after an account has been located, bu
|
|
96
97
|
before_rodauth :: Run arbitrary code before handling any rodauth route, but after CSRF checks if Rodauth is doing CSRF checks.
|
97
98
|
check_csrf :: Checks CSRF token using Roda's +check_csrf!+ method.
|
98
99
|
clear_session :: Clears the current session.
|
100
|
+
convert_token_id(id) :: Convert the token id string to an appropriate object to use for the token id (or return +nil+ to signal an invalid token id). By default, converts to a 64-bit signed integer if +convert_token_id_to_integer?+ is true.
|
99
101
|
csrf_tag(path=request.path) :: The HTML fragment containing the CSRF tag to use, if any.
|
100
102
|
function_name(name) :: The name of the database function to call. It's passed either :rodauth_get_salt or :rodauth_valid_password_hash.
|
101
103
|
logged_in? :: Whether the current session is logged in.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* Token ids submitting in requests are now converted to integers if
|
4
|
+
the configuration uses an integer primary key for the accounts
|
5
|
+
table. If the configuration uses a non-integer primary key for
|
6
|
+
the accounts table, the convert_token_id configuration method can
|
7
|
+
be used, which should return the token id converted to the
|
8
|
+
appropriate type, or nil if the token id is not valid for the type.
|
9
|
+
|
10
|
+
This revised handling avoids raising a database error when an
|
11
|
+
invalid token is submitted.
|
12
|
+
|
13
|
+
* The button template can now be overridden in the same way that
|
14
|
+
other Rodauth templates can be overridden.
|
15
|
+
|
16
|
+
* When using the Bootstrap CSS framework, the text field in the
|
17
|
+
Webauthn setup and auth forms is automatically hidden. The text
|
18
|
+
field already had a rodauth-hidden class to make it easy to hide
|
19
|
+
when using other CSS frameworks.
|
20
|
+
|
21
|
+
* The email_from and email_to methods are now public instead of
|
22
|
+
private.
|
23
|
+
|
24
|
+
* A nicer error is raised if the Sequel Database object is missing.
|
25
|
+
|
26
|
+
* A regression in the TOTP QR output that resulted in the QR codes
|
27
|
+
being solid black squares has been fixed (this was fixed in
|
28
|
+
Rodauth 2.26.1).
|
29
|
+
|
30
|
+
= Backwards Compatibility
|
31
|
+
|
32
|
+
* The webauth_credentials_for_get method in the webauthn feature has
|
33
|
+
been renamed to webauthn_credentials_for_get for consistency with
|
34
|
+
other methods. The webauth_credentials_for_get method will still
|
35
|
+
work until Rodauth 3, but will issue deprecation warnings.
|
data/doc/webauthn.rdoc
CHANGED
@@ -104,7 +104,7 @@ remove_all_webauthn_keys_and_user_ids :: Remove all WebAuthn credentials and the
|
|
104
104
|
remove_webauthn_key(webauthn_id) :: Remove the WebAuthn credential with the given WebAuthn ID from the current account.
|
105
105
|
valid_new_webauthn_credential?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during registration is valid.
|
106
106
|
valid_webauthn_credential_auth?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during authentication is valid.
|
107
|
-
|
107
|
+
webauthn_credential_options_for_get :: WebAuthn credential options to provide to the client during WebAuthn authentication.
|
108
108
|
webauthn_auth_js_path :: The path to the WebAuthn authentication javascript.
|
109
109
|
webauthn_auth_view :: The HTML to use for the page for authenticating via WebAuthn.
|
110
110
|
webauthn_remove_authenticated_session :: Remove the authenticated WebAuthn ID, used when removing the WebAuthn credential with the ID after authenticating with it.
|
@@ -24,6 +24,7 @@ module Rodauth
|
|
24
24
|
auth_value_method :check_csrf_block, nil
|
25
25
|
auth_value_method :check_csrf_opts, {}.freeze
|
26
26
|
auth_value_method :default_redirect, '/'
|
27
|
+
auth_value_method :convert_token_id_to_integer?, nil
|
27
28
|
flash_key :flash_error_key, :error
|
28
29
|
flash_key :flash_notice_key, :notice
|
29
30
|
auth_value_method :hmac_secret, nil
|
@@ -115,6 +116,7 @@ module Rodauth
|
|
115
116
|
auth_private_methods(
|
116
117
|
:account_from_login,
|
117
118
|
:account_from_session,
|
119
|
+
:convert_token_id,
|
118
120
|
:field_attributes,
|
119
121
|
:field_error_attributes,
|
120
122
|
:formatted_field_error,
|
@@ -264,7 +266,7 @@ module Rodauth
|
|
264
266
|
end
|
265
267
|
|
266
268
|
def db
|
267
|
-
Sequel::DATABASES.first
|
269
|
+
Sequel::DATABASES.first or raise "Sequel database connection is missing"
|
268
270
|
end
|
269
271
|
|
270
272
|
def password_field_autocomplete_value
|
@@ -376,10 +378,9 @@ module Rodauth
|
|
376
378
|
def button_opts(value, opts)
|
377
379
|
opts = Hash[template_opts].merge!(opts)
|
378
380
|
opts[:locals] = {:value=>value, :opts=>opts}
|
379
|
-
opts[:path] = template_path('button')
|
380
381
|
opts[:cache] = cache_templates
|
381
382
|
opts[:cache_key] = :rodauth_button
|
382
|
-
opts
|
383
|
+
_template_opts(opts, 'button')
|
383
384
|
end
|
384
385
|
|
385
386
|
def button(value, opts={})
|
@@ -402,6 +403,11 @@ module Rodauth
|
|
402
403
|
def post_configure
|
403
404
|
require 'bcrypt' if require_bcrypt?
|
404
405
|
db.extension :date_arithmetic if use_date_arithmetic?
|
406
|
+
|
407
|
+
if convert_token_id_to_integer?.nil? && (db rescue false) && db.table_exists?(accounts_table) && db.schema(accounts_table).find{|col, v| break v[:type] == :integer if col == account_id_column}
|
408
|
+
self.class.send(:define_method, :convert_token_id_to_integer?){true}
|
409
|
+
end
|
410
|
+
|
405
411
|
route_hash= {}
|
406
412
|
self.class.routes.each do |meth|
|
407
413
|
route_meth = "#{meth.to_s.sub(/\Ahandle_/, '')}_route"
|
@@ -521,6 +527,25 @@ module Rodauth
|
|
521
527
|
token.split(token_separator, 2)
|
522
528
|
end
|
523
529
|
|
530
|
+
def convert_token_id(id)
|
531
|
+
if convert_token_id_to_integer?
|
532
|
+
convert_token_id_to_integer(id)
|
533
|
+
else
|
534
|
+
id
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
def convert_token_id_to_integer(id)
|
539
|
+
if id = (Integer(id, 10) rescue nil)
|
540
|
+
if id > 9223372036854775807 || id < -9223372036854775808
|
541
|
+
# Only allow 64-bit signed integer range to avoid problems on PostgreSQL
|
542
|
+
id = nil
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
id
|
547
|
+
end
|
548
|
+
|
524
549
|
def redirect(path)
|
525
550
|
request.redirect(path)
|
526
551
|
end
|
@@ -817,12 +842,16 @@ module Rodauth
|
|
817
842
|
opts[:locals][:rodauth] = self
|
818
843
|
opts[:cache] = cache_templates
|
819
844
|
opts[:cache_key] = :"rodauth_#{page}"
|
845
|
+
_template_opts(opts, page)
|
846
|
+
end
|
820
847
|
|
848
|
+
# Set the template path only if there isn't an overridden template in the application.
|
849
|
+
# Result should replace existing template opts.
|
850
|
+
def _template_opts(opts, page)
|
821
851
|
opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts))
|
822
852
|
unless File.file?(scope.send(:template_path, opts))
|
823
853
|
opts[:path] = template_path(page)
|
824
854
|
end
|
825
|
-
|
826
855
|
opts
|
827
856
|
end
|
828
857
|
|
@@ -23,6 +23,14 @@ module Rodauth
|
|
23
23
|
require 'mail' if require_mail?
|
24
24
|
end
|
25
25
|
|
26
|
+
def email_from
|
27
|
+
"webmaster@#{domain}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def email_to
|
31
|
+
account[login_column]
|
32
|
+
end
|
33
|
+
|
26
34
|
private
|
27
35
|
|
28
36
|
def send_email(email)
|
@@ -42,14 +50,6 @@ module Rodauth
|
|
42
50
|
m
|
43
51
|
end
|
44
52
|
|
45
|
-
def email_from
|
46
|
-
"webmaster@#{domain}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def email_to
|
50
|
-
account[login_column]
|
51
|
-
end
|
52
|
-
|
53
53
|
def token_link(route, param, key)
|
54
54
|
route_url(route, param => token_param_value(key))
|
55
55
|
end
|
@@ -64,6 +64,7 @@ module Rodauth
|
|
64
64
|
|
65
65
|
def account_from_key(token, status_id=nil)
|
66
66
|
id, key = split_token(token)
|
67
|
+
id = convert_token_id(id)
|
67
68
|
return unless id && key
|
68
69
|
|
69
70
|
return unless actual = yield(id)
|
@@ -107,7 +107,7 @@ module Rodauth
|
|
107
107
|
def before_webauthn_auth_route
|
108
108
|
super if defined?(super)
|
109
109
|
if use_json? && !param_or_nil(webauthn_auth_param)
|
110
|
-
cred =
|
110
|
+
cred = webauthn_credential_options_for_get
|
111
111
|
json_response[webauthn_auth_param] = cred.as_json
|
112
112
|
json_response[webauthn_auth_challenge_param] = cred.challenge
|
113
113
|
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
@@ -117,7 +117,7 @@ module Rodauth
|
|
117
117
|
def before_webauthn_login_route
|
118
118
|
super if defined?(super)
|
119
119
|
if use_json? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param))
|
120
|
-
cred =
|
120
|
+
cred = webauthn_credential_options_for_get
|
121
121
|
json_response[webauthn_auth_param] = cred.as_json
|
122
122
|
json_response[webauthn_auth_challenge_param] = cred.challenge
|
123
123
|
json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
|
@@ -112,7 +112,7 @@ module Rodauth
|
|
112
112
|
id, token_id, key = _account_refresh_token_split(token)
|
113
113
|
|
114
114
|
unless key &&
|
115
|
-
(id == session_value.to_s) &&
|
115
|
+
(id.to_s == session_value.to_s) &&
|
116
116
|
(actual = get_active_refresh_token(id, token_id)) &&
|
117
117
|
timing_safe_eql?(key, convert_token_key(actual)) &&
|
118
118
|
jwt_refresh_token_match?(key)
|
@@ -126,9 +126,11 @@ module Rodauth
|
|
126
126
|
|
127
127
|
def _account_refresh_token_split(token)
|
128
128
|
id, token = split_token(token)
|
129
|
+
id = convert_token_id(id)
|
129
130
|
return unless id && token
|
130
131
|
|
131
132
|
token_id, key = split_token(token)
|
133
|
+
token_id = convert_token_id(token_id)
|
132
134
|
return unless token_id && key
|
133
135
|
|
134
136
|
[id, token_id, key]
|
data/lib/rodauth/features/otp.rb
CHANGED
@@ -308,7 +308,7 @@ module Rodauth
|
|
308
308
|
end
|
309
309
|
|
310
310
|
def otp_qr_code
|
311
|
-
svg = RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8, :viewbox=>true, :use_path=>true, :fill=>"
|
311
|
+
svg = RQRCode::QRCode.new(otp_provisioning_uri).as_svg(:module_size=>8, :viewbox=>true, :use_path=>true, :fill=>"fff")
|
312
312
|
svg.sub(/\A<\?xml version="1\.0" standalone="yes"\?>/, '')
|
313
313
|
end
|
314
314
|
|
@@ -102,13 +102,15 @@ module Rodauth
|
|
102
102
|
:valid_new_webauthn_credential?,
|
103
103
|
:valid_webauthn_credential_auth?,
|
104
104
|
:webauthn_auth_js_path,
|
105
|
-
:
|
105
|
+
:webauthn_credential_options_for_get,
|
106
106
|
:webauthn_remove_authenticated_session,
|
107
107
|
:webauthn_setup_js_path,
|
108
108
|
:webauthn_update_session,
|
109
109
|
:webauthn_user_name,
|
110
110
|
)
|
111
111
|
|
112
|
+
def_deprecated_alias :webauthn_credential_options_for_get, :webauth_credential_options_for_get
|
113
|
+
|
112
114
|
route(:webauthn_auth_js) do |r|
|
113
115
|
before_webauthn_auth_js_route
|
114
116
|
r.get do
|
@@ -315,7 +317,7 @@ module Rodauth
|
|
315
317
|
webauthn_credential.verify(challenge)
|
316
318
|
end
|
317
319
|
|
318
|
-
def
|
320
|
+
def webauthn_credential_options_for_get
|
319
321
|
WebAuthn::Credential.options_for_get(
|
320
322
|
:allow => account_webauthn_ids,
|
321
323
|
:timeout => webauthn_auth_timeout,
|
data/lib/rodauth/version.rb
CHANGED
data/templates/webauthn-auth.str
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
<form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.
|
1
|
+
<form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.webauthn_credential_options_for_get).as_json.to_json)}">
|
2
2
|
#{rodauth.webauthn_auth_additional_form_tags}
|
3
3
|
#{rodauth.csrf_tag(rodauth.webauthn_auth_form_path)}
|
4
4
|
<input type="hidden" name="#{rodauth.webauthn_auth_challenge_param}" value="#{cred.challenge}" />
|
5
5
|
<input type="hidden" name="#{rodauth.webauthn_auth_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
|
6
|
-
<input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
|
6
|
+
<input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
|
7
7
|
<div id="webauthn-auth-button">
|
8
8
|
#{rodauth.button(rodauth.webauthn_auth_button)}
|
9
9
|
</div>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
#{rodauth.csrf_tag}
|
4
4
|
<input type="hidden" name="#{rodauth.webauthn_setup_challenge_param}" value="#{cred.challenge}" />
|
5
5
|
<input type="hidden" name="#{rodauth.webauthn_setup_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
|
6
|
-
<input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
|
6
|
+
<input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
|
7
7
|
#{rodauth.render('password-field') if rodauth.two_factor_modifications_require_password?}
|
8
8
|
<div id="webauthn-setup-button">
|
9
9
|
#{rodauth.button(rodauth.webauthn_setup_button)}
|
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.27.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: 2023-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -342,6 +342,7 @@ extra_rdoc_files:
|
|
342
342
|
- doc/release_notes/2.24.0.txt
|
343
343
|
- doc/release_notes/2.25.0.txt
|
344
344
|
- doc/release_notes/2.26.0.txt
|
345
|
+
- doc/release_notes/2.27.0.txt
|
345
346
|
- doc/release_notes/2.3.0.txt
|
346
347
|
- doc/release_notes/2.4.0.txt
|
347
348
|
- doc/release_notes/2.5.0.txt
|
@@ -455,6 +456,7 @@ files:
|
|
455
456
|
- doc/release_notes/2.24.0.txt
|
456
457
|
- doc/release_notes/2.25.0.txt
|
457
458
|
- doc/release_notes/2.26.0.txt
|
459
|
+
- doc/release_notes/2.27.0.txt
|
458
460
|
- doc/release_notes/2.3.0.txt
|
459
461
|
- doc/release_notes/2.4.0.txt
|
460
462
|
- doc/release_notes/2.5.0.txt
|
@@ -612,7 +614,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
612
614
|
- !ruby/object:Gem::Version
|
613
615
|
version: '0'
|
614
616
|
requirements: []
|
615
|
-
rubygems_version: 3.
|
617
|
+
rubygems_version: 3.4.1
|
616
618
|
signing_key:
|
617
619
|
specification_version: 4
|
618
620
|
summary: Authentication and Account Management Framework for Rack Applications
|