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'));