All checks were successful
Testar e publicar imagem Docker / publish (push) Successful in 44s
64 lines
5.1 KiB
JavaScript
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 });
|
|
}
|
|
});
|