Validate the username and email against every system they are projected into #151

Stängd
öppnade 2026-08-02 12:30:06 +00:00 av supernaut · 0 kommentarer
Ägare

The sign-up endpoint validates the username with /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,39}$/ and the
email with /^[^\s@]+@[^\s@]+\.[^\s@]+$/. Both comments say the identity provider is "the final
authority on validity", but neither rule matches its rules, and neither encodes the git host's
rules at all.

A value that the portal accepts can therefore be rejected downstream. The worst case is silent:
the identity provider accepts the name, the account is created, the set-up email is sent, the
password is set — and then the first sign-in to the git host fails with a 500, because the name is
reserved there. Nothing is shown to the user and nothing is logged.

Examples that pass sign-up today and produce an unusable account:

  • trailing or doubled separators: alice., bob-, a--b, foo..bar
  • reserved names: api, explore, metrics, user, repo, org, issues, pulls,
    notifications, ghost, robots.txt, sitemap.xml, favicon.ico
  • reserved suffixes: alice.keys, alice.png, alice.rss
  • names already taken by an organisation or an automation account

Examples that fail at the identity provider with an unexplained "check your details":

  • a leading digit: 7alice
  • anything that parses as a UUID
  • a non-ASCII address: användare@example.se — likely on a Swedish service

And one that succeeds while diverging: an uppercase username is silently lower-cased by the
identity provider, so the consent record we write (keyed on the submitted spelling) no longer
matches the account that exists.

What to do

Add one module — src/lib/identity-rules.ts — that is the single source of truth, and have
sign-up, the account panel and the client-side pattern attributes all read from it.

Username, the intersection of all three systems:

  • ^[a-z][a-z0-9._-]{0,39}$ — lower-case only, must start with a letter
  • reject /[-._]{2,}/ and /[-._]$/
  • reject the git host's reserved names and the .keys .gpg .rss .atom .png suffixes
  • reject root and anything that parses as a UUID
  • reject names held by an organisation or an automation account

Normalisation is visible at the form. Lower-case the value in the field as the user types, so
what they see is what is provisioned in every system. The identity provider lower-cases silently
already; doing it visibly removes the divergence instead of hiding it, and keeps the consent record
and the provisioned account in agreement by construction.

Email: keep the trim + lower-case + 254 cap, and replace the shape check with the identity
provider's own rule (the WHATWG <input type=email> pattern), which is the strictest of the three.
De-duplicate it — the same regex is currently copied into two modules.

Definition of done

  • one module, imported by every surface that validates these fields; no duplicated regex
  • the username field lower-cases visibly on input, and the submitted value is already normalised
  • a test per downstream rule, each naming the system it protects and citing the upstream source, so
    an upgrade that changes a rule fails a test instead of a user
  • the reserved list carries the pinned upstream version in a comment
  • a specific message per failure reason, not one "check your details" for all of them
  • audit existing consent rows for a case mismatch against the provisioned accounts and correct any

Part of gitborg/gitborg-docs#66.

The sign-up endpoint validates the username with `/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,39}$/` and the email with `/^[^\s@]+@[^\s@]+\.[^\s@]+$/`. Both comments say the identity provider is "the final authority on validity", but neither rule matches its rules, and neither encodes the git host's rules at all. A value that the portal accepts can therefore be rejected downstream. The worst case is silent: the identity provider accepts the name, the account is created, the set-up email is sent, the password is set — and then the first sign-in to the git host fails with a 500, because the name is reserved there. Nothing is shown to the user and nothing is logged. Examples that pass sign-up today and produce an unusable account: - trailing or doubled separators: `alice.`, `bob-`, `a--b`, `foo..bar` - reserved names: `api`, `explore`, `metrics`, `user`, `repo`, `org`, `issues`, `pulls`, `notifications`, `ghost`, `robots.txt`, `sitemap.xml`, `favicon.ico` - reserved suffixes: `alice.keys`, `alice.png`, `alice.rss` - names already taken by an organisation or an automation account Examples that fail at the identity provider with an unexplained "check your details": - a leading digit: `7alice` - anything that parses as a UUID - a non-ASCII address: `användare@example.se` — likely on a Swedish service And one that succeeds while diverging: an uppercase username is silently lower-cased by the identity provider, so the consent record we write (keyed on the submitted spelling) no longer matches the account that exists. ## What to do Add one module — `src/lib/identity-rules.ts` — that is the single source of truth, and have sign-up, the account panel and the client-side `pattern` attributes all read from it. Username, the intersection of all three systems: - `^[a-z][a-z0-9._-]{0,39}$` — lower-case only, must start with a letter - reject `/[-._]{2,}/` and `/[-._]$/` - reject the git host's reserved names and the `.keys` `.gpg` `.rss` `.atom` `.png` suffixes - reject `root` and anything that parses as a UUID - reject names held by an organisation or an automation account **Normalisation is visible at the form.** Lower-case the value in the field as the user types, so what they see is what is provisioned in every system. The identity provider lower-cases silently already; doing it visibly removes the divergence instead of hiding it, and keeps the consent record and the provisioned account in agreement by construction. Email: keep the trim + lower-case + 254 cap, and replace the shape check with the identity provider's own rule (the WHATWG `<input type=email>` pattern), which is the strictest of the three. De-duplicate it — the same regex is currently copied into two modules. ## Definition of done - one module, imported by every surface that validates these fields; no duplicated regex - the username field lower-cases visibly on input, and the submitted value is already normalised - a test per downstream rule, each naming the system it protects and citing the upstream source, so an upgrade that changes a rule fails a test instead of a user - the reserved list carries the pinned upstream version in a comment - a specific message per failure reason, not one "check your details" for all of them - audit existing consent rows for a case mismatch against the provisioned accounts and correct any Part of gitborg/gitborg-docs#66.
supernaut lade till detta till projektet Bitborg Web 2026-08-02 12:34:19 +00:00
Logga in för att delta i denna konversation.
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-web#151
Ingen beskrivning angiven.