From d7234e02a31bc489e1be8ccf99a14b36ad0a670d Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sun, 1 Feb 2026 14:24:19 -0600 Subject: [PATCH] fix: improve verify_totp_only validation logic --- lib/towerops/accounts.ex | 10 ++++------ test/towerops/accounts/verify_totp_only_test.exs | 10 ++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/towerops/accounts.ex b/lib/towerops/accounts.ex index d9126f10..7263375e 100644 --- a/lib/towerops/accounts.ex +++ b/lib/towerops/accounts.ex @@ -598,15 +598,13 @@ defmodule Towerops.Accounts do def verify_totp_only(%User{} = user, code) when is_binary(code) do # TOTP codes are exactly 6 numeric digits # Recovery codes contain letters and/or are longer than 6 digits - numeric_only = String.replace(code, ~r/[^0-9]/, "") - cond do - # Code contains non-numeric characters (recovery codes have letters) - String.length(numeric_only) != String.length(code) -> + # Reject if code contains any non-numeric characters + not String.match?(code, ~r/^\d+$/) -> {:error, :recovery_code_not_allowed} - # Code is longer than 6 digits - String.length(numeric_only) > 6 -> + # Reject if longer than 6 digits + String.length(code) > 6 -> {:error, :recovery_code_not_allowed} # Looks like a TOTP code, verify it diff --git a/test/towerops/accounts/verify_totp_only_test.exs b/test/towerops/accounts/verify_totp_only_test.exs index c375f003..f33a090c 100644 --- a/test/towerops/accounts/verify_totp_only_test.exs +++ b/test/towerops/accounts/verify_totp_only_test.exs @@ -39,5 +39,15 @@ defmodule Towerops.Accounts.VerifyTotpOnlyTest do assert {:error, :recovery_code_not_allowed} = Accounts.verify_totp_only(user, "1234567890") end + + test "rejects codes with whitespace", %{user: user} do + assert {:error, :recovery_code_not_allowed} = + Accounts.verify_totp_only(user, " 123456 ") + end + + test "rejects codes with hyphens", %{user: user} do + assert {:error, :recovery_code_not_allowed} = + Accounts.verify_totp_only(user, "123-456") + end end end