-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: pages for enabling and verifying two factor authentication
- Loading branch information
Showing
21 changed files
with
285 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,3 +40,5 @@ | |
coverage | ||
node_modules | ||
.DS_Store | ||
|
||
/config/credentials/development.key |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
app/components/page_layouts/settings/navigation_item/component.html.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
<a href="<%= path %>" class="flex py-4 hover:bg-surface-hover <%= current_page?(path) ? "bg-surface-hover" : nil %>"> | ||
<a href="<%= path %>" class="flex py-4 hover:bg-surface-hover <%= is_active? ? "bg-surface-hover" : nil %>"> | ||
<div class="w-20 flex justify-center items-center"> | ||
<i class="<%= icon %>"></i> | ||
</div> | ||
<div class="w-full flex flex-col"> | ||
<strong class="<%= current_page?(path) ? "text-primary" : nil %>"><%= label %></strong> | ||
<strong class="<%= is_active? ? "text-primary" : nil %>"><%= label %></strong> | ||
<span class="text-sm"><%= description %></span> | ||
</div> | ||
</a> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
class Users::TwoFactorController < ApplicationController | ||
before_action :setup_user | ||
before_action :ensure_not_enabled, only: %i[new setup verify] | ||
|
||
def new | ||
# Reset the OTP secret to make sure that the user has a fresh secret key. | ||
# This will also reset the otp_required_for_login flag to make sure the user | ||
# doesn't get locked out of their account. | ||
@user.reset_otp_secret! | ||
|
||
# Redirect to the setup page to show the QR code for verification. | ||
redirect_to setup_two_factor_path | ||
end | ||
|
||
def setup | ||
# Generate the QR code for scanning the OTP secret. | ||
# We'll use the RQRCode gem to generate the QR code. | ||
@qr_png = RQRCode::QRCode.new(current_user.otp_uri).as_svg( | ||
module_size: 4 | ||
) | ||
|
||
@qr_code_image = @qr_png.html_safe | ||
end | ||
|
||
def verify | ||
if @user.validate_and_consume_otp!(params[:user][:otp_attempt]) | ||
@user.update(otp_required_for_login: true) | ||
redirect_to edit_two_factor_path, notice: I18n.t("users.two_factor.setup.success") | ||
else | ||
@user.errors.add(:otp_attempt, I18n.t("users.two_factor.setup.invalid_code")) | ||
render turbo_stream: turbo_stream.replace("two_factor_form", partial: "users/two_factor/form", locals: {user: @user}) | ||
end | ||
end | ||
|
||
private | ||
|
||
# Don't refresh the OTP secret if it's already enabled. This may lock the user | ||
# out of their account if they've already setup 2FA. | ||
def ensure_not_enabled | ||
redirect_to edit_two_factor_path if enabled? | ||
end | ||
|
||
def setup_user | ||
@user = current_user | ||
end | ||
|
||
def enabled? | ||
current_user.otp_required_for_login? | ||
end | ||
helper_method :enabled? | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<div id="two_factor_form"> | ||
<p><%= t(".instructions") %></p> | ||
<%= simple_form_for(user, url: verify_two_factor_path, method: :post) do |f| %> | ||
<%= f.input :otp_attempt, label: t(".label"), placeholder: t(".placeholder") %> | ||
<div> | ||
<%= f.submit t(".verify_button"), class: "button" %> | ||
</div> | ||
<% end %> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<% title t(".title") %> | ||
|
||
<%= render(PageLayouts::Settings::Component.new( | ||
title: t(".title"), | ||
description: t(".description") | ||
)) do %> | ||
<div class="box"> | ||
<header class="border-b pb-4 mb-4"> | ||
<h3 class="font-bold text-primary uppercase"><%= t(".title") %></h3> | ||
</header> | ||
|
||
<article class="prose dark:prose-invert"> | ||
<p><%= t(".instructions") %></p> | ||
<ol> | ||
<% t(".steps").each do |step| %> | ||
<li><%= step %></li> | ||
<% end %> | ||
</ol> | ||
|
||
<div class="flex flex-col md:flex-row gap-6"> | ||
<div id="qr-code-wrapper" class="flex justify-center items-center py-8"> | ||
<%= @qr_code_image %> | ||
</div> | ||
<div> | ||
<%= render "form", user: @user %> | ||
</div> | ||
</div> | ||
</article> | ||
</div> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<% title t(".title") %> | ||
|
||
<%= render(PageLayouts::Settings::Component.new( | ||
title: t(".title"), | ||
description: t(".description") | ||
)) do %> | ||
<div class="box"> | ||
<header class="border-b pb-4 mb-4"> | ||
<h3 class="font-bold text-primary uppercase"> | ||
<%= t(".title") %> | ||
</h3> | ||
</header> | ||
<article class="prose dark:prose-invert"> | ||
<p><%= t(".content") %></p> | ||
<%= link_to t(".enable.button"), new_two_factor_path, class:"button" unless enabled? %> | ||
<%= link_to t(".disable.button"), "#", class:"button danger" if enabled? %> | ||
</article> | ||
</div> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
require "test_helper" | ||
|
||
class Users::TwoFactorControllerTest < ActionDispatch::IntegrationTest | ||
test "should not be able to setup 2fa if already enabled" do | ||
sign_in create(:user, :otp_enabled) | ||
get setup_two_factor_path | ||
assert_redirected_to edit_two_factor_path | ||
end | ||
|
||
test "secret code is refreshed on new setup" do | ||
user = create(:user) | ||
sign_in user | ||
get new_two_factor_path | ||
|
||
user.reload | ||
assert user.otp_secret | ||
|
||
get new_two_factor_path | ||
assert_not_equal user.otp_secret, user.reload.otp_secret | ||
end | ||
end |
Oops, something went wrong.