mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 16:16:49 +00:00
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.
50 lines
1.9 KiB
TypeScript
50 lines
1.9 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef } from 'react';
|
|
import { useTranslations } from 'next-intl';
|
|
import { consumeWipeNote, onRefusedLoginsChanged, takeSiblingToasts, waitDate, type WipeNote } from '@/lib/devices/wipe-state';
|
|
import { startDeviceWipe } from '@/lib/offline/device-wipe';
|
|
import { useAuthStore } from '@/stores/auth-store';
|
|
import { toast } from '@/stores/toast-store';
|
|
|
|
/** What a wipe left to say, as a sentence. Counts only. */
|
|
export function wipeNoteText(note: WipeNote, t: (key: string, values?: { count: number }) => string): string {
|
|
if (note.unknown) return t('note_unknown');
|
|
return note.unsent > 0 ? t('note_unsent', { count: note.unsent }) : t('note');
|
|
}
|
|
|
|
/**
|
|
* Runs the device's side of wipes on every page, the sign-in page too, so a
|
|
* device with nobody signed in still finishes a wipe and hears about a new one.
|
|
* When another account stays signed in, the note about lost mail is a toast here;
|
|
* otherwise the sign-in page shows it. Not mounted in Lite.
|
|
*/
|
|
export function DeviceWipeHost() {
|
|
const t = useTranslations('offlineWipe');
|
|
const tRef = useRef(t);
|
|
tRef.current = t;
|
|
const signedIn = useAuthStore((state) => state.isAuthenticated);
|
|
|
|
useEffect(() => startDeviceWipe(), []);
|
|
|
|
useEffect(() => {
|
|
if (!signedIn) return;
|
|
const note = consumeWipeNote();
|
|
if (note) toast.warning(wipeNoteText(note, tRef.current), { duration: 0 });
|
|
}, [signedIn]);
|
|
|
|
// An account beside this one signed out by itself: once, when it's known what waits.
|
|
useEffect(() => {
|
|
const look = () => {
|
|
for (const wait of takeSiblingToasts(useAuthStore.getState().activeAccountId)) {
|
|
const values = { name: wait.label, date: waitDate(wait.until) };
|
|
toast.warning(wait.unsent ? tRef.current('sibling_waiting', { ...values, count: wait.unsent }) : tRef.current('sibling_kept', values), { duration: 0 });
|
|
}
|
|
};
|
|
look();
|
|
return onRefusedLoginsChanged(look);
|
|
}, []);
|
|
|
|
return null;
|
|
}
|