mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: remember restored sign-ins only when the restoring account is remembered
This commit is contained in:
@@ -39,7 +39,7 @@ const FEATURE_GATE_LABELS: Partial<Record<keyof FeatureGates, { label: string; d
|
||||
crossStarredViewEnabled: { label: 'Unified Mailbox: Starred', description: 'Allow a "Starred" entry in the Unified Mailbox section that lists flagged/starred mail across the account and its shared folders (or every account when the cross-account sub-option is on). Honors the user\'s folder selection. Requires the matching per-user toggle in Settings → Appearance.' },
|
||||
crossAllViewEnabled: { label: 'Unified Mailbox: All Mail', description: 'Allow an "All mail" entry in the Unified Mailbox section that lists all mail across the account and its shared folders (or every account when the cross-account sub-option is on). Honors the user\'s folder selection. Requires the matching per-user toggle in Settings → Appearance.' },
|
||||
unifiedCrossAccountEnabled: { label: 'Unified Mailbox: Cross-account', description: 'Allow users to expand the Unified Mailbox beyond the active account boundary so its lists merge across every logged-in account. When off, the Unified Mailbox stays within the active account and its shared folders.' },
|
||||
accountArchiveEnabled: { label: 'Account List Backup', description: 'Let users save their list of accounts (address, server, label, colour) on this server, encrypted in the browser with a password of their choice, and restore it on another device. No mailbox passwords are stored. Archives live in SETTINGS_DATA_DIR/account-archives; requires SESSION_SECRET.' },
|
||||
accountArchiveEnabled: { label: 'Account List Backup', description: 'Let users save their list of accounts (address, server, label, colour) on this server, encrypted in the browser with a password of their choice, and restore it on another device. Mailbox passwords are stored only when the Passwords option below is on. Archives live in SETTINGS_DATA_DIR/account-archives; requires SESSION_SECRET.' },
|
||||
accountArchivePasswordsEnabled: { label: 'Account List Backup: Passwords', description: 'With Account List Backup on, offer to include the mailbox passwords of accounts signed in with a password, so a restore signs in to them by itself. They are encrypted in the browser with the backup password together with the list; the server never sees them in clear, but anyone who learns the backup password gets every mailbox in it. Accounts signed in with OAuth or a TOTP code are saved without.' },
|
||||
customFromEnabled: { label: 'Custom From Address', description: 'Let users type any sender address in the composer instead of picking one of their identities, and let replies to a catch-all address on their domain send from that address. Turn this off when users may only send as their configured identities.' },
|
||||
archiveActionEnabled: { label: 'Archive Action', description: 'Offer "Archive" on messages: the toolbar button, the context menu and selection bar, the hover and swipe actions, the E shortcut and archiving after an export. Turn this off when mail is archived elsewhere, for example by a mail gateway; existing Archive folders stay as ordinary folders and Bulwark no longer creates one.' },
|
||||
|
||||
@@ -59,10 +59,26 @@ describe('restoreArchive', () => {
|
||||
});
|
||||
const result = await restoreArchive([entry('a@example.com', 'right'), entry('b@example.com', 'stale'), entry('c@example.com')], true);
|
||||
expect(auth.signIn).toHaveBeenCalledTimes(2);
|
||||
expect(auth.signIn).toHaveBeenCalledWith(generateAccountId('a@example.com', server), 'right', true);
|
||||
expect(auth.signIn).toHaveBeenCalledWith(generateAccountId('a@example.com', server), 'right', false);
|
||||
expect(result).toMatchObject({ added: 3, signedIn: 1, signInFailed: 1, waiting: 2 });
|
||||
});
|
||||
|
||||
it('remembers the restored sign-ins only when the restoring account is remembered', async () => {
|
||||
auth.signIn.mockResolvedValue(true);
|
||||
const owner = add('owner@example.com', 'basic');
|
||||
useAccountStore.getState().updateAccount(owner, { rememberMe: false });
|
||||
useAccountStore.setState({ activeAccountId: owner });
|
||||
await restoreArchive([entry('a@example.com', 'right')], true);
|
||||
expect(auth.signIn).toHaveBeenLastCalledWith(generateAccountId('a@example.com', server), 'right', false);
|
||||
|
||||
useAccountStore.getState().updateAccount(owner, { rememberMe: true });
|
||||
await restoreArchive([entry('b@example.com', 'right')], true);
|
||||
expect(auth.signIn).toHaveBeenLastCalledWith(generateAccountId('b@example.com', server), 'right', true);
|
||||
|
||||
await restoreArchive([entry('c@example.com', 'right')], false);
|
||||
expect(auth.signIn).toHaveBeenLastCalledWith(generateAccountId('c@example.com', server), 'right', false);
|
||||
});
|
||||
|
||||
it('does not sign in again to an account already connected here', async () => {
|
||||
const id = add('a@example.com', 'basic');
|
||||
auth.clients.set(id, { getBasicPassword: () => 'right' });
|
||||
|
||||
@@ -75,8 +75,15 @@ export function restoreAccounts(archived: ArchivedAccount[]): { added: number; u
|
||||
* Restores the list, then signs in one by one to the accounts saved with a
|
||||
* password that are not signed in here yet. An account whose password no
|
||||
* longer works keeps waiting for a sign-in by hand.
|
||||
*
|
||||
* A restored sign-in is remembered only when the server allows it and the
|
||||
* account doing the restore was itself signed in with "Remember me": on a
|
||||
* shared computer, restoring must not leave long-lived sessions behind.
|
||||
*/
|
||||
export async function restoreArchive(archived: ArchivedAccount[], rememberMe: boolean) {
|
||||
export async function restoreArchive(archived: ArchivedAccount[], rememberMeAllowed: boolean) {
|
||||
const accounts = useAccountStore.getState();
|
||||
const active = accounts.accounts.find(a => a.id === accounts.activeAccountId);
|
||||
const rememberMe = rememberMeAllowed && !!active?.rememberMe;
|
||||
const result = restoreAccounts(archived);
|
||||
let signedIn = 0, signInFailed = 0;
|
||||
for (const entry of archived) {
|
||||
|
||||
Reference in New Issue
Block a user