refactor: DRY token verification — extract shared verify_hashed_token_query helper

Consolidate verify_magic_link/confirm/password_reset_token_query into
one-line delegations to a private helper, removing 29 lines of
duplicated decode/hash/query logic.
This commit is contained in:
Graham McInitre 2026-07-21 11:18:15 -05:00
parent aa6f2ea647
commit 5c6cef2227

View file

@ -117,6 +117,25 @@ defmodule Microwaveprop.Accounts.UserToken do
}}
end
defp verify_hashed_token_query(token, context, validity, unit) do
case Base.url_decode64(token, padding: false) do
{:ok, decoded_token} ->
hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query =
from token in by_token_and_context_query(hashed_token, context),
join: user in assoc(token, :user),
where: token.inserted_at > ago(^validity, ^unit),
where: token.sent_to == user.email,
select: {user, token}
{:ok, query}
:error ->
:error
end
end
@doc """
Checks if the token is valid and returns its underlying lookup query.
@ -127,24 +146,8 @@ defmodule Microwaveprop.Accounts.UserToken do
of a magic link token is always "login".
"""
@spec verify_magic_link_token_query(String.t()) :: {:ok, Ecto.Query.t()} | :error
def verify_magic_link_token_query(token) do
case Base.url_decode64(token, padding: false) do
{:ok, decoded_token} ->
hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query =
from token in by_token_and_context_query(hashed_token, "login"),
join: user in assoc(token, :user),
where: token.inserted_at > ago(^@magic_link_validity_in_minutes, "minute"),
where: token.sent_to == user.email,
select: {user, token}
{:ok, query}
:error ->
:error
end
end
def verify_magic_link_token_query(token),
do: verify_hashed_token_query(token, "login", @magic_link_validity_in_minutes, "minute")
@doc """
Checks if the token is valid and returns its underlying lookup query.
@ -153,24 +156,7 @@ defmodule Microwaveprop.Accounts.UserToken do
"confirm" and the token is valid for @confirm_validity_in_days days.
"""
@spec verify_confirm_token_query(String.t()) :: {:ok, Ecto.Query.t()} | :error
def verify_confirm_token_query(token) do
case Base.url_decode64(token, padding: false) do
{:ok, decoded_token} ->
hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query =
from token in by_token_and_context_query(hashed_token, "confirm"),
join: user in assoc(token, :user),
where: token.inserted_at > ago(^@confirm_validity_in_days, "day"),
where: token.sent_to == user.email,
select: {user, token}
{:ok, query}
:error ->
:error
end
end
def verify_confirm_token_query(token), do: verify_hashed_token_query(token, "confirm", @confirm_validity_in_days, "day")
@doc """
Checks if the token is valid and returns its underlying lookup query.
@ -179,24 +165,8 @@ defmodule Microwaveprop.Accounts.UserToken do
"reset_password" and the token is valid for @reset_password_validity_in_days.
"""
@spec verify_password_reset_token_query(String.t()) :: {:ok, Ecto.Query.t()} | :error
def verify_password_reset_token_query(token) do
case Base.url_decode64(token, padding: false) do
{:ok, decoded_token} ->
hashed_token = :crypto.hash(@hash_algorithm, decoded_token)
query =
from token in by_token_and_context_query(hashed_token, "reset_password"),
join: user in assoc(token, :user),
where: token.inserted_at > ago(^@reset_password_validity_in_days, "day"),
where: token.sent_to == user.email,
select: {user, token}
{:ok, query}
:error ->
:error
end
end
def verify_password_reset_token_query(token),
do: verify_hashed_token_query(token, "reset_password", @reset_password_validity_in_days, "day")
@doc """
Checks if the token is valid and returns its underlying lookup query.