ts6-botflow/auth.test.mjs
Bxio 1be8a45dde
All checks were successful
Testar e publicar imagem Docker / publish (push) Successful in 44s
Expand flow editor with TeamSpeak events, permissions and execution controls
2026-10-10 20:38:31 +01:00

64 lines
5.1 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createApp } from './server.mjs';
test('OAuth rejects strangers, invalid state and replay; both owners can write and readers cannot', async () => {
const directory = mkdtempSync(join(tmpdir(), 'botflow-test-'));
let profileId = '999999999999999999';
let requests = 0;
const server = createApp({ env: { DATA_DIR: directory, APP_URL: 'http://localhost:3080', DISCORD_CLIENT_ID: 'client', DISCORD_CLIENT_SECRET: 'secret', OWNER_DISCORD_ID: '376768118535749633, 723613831196311603', ALLOWED_DISCORD_IDS: '222222222222222222,723613831196311603' }, discordFetch: async (url) => {
requests++;
return { ok: true, json: async () => url.endsWith('/token') ? { access_token: 'temporary' } : { id: profileId, username: 'bxio' } };
} });
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
const base = `http://127.0.0.1:${server.address().port}`;
const request = (path, options = {}) => fetch(base + path, { redirect: 'manual', ...options });
const begin = async () => { const response = await request('/auth/discord'); const state = new URL(response.headers.get('location')).searchParams.get('state'); return { state, cookie: `oauth_state=${state}` }; };
try {
assert.equal((await request('/')).status, 200);
assert.equal((await request('/api/dashboard')).status, 401);
assert.equal((await request('/flow-editor.js')).status, 200);
assert.equal((await request('/api/hooks/missing', { method: 'POST', body: '{}' })).status, 404);
assert.equal((await request('/auth/discord/callback?state=fake&code=code', { headers: { Cookie: 'oauth_state=fake' } })).headers.get('location'), '/?error=authentication');
assert.equal(requests, 0);
const outsider = await begin();
const denied = await request(`/auth/discord/callback?state=${outsider.state}&code=code`, { headers: { Cookie: outsider.cookie } });
assert.equal(denied.headers.get('location'), '/?error=denied');
profileId = '222222222222222222';
const reader = await begin();
const readerLogin = await request(`/auth/discord/callback?state=${reader.state}&code=code`, { headers: { Cookie: reader.cookie } });
assert.equal(readerLogin.headers.get('location'), '/');
const readerCookie = readerLogin.headers.getSetCookie().find(v => v.startsWith('session=')).split(';')[0];
const readerProfile = await (await request('/api/me', { headers: { Cookie: readerCookie } })).json();
assert.equal(readerProfile.user.role, 'Leitor');
assert.equal((await request('/api/dashboard', { headers: { Cookie: readerCookie } })).status, 200);
assert.equal((await request('/api/bots', { method: 'POST', headers: { Cookie: readerCookie, Origin: 'http://localhost:3080', 'Content-Type': 'application/json' }, body: JSON.stringify({name:'Reader bot'}) })).status, 403);
profileId = '723613831196311603';
const secondOwner = await begin();
const secondLogin = await request(`/auth/discord/callback?state=${secondOwner.state}&code=code`, { headers: { Cookie: secondOwner.cookie } });
assert.equal(secondLogin.headers.get('location'), '/');
const secondCookie = secondLogin.headers.getSetCookie().find(v => v.startsWith('session=')).split(';')[0];
assert.equal((await (await request('/api/me', { headers: { Cookie: secondCookie } })).json()).user.role, 'Dono');
assert.equal((await request('/api/bots', { method: 'POST', headers: { Cookie: secondCookie, Origin: 'http://localhost:3080', 'Content-Type': 'application/json' }, body: JSON.stringify({name:'Second owner bot'}) })).status, 201);
profileId = '376768118535749633';
const owner = await begin();
const callback = `/auth/discord/callback?state=${owner.state}&code=code`;
const login = await request(callback, { headers: { Cookie: owner.cookie } });
assert.equal(login.headers.get('location'), '/');
const sessionCookie = login.headers.getSetCookie().find(v => v.startsWith('session=')).split(';')[0];
assert.equal((await (await request('/api/me', { headers: { Cookie: sessionCookie } })).json()).user.role, 'Dono');
assert.equal((await request('/api/dashboard', { headers: { Cookie: sessionCookie } })).status, 200);
assert.equal((await request('/api/bots', { method: 'POST', headers: { Cookie: sessionCookie, Origin: 'http://localhost:3080', 'Content-Type': 'application/json' }, body: JSON.stringify({name:'First owner bot'}) })).status, 201);
assert.equal((await request(callback, { headers: { Cookie: owner.cookie } })).headers.get('location'), '/?error=authentication');
assert.equal((await request('/auth/logout', { method: 'POST', headers: { Cookie: sessionCookie, Origin: 'http://evil.example' } })).status, 403);
assert.equal((await request('/auth/logout', { method: 'POST', headers: { Cookie: sessionCookie, Origin: 'http://localhost:3080' } })).status, 200);
assert.equal((await request('/api/dashboard', { headers: { Cookie: sessionCookie } })).status, 401);
} finally {
await new Promise(resolve => server.close(resolve));
rmSync(directory, { recursive: true, force: true });
}
});