authentication-zero 2.16.20 → 2.16.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/CI.yml +6 -6
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -2
- data/lib/authentication_zero/version.rb +1 -1
- data/lib/generators/authentication/authentication_generator.rb +58 -5
- data/lib/generators/authentication/templates/config/initializers/webauthn.rb +4 -0
- data/lib/generators/authentication/templates/controllers/html/application_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/recovery_codes_controller.rb.tt +30 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/security_keys_controller.rb.tt +46 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/totps_controller.rb.tt +32 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/{recovery_codes_controller.rb.tt → profile/recovery_codes_controller.rb.tt} +2 -2
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/profile/security_keys_controller.rb.tt +62 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/{totps_controller.rb.tt → profile/totps_controller.rb.tt} +3 -3
- data/lib/generators/authentication/templates/erb/home/index.html.erb.tt +5 -2
- data/lib/generators/authentication/templates/erb/two_factor_authentication/{challenges/_recovery_code_form.html.erb.tt → challenge/recovery_codes/new.html.erb.tt} +3 -3
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenge/security_keys/new.html.erb.tt +12 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenge/totps/new.html.erb.tt +26 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/{recovery_codes → profile/recovery_codes}/index.html.erb.tt +1 -1
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_form_confirm.html.erb.tt +13 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_form_edit.html.erb.tt +17 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_security_key.html.erb.tt +1 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/edit.html.erb.tt +3 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/index.html.erb.tt +10 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/new.html.erb.tt +12 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/{totps → profile/totps}/new.html.erb.tt +1 -1
- data/lib/generators/authentication/templates/javascript/controllers/application.js.tt +15 -0
- data/lib/generators/authentication/templates/migrations/create_security_keys_migration.rb.tt +13 -0
- data/lib/generators/authentication/templates/migrations/create_users_migration.rb.tt +3 -0
- data/lib/generators/authentication/templates/models/security_key.rb.tt +3 -0
- data/lib/generators/authentication/templates/models/user.rb.tt +8 -0
- metadata +24 -11
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt +0 -52
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/_totp_form.html.erb.tt +0 -19
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt +0 -7
- /data/lib/generators/authentication/templates/erb/two_factor_authentication/{recovery_codes → profile/recovery_codes}/_recovery_code.html.erb.tt +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c87cbd4d780d1170998c49949d6f28dbe0305df16880f012a7fd6a9cd19ce698
|
4
|
+
data.tar.gz: bb6dbd332c8d4fc221d4de3e8264204d0c999f1707f7529b3d547cb2eb4f5fe4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc453d93036ca66a4df78da04c2fb1da2a21e862a409bad8608ec1661b315c9670e126b5de14ccd1b0a6b4fedb0445f258b0a472cb6f81c90ef588a178484cfc
|
7
|
+
data.tar.gz: c1d014b975a078302d919ba3ec52b4b2b4f0c94017cb04178785ae28bb5e5c8ff6e5d5e2fb84a8dc551cf3b5dc757c392af3061718ecf4e3a64c176292faaad2
|
data/.github/workflows/CI.yml
CHANGED
@@ -26,6 +26,9 @@ jobs:
|
|
26
26
|
- name: Install Rubocop
|
27
27
|
run: gem install rubocop rubocop-performance rubocop-minitest rubocop-packaging rubocop-minitest rubocop-rails
|
28
28
|
|
29
|
+
- name: Install Brakeman
|
30
|
+
run: gem install brakeman
|
31
|
+
|
29
32
|
- name: Create fresh Rails app and run generator
|
30
33
|
run: |
|
31
34
|
rails new test-app
|
@@ -39,9 +42,6 @@ jobs:
|
|
39
42
|
- name: Rubocop
|
40
43
|
run: cd test-app && rubocop
|
41
44
|
|
42
|
-
- name: Install Brakeman
|
43
|
-
run: gem install brakeman
|
44
|
-
|
45
45
|
- name: Brakeman
|
46
46
|
run: cd test-app && brakeman
|
47
47
|
|
@@ -69,6 +69,9 @@ jobs:
|
|
69
69
|
- name: Install Rubocop
|
70
70
|
run: gem install rubocop rubocop-performance rubocop-minitest rubocop-packaging rubocop-minitest rubocop-rails
|
71
71
|
|
72
|
+
- name: Install Brakeman
|
73
|
+
run: gem install brakeman
|
74
|
+
|
72
75
|
- name: Create fresh Rails app and run generator
|
73
76
|
run: |
|
74
77
|
rails new test-app
|
@@ -82,9 +85,6 @@ jobs:
|
|
82
85
|
- name: Rubocop
|
83
86
|
run: cd test-app && rubocop
|
84
87
|
|
85
|
-
- name: Install Brakeman
|
86
|
-
run: gem install brakeman
|
87
|
-
|
88
88
|
- name: Brakeman
|
89
89
|
run: cd test-app && brakeman
|
90
90
|
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -20,7 +20,7 @@ Since Authentication Zero generates this code into your application instead of b
|
|
20
20
|
|
21
21
|
## Features
|
22
22
|
|
23
|
-
- **
|
23
|
+
- **Simple code**
|
24
24
|
- **Inspired by hey.com**
|
25
25
|
- Sign up
|
26
26
|
- Email and password validations
|
@@ -29,6 +29,7 @@ Since Authentication Zero generates this code into your application instead of b
|
|
29
29
|
- Authentication by token (--api)
|
30
30
|
- Passwordless authentication (--passwordless)
|
31
31
|
- Two factor authentication + recovery codes (--two-factor)
|
32
|
+
- Two factor authentication using a hardware security key (--webauthn)
|
32
33
|
- Social Login with OmniAuth (--omniauthable)
|
33
34
|
- Send invitations (--invitable)
|
34
35
|
- Sign-in as button functionallity (--masqueradable)
|
@@ -36,7 +37,7 @@ Since Authentication Zero generates this code into your application instead of b
|
|
36
37
|
- Ask password before sensitive data changes, aka: sudo (--sudoable)
|
37
38
|
- Reset the user password and send reset instructions
|
38
39
|
- Reset the user password only from verified emails
|
39
|
-
- Lock mechanism to prevent
|
40
|
+
- Lock mechanism to prevent email bombing (--lockable)
|
40
41
|
- Rate limiting for your app, 1000 reqs/minute (--ratelimit)
|
41
42
|
- Send e-mail confirmation when your email has been changed
|
42
43
|
- Manage multiple sessions & devices
|
@@ -12,6 +12,7 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
12
12
|
class_option :omniauthable, type: :boolean, desc: "Add social login support"
|
13
13
|
class_option :trackable, type: :boolean, desc: "Add activity log support"
|
14
14
|
class_option :two_factor, type: :boolean, desc: "Add two factor authentication"
|
15
|
+
class_option :webauthn, type: :boolean, desc: "Add two factor authentication using a hardware security key"
|
15
16
|
class_option :invitable, type: :boolean, desc: "Add sending invitations"
|
16
17
|
class_option :masqueradable, type: :boolean, desc: "Add sign-in as button functionallity"
|
17
18
|
|
@@ -42,6 +43,10 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
42
43
|
gem "rotp", comment: "Use rotp for generating and validating one time passwords [https://github.com/mdp/rotp]"
|
43
44
|
gem "rqrcode", comment: "Use rqrcode for creating and rendering QR codes into various formats [https://github.com/whomwah/rqrcode]"
|
44
45
|
end
|
46
|
+
|
47
|
+
if webauthn?
|
48
|
+
gem "webauthn", comment: "Use webauthn for making rails become a conformant web authn relying party [https://github.com/cedarcode/webauthn-ruby]"
|
49
|
+
end
|
45
50
|
end
|
46
51
|
|
47
52
|
def add_environment_configurations
|
@@ -53,6 +58,7 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
53
58
|
def create_configuration_files
|
54
59
|
copy_file "config/redis/shared.yml", "config/redis/shared.yml" if redis?
|
55
60
|
copy_file "config/initializers/omniauth.rb", "config/initializers/omniauth.rb" if omniauthable?
|
61
|
+
copy_file "config/initializers/webauthn.rb", "config/initializers/webauthn.rb" if webauthn?
|
56
62
|
end
|
57
63
|
|
58
64
|
def create_migrations
|
@@ -63,6 +69,7 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
63
69
|
migration_template "migrations/create_sign_in_tokens_migration.rb", "#{db_migrate_path}/create_sign_in_tokens_migration.rb" if passwordless?
|
64
70
|
migration_template "migrations/create_events_migration.rb", "#{db_migrate_path}/create_events.rb" if options.trackable?
|
65
71
|
migration_template "migrations/create_recovery_codes_migration.rb", "#{db_migrate_path}/create_recovery_codes.rb" if two_factor?
|
72
|
+
migration_template "migrations/create_security_keys_migration.rb", "#{db_migrate_path}/create_security_keys.rb" if webauthn?
|
66
73
|
end
|
67
74
|
|
68
75
|
def create_models
|
@@ -74,6 +81,7 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
74
81
|
template "models/current.rb", "app/models/current.rb"
|
75
82
|
template "models/event.rb", "app/models/event.rb" if options.trackable?
|
76
83
|
template "models/recovery_code.rb", "app/models/recovery_code.rb" if two_factor?
|
84
|
+
template "models/security_key.rb", "app/models/security_key.rb" if webauthn?
|
77
85
|
end
|
78
86
|
|
79
87
|
def create_fixture_file
|
@@ -84,7 +92,17 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
84
92
|
template "controllers/#{format_folder}/application_controller.rb", "app/controllers/application_controller.rb", force: true
|
85
93
|
|
86
94
|
directory "controllers/#{format_folder}/identity", "app/controllers/identity"
|
87
|
-
|
95
|
+
|
96
|
+
if two_factor?
|
97
|
+
template "controllers/html/two_factor_authentication/profile/totps_controller.rb", "app/controllers/two_factor_authentication/profile/totps_controller.rb"
|
98
|
+
template "controllers/html/two_factor_authentication/profile/recovery_codes_controller.rb", "app/controllers/two_factor_authentication/profile/recovery_codes_controller.rb"
|
99
|
+
template "controllers/html/two_factor_authentication/profile/security_keys_controller.rb", "app/controllers/two_factor_authentication/profile/security_keys_controller.rb" if webauthn?
|
100
|
+
|
101
|
+
template "controllers/html/two_factor_authentication/challenge/totps_controller.rb", "app/controllers/two_factor_authentication/challenge/totps_controller.rb"
|
102
|
+
template "controllers/html/two_factor_authentication/challenge/recovery_codes_controller.rb", "app/controllers/two_factor_authentication/challenge/recovery_codes_controller.rb"
|
103
|
+
template "controllers/html/two_factor_authentication/challenge/security_keys_controller.rb", "app/controllers/two_factor_authentication/challenge/security_keys_controller.rb" if webauthn?
|
104
|
+
end
|
105
|
+
|
88
106
|
template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
|
89
107
|
template "controllers/#{format_folder}/passwords_controller.rb", "app/controllers/passwords_controller.rb"
|
90
108
|
template "controllers/#{format_folder}/invitations_controller.rb", "app/controllers/invitations_controller.rb" if invitable?
|
@@ -97,6 +115,16 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
97
115
|
template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
|
98
116
|
end
|
99
117
|
|
118
|
+
def install_javascript_dependencies
|
119
|
+
return if options.api?
|
120
|
+
template "javascript/controllers/application.js", "app/javascript/controllers/application.js"
|
121
|
+
|
122
|
+
if webauthn?
|
123
|
+
run "bin/importmap pin stimulus-web-authn" if importmaps?
|
124
|
+
run "yarn add stimulus-web-authn" if node?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
100
128
|
def create_views
|
101
129
|
if options.api?
|
102
130
|
template "erb/user_mailer/email_verification.html.erb", "app/views/user_mailer/email_verification.html.erb"
|
@@ -122,8 +150,17 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
122
150
|
|
123
151
|
directory "erb/sessions/passwordlesses", "app/views/sessions/passwordlesses" if passwordless?
|
124
152
|
|
125
|
-
directory "erb/two_factor_authentication", "app/views/two_factor_authentication" if two_factor?
|
126
153
|
directory "erb/authentications/events", "app/views/authentications/events" if options.trackable?
|
154
|
+
|
155
|
+
if two_factor?
|
156
|
+
directory "erb/two_factor_authentication/profile/totps", "app/views/two_factor_authentication/profile/totps"
|
157
|
+
directory "erb/two_factor_authentication/profile/recovery_codes", "app/views/two_factor_authentication/profile/recovery_codes"
|
158
|
+
directory "erb/two_factor_authentication/profile/security_keys", "app/views/two_factor_authentication/profile/security_keys" if webauthn?
|
159
|
+
|
160
|
+
directory "erb/two_factor_authentication/challenge/totps", "app/views/two_factor_authentication/challenge/totps"
|
161
|
+
directory "erb/two_factor_authentication/challenge/recovery_codes", "app/views/two_factor_authentication/challenge/recovery_codes"
|
162
|
+
directory "erb/two_factor_authentication/challenge/security_keys", "app/views/two_factor_authentication/challenge/security_keys" if webauthn?
|
163
|
+
end
|
127
164
|
end
|
128
165
|
end
|
129
166
|
|
@@ -157,9 +194,13 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
157
194
|
end
|
158
195
|
|
159
196
|
if two_factor?
|
160
|
-
route "resources :recovery_codes, only: [:index, :create]", namespace: :two_factor_authentication
|
161
|
-
route "resource :totp, only: [:new, :create]", namespace: :two_factor_authentication
|
162
|
-
route "
|
197
|
+
route "resources :recovery_codes, only: [:index, :create]", namespace: [:two_factor_authentication, :profile]
|
198
|
+
route "resource :totp, only: [:new, :create]", namespace: [:two_factor_authentication, :profile]
|
199
|
+
route "resources :security_keys", namespace: [:two_factor_authentication, :profile] if webauthn?
|
200
|
+
|
201
|
+
route "resource :recovery_codes, only: [:new, :create]", namespace: [:two_factor_authentication, :challenge]
|
202
|
+
route "resource :totp, only: [:new, :create]", namespace: [:two_factor_authentication, :challenge]
|
203
|
+
route "resource :security_keys, only: [:new, :create]", namespace: [:two_factor_authentication, :challenge] if webauthn?
|
163
204
|
end
|
164
205
|
|
165
206
|
if options.trackable?
|
@@ -212,6 +253,10 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
212
253
|
options.two_factor? && !options.api?
|
213
254
|
end
|
214
255
|
|
256
|
+
def webauthn?
|
257
|
+
options.webauthn? && two_factor?
|
258
|
+
end
|
259
|
+
|
215
260
|
def invitable?
|
216
261
|
options.invitable? && !options.api?
|
217
262
|
end
|
@@ -227,4 +272,12 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
227
272
|
def redis?
|
228
273
|
options.lockable? || options.ratelimit? || sudoable?
|
229
274
|
end
|
275
|
+
|
276
|
+
def importmaps?
|
277
|
+
Rails.root.join("config/importmap.rb").exist?
|
278
|
+
end
|
279
|
+
|
280
|
+
def node?
|
281
|
+
Rails.root.join("package.json").exist?
|
282
|
+
end
|
230
283
|
end
|
@@ -28,7 +28,7 @@ class ApplicationController < ActionController::Base
|
|
28
28
|
<%- if sudoable? %>
|
29
29
|
def require_sudo
|
30
30
|
unless Current.session.sudo?
|
31
|
-
redirect_to new_sessions_sudo_path(proceed_to_url: request.
|
31
|
+
redirect_to new_sessions_sudo_path(proceed_to_url: request.original_url)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
<%- end -%>
|
@@ -18,7 +18,7 @@ class SessionsController < ApplicationController
|
|
18
18
|
<%- if two_factor? -%>
|
19
19
|
if user.otp_secret.present?
|
20
20
|
session[:challenge_token] = user.signed_id(purpose: :authentication_challenge, expires_in: 20.minutes)
|
21
|
-
redirect_to
|
21
|
+
redirect_to new_two_factor_authentication_challenge_totp_path
|
22
22
|
else
|
23
23
|
@session = user.sessions.create!
|
24
24
|
cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class TwoFactorAuthentication::Challenge::RecoveryCodesController < ApplicationController
|
2
|
+
skip_before_action :authenticate
|
3
|
+
|
4
|
+
before_action :set_user
|
5
|
+
|
6
|
+
def new
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
if recover_code = @user.recovery_codes.find_by(code: params[:code], used: false)
|
11
|
+
recover_code.update!(used: true); sign_in_and_redirect_to_root
|
12
|
+
else
|
13
|
+
redirect_to new_two_factor_authentication_challenge_recovery_codes_path, alert: "That code didn't work. Please try again"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def set_user
|
19
|
+
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
|
20
|
+
rescue StandardError
|
21
|
+
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
|
22
|
+
end
|
23
|
+
|
24
|
+
def sign_in_and_redirect_to_root
|
25
|
+
session = @user.sessions.create!
|
26
|
+
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
27
|
+
|
28
|
+
redirect_to root_path, notice: "Signed in successfully"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class TwoFactorAuthentication::Challenge::SecurityKeysController < ApplicationController
|
2
|
+
skip_before_action :authenticate
|
3
|
+
|
4
|
+
before_action :set_user
|
5
|
+
|
6
|
+
def new
|
7
|
+
respond_to do |format|
|
8
|
+
format.html
|
9
|
+
format.json { render json: options_for_get }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
if @user.security_keys.exists?(external_id: credential.id)
|
15
|
+
sign_in_and_redirect_to_root
|
16
|
+
else
|
17
|
+
render json: { error: "Verification failed: #{e.message}" }, status: :unprocessable_entity
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def set_user
|
23
|
+
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
|
24
|
+
rescue StandardError
|
25
|
+
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
|
26
|
+
end
|
27
|
+
|
28
|
+
def sign_in_and_redirect_to_root
|
29
|
+
session = @user.sessions.create!
|
30
|
+
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
31
|
+
|
32
|
+
render json: { status: "ok", location: root_url }, status: :created
|
33
|
+
end
|
34
|
+
|
35
|
+
def options_for_get
|
36
|
+
WebAuthn::Credential.options_for_get(allow: external_ids)
|
37
|
+
end
|
38
|
+
|
39
|
+
def external_ids
|
40
|
+
@user.security_keys.pluck(:external_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def credential
|
44
|
+
@credential ||= WebAuthn::Credential.from_get(params.require(:credential))
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class TwoFactorAuthentication::Challenge::TotpsController < ApplicationController
|
2
|
+
skip_before_action :authenticate
|
3
|
+
|
4
|
+
before_action :set_user
|
5
|
+
|
6
|
+
def new
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
@totp = ROTP::TOTP.new(@user.otp_secret, issuer: "YourAppName")
|
11
|
+
|
12
|
+
if @totp.verify(params[:code], drift_behind: 15)
|
13
|
+
sign_in_and_redirect_to_root
|
14
|
+
else
|
15
|
+
redirect_to new_two_factor_authentication_challenge_totp_path, alert: "That code didn't work. Please try again"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def set_user
|
21
|
+
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
|
22
|
+
rescue StandardError
|
23
|
+
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
|
24
|
+
end
|
25
|
+
|
26
|
+
def sign_in_and_redirect_to_root
|
27
|
+
session = @user.sessions.create!
|
28
|
+
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
29
|
+
|
30
|
+
redirect_to root_path, notice: "Signed in successfully"
|
31
|
+
end
|
32
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class TwoFactorAuthentication::RecoveryCodesController < ApplicationController
|
1
|
+
class TwoFactorAuthentication::Profile::RecoveryCodesController < ApplicationController
|
2
2
|
before_action :set_user
|
3
3
|
|
4
4
|
def index
|
@@ -13,7 +13,7 @@ class TwoFactorAuthentication::RecoveryCodesController < ApplicationController
|
|
13
13
|
@user.recovery_codes.delete_all
|
14
14
|
@user.recovery_codes.create!(new_recovery_codes)
|
15
15
|
|
16
|
-
redirect_to
|
16
|
+
redirect_to two_factor_authentication_profile_recovery_codes_path, notice: "Your new recovery codes have been generated"
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class TwoFactorAuthentication::Profile::SecurityKeysController < ApplicationController
|
2
|
+
before_action :set_user
|
3
|
+
before_action :set_security_key, only: %i[ edit update destroy ]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@security_keys = @user.security_keys
|
7
|
+
end
|
8
|
+
|
9
|
+
def new
|
10
|
+
respond_to do |format|
|
11
|
+
format.html
|
12
|
+
format.json { render json: options_for_create }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def edit
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
@security_key = @user.security_keys.create!(credential_params)
|
21
|
+
render json: { status: "ok", location: edit_two_factor_authentication_profile_security_key_url(@security_key, confirmation: true) }, status: :created
|
22
|
+
end
|
23
|
+
|
24
|
+
def update
|
25
|
+
@security_key.update! name: params[:name]
|
26
|
+
redirect_to two_factor_authentication_profile_security_keys_path, notice: "Your changes have been saved"
|
27
|
+
end
|
28
|
+
|
29
|
+
def destroy
|
30
|
+
@security_key.destroy
|
31
|
+
redirect_to two_factor_authentication_profile_security_keys_path, notice: "#{@security_key.name} has been removed"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def set_user
|
36
|
+
@user = Current.user
|
37
|
+
end
|
38
|
+
|
39
|
+
def set_security_key
|
40
|
+
@security_key = @user.security_keys.find(params[:id])
|
41
|
+
end
|
42
|
+
|
43
|
+
def options_for_create
|
44
|
+
WebAuthn::Credential.options_for_create(user: user_info, exclude: external_ids)
|
45
|
+
end
|
46
|
+
|
47
|
+
def user_info
|
48
|
+
{ id: @user.webauthn_id, name: @user.email }
|
49
|
+
end
|
50
|
+
|
51
|
+
def external_ids
|
52
|
+
@user.security_keys.pluck(:external_id)
|
53
|
+
end
|
54
|
+
|
55
|
+
def credential_params
|
56
|
+
{ external_id: credential.id, name: "security key" }
|
57
|
+
end
|
58
|
+
|
59
|
+
def credential
|
60
|
+
@credential ||= WebAuthn::Credential.from_create(params.require(:credential))
|
61
|
+
end
|
62
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class TwoFactorAuthentication::TotpsController < ApplicationController
|
1
|
+
class TwoFactorAuthentication::Profile::TotpsController < ApplicationController
|
2
2
|
before_action :set_user
|
3
3
|
before_action :set_totp
|
4
4
|
|
@@ -9,9 +9,9 @@ class TwoFactorAuthentication::TotpsController < ApplicationController
|
|
9
9
|
def create
|
10
10
|
if @totp.verify(params[:code], drift_behind: 15)
|
11
11
|
@user.update! otp_secret: params[:secret]
|
12
|
-
redirect_to
|
12
|
+
redirect_to two_factor_authentication_profile_recovery_codes_path
|
13
13
|
else
|
14
|
-
redirect_to
|
14
|
+
redirect_to new_two_factor_authentication_profile_totp_path, alert: "That code didn't work. Please try again"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -13,11 +13,14 @@
|
|
13
13
|
</div>
|
14
14
|
<%- if two_factor? %>
|
15
15
|
<div>
|
16
|
-
<%%= link_to "Two-Factor Authentication",
|
16
|
+
<%%= link_to "Two-Factor Authentication", new_two_factor_authentication_profile_totp_path %>
|
17
17
|
</div>
|
18
18
|
|
19
19
|
<%% if Current.user.otp_secret.present? %>
|
20
|
-
<div><%%= link_to "Recovery Codes",
|
20
|
+
<div><%%= link_to "Recovery Codes", two_factor_authentication_profile_recovery_codes_path %></div>
|
21
|
+
<%- if webauthn? -%>
|
22
|
+
<div><%%= link_to "Security keys", two_factor_authentication_profile_security_keys_path %></div>
|
23
|
+
<%- end -%>
|
21
24
|
<%% end %>
|
22
25
|
<%- end -%>
|
23
26
|
<%- if invitable? %>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
<%%= form.hidden_field :scheme_type, value: "recovery_codes" %>
|
1
|
+
<p style="color: red"><%%= alert %></p>
|
3
2
|
|
3
|
+
<%%= form_with(url: two_factor_authentication_challenge_recovery_codes_path) do |form| %>
|
4
4
|
<div>
|
5
5
|
<%%= form.label :code do %>
|
6
6
|
<h1>OK, enter one of your recovery codes below:</h1>
|
@@ -14,5 +14,5 @@
|
|
14
14
|
<%% end %>
|
15
15
|
|
16
16
|
<div>
|
17
|
-
<p>To access your account, enter one of the recovery codes (e.g.,
|
17
|
+
<p>To access your account, enter one of the recovery codes (e.g., xxxxxxxxxx) you saved when you set up your two-factor authentication device.</p>
|
18
18
|
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div data-controller="web-authn"
|
2
|
+
data-web-authn-loading-class="web-authn-loading"
|
3
|
+
data-web-authn-fallback-url-value="<%%= new_two_factor_authentication_challenge_totp_path %>"
|
4
|
+
data-web-authn-challenge-url-value="<%%= new_two_factor_authentication_challenge_security_keys_url %>"
|
5
|
+
data-web-authn-verification-url-value="<%%= two_factor_authentication_challenge_security_keys_url %>">
|
6
|
+
|
7
|
+
<p data-web-authn-target="error" style="color: red" hidden></p>
|
8
|
+
|
9
|
+
<h1>Verify with your security key.</h1>
|
10
|
+
<%%= button_tag "Use security key", type: :button, data: { web_authn_target: "button", action: "web-authn#getCredential" } %>
|
11
|
+
<p>Have your security key ready. If it's the USB kind insert it now and then, if it has one, press the activation button when asked.</p>
|
12
|
+
<div>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<p style="color: red"><%%= alert %></p>
|
2
|
+
|
3
|
+
<%%= form_with(url: two_factor_authentication_challenge_totp_path) do |form| %>
|
4
|
+
<div>
|
5
|
+
<%%= form.label :code do %>
|
6
|
+
<h1>Next, open the 2FA authenticator app on your phone and type the six digit code below:</h1>
|
7
|
+
<%% end %>
|
8
|
+
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div>
|
12
|
+
<%%= form.submit "Verify" %>
|
13
|
+
</div>
|
14
|
+
<%% end %>
|
15
|
+
|
16
|
+
<div>
|
17
|
+
<p><strong>Don't have your phone?</strong></p>
|
18
|
+
<div>
|
19
|
+
<%%= link_to "Use a recovery code to access your account.", new_two_factor_authentication_challenge_recovery_codes_path %>
|
20
|
+
</div>
|
21
|
+
<%- if webauthn? %>
|
22
|
+
<%% if @user.security_keys.exists? %>
|
23
|
+
<div><%%= link_to "Use a security key to access your account.", new_two_factor_authentication_challenge_security_keys_path %></div>
|
24
|
+
<%% end %>
|
25
|
+
<%- end -%>
|
26
|
+
</div>
|
@@ -13,4 +13,4 @@
|
|
13
13
|
|
14
14
|
<p>If you think your codes have fallen into the wrong hands, you can get a new set. Be sure to save the new ones because the old codes will stop working.</p>
|
15
15
|
|
16
|
-
<%%= button_to "Generate new recovery codes",
|
16
|
+
<%%= button_to "Generate new recovery codes", two_factor_authentication_profile_recovery_codes_path %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%%= form_with(url: two_factor_authentication_profile_security_key_path, method: :patch) do |form| %>
|
2
|
+
<p>One more step. Please give this security key a nickname to help you remember it.</p>
|
3
|
+
|
4
|
+
<div>
|
5
|
+
<%%= form.label :name, style: "display: block" %>
|
6
|
+
<%%= form.text_field :name, autofocus: true, required: true %>
|
7
|
+
<div>e.g., Macbook Touch ID</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div>
|
11
|
+
<%%= form.submit "Save" %>
|
12
|
+
</div>
|
13
|
+
<%% end %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%%= form_with(url: two_factor_authentication_profile_security_key_path, method: :patch) do |form| %>
|
2
|
+
<div>
|
3
|
+
<%%= form.label :name, style: "display: block" %>
|
4
|
+
<%%= form.text_field :name, value: @security_key.name, autofocus: true, required: true %>
|
5
|
+
<div>e.g., Macbook Touch ID</div>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div>
|
9
|
+
<%%= form.submit "Save changes" %>
|
10
|
+
</div>
|
11
|
+
<%% end %>
|
12
|
+
|
13
|
+
<br>
|
14
|
+
|
15
|
+
<div>
|
16
|
+
<%%= button_to "Remove this security key...", two_factor_authentication_profile_security_key_path(@security_key), method: :delete %>
|
17
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<li><%%= link_to security_key.name, edit_two_factor_authentication_profile_security_key_path(security_key) %></li>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<p style="color: green"><%%= notice %></p>
|
2
|
+
|
3
|
+
<h1>Security keys</h1>
|
4
|
+
<p>A security key is a hardware device used to verify your identity. For example, a built-in fingerprint reader, a plug-in USB key, or a login system like Windows Hello.</p>
|
5
|
+
|
6
|
+
<ul><%%= render @security_keys %></ul>
|
7
|
+
|
8
|
+
<br>
|
9
|
+
|
10
|
+
<%%= link_to "Add security key", new_two_factor_authentication_profile_security_key_path %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div data-controller="web-authn"
|
2
|
+
data-web-authn-loading-class="web-authn-loading"
|
3
|
+
data-web-authn-challenge-url-value="<%%= new_two_factor_authentication_profile_security_key_url %>"
|
4
|
+
data-web-authn-verification-url-value="<%%= two_factor_authentication_profile_security_keys_url %>">
|
5
|
+
|
6
|
+
<p data-web-authn-target="error" style="color: red" hidden></p>
|
7
|
+
|
8
|
+
<h1>Add a security key</h1>
|
9
|
+
<p>Have your security key ready. If it's the USB kind insert it now and then, if it has one, press the activation button when asked.</p>
|
10
|
+
|
11
|
+
<%%= button_tag "I'm ready, let's go", type: :button, data: { web_authn_target: "button", action: "web-authn#createCredential" } %>
|
12
|
+
</div>
|
@@ -14,7 +14,7 @@
|
|
14
14
|
<figcaption>Point your camera here</figcaption>
|
15
15
|
</figure>
|
16
16
|
|
17
|
-
<%%= form_with(url:
|
17
|
+
<%%= form_with(url: two_factor_authentication_profile_totp_path) do |form| %>
|
18
18
|
<%%= form.hidden_field :secret, value: @totp.secret %>
|
19
19
|
|
20
20
|
<div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Application } from "@hotwired/stimulus"
|
2
|
+
<%- if webauthn? -%>
|
3
|
+
import WebAuthnController from "stimulus-web-authn"
|
4
|
+
<%- end -%>
|
5
|
+
|
6
|
+
const application = Application.start()
|
7
|
+
<%- if webauthn? -%>
|
8
|
+
application.register("web-authn", WebAuthnController)
|
9
|
+
<%- end -%>
|
10
|
+
|
11
|
+
// Configure Stimulus development experience
|
12
|
+
application.debug = false
|
13
|
+
window.Stimulus = application
|
14
|
+
|
15
|
+
export { application }
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
def change
|
3
|
+
create_table :security_keys do |t|
|
4
|
+
t.references :user, null: false, foreign_key: true
|
5
|
+
t.string :name, null: false
|
6
|
+
t.string :external_id, null: false
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :security_keys, :external_id, unique: true
|
12
|
+
end
|
13
|
+
end
|
@@ -7,6 +7,9 @@ class User < ApplicationRecord
|
|
7
7
|
<%- if two_factor? -%>
|
8
8
|
has_many :recovery_codes, dependent: :destroy
|
9
9
|
<%- end -%>
|
10
|
+
<%- if webauthn? -%>
|
11
|
+
has_many :security_keys, dependent: :destroy
|
12
|
+
<%- end -%>
|
10
13
|
<%- if passwordless? -%>
|
11
14
|
has_many :sign_in_tokens, dependent: :destroy
|
12
15
|
<%- end -%>
|
@@ -27,6 +30,11 @@ class User < ApplicationRecord
|
|
27
30
|
before_validation if: :email_changed?, on: :update do
|
28
31
|
self.verified = false
|
29
32
|
end
|
33
|
+
<%- if webauthn? %>
|
34
|
+
before_validation on: :create do
|
35
|
+
self.webauthn_id = WebAuthn.generate_user_id
|
36
|
+
end
|
37
|
+
<%- end -%>
|
30
38
|
|
31
39
|
after_update if: :password_digest_previously_changed? do
|
32
40
|
sessions.where.not(id: Current.session).delete_all
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authentication-zero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.16.
|
4
|
+
version: 2.16.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nixon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/generators/authentication/USAGE
|
37
37
|
- lib/generators/authentication/authentication_generator.rb
|
38
38
|
- lib/generators/authentication/templates/config/initializers/omniauth.rb
|
39
|
+
- lib/generators/authentication/templates/config/initializers/webauthn.rb
|
39
40
|
- lib/generators/authentication/templates/config/redis/shared.yml
|
40
41
|
- lib/generators/authentication/templates/controllers/api/application_controller.rb.tt
|
41
42
|
- lib/generators/authentication/templates/controllers/api/authentications/events_controller.rb.tt
|
@@ -59,9 +60,12 @@ files:
|
|
59
60
|
- lib/generators/authentication/templates/controllers/html/sessions/passwordlesses_controller.rb.tt
|
60
61
|
- lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
|
61
62
|
- lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
|
62
|
-
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/
|
63
|
-
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/
|
64
|
-
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt
|
63
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/recovery_codes_controller.rb.tt
|
64
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/security_keys_controller.rb.tt
|
65
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenge/totps_controller.rb.tt
|
66
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/profile/recovery_codes_controller.rb.tt
|
67
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/profile/security_keys_controller.rb.tt
|
68
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/profile/totps_controller.rb.tt
|
65
69
|
- lib/generators/authentication/templates/erb/authentications/events/index.html.erb.tt
|
66
70
|
- lib/generators/authentication/templates/erb/home/index.html.erb.tt
|
67
71
|
- lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt
|
@@ -74,21 +78,29 @@ files:
|
|
74
78
|
- lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
|
75
79
|
- lib/generators/authentication/templates/erb/sessions/passwordlesses/new.html.erb.tt
|
76
80
|
- lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt
|
77
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/
|
78
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/
|
79
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/
|
80
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/recovery_codes/_recovery_code.html.erb.tt
|
81
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/recovery_codes/index.html.erb.tt
|
82
|
-
- lib/generators/authentication/templates/erb/two_factor_authentication/
|
81
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/challenge/recovery_codes/new.html.erb.tt
|
82
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/challenge/security_keys/new.html.erb.tt
|
83
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/challenge/totps/new.html.erb.tt
|
84
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/recovery_codes/_recovery_code.html.erb.tt
|
85
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/recovery_codes/index.html.erb.tt
|
86
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_form_confirm.html.erb.tt
|
87
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_form_edit.html.erb.tt
|
88
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/_security_key.html.erb.tt
|
89
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/edit.html.erb.tt
|
90
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/index.html.erb.tt
|
91
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/security_keys/new.html.erb.tt
|
92
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/profile/totps/new.html.erb.tt
|
83
93
|
- lib/generators/authentication/templates/erb/user_mailer/email_verification.html.erb.tt
|
84
94
|
- lib/generators/authentication/templates/erb/user_mailer/invitation_instructions.html.erb.tt
|
85
95
|
- lib/generators/authentication/templates/erb/user_mailer/password_reset.html.erb.tt
|
86
96
|
- lib/generators/authentication/templates/erb/user_mailer/passwordless.html.erb.tt
|
97
|
+
- lib/generators/authentication/templates/javascript/controllers/application.js.tt
|
87
98
|
- lib/generators/authentication/templates/mailers/user_mailer.rb.tt
|
88
99
|
- lib/generators/authentication/templates/migrations/create_email_verification_tokens_migration.rb.tt
|
89
100
|
- lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
|
90
101
|
- lib/generators/authentication/templates/migrations/create_password_reset_tokens_migration.rb.tt
|
91
102
|
- lib/generators/authentication/templates/migrations/create_recovery_codes_migration.rb.tt
|
103
|
+
- lib/generators/authentication/templates/migrations/create_security_keys_migration.rb.tt
|
92
104
|
- lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt
|
93
105
|
- lib/generators/authentication/templates/migrations/create_sign_in_tokens_migration.rb.tt
|
94
106
|
- lib/generators/authentication/templates/migrations/create_users_migration.rb.tt
|
@@ -97,6 +109,7 @@ files:
|
|
97
109
|
- lib/generators/authentication/templates/models/event.rb.tt
|
98
110
|
- lib/generators/authentication/templates/models/password_reset_token.rb.tt
|
99
111
|
- lib/generators/authentication/templates/models/recovery_code.rb.tt
|
112
|
+
- lib/generators/authentication/templates/models/security_key.rb.tt
|
100
113
|
- lib/generators/authentication/templates/models/session.rb.tt
|
101
114
|
- lib/generators/authentication/templates/models/sign_in_token.rb.tt
|
102
115
|
- lib/generators/authentication/templates/models/user.rb.tt
|
@@ -1,52 +0,0 @@
|
|
1
|
-
class TwoFactorAuthentication::ChallengesController < ApplicationController
|
2
|
-
skip_before_action :authenticate
|
3
|
-
|
4
|
-
before_action :set_user
|
5
|
-
|
6
|
-
def new
|
7
|
-
end
|
8
|
-
|
9
|
-
def create
|
10
|
-
if params[:scheme_type] == "recovery_codes"
|
11
|
-
verify_recovery_code
|
12
|
-
else
|
13
|
-
verify_time_based_one_time_password
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
def set_user
|
19
|
-
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
|
20
|
-
rescue StandardError
|
21
|
-
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
|
22
|
-
end
|
23
|
-
|
24
|
-
def verify_recovery_code
|
25
|
-
if recover_code = @user.recovery_codes.find_by(code: params[:code], used: false)
|
26
|
-
recover_code.update!(used: true); sign_in_and_redirect_to_root
|
27
|
-
else
|
28
|
-
redirect_to_authentication_challenge
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def verify_time_based_one_time_password
|
33
|
-
@totp = ROTP::TOTP.new(@user.otp_secret, issuer: "YourAppName")
|
34
|
-
|
35
|
-
if @totp.verify(params[:code], drift_behind: 15)
|
36
|
-
sign_in_and_redirect_to_root
|
37
|
-
else
|
38
|
-
redirect_to_authentication_challenge
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def sign_in_and_redirect_to_root
|
43
|
-
session = @user.sessions.create!
|
44
|
-
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
45
|
-
|
46
|
-
redirect_to root_path, notice: "Signed in successfully"
|
47
|
-
end
|
48
|
-
|
49
|
-
def redirect_to_authentication_challenge
|
50
|
-
redirect_to new_two_factor_authentication_challenge_path(scheme_type: params[:scheme_type]), alert: "That code didn't work. Please try again"
|
51
|
-
end
|
52
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
<%%= form_with(url: two_factor_authentication_challenge_path) do |form| %>
|
2
|
-
<%%= form.hidden_field :scheme_type, value: "totp" %>
|
3
|
-
|
4
|
-
<div>
|
5
|
-
<%%= form.label :code do %>
|
6
|
-
<h1>Next, open the 2FA authenticator app on your phone and type the six digit code below:</h1>
|
7
|
-
<%% end %>
|
8
|
-
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
9
|
-
</div>
|
10
|
-
|
11
|
-
<div>
|
12
|
-
<%%= form.submit "Verify" %>
|
13
|
-
</div>
|
14
|
-
<%% end %>
|
15
|
-
|
16
|
-
<div>
|
17
|
-
<p><strong>Don't have your phone?</strong></p>
|
18
|
-
<%%= link_to "Use a recovery code to access your account.", new_two_factor_authentication_challenge_path(scheme_type: "recovery_codes") %>
|
19
|
-
</div>
|