mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-19 17:25:19 +03:00
fix(api): a misshapen id is bad input, not a server fault
Ids are stored in a fixed-width column, so an overlong one is refused by Postgres rather than simply matching nothing. That refusal is not a foreign-key violation, so it fell through to the global error boundary and reached the caller as a 500 — telling a host to retry something that can never succeed. Measured: a 44-character user id returned 500, where an absent but well-formed one correctly returned 404. `Identifier.schema` is the natural place for the check and had no callers yet, so it now asserts the exact width an id has as well as its prefix — including the separator, without which `usrsomething` reads as a user id. The enrolment schema uses it for both foreign keys, so the refusal happens where the input arrives and names the field. Also index `steam_enrolment.user_id`. The primary key begins with the machine, which answers what one host holds and nothing else, so neither of the two things that read by user alone can use it: the cascade behind deleting a user, and asking which hosts hold a token for one person. The table's migration has not been released, so this is folded into it rather than following it with a correction.
This commit is contained in:
@@ -27,8 +27,24 @@ export namespace Identifier {
|
||||
refreshToken: 'rft'
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* An id as this control plane issues them: the right prefix, and the exact
|
||||
* width the column has.
|
||||
*
|
||||
* The width is the half that matters at an API boundary. Ids are stored in
|
||||
* a fixed-width column, so an overlong string is *refused by the database*
|
||||
* rather than simply not matching anything — which surfaces to the caller
|
||||
* as a server fault instead of the validation error it actually is.
|
||||
* Checking it where the input arrives is what keeps the two apart.
|
||||
*
|
||||
* The separator is part of the prefix check for the same reason: without
|
||||
* it, `usrsomething` reads as a user id.
|
||||
*/
|
||||
export function schema(prefix: keyof typeof prefixes) {
|
||||
return z.string().startsWith(prefixes[prefix]);
|
||||
return z
|
||||
.string()
|
||||
.startsWith(`${prefixes[prefix]}_`)
|
||||
.length(prefixes[prefix].length + 1 + LENGTH);
|
||||
}
|
||||
|
||||
const LENGTH = 26;
|
||||
|
||||
Reference in New Issue
Block a user