Files
webmail/lib/admin/__tests__/server-device-offline-caps.test.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

43 lines
2.3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { DEFAULT_POLICY, type SettingsPolicy } from '../types';
import { ALL_DEVICE_LIMITS, strictestOfAllScopes } from '../server-device-policy';
import { sanitizeOrganisationPartial } from '../organisation-policy';
// The offline caps are numbers in a section that used to hold only booleans.
const scope = (id: string, devices: Record<string, unknown>) => ({ id, label: id, match: { domains: [`${id}.example.org`] }, policy: { organisation: { devices } } });
describe('wipeOnForcedSignOut', () => {
it('is off unless asked for, and survives the sanitizer', () => {
expect(DEFAULT_POLICY.organisation?.devices?.wipeOnForcedSignOut ?? false).toBe(false);
expect(sanitizeOrganisationPartial({ devices: { wipeOnForcedSignOut: true } }).devices).toMatchObject({ wipeOnForcedSignOut: true });
expect(sanitizeOrganisationPartial({ devices: { wipeOnForcedSignOut: 'yes' } }).devices?.wipeOnForcedSignOut).not.toBe(true);
});
it('isn\'t set by the stand-in for a login nobody can read: that\'s for what stays on the server', () => {
expect(ALL_DEVICE_LIMITS.wipeOnForcedSignOut).toBe(false);
});
});
describe('strictest of all scopes', () => {
it('keeps the lowest cap, and a boolean switch still turns on', () => {
const policy = {
...DEFAULT_POLICY,
organisation: { devices: { offlineMaxDays: 90 } },
scopes: [scope('a', { offlineMaxDays: 30, offlineMaxTotalMb: 500 }), scope('b', { offlineMaxDays: 60, noPrint: true })],
} as unknown as SettingsPolicy;
expect(strictestOfAllScopes(policy)).toMatchObject({ offlineMaxDays: 30, offlineMaxTotalMb: 500, offlineMaxAttachmentMb: 0, noPrint: true, noExport: false });
});
it('a scope saying 0 does not lift a cap', () => {
const policy = { ...DEFAULT_POLICY, organisation: { devices: { offlineMaxDays: 90 } }, scopes: [scope('a', { offlineMaxDays: 0 })] } as unknown as SettingsPolicy;
expect(strictestOfAllScopes(policy).offlineMaxDays).toBe(90);
});
});
describe('everything on', () => {
it('holds booleans as true and caps as the lowest number', () => {
expect(ALL_DEVICE_LIMITS).toMatchObject({ noOffline: true, noDownloads: true, noOfflineAttachments: true, offlineMaxDays: 1, offlineMaxAttachmentMb: 1, offlineMaxTotalMb: 1 });
});
});