lat and long
This commit is contained in:
@@ -77,6 +77,60 @@ export async function login(email: string, password: string): Promise<SessionUse
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* What the next step is for this email — before anyone types a password.
|
||||
*
|
||||
* `'setup'` means the account exists and has never had a password; `'password'`
|
||||
* means it has one. Anything else throws with a message worth showing.
|
||||
*
|
||||
* ── Why probe at all ─────────────────────────────────────────────────────────
|
||||
*
|
||||
* A tenant created by `createtenantuser`, and every branch created by
|
||||
* `createtenantlocation`, is spawned with an EMPTY password. Their owner's
|
||||
* first sign-in therefore cannot succeed, and asking them for a password first
|
||||
* asks for something that does not exist — they type a guess, watch it fail,
|
||||
* and only then are told to invent one. The old console avoids that by checking
|
||||
* the email before the password field is ever shown, and it is right to.
|
||||
*
|
||||
* ── How one endpoint answers two questions ───────────────────────────────────
|
||||
*
|
||||
* There is no lookup endpoint. This posts to `applogin` with no password at
|
||||
* all, which `userService.go:64-123` answers in four distinguishable ways:
|
||||
*
|
||||
* 409 + status false → no such account ("Invalid Email")
|
||||
* 403 → account deactivated
|
||||
* 409 + status true → exists, no password set (carries the userid)
|
||||
* 401 + status true → exists, has a password ("Password is required")
|
||||
*
|
||||
* The last one is the whole trick: a password-less attempt against a real
|
||||
* account is refused with a DIFFERENT code than a wrong password, so existence
|
||||
* can be established without guessing at one.
|
||||
*
|
||||
* This does tell an anonymous caller whether an email has an account here. That
|
||||
* is a real disclosure and worth naming — but the login already answers
|
||||
* "Invalid Email" versus "Incorrect password" to any caller who sends a wrong
|
||||
* password, so the probe reveals nothing that was not already available with
|
||||
* one more field filled in.
|
||||
*/
|
||||
export type AccountCheck = { state: 'password' } | { state: 'setup'; userid: number };
|
||||
|
||||
export async function checkAccount(email: string): Promise<AccountCheck> {
|
||||
const envelope = await api.envelope<{ setup?: boolean; userid?: number }>(
|
||||
`${WEB}/users/applogin`,
|
||||
{ method: 'POST', body: { authname: email.trim(), configid: CONFIG_ID } },
|
||||
);
|
||||
|
||||
if (envelope.code === 409 && envelope.details?.setup === true) {
|
||||
return { state: 'setup', userid: envelope.details.userid ?? 0 };
|
||||
}
|
||||
// "Password is required" — the account is real and has one. Exactly what we
|
||||
// wanted to learn, arriving as a refusal.
|
||||
if (envelope.code === 401) {
|
||||
return { state: 'password' };
|
||||
}
|
||||
throw new Error(loginMessage(envelope.code, envelope.message));
|
||||
}
|
||||
|
||||
/** The backend's floor, enforced here too so the refusal is instant. */
|
||||
export const MIN_PASSWORD_LENGTH = 6;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user