Admin: Gmail and Discord-bot settings for password reset, setup warning on open; export notes admin guard

This commit is contained in:
Jonathan Sykes
2026-10-15 19:02:53 +08:00
parent 69704d3e1a
commit 63cea89b68
5 changed files with 232 additions and 7 deletions

View File

@@ -82,3 +82,33 @@ test('unprotected profiles and unconfigured channels are refused', async () => {
await expect(postWebhook('https://example.com/x', 'hi')).rejects.toThrow(/not a Discord webhook/);
expect(maskEmail('a@b.co')).toBe('a••@b.co');
});
test('admin can save Gmail settings and forward a bot token to the relay', async () => {
const calls = [];
const fakeRelay = async (url, init = {}) => {
calls.push({ url, method: init.method || 'GET', auth: init.headers.Authorization, body: init.body });
const ready = calls.some((x) => x.method === 'PUT');
return new Response(JSON.stringify(url.endsWith('/v1/bot-token') && !JSON.parse(init.body).token.includes('.')
? { ok: false, error: 'that does not look like a Discord bot token' }
: { ok: true, bot_set: ready, gateway: ready, bot: ready ? 'YT Player' : '' }));
};
const admin = new Hono();
const env = { DISCORD_RELAY_URL: 'http://relay:8791/', DISCORD_RELAY_TOKEN: 'r'.repeat(64) };
registerProfileRecoveryRoutes(admin, { db, getProfile, setProfileSecret, profileGate, env, fetchImpl: fakeRelay, adminAuth: async (_c, next) => next() });
const call = async (path, method, body) => { const r = await admin.request(path, { method, headers: { 'content-type': 'application/json' }, body: body && JSON.stringify(body) }); return { status: r.status, json: await r.json() }; };
let s = await call('/api/admin/notify', 'GET');
expect(s.json.email).toMatchObject({ configured: false, source: null });
expect(s.json.discord).toMatchObject({ relay: true, botSet: false, ready: false });
expect((await call('/api/admin/notify', 'PUT', { smtpUser: 'sender@gmail.com' })).status).toBe(400);
s = await call('/api/admin/notify', 'PUT', { smtpUser: 'Sender@Gmail.com', smtpPass: 'abcd efgh ijkl mnop' });
expect(s.json.email).toMatchObject({ configured: true, source: 'admin', user: 'sender@gmail.com', passwordSet: true });
expect(JSON.stringify(s.json)).not.toContain('abcdefghijklmnop');
expect((await call('/api/admin/notify', 'PUT', { discordBotToken: 'junk' })).status).toBe(400);
s = await call('/api/admin/notify', 'PUT', { discordBotToken: 'MTIz.abcd.efgh' });
expect(s.json.discord).toMatchObject({ botSet: true, ready: true, bot: 'YT Player' });
expect(calls.every((x) => x.auth === `Bearer ${'r'.repeat(64)}` && x.url.startsWith('http://relay:8791/v1/'))).toBe(true);
expect((await call('/api/admin/notify/test', 'POST', { via: 'email', to: 'nope' })).json.error).toMatch(/email address/);
s = await call('/api/admin/notify', 'PUT', { smtpUser: '' });
expect(s.json.email.configured).toBe(false);
expect((await db.execute('SELECT COUNT(*) AS n FROM app_settings')).rows[0].n).toBe(0);
});