Skip to content

fix/2445 HOTP (and 2426 TOTP) type errors#2620

Merged
C85297 merged 1 commit into
gchq:masterfrom
alleria173:fix/hotp-type-error
Jul 3, 2026
Merged

fix/2445 HOTP (and 2426 TOTP) type errors#2620
C85297 merged 1 commit into
gchq:masterfrom
alleria173:fix/hotp-type-error

Conversation

@alleria173

@alleria173 alleria173 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description
Fixes #2445 and fixes #2426 which reports that entering non-base32 characters (e.g. |, ,, ;) into the Generate HOTP secret field produces a cryptic error referencing an internal blob URL:

"Generate HOTP - TypeError in blob:https://... Message: Invalid character found: ,"

The base32 input format is correct by design — the otpauth URI format requires the secret parameter to be base32-encoded (RFC 4648, characters A–Z and 2–7). The bug is in error handling: when OTPAuth.Secret.fromBase32() encounters an invalid character it throws a raw TypeError, not an OperationError. Recipe.mjs only silences OperationError; any other error type propagates with its blob URL filename attached, producing the unhelpful message.

GenerateTOTP.mjs shares identical secret-handling code and has the same bug, so both operations are fixed together. Additionally, both had a pre-existing issue where blank input called Secret.fromBase32("") (producing an empty secret) rather than new OTPAuth.Secret() (random secret), contradicting the description's "leave it blank for a random secret to be generated" promise.

The fix wraps fromBase32() in a try-catch in both operations and throws a user-friendly OperationError on failure. The operation descriptions are also updated to make the base32 requirement explicit.

src/core/operations/GenerateHOTP.mjs

Added import OperationError from "../errors/OperationError.mjs". Replaced the bare fromBase32() call with a try-catch block:

let secret;
try {
    secret = secretStr ?
        OTPAuth.Secret.fromBase32(secretStr.toUpperCase().replace(/\s+/g, "")) :
        new OTPAuth.Secret();
} catch {
    throw new OperationError("Invalid secret. The input must be a valid base32 string (characters A–Z and 2–7).");
}

Updated description to append: "The secret must be a valid base32 string (characters A–Z and 2–7)."


src/core/operations/GenerateTOTP.mjs

Identical changes — same import, same try-catch, same description update, same empty-input fix.

Existing Issue
#2445

Screenshots
N/A — no visual changes.

AI disclosure
Claude Code (claude.ai/code) was used to diagnose the root cause and generate test cases. All other code was added by the submitter.

Test Coverage
Two new test cases added to tests/operations/tests/OTP.mjs, one per operation, verifying that invalid base32 input produces the friendly OperationError output rather than a blob TypeError:

  • "Generate HOTP - invalid base32 secret rejected" — input "not,valid|base32;input", expected output "Invalid secret. The input must be a valid base32 string (characters A–Z and 2–7)."
  • "Generate TOTP - invalid base32 secret rejected" — same input and expected output

All 2058 operation tests pass (npm test).

@alleria173 alleria173 changed the title fix/2445 HOTP (and TOTP) type error fix/2445 HOTP (and 2426 TOTP) type errors Jul 1, 2026
C85297
C85297 previously approved these changes Jul 3, 2026
@C85297

C85297 commented Jul 3, 2026

Copy link
Copy Markdown
Member

@alleria173 I think there is a merge conflict which needs resolving - otherwise, looks good!

@alleria173

Copy link
Copy Markdown
Contributor Author

@alleria173 I think there is a merge conflict which needs resolving - otherwise, looks good!

Thank you @C85297, I've rebased the branch follow the previous pulls that affected HOTP/TOTP and resolved the merge conflict.

@C85297 C85297 enabled auto-merge (squash) July 3, 2026 11:46
@C85297 C85297 merged commit 79de8f1 into gchq:master Jul 3, 2026
3 checks passed
@C85297

C85297 commented Jul 3, 2026

Copy link
Copy Markdown
Member

Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants