rodauth 2.29.0 → 2.30.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +6 -0
- data/README.rdoc +19 -0
- data/doc/release_notes/2.30.0.txt +15 -0
- data/doc/webauthn_autofill.rdoc +14 -0
- data/doc/webauthn_login.rdoc +1 -1
- data/doc/webauthn_verify_account.rdoc +1 -1
- data/javascript/webauthn_autofill.js +38 -0
- data/lib/rodauth/features/base.rb +4 -0
- data/lib/rodauth/features/json.rb +1 -1
- data/lib/rodauth/features/remember.rb +6 -2
- data/lib/rodauth/features/webauthn.rb +30 -22
- data/lib/rodauth/features/webauthn_autofill.rb +58 -0
- data/lib/rodauth/features/webauthn_login.rb +9 -1
- data/lib/rodauth/version.rb +1 -1
- data/templates/login-field.str +1 -1
- data/templates/webauthn-autofill.str +9 -0
- metadata +10 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8270d10e6c0fbe554fc322958893f2c8069363af6455c0d17b0a7d3aafab11bd
|
4
|
+
data.tar.gz: 6eae8a9487764a9b189b27b8f1588e1516d86a6953fdabe0cff6adfd84facb5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4dca9a0819842a478fac05f138b07452a054c7e498821eee7e61ab49640eccc46974d38c3aea1f71bf226eb7f76b03888a6734d7ae2139bcc74aca9a24bad6c
|
7
|
+
data.tar.gz: 5075118b0c6a8b27df251a2e6bfcd45e3dacc7ba1402bf5bacfc38a50b93b424a0ccdb479b1f5541d589f5687a8424c7319a194c0b01a80c762b725065190013
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
=== 2.30.0 (2023-05-22)
|
2
|
+
|
3
|
+
* Make load_memory in the remember feature not raise NoMethodError if logged in when the account no longer exists (jeremyevans) (#331)
|
4
|
+
|
5
|
+
* Add webauthn_autofill feature, for supporting autofill of webauthn information on the login form (janko) (#328)
|
6
|
+
|
1
7
|
=== 2.29.0 (2023-03-22)
|
2
8
|
|
3
9
|
* Support :render=>false plugin options (davekaro) (#319)
|
data/README.rdoc
CHANGED
@@ -37,6 +37,7 @@ HTML and JSON API for all supported features.
|
|
37
37
|
* WebAuthn (Multifactor authentication via WebAuthn)
|
38
38
|
* WebAuthn Login (Passwordless login via WebAuthn)
|
39
39
|
* WebAuthn Verify Account (Passwordless WebAuthn Setup)
|
40
|
+
* WebAuthn Autofill (Autofill WebAuthn credentials on login)
|
40
41
|
* OTP (Multifactor authentication via TOTP)
|
41
42
|
* Recovery Codes (Multifactor authentication via backup codes)
|
42
43
|
* SMS Codes (Multifactor authentication via SMS)
|
@@ -318,6 +319,16 @@ bad idea), you don't need to use the PostgreSQL citext extension. Just
|
|
318
319
|
remember to modify the migration below to use +String+ instead of +citext+
|
319
320
|
for the email in that case.
|
320
321
|
|
322
|
+
=== Grant schema rights (PostgreSQL 15+)
|
323
|
+
|
324
|
+
PostgreSQL 15 changed default database security so that only the database
|
325
|
+
owner has writable access to the public schema. Rodauth expects the
|
326
|
+
+ph+ account to have writable access to the public schema when setting
|
327
|
+
things up. Temporarily grant that access (it will be revoked after the
|
328
|
+
migation has run)
|
329
|
+
|
330
|
+
psql -U postgres -c "GRANT CREATE ON SCHEMA public TO ${DATABASE_NAME}_password" ${DATABASE_NAME}
|
331
|
+
|
321
332
|
=== Using non-default schema
|
322
333
|
|
323
334
|
PostgreSQL sets up new tables in the public schema by default.
|
@@ -739,6 +750,13 @@ One thing to notice in the above migrations is that Rodauth uses additional
|
|
739
750
|
tables for additional features, instead of additional columns in a single
|
740
751
|
table.
|
741
752
|
|
753
|
+
=== Revoking schema rights (PostgreSQL 15+)
|
754
|
+
|
755
|
+
If you explicit granted access to the public schema before running the
|
756
|
+
migration, revoke it afterward:
|
757
|
+
|
758
|
+
psql -U postgres -c "REVOKE CREATE ON SCHEMA public FROM ${DATABASE_NAME}_password" ${DATABASE_NAME}
|
759
|
+
|
742
760
|
=== Locking Down (PostgreSQL only)
|
743
761
|
|
744
762
|
After running the migrations, you can increase security slightly by making
|
@@ -915,6 +933,7 @@ view the appropriate file in the doc directory.
|
|
915
933
|
* {Verify Account Grace Period}[rdoc-ref:doc/verify_account_grace_period.rdoc]
|
916
934
|
* {Verify Login Change}[rdoc-ref:doc/verify_login_change.rdoc]
|
917
935
|
* {WebAuthn}[rdoc-ref:doc/webauthn.rdoc]
|
936
|
+
* {WebAuthn Autofill}[rdoc-ref:doc/webauthn_autofill.rdoc]
|
918
937
|
* {WebAuthn Login}[rdoc-ref:doc/webauthn_login.rdoc]
|
919
938
|
* {WebAuthn Verify Account}[rdoc-ref:doc/webauthn_verify_account.rdoc]
|
920
939
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A webauthn_autofill feature has been added to allow autofilling
|
4
|
+
webauthn credentials during login (also known as conditional
|
5
|
+
mediation). This allows for easier login using passkeys.
|
6
|
+
This requires a supported browser and operating system on the
|
7
|
+
client side to work.
|
8
|
+
|
9
|
+
= Other Improvements
|
10
|
+
|
11
|
+
* The load_memory method in the remember feature no longer raises
|
12
|
+
a NoMethodError if the there is a remember cookie, the session is
|
13
|
+
already logged in, and the account no longer exists. The
|
14
|
+
load_memory method now removes the remember cookie and clears the
|
15
|
+
session in that case.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
= Documentation for WebAuthn Autofill Feature
|
2
|
+
|
3
|
+
The webauthn_autofill feature enables autofill UI (aka "conditional mediation")
|
4
|
+
for WebAuthn credentials, logging the user in on selection. It depends on the
|
5
|
+
webauthn_login feature.
|
6
|
+
|
7
|
+
== Auth Value Methods
|
8
|
+
|
9
|
+
webauthn_autofill_js :: The javascript code to execute on the login page to enable autofill UI.
|
10
|
+
webauthn_autofill_js_route :: The route to the webauthn autofill javascript file.
|
11
|
+
|
12
|
+
== Auth Methods
|
13
|
+
|
14
|
+
before_webauthn_autofill_js_route :: Run arbitrary code before handling a webauthn autofill javascript route.
|
data/doc/webauthn_login.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Documentation for WebAuthn Verify Account Feature
|
2
2
|
|
3
|
-
The
|
3
|
+
The webauthn_verify_account feature implements setting up an WebAuthn authenticator
|
4
4
|
during the account verification process, and making such setup
|
5
5
|
a requirement for account verification. By default, it disables
|
6
6
|
asking for a password during account creation and verification,
|
@@ -0,0 +1,38 @@
|
|
1
|
+
(function() {
|
2
|
+
var pack = function(v) { return btoa(String.fromCharCode.apply(null, new Uint8Array(v))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); };
|
3
|
+
var unpack = function(v) { return Uint8Array.from(atob(v.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); };
|
4
|
+
var element = document.getElementById('webauthn-login-form');
|
5
|
+
|
6
|
+
if (!window.PublicKeyCredential || !PublicKeyCredential.isConditionalMediationAvailable) return;
|
7
|
+
|
8
|
+
PublicKeyCredential.isConditionalMediationAvailable().then(function(available) {
|
9
|
+
if (!available) return;
|
10
|
+
|
11
|
+
var opts = JSON.parse(element.getAttribute("data-credential-options"));
|
12
|
+
opts.challenge = unpack(opts.challenge);
|
13
|
+
opts.allowCredentials.forEach(function(cred) { cred.id = unpack(cred.id); });
|
14
|
+
|
15
|
+
navigator.credentials.get({mediation: "conditional", publicKey: opts}).then(function(cred) {
|
16
|
+
var rawId = pack(cred.rawId);
|
17
|
+
var authValue = {
|
18
|
+
type: cred.type,
|
19
|
+
id: rawId,
|
20
|
+
rawId: rawId,
|
21
|
+
response: {
|
22
|
+
authenticatorData: pack(cred.response.authenticatorData),
|
23
|
+
clientDataJSON: pack(cred.response.clientDataJSON),
|
24
|
+
signature: pack(cred.response.signature)
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
28
|
+
if (cred.response.userHandle) {
|
29
|
+
authValue.response.userHandle = pack(cred.response.userHandle);
|
30
|
+
}
|
31
|
+
|
32
|
+
document.getElementById('webauthn-auth').value = JSON.stringify(authValue);
|
33
|
+
|
34
|
+
element.submit();
|
35
|
+
});
|
36
|
+
});
|
37
|
+
})();
|
38
|
+
|
@@ -269,6 +269,10 @@ module Rodauth
|
|
269
269
|
Sequel::DATABASES.first or raise "Sequel database connection is missing"
|
270
270
|
end
|
271
271
|
|
272
|
+
def login_field_autocomplete_value
|
273
|
+
login_uses_email? ? "email" : "on"
|
274
|
+
end
|
275
|
+
|
272
276
|
def password_field_autocomplete_value
|
273
277
|
@password_field_autocomplete_value || 'current-password'
|
274
278
|
end
|
@@ -116,7 +116,7 @@ module Rodauth
|
|
116
116
|
|
117
117
|
def before_webauthn_login_route
|
118
118
|
super if defined?(super)
|
119
|
-
if use_json? && !param_or_nil(webauthn_auth_param) &&
|
119
|
+
if use_json? && !param_or_nil(webauthn_auth_param) && webauthn_login_options?
|
120
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
|
@@ -114,8 +114,12 @@ module Rodauth
|
|
114
114
|
def load_memory
|
115
115
|
if logged_in?
|
116
116
|
if extend_remember_deadline_while_logged_in?
|
117
|
-
account_from_session
|
118
|
-
|
117
|
+
if account_from_session
|
118
|
+
extend_remember_deadline
|
119
|
+
else
|
120
|
+
forget_login
|
121
|
+
clear_session
|
122
|
+
end
|
119
123
|
end
|
120
124
|
elsif account_from_remember_cookie
|
121
125
|
before_load_memory
|
@@ -320,7 +320,7 @@ module Rodauth
|
|
320
320
|
|
321
321
|
def webauthn_credential_options_for_get
|
322
322
|
WebAuthn::Credential.options_for_get(
|
323
|
-
:allow =>
|
323
|
+
:allow => webauthn_allow,
|
324
324
|
:timeout => webauthn_auth_timeout,
|
325
325
|
:rp_id => webauthn_rp_id,
|
326
326
|
:user_verification => webauthn_user_verification,
|
@@ -336,6 +336,10 @@ module Rodauth
|
|
336
336
|
base_url
|
337
337
|
end
|
338
338
|
|
339
|
+
def webauthn_allow
|
340
|
+
account_webauthn_ids
|
341
|
+
end
|
342
|
+
|
339
343
|
def webauthn_rp_id
|
340
344
|
webauthn_origin.sub(/\Ahttps?:\/\//, '').sub(/:\d+\z/, '')
|
341
345
|
end
|
@@ -453,21 +457,8 @@ module Rodauth
|
|
453
457
|
end
|
454
458
|
|
455
459
|
def webauthn_auth_credential_from_form_submission
|
456
|
-
case auth_data = raw_param(webauthn_auth_param)
|
457
|
-
when String
|
458
|
-
begin
|
459
|
-
auth_data = JSON.parse(auth_data)
|
460
|
-
rescue
|
461
|
-
throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
462
|
-
end
|
463
|
-
when Hash
|
464
|
-
# nothing
|
465
|
-
else
|
466
|
-
throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
467
|
-
end
|
468
|
-
|
469
460
|
begin
|
470
|
-
webauthn_credential = WebAuthn::Credential.from_get(
|
461
|
+
webauthn_credential = WebAuthn::Credential.from_get(webauthn_auth_data)
|
471
462
|
unless valid_webauthn_credential_auth?(webauthn_credential)
|
472
463
|
throw_error_reason(:invalid_webauthn_auth_param, invalid_key_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
473
464
|
end
|
@@ -480,26 +471,28 @@ module Rodauth
|
|
480
471
|
webauthn_credential
|
481
472
|
end
|
482
473
|
|
483
|
-
def
|
484
|
-
case
|
474
|
+
def webauthn_auth_data
|
475
|
+
case auth_data = raw_param(webauthn_auth_param)
|
485
476
|
when String
|
486
477
|
begin
|
487
|
-
|
478
|
+
JSON.parse(auth_data)
|
488
479
|
rescue
|
489
|
-
throw_error_reason(:
|
480
|
+
throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
490
481
|
end
|
491
482
|
when Hash
|
492
|
-
|
483
|
+
auth_data
|
493
484
|
else
|
494
|
-
throw_error_reason(:
|
485
|
+
throw_error_reason(:invalid_webauthn_auth_param, invalid_field_error_status, webauthn_auth_param, webauthn_invalid_auth_param_message)
|
495
486
|
end
|
487
|
+
end
|
496
488
|
|
489
|
+
def webauthn_setup_credential_from_form_submission
|
497
490
|
unless two_factor_password_match?(param(password_param))
|
498
491
|
throw_error_reason(:invalid_password, invalid_password_error_status, password_param, invalid_password_message)
|
499
492
|
end
|
500
493
|
|
501
494
|
begin
|
502
|
-
webauthn_credential = WebAuthn::Credential.from_create(
|
495
|
+
webauthn_credential = WebAuthn::Credential.from_create(webauthn_setup_data)
|
503
496
|
unless valid_new_webauthn_credential?(webauthn_credential)
|
504
497
|
throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message)
|
505
498
|
end
|
@@ -509,5 +502,20 @@ module Rodauth
|
|
509
502
|
|
510
503
|
webauthn_credential
|
511
504
|
end
|
505
|
+
|
506
|
+
def webauthn_setup_data
|
507
|
+
case setup_data = raw_param(webauthn_setup_param)
|
508
|
+
when String
|
509
|
+
begin
|
510
|
+
JSON.parse(setup_data)
|
511
|
+
rescue
|
512
|
+
throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message)
|
513
|
+
end
|
514
|
+
when Hash
|
515
|
+
setup_data
|
516
|
+
else
|
517
|
+
throw_error_reason(:invalid_webauthn_setup_param, invalid_field_error_status, webauthn_setup_param, webauthn_invalid_setup_param_message)
|
518
|
+
end
|
519
|
+
end
|
512
520
|
end
|
513
521
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Feature.define(:webauthn_autofill, :WebauthnAutofill) do
|
5
|
+
depends :webauthn_login
|
6
|
+
|
7
|
+
auth_value_method :webauthn_autofill_js, File.binread(File.expand_path('../../../../javascript/webauthn_autofill.js', __FILE__)).freeze
|
8
|
+
|
9
|
+
route(:webauthn_autofill_js) do |r|
|
10
|
+
before_webauthn_autofill_js_route
|
11
|
+
r.get do
|
12
|
+
response['Content-Type'] = 'text/javascript'
|
13
|
+
webauthn_autofill_js
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def webauthn_allow
|
18
|
+
return [] unless logged_in? || account
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def webauthn_user_verification
|
23
|
+
'preferred'
|
24
|
+
end
|
25
|
+
|
26
|
+
def webauthn_authenticator_selection
|
27
|
+
super.merge({ 'residentKey' => 'required', 'requireResidentKey' => true })
|
28
|
+
end
|
29
|
+
|
30
|
+
def login_field_autocomplete_value
|
31
|
+
request.path_info == login_path ? "#{super} webauthn" : super
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def _login_form_footer
|
37
|
+
footer = super
|
38
|
+
footer += render("webauthn-autofill") unless valid_login_entered?
|
39
|
+
footer
|
40
|
+
end
|
41
|
+
|
42
|
+
def account_from_webauthn_login
|
43
|
+
return super if param_or_nil(login_param)
|
44
|
+
|
45
|
+
credential_id = webauthn_auth_data["id"]
|
46
|
+
account_id = db[webauthn_keys_table]
|
47
|
+
.where(webauthn_keys_webauthn_id_column => credential_id)
|
48
|
+
.get(webauthn_keys_account_id_column)
|
49
|
+
|
50
|
+
@account = account_ds(account_id).first if account_id
|
51
|
+
end
|
52
|
+
|
53
|
+
def webauthn_login_options?
|
54
|
+
return true unless param_or_nil(login_param)
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -16,7 +16,7 @@ module Rodauth
|
|
16
16
|
|
17
17
|
r.post do
|
18
18
|
catch_error do
|
19
|
-
unless
|
19
|
+
unless account_from_webauthn_login && open_account?
|
20
20
|
throw_error_reason(:no_matching_login, no_matching_login_error_status, login_param, no_matching_login_message)
|
21
21
|
end
|
22
22
|
|
@@ -54,6 +54,14 @@ module Rodauth
|
|
54
54
|
|
55
55
|
private
|
56
56
|
|
57
|
+
def account_from_webauthn_login
|
58
|
+
account_from_login(param(login_param))
|
59
|
+
end
|
60
|
+
|
61
|
+
def webauthn_login_options?
|
62
|
+
!!account_from_webauthn_login
|
63
|
+
end
|
64
|
+
|
57
65
|
def _multi_phase_login_forms
|
58
66
|
forms = super
|
59
67
|
if valid_login_entered? && webauthn_setup?
|
data/lib/rodauth/version.rb
CHANGED
data/templates/login-field.str
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
<div class="form-group mb-3">
|
2
2
|
<label for="login" class="form-label">#{rodauth.login_label}#{rodauth.input_field_label_suffix}</label>
|
3
|
-
#{rodauth.input_field_string(rodauth.login_param, 'login', :type=>rodauth.login_input_type, :autocomplete=>rodauth.
|
3
|
+
#{rodauth.input_field_string(rodauth.login_param, 'login', :type=>rodauth.login_input_type, :autocomplete=>rodauth.login_field_autocomplete_value)}
|
4
4
|
</div>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<form method="post" action="#{rodauth.webauthn_login_path}" class="rodauth" role="form" id="webauthn-login-form" data-credential-options="#{h((cred = rodauth.webauthn_credential_options_for_get).as_json.to_json)}">
|
2
|
+
#{rodauth.webauthn_auth_additional_form_tags}
|
3
|
+
#{rodauth.csrf_tag(rodauth.webauthn_login_path)}
|
4
|
+
<input type="hidden" name="#{rodauth.webauthn_auth_challenge_param}" value="#{cred.challenge}" />
|
5
|
+
<input type="hidden" name="#{rodauth.webauthn_auth_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
|
6
|
+
<input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
|
7
|
+
#{rodauth.button(rodauth.webauthn_auth_button, class: "d-none")}
|
8
|
+
</form>
|
9
|
+
<script src="#{rodauth.webauthn_js_host}#{rodauth.webauthn_autofill_js_path}"></script>
|
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.30.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: 2023-
|
11
|
+
date: 2023-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -296,6 +296,7 @@ extra_rdoc_files:
|
|
296
296
|
- doc/verify_account_grace_period.rdoc
|
297
297
|
- doc/verify_login_change.rdoc
|
298
298
|
- doc/webauthn.rdoc
|
299
|
+
- doc/webauthn_autofill.rdoc
|
299
300
|
- doc/webauthn_login.rdoc
|
300
301
|
- doc/webauthn_verify_account.rdoc
|
301
302
|
- doc/release_notes/1.0.0.txt
|
@@ -346,6 +347,7 @@ extra_rdoc_files:
|
|
346
347
|
- doc/release_notes/2.28.0.txt
|
347
348
|
- doc/release_notes/2.29.0.txt
|
348
349
|
- doc/release_notes/2.3.0.txt
|
350
|
+
- doc/release_notes/2.30.0.txt
|
349
351
|
- doc/release_notes/2.4.0.txt
|
350
352
|
- doc/release_notes/2.5.0.txt
|
351
353
|
- doc/release_notes/2.6.0.txt
|
@@ -462,6 +464,7 @@ files:
|
|
462
464
|
- doc/release_notes/2.28.0.txt
|
463
465
|
- doc/release_notes/2.29.0.txt
|
464
466
|
- doc/release_notes/2.3.0.txt
|
467
|
+
- doc/release_notes/2.30.0.txt
|
465
468
|
- doc/release_notes/2.4.0.txt
|
466
469
|
- doc/release_notes/2.5.0.txt
|
467
470
|
- doc/release_notes/2.6.0.txt
|
@@ -480,9 +483,11 @@ files:
|
|
480
483
|
- doc/verify_account_grace_period.rdoc
|
481
484
|
- doc/verify_login_change.rdoc
|
482
485
|
- doc/webauthn.rdoc
|
486
|
+
- doc/webauthn_autofill.rdoc
|
483
487
|
- doc/webauthn_login.rdoc
|
484
488
|
- doc/webauthn_verify_account.rdoc
|
485
489
|
- javascript/webauthn_auth.js
|
490
|
+
- javascript/webauthn_autofill.js
|
486
491
|
- javascript/webauthn_setup.js
|
487
492
|
- lib/roda/plugins/rodauth.rb
|
488
493
|
- lib/rodauth.rb
|
@@ -530,6 +535,7 @@ files:
|
|
530
535
|
- lib/rodauth/features/verify_account_grace_period.rb
|
531
536
|
- lib/rodauth/features/verify_login_change.rb
|
532
537
|
- lib/rodauth/features/webauthn.rb
|
538
|
+
- lib/rodauth/features/webauthn_autofill.rb
|
533
539
|
- lib/rodauth/features/webauthn_login.rb
|
534
540
|
- lib/rodauth/features/webauthn_verify_account.rb
|
535
541
|
- lib/rodauth/migrations.rb
|
@@ -585,6 +591,7 @@ files:
|
|
585
591
|
- templates/verify-login-change-email.str
|
586
592
|
- templates/verify-login-change.str
|
587
593
|
- templates/webauthn-auth.str
|
594
|
+
- templates/webauthn-autofill.str
|
588
595
|
- templates/webauthn-remove.str
|
589
596
|
- templates/webauthn-setup.str
|
590
597
|
homepage: https://rodauth.jeremyevans.net
|
@@ -618,7 +625,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
618
625
|
- !ruby/object:Gem::Version
|
619
626
|
version: '0'
|
620
627
|
requirements: []
|
621
|
-
rubygems_version: 3.4.
|
628
|
+
rubygems_version: 3.4.10
|
622
629
|
signing_key:
|
623
630
|
specification_version: 4
|
624
631
|
summary: Authentication and Account Management Framework for Rack Applications
|