Skip to content

fix(#48): username confusable protection#50

Open
DSanich wants to merge 2 commits into
divinevideo:mainfrom
DSanich:fix/48-username-confusable-protection
Open

fix(#48): username confusable protection#50
DSanich wants to merge 2 commits into
divinevideo:mainfrom
DSanich:fix/48-username-confusable-protection

Conversation

@DSanich
Copy link
Copy Markdown

@DSanich DSanich commented May 18, 2026

Summary

  • Added protection against visually confusable usernames (homographs / cross-script lookalikes) using a skeleton check (via namespace-guard) on registration-related flows.
  • Applied NFKC normalization at the start of validateUsername so equivalent Unicode representations collapse before other rules run.
  • New DB helper getPotentialConfusableUsernames and utility module src/utils/username-confusable.ts (including shared getConfusableCollision).
  • Public routes: GET /api/username/check/:name, POST /api/username/reserve, POST /api/username/claim — reject with clear messaging; check returns code: "confusable" when applicable.
  • Admin routes: POST .../reserve, reserve-bulk, assign, assign-bulk — same rules; bulk failures for confusables use a consistent status: "confusable" (aligned between reserve-bulk and assign-bulk).
  • Tests for routes, username-confusable, and NFKC in validation; separate commit adjusts nip05-status expectations for revoked users when the Fastly key is absent.

Motivation

  • Reduces identity-spoofing risk for NIP-05: different bytes/canonical labels (e.g. Latin vs Cyrillic in the same visual slot) that would otherwise both verify.
  • Matches the issue recommendation: skeleton-style detection + NFKC, without dropping IDN support and without running confusable checks on NIP-05 read/lookup paths.

Related Issue

Validation

  • npm run test:once
  • npm run build:admin
  • relevant local Wrangler validation if applicable
  • I could not run some validation locally, and I explained why below

Manual Test Plan / Notes

  • Public: GET /api/username/check/... for a string that looks like an existing name but uses a different script — expect available: false, code: "confusable", HTTP 200.
  • POST /api/username/reserve and POST /api/username/claim with such a name — HTTP 409 and an error mentioning visually confusable.
  • Admin: single reserve/assign and bulk paths reject confusable collisions; for reserve-bulk / assign-bulk, failed rows have success: false and status: "confusable".
  • Regression: NIP-05 name resolution behavior unchanged (checks are on write/registration paths only).
  • Optional follow-up from the issue: audit existing DB rows for confusable pairs (not part of this change).

Visuals / API Examples

  • No visual change
  • Screenshots, sample payloads, or logs attached if needed

Example check response when an existing matt collides with a visually similar label that punycodes differently:

{
  "ok": true,
  "available": false,
  "name": "",
  "canonical": "",
  "code": "confusable",
  "reason": "Username is visually confusable with existing name \"matt\""
}

DSanich added 2 commits May 18, 2026 14:50
Normalize usernames with NFKC before validation, add namespace-guard
skeleton collision checks on public check/reserve/claim and admin
assign/reserve paths (including bulk).
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.

fix: add confusable/homograph protection to username validation

1 participant