authentication-zero 2.16.15 → 2.16.16
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/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -2
- data/lib/authentication_zero/version.rb +1 -1
- data/lib/generators/authentication/authentication_generator.rb +29 -24
- data/lib/generators/authentication/templates/controllers/api/identity/email_verifications_controller.rb.tt +1 -11
- data/lib/generators/authentication/templates/controllers/api/identity/password_resets_controller.rb.tt +5 -1
- data/lib/generators/authentication/templates/controllers/html/identity/email_verifications_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/identity/password_resets_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/sessions/passwordlesses_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/challenges_controller.rb.tt +33 -9
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/recovery_codes_controller.rb.tt +31 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt +8 -7
- data/lib/generators/authentication/templates/erb/home/index.html.erb.tt +4 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/_recovery_code_form.html.erb.tt +19 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/_totp_form.html.erb.tt +20 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt +4 -13
- data/lib/generators/authentication/templates/erb/two_factor_authentication/recovery_codes/_recovery_code.html.erb.tt +5 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/recovery_codes/index.html.erb.tt +16 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt +2 -2
- data/lib/generators/authentication/templates/erb/user_mailer/email_verification.html.erb.tt +1 -5
- data/lib/generators/authentication/templates/mailers/user_mailer.rb.tt +0 -4
- data/lib/generators/authentication/templates/migrations/create_recovery_codes_migration.rb.tt +11 -0
- data/lib/generators/authentication/templates/models/recovery_code.rb.tt +3 -0
- data/lib/generators/authentication/templates/models/user.rb.tt +4 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt +7 -0
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99df48ab46b9859695eadb1675580d523f1953a3f211b648b3c752e22598557a
|
4
|
+
data.tar.gz: c9fa8cfc8785c16a3329737b89c43ded33f74b79857e52a32f5e1b00872e388f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72daf22b87d0960c34885348cdf1c24ae3d67dbc9e34c816ac0d1592fd9e46299776b624383d4d318034edfbcedfa5e894fa65495188afe94aee6b011d3b4281
|
7
|
+
data.tar.gz: 219aa2ebe407eacf4344c462e20aad1abea1389b96b629f6313486821d07f04ea3682e789accaef04fb2bf60365cacb229fddbbafbf8c6e2bb8172ab18195ec7
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -28,12 +28,11 @@ Since Authentication Zero generates this code into your application instead of b
|
|
28
28
|
- Authentication by cookie
|
29
29
|
- Authentication by token (--api)
|
30
30
|
- Passwordless authentication (--passwordless)
|
31
|
-
- Two factor authentication (--two-factor)
|
31
|
+
- Two factor authentication + recovery codes (--two-factor)
|
32
32
|
- Social Login with OmniAuth (--omniauthable)
|
33
33
|
- Send invitations (--invitable)
|
34
34
|
- Sign-in as button functionallity (--masqueradable)
|
35
35
|
- Verify email using a link with token
|
36
|
-
- Verify email using a six random digits code for api (--code-verifiable)
|
37
36
|
- Ask password before sensitive data changes, aka: sudo (--sudoable)
|
38
37
|
- Reset the user password and send reset instructions
|
39
38
|
- Reset the user password only from verified emails
|
@@ -3,18 +3,17 @@ require "rails/generators/active_record"
|
|
3
3
|
class AuthenticationGenerator < Rails::Generators::Base
|
4
4
|
include ActiveRecord::Generators::Migration
|
5
5
|
|
6
|
-
class_option :api,
|
7
|
-
class_option :pwned,
|
8
|
-
class_option :
|
9
|
-
class_option :
|
10
|
-
class_option :
|
11
|
-
class_option :
|
12
|
-
class_option :
|
13
|
-
class_option :
|
14
|
-
class_option :
|
15
|
-
class_option :
|
16
|
-
class_option :
|
17
|
-
class_option :masqueradable, type: :boolean, desc: "Add sign-in as button functionallity"
|
6
|
+
class_option :api, type: :boolean, desc: "Generates API authentication"
|
7
|
+
class_option :pwned, type: :boolean, desc: "Add pwned password validation"
|
8
|
+
class_option :sudoable, type: :boolean, desc: "Add password request before sensitive data changes"
|
9
|
+
class_option :lockable, type: :boolean, desc: "Add password reset locking"
|
10
|
+
class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
|
11
|
+
class_option :passwordless, type: :boolean, desc: "Add passwordless sign"
|
12
|
+
class_option :omniauthable, type: :boolean, desc: "Add social login support"
|
13
|
+
class_option :trackable, type: :boolean, desc: "Add activity log support"
|
14
|
+
class_option :two_factor, type: :boolean, desc: "Add two factor authentication"
|
15
|
+
class_option :invitable, type: :boolean, desc: "Add sending invitations"
|
16
|
+
class_option :masqueradable, type: :boolean, desc: "Add sign-in as button functionallity"
|
18
17
|
|
19
18
|
source_root File.expand_path("templates", __dir__)
|
20
19
|
|
@@ -98,9 +97,13 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
98
97
|
|
99
98
|
def create_views
|
100
99
|
if options.api?
|
101
|
-
|
100
|
+
template "erb/user_mailer/email_verification.html.erb", "app/views/user_mailer/email_verification.html.erb"
|
101
|
+
template "erb/user_mailer/password_reset.html.erb", "app/views/user_mailer/password_reset.html.erb"
|
102
102
|
else
|
103
|
-
|
103
|
+
template "erb/user_mailer/email_verification.html.erb", "app/views/user_mailer/email_verification.html.erb"
|
104
|
+
template "erb/user_mailer/password_reset.html.erb", "app/views/user_mailer/password_reset.html.erb"
|
105
|
+
template "erb/user_mailer/invitation_instructions.html.erb", "app/views/user_mailer/invitation_instructions.html.erb" if invitable?
|
106
|
+
template "erb/user_mailer/passwordless.html.erb", "app/views/user_mailer/passwordless.html.erb" if passwordless?
|
104
107
|
|
105
108
|
directory "erb/home", "app/views/home"
|
106
109
|
|
@@ -133,6 +136,10 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
133
136
|
route "resource :sudo, only: [:new, :create]", namespace: :sessions
|
134
137
|
end
|
135
138
|
|
139
|
+
if invitable?
|
140
|
+
route "resource :invitation, only: [:new, :create]"
|
141
|
+
end
|
142
|
+
|
136
143
|
if passwordless?
|
137
144
|
route "resource :passwordless, only: [:new, :edit, :create]", namespace: :sessions
|
138
145
|
end
|
@@ -148,8 +155,9 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
148
155
|
end
|
149
156
|
|
150
157
|
if two_factor?
|
151
|
-
route "
|
152
|
-
route "resource
|
158
|
+
route "resources :recovery_codes, only: [:index, :create]", namespace: :two_factor_authentication
|
159
|
+
route "resource :totp, only: [:new, :create]", namespace: :two_factor_authentication
|
160
|
+
route "resource :challenge, only: [:new, :create]", namespace: :two_factor_authentication
|
153
161
|
end
|
154
162
|
|
155
163
|
if options.trackable?
|
@@ -160,11 +168,12 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
160
168
|
route "resource :email_verification, only: [:show, :create]", namespace: :identity
|
161
169
|
route "resource :email, only: [:edit, :update]", namespace: :identity
|
162
170
|
|
163
|
-
route "resource :
|
164
|
-
route "
|
165
|
-
|
171
|
+
route "resource :password, only: [:edit, :update]"
|
172
|
+
route "resources :sessions, only: [:index, :show, :destroy]"
|
173
|
+
|
166
174
|
route 'post "sign_up", to: "registrations#create"'
|
167
175
|
route 'get "sign_up", to: "registrations#new"' unless options.api?
|
176
|
+
|
168
177
|
route 'post "sign_in", to: "sessions#create"'
|
169
178
|
route 'get "sign_in", to: "sessions#new"' unless options.api?
|
170
179
|
end
|
@@ -213,11 +222,7 @@ class AuthenticationGenerator < Rails::Generators::Base
|
|
213
222
|
options.sudoable? && !options.api?
|
214
223
|
end
|
215
224
|
|
216
|
-
def code_verifiable?
|
217
|
-
options.code_verifiable? && options.api?
|
218
|
-
end
|
219
|
-
|
220
225
|
def redis?
|
221
|
-
options.lockable? || options.ratelimit? || sudoable?
|
226
|
+
options.lockable? || options.ratelimit? || sudoable?
|
222
227
|
end
|
223
228
|
end
|
@@ -13,18 +13,8 @@ class Identity::EmailVerificationsController < ApplicationController
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def set_user
|
16
|
-
<%- if code_verifiable? -%>
|
17
|
-
verified_user = User.find_by(email: params[:email])
|
18
|
-
|
19
|
-
if verified_user && verified_user.verification_code.value == params[:token]
|
20
|
-
@user = verified_user
|
21
|
-
else
|
22
|
-
render json: { error: "That email verification code is invalid" }, status: :bad_request
|
23
|
-
end
|
24
|
-
<%- else -%>
|
25
16
|
@token = EmailVerificationToken.find_signed!(params[:sid]); @user = @token.user
|
26
|
-
rescue
|
17
|
+
rescue StandardError
|
27
18
|
render json: { error: "That email verification link is invalid" }, status: :bad_request
|
28
|
-
<%- end -%>
|
29
19
|
end
|
30
20
|
end
|
@@ -6,6 +6,10 @@ class Identity::PasswordResetsController < ApplicationController
|
|
6
6
|
<%- end -%>
|
7
7
|
before_action :set_user, only: :update
|
8
8
|
|
9
|
+
def edit
|
10
|
+
head :no_content
|
11
|
+
end
|
12
|
+
|
9
13
|
def create
|
10
14
|
if @user = User.find_by(email: params[:email], verified: true)
|
11
15
|
UserMailer.with(user: @user).password_reset.deliver_later
|
@@ -25,7 +29,7 @@ class Identity::PasswordResetsController < ApplicationController
|
|
25
29
|
private
|
26
30
|
def set_user
|
27
31
|
@token = PasswordResetToken.find_signed!(params[:sid]); @user = @token.user
|
28
|
-
rescue
|
32
|
+
rescue StandardError
|
29
33
|
render json: { error: "That password reset link is invalid" }, status: :bad_request
|
30
34
|
end
|
31
35
|
|
@@ -16,7 +16,7 @@ class Identity::EmailVerificationsController < ApplicationController
|
|
16
16
|
private
|
17
17
|
def set_user
|
18
18
|
@token = EmailVerificationToken.find_signed!(params[:sid]); @user = @token.user
|
19
|
-
rescue
|
19
|
+
rescue StandardError
|
20
20
|
redirect_to edit_identity_email_path, alert: "That email verification link is invalid"
|
21
21
|
end
|
22
22
|
|
@@ -32,7 +32,7 @@ class Identity::PasswordResetsController < ApplicationController
|
|
32
32
|
private
|
33
33
|
def set_user
|
34
34
|
@token = PasswordResetToken.find_signed!(params[:sid]); @user = @token.user
|
35
|
-
rescue
|
35
|
+
rescue StandardError
|
36
36
|
redirect_to new_identity_password_reset_path, alert: "That password reset link is invalid"
|
37
37
|
end
|
38
38
|
|
@@ -28,7 +28,7 @@ class Sessions::PasswordlessesController < ApplicationController
|
|
28
28
|
private
|
29
29
|
def set_user
|
30
30
|
@token = SignInToken.find_signed!(params[:sid]); @user = @token.user
|
31
|
-
rescue
|
31
|
+
rescue StandardError
|
32
32
|
redirect_to new_sessions_passwordless_path, alert: "That sign in link is invalid"
|
33
33
|
end
|
34
34
|
|
@@ -16,7 +16,7 @@ class SessionsController < ApplicationController
|
|
16
16
|
|
17
17
|
if user && user.authenticate(params[:password])
|
18
18
|
<%- if two_factor? -%>
|
19
|
-
if user.otp_secret
|
19
|
+
if user.otp_secret.present?
|
20
20
|
signed_id = user.signed_id(purpose: :authentication_challenge, expires_in: 20.minutes)
|
21
21
|
redirect_to new_two_factor_authentication_challenge_path(token: signed_id)
|
22
22
|
else
|
@@ -7,22 +7,46 @@ class TwoFactorAuthentication::ChallengesController < ApplicationController
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def create
|
10
|
-
|
11
|
-
|
12
|
-
if @totp.verify(params[:code], drift_behind: 15)
|
13
|
-
session = @user.sessions.create!
|
14
|
-
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
15
|
-
|
16
|
-
redirect_to root_path, notice: "Signed in successfully"
|
10
|
+
if params[:scheme_type] == "recovery_codes"
|
11
|
+
verify_recovery_code
|
17
12
|
else
|
18
|
-
|
13
|
+
verify_time_based_one_time_password
|
19
14
|
end
|
20
15
|
end
|
21
16
|
|
22
17
|
private
|
23
18
|
def set_user
|
24
19
|
@user = User.find_signed!(params[:token], purpose: :authentication_challenge)
|
25
|
-
rescue
|
20
|
+
rescue StandardError
|
26
21
|
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
|
27
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(token: params[:token], scheme_type: params[:scheme_type]), alert: "That code didn't work. Please try again"
|
51
|
+
end
|
28
52
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class TwoFactorAuthentication::RecoveryCodesController < ApplicationController
|
2
|
+
before_action :set_user
|
3
|
+
|
4
|
+
def index
|
5
|
+
if Current.user.recovery_codes.exists?
|
6
|
+
@recovery_codes = @user.recovery_codes
|
7
|
+
else
|
8
|
+
@recovery_codes = @user.recovery_codes.create!(new_recovery_codes)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
@user.recovery_codes.delete_all
|
14
|
+
@user.recovery_codes.create!(new_recovery_codes)
|
15
|
+
|
16
|
+
redirect_to two_factor_authentication_recovery_codes_path, notice: "Your new recovery codes have been generated"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def set_user
|
21
|
+
@user = Current.user
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_recovery_codes
|
25
|
+
10.times.map { { code: new_recovery_code } }
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_recovery_code
|
29
|
+
SecureRandom.alphanumeric(10).insert(5, "-").downcase
|
30
|
+
end
|
31
|
+
end
|
@@ -9,17 +9,18 @@ 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_recovery_codes_path
|
13
13
|
else
|
14
14
|
redirect_to new_two_factor_authentication_totp_path, alert: "That code didn't work. Please try again"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
private
|
19
|
+
def set_user
|
20
|
+
@user = Current.user
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
def set_totp
|
24
|
+
@totp = ROTP::TOTP.new(params[:secret] || ROTP::Base32.random, issuer: "YourAppName")
|
25
|
+
end
|
25
26
|
end
|
@@ -33,6 +33,10 @@
|
|
33
33
|
<div>
|
34
34
|
<%%= link_to "Two-Factor Authentication", new_two_factor_authentication_totp_path %>
|
35
35
|
</div>
|
36
|
+
|
37
|
+
<%% if Current.user.otp_secret.present? %>
|
38
|
+
<div><%%= link_to "Recovery Codes", two_factor_authentication_recovery_codes_path %></div>
|
39
|
+
<%% end %>
|
36
40
|
<%- end -%>
|
37
41
|
|
38
42
|
<br>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%%= form_with(url: two_factor_authentication_challenge_path) do |form| %>
|
2
|
+
<%%= form.hidden_field :token, value: params[:token] %>
|
3
|
+
<%%= form.hidden_field :scheme_type, value: "recovery_codes" %>
|
4
|
+
|
5
|
+
<div>
|
6
|
+
<%%= form.label :code do %>
|
7
|
+
<h1>OK, enter one of your recovery codes below:</h1>
|
8
|
+
<%% end %>
|
9
|
+
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div>
|
13
|
+
<%%= form.submit "Continue" %>
|
14
|
+
</div>
|
15
|
+
<%% end %>
|
16
|
+
|
17
|
+
<div>
|
18
|
+
<p>To access your account, enter one of the recovery codes (e.g., XXXXX-XXXXX) you saved when you set up your two-factor authentication device.</p>
|
19
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%%= form_with(url: two_factor_authentication_challenge_path) do |form| %>
|
2
|
+
<%%= form.hidden_field :token, value: params[:token] %>
|
3
|
+
<%%= form.hidden_field :scheme_type, value: "totp" %>
|
4
|
+
|
5
|
+
<div>
|
6
|
+
<%%= form.label :code do %>
|
7
|
+
<h1>Next, open the 2FA authenticator app on your phone and type the six digit code below:</h1>
|
8
|
+
<%% end %>
|
9
|
+
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div>
|
13
|
+
<%%= form.submit "Verify" %>
|
14
|
+
</div>
|
15
|
+
<%% end %>
|
16
|
+
|
17
|
+
<div>
|
18
|
+
<p><strong>Don't have your phone?</strong></p>
|
19
|
+
<%%= link_to "Use a recovery code to access your account.", new_two_factor_authentication_challenge_path(token: params[:token], scheme_type: "recovery_codes") %>
|
20
|
+
</div>
|
@@ -1,16 +1,7 @@
|
|
1
1
|
<p style="color: red"><%%= alert %></p>
|
2
2
|
|
3
|
-
|
4
|
-
<%%=
|
5
|
-
|
6
|
-
|
7
|
-
<%%= form.label :code do %>
|
8
|
-
<h1>Next, open the 2FA authenticator app on your phone and type the six digit code below:</h1>
|
9
|
-
<%% end %>
|
10
|
-
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
11
|
-
</div>
|
12
|
-
|
13
|
-
<div>
|
14
|
-
<%%= form.submit "Verify" %>
|
15
|
-
</div>
|
3
|
+
<%% if params[:scheme_type] == "recovery_codes" %>
|
4
|
+
<%%= render "recovery_code_form" %>
|
5
|
+
<%% else %>
|
6
|
+
<%%= render "totp_form" %>
|
16
7
|
<%% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<p style="color: green"><%%= notice %></p>
|
2
|
+
|
3
|
+
<h1>Two-factor recovery codes</h1>
|
4
|
+
<p>Recovery codes provide a way to log in if you lose your phone (or don't have it with you). Save these and keep them somewhere safe.</p>
|
5
|
+
|
6
|
+
<ul><%%= render @recovery_codes %></ul>
|
7
|
+
|
8
|
+
<%%= link_to "OK, I'm done", root_path %>
|
9
|
+
|
10
|
+
<hr>
|
11
|
+
|
12
|
+
<h2>Need new recovery codes?</h2>
|
13
|
+
|
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
|
+
|
16
|
+
<%%= button_to "Generate new recovery codes", two_factor_authentication_recovery_codes_path %>
|
data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
CHANGED
@@ -10,8 +10,8 @@
|
|
10
10
|
<p>Next, open the authenticator app, tap "Scan QR code" or "+", and, when it asks, point your phone's camera at this QR code picture below.</p>
|
11
11
|
|
12
12
|
<figure>
|
13
|
-
|
14
|
-
|
13
|
+
<%%= image_tag @qr_code.as_png(resize_exactly_to: 200).to_data_url%>
|
14
|
+
<figcaption>Point your camera here</figcaption>
|
15
15
|
</figure>
|
16
16
|
|
17
17
|
<%%= form_with(url: two_factor_authentication_totp_path) do |form| %>
|
@@ -2,13 +2,9 @@
|
|
2
2
|
|
3
3
|
<p>This is to confirm that <%%= @user.email %> is the email you want to use on your account. If you ever lose your password, that's where we'll email a reset link.</p>
|
4
4
|
|
5
|
-
<p><strong>You must
|
5
|
+
<p><strong>You must hit the link below to confirm that you received this email.</strong></p>
|
6
6
|
|
7
|
-
<%- if code_verifiable? -%>
|
8
|
-
<strong><%%= @user.verification_code.value %></strong>
|
9
|
-
<%- else -%>
|
10
7
|
<%%= link_to "Yes, use this email for my account", identity_email_verification_url(sid: @signed_id) %>
|
11
|
-
<%- end -%>
|
12
8
|
|
13
9
|
<hr>
|
14
10
|
|
@@ -8,11 +8,7 @@ class UserMailer < ApplicationMailer
|
|
8
8
|
|
9
9
|
def email_verification
|
10
10
|
@user = params[:user]
|
11
|
-
<%- if code_verifiable? -%>
|
12
|
-
@user.verification_code.value = rand.to_s[2..7]
|
13
|
-
<%- else -%>
|
14
11
|
@signed_id = @user.email_verification_tokens.create.signed_id(expires_in: 2.days)
|
15
|
-
<%- end -%>
|
16
12
|
|
17
13
|
mail to: @user.email, subject: "Verify your email"
|
18
14
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
|
+
def change
|
3
|
+
create_table :recovery_codes do |t|
|
4
|
+
t.references :user, null: false, foreign_key: true
|
5
|
+
t.string :code, null: false
|
6
|
+
t.boolean :used, null: false, default: false
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -3,6 +3,9 @@ class User < ApplicationRecord
|
|
3
3
|
|
4
4
|
has_many :email_verification_tokens, dependent: :destroy
|
5
5
|
has_many :password_reset_tokens, dependent: :destroy
|
6
|
+
<%- if two_factor? -%>
|
7
|
+
has_many :recovery_codes, dependent: :destroy
|
8
|
+
<%- end -%>
|
6
9
|
<%- if passwordless? -%>
|
7
10
|
has_many :sign_in_tokens, dependent: :destroy
|
8
11
|
<%- end -%>
|
@@ -11,9 +14,6 @@ class User < ApplicationRecord
|
|
11
14
|
<%- if options.trackable? -%>
|
12
15
|
has_many :events, dependent: :destroy
|
13
16
|
<%- end -%>
|
14
|
-
<%- if code_verifiable? %>
|
15
|
-
kredis_string :verification_code, expires_in: 2.days
|
16
|
-
<%- end -%>
|
17
17
|
|
18
18
|
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
|
19
19
|
validates :password, allow_nil: true, length: { minimum: 12 }
|
@@ -30,7 +30,7 @@ class User < ApplicationRecord
|
|
30
30
|
end
|
31
31
|
|
32
32
|
after_update if: :password_digest_previously_changed? do
|
33
|
-
sessions.where.not(id: Current.session).
|
33
|
+
sessions.where.not(id: Current.session).delete_all
|
34
34
|
end
|
35
35
|
<%- if options.trackable? %>
|
36
36
|
after_update if: :email_previously_changed? do
|
@@ -5,6 +5,13 @@ class Identity::PasswordResetsControllerTest < ActionDispatch::IntegrationTest
|
|
5
5
|
@user = users(:lazaro_nixon)
|
6
6
|
end
|
7
7
|
|
8
|
+
test "should get edit" do
|
9
|
+
sid = @user.password_reset_tokens.create.signed_id(expires_in: 20.minutes)
|
10
|
+
|
11
|
+
get edit_identity_password_reset_url(sid: sid)
|
12
|
+
assert_response :no_content
|
13
|
+
end
|
14
|
+
|
8
15
|
test "should send a password reset email" do
|
9
16
|
assert_enqueued_email_with UserMailer, :password_reset, args: { user: @user } do
|
10
17
|
post identity_password_reset_url, params: { email: @user.email }
|
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.16
|
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-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
|
61
61
|
- lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
|
62
62
|
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt
|
63
|
+
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/recovery_codes_controller.rb.tt
|
63
64
|
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt
|
64
65
|
- lib/generators/authentication/templates/erb/authentications/events/index.html.erb.tt
|
65
66
|
- lib/generators/authentication/templates/erb/home/index.html.erb.tt
|
@@ -73,7 +74,11 @@ files:
|
|
73
74
|
- lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
|
74
75
|
- lib/generators/authentication/templates/erb/sessions/passwordlesses/new.html.erb.tt
|
75
76
|
- lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt
|
77
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/challenges/_recovery_code_form.html.erb.tt
|
78
|
+
- lib/generators/authentication/templates/erb/two_factor_authentication/challenges/_totp_form.html.erb.tt
|
76
79
|
- lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt
|
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
|
77
82
|
- lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
|
78
83
|
- lib/generators/authentication/templates/erb/user_mailer/email_verification.html.erb.tt
|
79
84
|
- lib/generators/authentication/templates/erb/user_mailer/invitation_instructions.html.erb.tt
|
@@ -83,6 +88,7 @@ files:
|
|
83
88
|
- lib/generators/authentication/templates/migrations/create_email_verification_tokens_migration.rb.tt
|
84
89
|
- lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
|
85
90
|
- lib/generators/authentication/templates/migrations/create_password_reset_tokens_migration.rb.tt
|
91
|
+
- lib/generators/authentication/templates/migrations/create_recovery_codes_migration.rb.tt
|
86
92
|
- lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt
|
87
93
|
- lib/generators/authentication/templates/migrations/create_sign_in_tokens_migration.rb.tt
|
88
94
|
- lib/generators/authentication/templates/migrations/create_users_migration.rb.tt
|
@@ -90,6 +96,7 @@ files:
|
|
90
96
|
- lib/generators/authentication/templates/models/email_verification_token.rb.tt
|
91
97
|
- lib/generators/authentication/templates/models/event.rb.tt
|
92
98
|
- lib/generators/authentication/templates/models/password_reset_token.rb.tt
|
99
|
+
- lib/generators/authentication/templates/models/recovery_code.rb.tt
|
93
100
|
- lib/generators/authentication/templates/models/session.rb.tt
|
94
101
|
- lib/generators/authentication/templates/models/sign_in_token.rb.tt
|
95
102
|
- lib/generators/authentication/templates/models/user.rb.tt
|