lat and long

This commit is contained in:
2026-08-27 13:58:19 +05:30
parent 60efac7a7e
commit a214ea67da
15 changed files with 1816 additions and 445 deletions

View File

@@ -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;