Look-alike handles.User.normalize already refuses two accounts differing only in
case — its own comment calls that an impersonation primitive. A digit drawn like a letter
is the same attack: paulh1tt beside paulhitt.
User.confusableSkeleton folds ten single-character swaps, stored in an indexed username_skeleton column so the check is a lookup, not a scan.
Both creation paths.signup, and the provisioning route for accounts
authenticated elsewhere — a check on only the password path is one an impersonator walks
around.
Deliberately not rn → m. Real, but it folds corner into comer, and
refusing an ordinary word costs a legitimate sign-up. testOrdinaryDifferentNamesDoNotCollide holds that line.
The migration backfills, or every existing account stays freely impersonable.
Folded in Swift, not SQL, so the mapping cannot drift from a second copy.
Throwaway addresses. Short built-in list, extendable via FN_DISPOSABLE_EMAIL_DOMAINS, matches domain and subdomains. Not a security control —
it raises the floor on bulk sign-ups, and the email is how somebody gets back in.
Tests: 9 new, proven able to fail (weakening the fold turns the look-alike test red on
four pairs). 470 tests in 40 suites still pass.
Not deployed and not to be deployed from this MR. Adds a migration that runs at
boot; production is fine as it stands.
Closes part of #42.
**Look-alike handles.** `User.normalize` already refuses two accounts differing only in
case — its own comment calls that an impersonation primitive. A digit drawn like a letter
is the same attack: `paulh1tt` beside `paulhitt`.
`User.confusableSkeleton` folds ten single-character swaps, stored in an indexed
`username_skeleton` column so the check is a lookup, not a scan.
**Both creation paths.** `signup`, and the provisioning route for accounts
authenticated elsewhere — a check on only the password path is one an impersonator walks
around.
**Deliberately not `rn` → `m`.** Real, but it folds `corner` into `comer`, and
refusing an ordinary word costs a legitimate sign-up.
`testOrdinaryDifferentNamesDoNotCollide` holds that line.
**The migration backfills**, or every existing account stays freely impersonable.
Folded in Swift, not SQL, so the mapping cannot drift from a second copy.
**Throwaway addresses.** Short built-in list, extendable via
`FN_DISPOSABLE_EMAIL_DOMAINS`, matches domain and subdomains. Not a security control —
it raises the floor on bulk sign-ups, and the email is how somebody gets back in.
**Tests:** 9 new, proven able to fail (weakening the fold turns the look-alike test red on
four pairs). 470 tests in 40 suites still pass.
**Not deployed and not to be deployed from this MR.** Adds a migration that runs at
boot; production is fine as it stands.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes part of #42.
Look-alike handles.
User.normalizealready refuses two accounts differing only incase — its own comment calls that an impersonation primitive. A digit drawn like a letter
is the same attack:
paulh1ttbesidepaulhitt.User.confusableSkeletonfolds ten single-character swaps, stored in an indexedusername_skeletoncolumn so the check is a lookup, not a scan.Both creation paths.
signup, and the provisioning route for accountsauthenticated elsewhere — a check on only the password path is one an impersonator walks
around.
Deliberately not
rn→m. Real, but it foldscornerintocomer, andrefusing an ordinary word costs a legitimate sign-up.
testOrdinaryDifferentNamesDoNotCollideholds that line.The migration backfills, or every existing account stays freely impersonable.
Folded in Swift, not SQL, so the mapping cannot drift from a second copy.
Throwaway addresses. Short built-in list, extendable via
FN_DISPOSABLE_EMAIL_DOMAINS, matches domain and subdomains. Not a security control —it raises the floor on bulk sign-ups, and the email is how somebody gets back in.
Tests: 9 new, proven able to fail (weakening the fold turns the look-alike test red on
four pairs). 470 tests in 40 suites still pass.
Not deployed and not to be deployed from this MR. Adds a migration that runs at
boot; production is fine as it stands.
mentioned in commit flamenet-messenger-ios@6407448af2ded8a9fe95b113b8a98f2624304396
mentioned in merge request flamenet-messenger-ios!45
mentioned in commit flamenet-messenger-android@e5f4397b28fa8ccaf3cfa7be8f769386a5454892
mentioned in merge request flamenet-messenger-android!9
mentioned in merge request !25
added 31 commits
main54e1c2b9- Refuse look-alike handles and throwaway addresses at sign-upCompare with previous version
mentioned in commit
67b7e2196cmentioned in commit flamenet-messenger-ios@77b3581f16db331996cd6a493fb8b756c4578034
mentioned in merge request flamenet-messenger-ios!91
mentioned in commit flamenet-messenger-android@8a1a51073e984e0f6a59584548ab4a537e5f1576
changed the description