Files
HamHam/tests/e2e/mail.spec.ts

119 lines
3.9 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { SMTPServer } from 'smtp-server';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import postgres from 'postgres';
test('encrypted SMTP credentials, real TLS delivery and optional login alerts', async ({
request,
}) => {
const messages: string[] = [];
const recipients: string[] = [];
const server = new SMTPServer({
secure: true,
key: readFileSync(join(process.env.TEST_TLS_DIR!, 'key.pem')),
cert: readFileSync(join(process.env.TEST_TLS_DIR!, 'cert.pem')),
onAuth(auth, _session, done) {
if (auth.username === 'testmailer' && auth.password === 'smtp-test-password')
done(null, { user: 'testmailer' });
else done(new Error('Invalid credentials'));
},
onData(stream, session, done) {
let message = '';
stream.on('data', (chunk) => {
message += chunk.toString();
});
stream.on('end', () => {
messages.push(message);
recipients.push(...session.envelope.rcptTo.map((r) => r.address));
done();
});
},
});
await new Promise<void>((resolve, reject) => {
server.on('error', reject);
server.listen(15440, '127.0.0.1', resolve);
});
const db = postgres(process.env.TEST_DATABASE_URL!, { max: 1 });
const password = process.env.TEST_PASSWORD!;
const headers = {
origin: 'http://localhost:3100',
'x-forwarded-for': '1.2.3.4, 2001:db8::123',
'user-agent': 'HamHam-TestBrowser',
};
const mail = {
host: '127.0.0.1',
port: 15440,
secure: true,
username: 'testmailer',
password: 'smtp-test-password',
from: 'hamham@example.org',
};
try {
expect(
(
await request.post('/api/auth/login', {
headers,
data: { username: 'testadmin', password },
})
).status(),
).toBe(200);
expect(
(
await request.put('/api/settings/mail', {
headers,
data: { password, email: 'admin@example.org', loginNotifications: true, mail },
})
).status(),
).toBe(200);
expect((await request.post('/api/settings/mail/test', { headers })).status()).toBe(200);
expect(messages).toHaveLength(1);
expect(recipients).toEqual(['admin@example.org']);
await request.post('/api/auth/logout', { headers });
expect(
(
await request.post('/api/auth/login', {
headers,
data: { username: 'testadmin', password },
})
).status(),
).toBe(200);
await expect
.poll(
async () => (await (await request.get('/api/auth/security')).json()).events[0].mail_status,
)
.toBe('sent');
expect(messages).toHaveLength(2);
expect(messages[1]).toContain('HamHam-TestBrowser');
expect(messages[1]).toContain('2001:db8::123');
expect(messages[1]).not.toContain('1.2.3.4');
expect(messages[1]).not.toContain(password);
expect(
(
await request.put('/api/settings/mail', {
headers,
data: {
password,
email: 'admin@example.org',
loginNotifications: false,
mail: { ...mail, password: '' },
},
})
).status(),
).toBe(200);
expect((await request.post('/api/settings/mail/test', { headers })).status()).toBe(200);
expect(messages).toHaveLength(3); // Blank password preserved the encrypted credential.
await request.post('/api/auth/logout', { headers });
await request.post('/api/auth/login', { headers, data: { username: 'testadmin', password } });
expect((await (await request.get('/api/auth/security')).json()).events[0].mail_status).toBe(
'disabled',
);
expect(messages).toHaveLength(3);
} finally {
await db`UPDATE admin_security SET login_notifications = false`;
await db`DELETE FROM mail_config`;
await db.end();
await new Promise<void>((resolve) => server.close(resolve));
}
});