berrypod/lib/berrypod_web/live/auth/totp_verification.ex

91 lines
2.4 KiB
Elixir
Raw Normal View History

defmodule BerrypodWeb.Auth.TotpVerification do
use BerrypodWeb, :live_view
alias Berrypod.Accounts
@impl true
def mount(_params, session, socket) do
user_id = session["totp_pending_user_id"]
remember_me = session["totp_pending_remember_me"]
if user_id do
{:ok,
socket
|> assign(:user_id, user_id)
|> assign(:remember_me, remember_me)
|> assign(:form, to_form(%{"code" => ""}, as: :totp))
|> assign(:trigger_submit, false)}
else
{:ok,
socket
|> put_flash(:error, "Session expired. Please log in again.")
|> redirect(to: ~p"/users/log-in")}
end
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="setup-page">
<div class="setup-header">
<.header>
Two-factor authentication
<:subtitle>
Enter the 6-digit code from your authenticator app.
</:subtitle>
</.header>
</div>
<.form
for={@form}
id="totp_form"
action={~p"/users/verify-totp"}
phx-submit="verify"
phx-trigger-action={@trigger_submit}
>
<input type="hidden" name="remember_me" value={to_string(@remember_me)} />
<.input
field={@form[:code]}
type="text"
label="Verification code"
placeholder="000000"
inputmode="numeric"
pattern="[0-9]*"
autocomplete="one-time-code"
maxlength="6"
autofocus
phx-mounted={JS.focus()}
/>
<.button variant="primary" class="admin-btn-block">
Verify <span aria-hidden="true">&rarr;</span>
</.button>
</.form>
<p class="setup-footer admin-text-tertiary">
Lost your device? Enter one of your backup codes instead.
</p>
</div>
</Layouts.app>
"""
end
@impl true
def handle_event("verify", %{"totp" => %{"code" => code}}, socket) do
user = Accounts.get_user!(socket.assigns.user_id)
case Accounts.verify_totp(user, code) do
:ok ->
{:noreply, assign(socket, :trigger_submit, true)}
:error ->
{:noreply,
socket
|> assign(:form, to_form(%{"code" => ""}, as: :totp))
|> put_flash(:error, "Invalid code. Please try again.")}
end
end
end