authentication-zero 2.16.20 → 2.16.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>
|