Skip to content

fix: correct Stellar base32 regex from [A-Z0-9] to [A-Z2-7] - #208

Open
Unclebaffa wants to merge 1 commit into
Stellar-Deejah:mainfrom
Unclebaffa:fix/frontend-lookslikestellar-base32-regex
Open

Unclebaffa wants to merge 1 commit into
Stellar-Deejah:mainfrom
Unclebaffa:fix/frontend-lookslikestellar-base32-regex

Conversation

@Unclebaffa

@Unclebaffa Unclebaffa commented Aug 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Branch

fix/frontend-lookslikestellar-base32-regex


The Bug

QueuePage.tsx defined an inline helper:

const looksLikeStellar = (v: string) => /^G[A-Z0-9]{55}$/.test(v);

The character class [A-Z0-9] is wrong. Stellar public keys use Strkey encoding, which is base32 with the alphabet A–Z and digits 2–7 only. The digits 0, 1, 8, and 9 do not exist in this alphabet. A key like G000...000 (56 chars) would pass this frontend check, get submitted to the API, and fail inside the Stellar SDK — producing a confusing HTTP 400 with no indication the problem was at the input.

The backend middleware (validateStellarAddress.ts) and the Zod schema (backend/src/schemas/stellar.ts) both already used the correct /^G[A-Z2-7]{55}$/. The frontend was silently diverging.


What Was Changed

frontend/src/utils/stellar.ts — new file

A shared utility module that centralises the regex in one place so it can never drift again:

export const STELLAR_PUBLIC_KEY_RE = /^G[A-Z2-7]{55}$/;

export function isValidStellarAddress(s: string): boolean {
return STELLAR_PUBLIC_KEY_RE.test(s);
}

The regex is identical to the one in the backend middleware. Both the constant and the function are exported so tests can reference the pattern directly.


frontend/src/pages/QueuePage.tsx — bug fix

  • Removed the inline looksLikeStellar function (which carried the wrong regex).
  • Added import { isValidStellarAddress } from '../utils/stellar'.
  • The enrollment handleEnroll guard now calls isValidStellarAddress(publicKey).

Keys containing 0, 1, 8, or 9 now produce the inline input error "Enter a valid Stellar public key (starts with G, 56 characters)." before any network call is made.


frontend/src/pages/DashboardPage.tsx — validation added

The Dashboard had no key format validation at all — it would fire a fetch for any non-empty string. Added an early return in lookup():

if (!isValidStellarAddress(publicKey.trim())) {
  setError('Enter a valid Stellar public key (starts with G, 56 characters).');
  setSearched(true);
  return;
}

Invalid keys now get an immediate UI error instead of a round-trip to the API that was always going to fail.


frontend/src/utils/stellar.test.ts — new regression test file (19 tests)

Covers three categories:

Category Cases
Invalid — previously accepted G + 55 zeros, G + 55 ones, G + 55 eights, G + 55 nines, mixed valid+0, mixed valid+1, mixed valid+8
Valid — must still pass All-A, all-2, all-7, realistic A–Z/2–7 mix
Edge cases Empty string, bare G, 55-char key (too short), 57-char key (too long), lowercase g prefix, non-G prefix

Also asserts that STELLAR_PUBLIC_KEY_RE is a RegExp instance and produces identical results to isValidStellarAddress for the same inputs.


frontend/src/pages/accessibility.test.tsx — test correction

The existing DashboardPage accessibility test typed 'GINVALID' and expected a Network error. Once the validation guard was in place, GINVALID was correctly caught before the fetch — so the test got the validation error message instead. Updated the test to type a well-formed key (G + 55 As) so it exercises the actual network-error path as originally intended.


Pre-existing Test Failures Fixed

Two tests in accessibility.test.tsx were already failing on main before this work:

1. QueuesPage — IntersectionObserver is not defined

QueuesPage uses IntersectionObserver for infinite scroll. jsdom (the test environment) does not implement this browser API, so the component crashed on mount. Fixed by adding a no-op stub in setupTests.ts:

beforeAll(() => {
  if (typeof globalThis.IntersectionObserver === 'undefined') {
    globalThis.IntersectionObserver = class IntersectionObserver {
      observe() {}
      unobserve() {}
      disconnect() {}
    } as unknown as typeof IntersectionObserver;
  }
});

2. "announces successful enrollment" — multiple role="status" elements

After a successful enrollment, QueuePage renders two role="status" live regions simultaneously — the page-level "Content loaded" announcement and the enrollment success message. Both are correct and intentional for accessibility. The test was using findByRole('status') which throws when more than one match exists. Changed to findAllByRole('status') with a check that at least one element contains 'Enrolled successfully'.


Final State

Test Files  11 passed (11)
Tests       59 passed (59)

Closes #188

The frontend looksLikeStellar helper in QueuePage used /^G[A-Z0-9]{55}$/
which accepted characters 0, 1, 8 and 9 -- all invalid in the Stellar
Strkey base32 alphabet (A-Z plus 2-7 only). A key containing these
characters would pass frontend validation, be submitted to the API, and
then fail Stellar SDK validation downstream with a confusing HTTP 400.

Changes:
- Add frontend/src/utils/stellar.ts with STELLAR_PUBLIC_KEY_RE constant
  and isValidStellarAddress() helper using the correct /^G[A-Z2-7]{55}$/
  regex, matching the backend validateStellarAddress middleware exactly
- Remove inline looksLikeStellar from QueuePage; import shared utility
- Add input validation to DashboardPage lookup() so invalid keys are
  rejected before any fetch is fired
- Add frontend/src/utils/stellar.test.ts with 19 regression tests:
  keys containing 0/1/8/9 now return false, valid A-Z2-7 keys pass,
  edge cases (wrong length, wrong prefix, empty string) all covered
- Update accessibility.test.tsx: DashboardPage test now types a valid
  key so the mocked network error path is exercised as intended
- Fix pre-existing QueuesPage test failure: add IntersectionObserver
  no-op stub in setupTests.ts (jsdom does not implement this API)
- Fix pre-existing enrollment success test: use findAllByRole('status')
  since QueuePage correctly renders two live regions simultaneously

All 59 tests pass (11 test files).
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

@Unclebaffa is attempting to deploy a commit to the Deejah Team on Vercel.

A member of the Team first needs to authorize it.

@k-deejah

Copy link
Copy Markdown
Collaborator

well done so far, but please resolve conflicts and ci

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Frontend: QueuePage looksLikeStellar regex admits invalid base32 characters — 0,1,8,9 accepted

2 participants