mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
117 lines
5.0 KiB
TypeScript
117 lines
5.0 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { createHash } from 'node:crypto';
|
|
import type { InstalledPlugin } from '../plugin-types';
|
|
|
|
// Copies of the external-mail-warning plugin older than the release that
|
|
// steps back on its own keep their send check. While the organisation's
|
|
// own warnings are on, the host skips that plugin's hooks by id, so the
|
|
// user isn't asked twice; other plugins keep theirs.
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
hooks: [] as string[],
|
|
invokeHook: null as null | ReturnType<typeof vi.fn>,
|
|
}));
|
|
|
|
const CODE = 'export default { activate() {} }';
|
|
const HASH = createHash('sha256').update(CODE, 'utf-8').digest('hex');
|
|
|
|
vi.mock('../plugin-storage', () => ({
|
|
pluginStorage: { getCode: async () => CODE, saveCode: async () => {}, deleteCode: vi.fn() },
|
|
}));
|
|
vi.mock('../plugin-sandbox/bundle-fetch', () => ({ downloadManagedBundle: vi.fn() }));
|
|
vi.mock('../plugin-sandbox/host-bridge', () => ({
|
|
createBackgroundInstance: () => {
|
|
// The old plugin's check: "Send to external recipients?" answered with Cancel.
|
|
const invokeHook = vi.fn(async () => false);
|
|
mocks.invokeHook = invokeHook;
|
|
return {
|
|
initPromise: Promise.resolve({ hooks: mocks.hooks, slots: [], shortcuts: [] }),
|
|
invokeHook,
|
|
destroy: vi.fn(),
|
|
};
|
|
},
|
|
snapshotRegionalSettings: vi.fn((locale: string) => ({ locale, dateLocale: locale, hour12: false, timeZone: 'UTC', firstDayOfWeek: 1 })),
|
|
forEachInstance: vi.fn(),
|
|
SandboxInstance: class {},
|
|
}));
|
|
vi.mock('../plugin-sandbox/host-api', () => ({ cancelPluginDialogs: vi.fn() }));
|
|
vi.mock('../plugin-sandbox/shortcuts', () => ({ registerShortcuts: () => () => {} }));
|
|
|
|
import { loadSandboxedPlugin, unloadSandboxedPlugin, setSandboxStoreAccessor } from '../plugin-sandbox/loader';
|
|
import { emailHooks } from '../plugin-hooks';
|
|
import { DEFAULT_ORGANISATION_POLICY } from '@/lib/admin/organisation-policy';
|
|
import { DEFAULT_POLICY } from '@/lib/admin/types';
|
|
import { usePolicyStore } from '@/stores/policy-store';
|
|
|
|
function plugin(id: string): InstalledPlugin {
|
|
return {
|
|
id, name: id, version: '1.5.1', author: 'someone', description: '', type: 'hook',
|
|
permissions: ['email:send', 'email:read'], entrypoint: 'index.js', enabled: true, status: 'enabled',
|
|
settings: {}, managed: true, adminApproved: true, bundleHash: HASH,
|
|
};
|
|
}
|
|
|
|
function setExternalMail(patch: Partial<typeof DEFAULT_ORGANISATION_POLICY.externalMail>) {
|
|
usePolicyStore.setState({
|
|
policy: {
|
|
...DEFAULT_POLICY,
|
|
organisation: { ...DEFAULT_ORGANISATION_POLICY, externalMail: { ...DEFAULT_ORGANISATION_POLICY.externalMail, ...patch } },
|
|
},
|
|
});
|
|
}
|
|
|
|
const OUTGOING = { to: ['dave@org-two.test'], cc: [], bcc: [], subject: 'Hi' };
|
|
let loaded: string | null = null;
|
|
|
|
beforeEach(() => {
|
|
setSandboxStoreAccessor({ setPluginStatus: () => {} });
|
|
mocks.hooks = ['onBeforeEmailSend', 'onNewEmailReceived'];
|
|
setExternalMail({});
|
|
vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
vi.spyOn(console, 'info').mockImplementation(() => {});
|
|
});
|
|
afterEach(() => {
|
|
if (loaded) unloadSandboxedPlugin(loaded);
|
|
loaded = null;
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe('the retired external-mail-warning plugin', () => {
|
|
it('asks as before while the core warnings are off', async () => {
|
|
loaded = 'external-mail-warning';
|
|
await loadSandboxedPlugin(plugin(loaded));
|
|
expect(await emailHooks.onBeforeEmailSend.interceptOutcome(OUTGOING as never)).toBe('vetoed');
|
|
expect(mocks.invokeHook).toHaveBeenCalledWith('onBeforeEmailSend', [OUTGOING]);
|
|
});
|
|
|
|
it('loses its send check to the recipient warning, and gets it back once that is off', async () => {
|
|
loaded = 'external-mail-warning';
|
|
await loadSandboxedPlugin(plugin(loaded));
|
|
setExternalMail({ recipientWarning: true });
|
|
expect(await emailHooks.onBeforeEmailSend.interceptOutcome(OUTGOING as never)).toBe('allowed');
|
|
expect(mocks.invokeHook).not.toHaveBeenCalled();
|
|
// The toast is about incoming mail: it stays while only the warning is on.
|
|
await emailHooks.onNewEmailReceived.emit({ from: [{ email: 'dave@org-two.test' }] } as never);
|
|
expect(mocks.invokeHook).toHaveBeenCalledWith('onNewEmailReceived', expect.anything());
|
|
|
|
setExternalMail({});
|
|
expect(await emailHooks.onBeforeEmailSend.interceptOutcome(OUTGOING as never)).toBe('vetoed');
|
|
});
|
|
|
|
it('loses its new-mail toast to the sender label but keeps its send check', async () => {
|
|
loaded = 'external-mail-warning';
|
|
await loadSandboxedPlugin(plugin(loaded));
|
|
setExternalMail({ senderLabel: true });
|
|
await emailHooks.onNewEmailReceived.emit({ from: [{ email: 'dave@org-two.test' }] } as never);
|
|
expect(mocks.invokeHook).not.toHaveBeenCalled();
|
|
expect(await emailHooks.onBeforeEmailSend.interceptOutcome(OUTGOING as never)).toBe('vetoed');
|
|
});
|
|
|
|
it('leaves the send checks of other plugins alone', async () => {
|
|
loaded = 'reply-all-guardrail';
|
|
await loadSandboxedPlugin(plugin(loaded));
|
|
setExternalMail({ recipientWarning: true });
|
|
expect(await emailHooks.onBeforeEmailSend.interceptOutcome(OUTGOING as never)).toBe('vetoed');
|
|
});
|
|
});
|