Files
webmail/lib/offline/credentials-rejected.ts
T
Linus Rath af6cdfb997 fix: keep unsent mail through the idle and session limits, and mark a signed-out account in the switcher
The timers used to delete everything an account kept, unsent mail included.
They now follow the refused-login rule: sign out and hide, the next sign-in
brings it back, otherwise it goes after 30 days. A login without "Remember
me" that ends with the browser, an admin wipe and a wipe from settings don't
change.

- `wipeOnRefusedLogin` is now `wipeOnForcedSignOut`, since it also covers the
  limits. The server's `SESSION_TOO_OLD` goes the same way, as `session`.
- A refused account beside one that stays signed in shows in the switcher as
  needing sign-in, with the count and the date, and gets one toast.

Existing tests changed because the rule did: the session timer tests expected
a plain `logoutAll`, and the auth store tests expected no hook at the session
limit.
2026-11-03 16:36:13 +01:00

32 lines
1.2 KiB
TypeScript

/**
* A login ended with nobody asking. `refused`: the server refused it, by
* `invalid_grant` or a lasting 401 after a fresh try (both `certain`), or a 401 at a
* connect that then failed (not, it's one answer). `session`: the organisation's
* idle or session limit. The auth store follows with a sign-out that hides the
* account's data, which waits for the next sign-in. An outage or any other refusal
* doesn't come here. lib/offline/device-wipe.ts listens, to keep the count for the
* sign-in page and to delete at once where the organisation asks for that. Free of
* the stores, so the auth store can call it.
*/
export type ForcedSignOutKind = 'refused' | 'session';
type Listener = (accountId: string, certain: boolean, kind: ForcedSignOutKind) => void;
const listeners = new Set<Listener>();
export function onCredentialsRejected(listener: Listener): () => void {
listeners.add(listener);
return () => listeners.delete(listener);
}
export function noteCredentialsRejected(accountId: string, certain = true, kind: ForcedSignOutKind = 'refused'): void {
for (const listener of [...listeners]) {
try {
listener(accountId, certain, kind);
} catch {
// A sign-out must go on whatever a listener does.
}
}
}