Files
SGF/scripts/http-proof.mjs
T

60 lines
4.3 KiB
JavaScript

import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const base = 'http://127.0.0.1:8001';
const fixture = JSON.parse(await fs.readFile('C:/laragon/data/sgf-tempo/secrets/browser-fixture.json', 'utf8'));
const results = [];
function client() {
const cookies = new Map();
let csrf = ''; let context = '';
return {
cookies,
async request(path, method = 'GET', body, {token = context, csrfHeader = true} = {}) {
const headers = {Accept:'application/json', 'Content-Type':'application/json', Cookie:[...cookies].map(([k,v]) => `${k}=${v}`).join('; '), 'X-SGF-Context':token};
if (csrfHeader) headers['X-CSRF-TOKEN'] = csrf;
const response = await fetch(base+path, {method, headers, ...(body === undefined ? {} : {body:JSON.stringify(body)})});
for (const cookie of response.headers.getSetCookie()) { const pair=cookie.split(';',1)[0]; const split=pair.indexOf('='); cookies.set(pair.slice(0,split),pair.slice(split+1)); }
const data = await response.json().catch(() => ({}));
if (data.csrf) csrf=data.csrf;
if (data.context?.token) context=data.context.token;
return {status:response.status,data};
},
async login(email) {
assert.equal((await this.request('/api/session')).status,200);
assert.equal((await this.request('/api/login','POST',{email,password:fixture.password})).status,200);
},
async select(company=fixture.company,unit=fixture.unit) {
const result=await this.request('/api/context','POST',{tenant_id:fixture.tenant,company_id:company,unit_id:unit});
assert.equal(result.status,200); return result.data.context.token;
}
};
}
const manager=client(); await manager.login('gestor@example.test'); const token=await manager.select();
assert.equal((await manager.request(`/api/companies/${fixture.company}`,'PATCH',{name:'CSRF must refuse'},{csrfHeader:false})).status,419);
results.push('CSRF: pedido de alteração sem token/origem válida recusado (419).');
const reader=client(); await reader.login('consulta@example.test'); const readerToken=await reader.select();
assert.equal((await reader.request(`/api/companies/${fixture.sibling}`)).status,403);
assert.equal((await reader.request(`/api/units/${fixture.hidden}`)).status,403);
assert.equal((await reader.request(`/api/companies/${fixture.company}`,'PATCH',{name:'Not allowed'})).status,403);
results.push('URLs/API: empresa do mesmo tenant e unidade sem acesso recusadas; consulta não permite edição (403).');
const grant={email:'consulta@example.test',permission:'company.edit',reason:'Prova HTTP sintética'};
assert.equal((await manager.request('/api/accesses','POST',grant)).status,200);
assert.equal((await reader.request(`/api/companies/${fixture.company}`,'PATCH',{name:'Empresa Horizonte — Prova HTTP'})).status,200);
assert.equal((await manager.request('/api/accesses/revoke','POST',grant)).status,200);
assert.equal((await reader.request(`/api/companies/${fixture.company}`,'PATCH',{name:'Revoked'})).status,403);
results.push('Concessão e revogação: efeito no pedido seguinte em sessão independente (200 → 403).');
await manager.select(fixture.sibling,null);
assert.equal((await manager.request(`/api/companies/${fixture.company}`,'PATCH',{name:'Stale'},{token})).status,409);
results.push('Formulário anterior à mudança de contexto recusado (409).');
const limited=client(); await limited.login('limitado@example.test'); await limited.select();
assert.equal((await limited.request('/api/accesses','POST',grant)).status,403);
results.push('Gestor limitado não consegue conceder edição que não possui (403).');
const oldCookies=new Map(reader.cookies);
assert.equal((await reader.request('/api/logout','POST')).status,200);
reader.cookies.clear(); for(const [key,value] of oldCookies) reader.cookies.set(key,value);
assert.equal((await reader.request('/api/context')).status,401);
results.push('Replay do cookie da sessão terminada recusado (401).');
await manager.request('/api/logout','POST'); await limited.request('/api/logout','POST');
await fs.writeFile(new URL('../docs/proofs/http-results.json',import.meta.url),JSON.stringify({environment:'sgf_tempo_test, browser-testing, localhost:8001',results},null,2));
console.log(results.join('\n'));