22 lines
6.4 KiB
JavaScript
22 lines
6.4 KiB
JavaScript
const {start,assert,DIR,path,fs,sanitized,TARGET,BASE}=require('./portal-service-followup-browser-lib.cjs');
|
||
const cp=require('node:child_process'),crypto=require('node:crypto');
|
||
const PHP='C:/laragon/bin/php/php-8.5.11-Win32-vs17-x64/php.exe';
|
||
void(async()=>{const q=await start('service-followup-web-uploads-qa');let ctx;try{
|
||
const a=await q.context('promoter');ctx=a.ctx;const page=a.page;await q.login(page,'promoter');
|
||
const runtime=await q.json(page,'/__qa/services-runtime');assert.equal(runtime.status,200);q.proof.web_runtime=runtime.data;
|
||
assert.equal(runtime.data.sapi,'apache2handler');assert.equal(runtime.data.upload_max_filesize,'20M');assert.equal(runtime.data.post_max_size,'24M');
|
||
async function post(url,data){return await page.evaluate(async({url,data})=>{const token=decodeURIComponent(document.cookie.split('; ').find(v=>v.startsWith('XSRF-TOKEN='))?.slice(11)||'');const r=await fetch(url,{method:'POST',headers:{Accept:'application/json','Content-Type':'application/json','X-XSRF-TOKEN':token},body:JSON.stringify(data)});return {status:r.status,data:await r.json()};},{url,data});}
|
||
const r=await post('/minhas-oportunidades/drafts',{creation_key:crypto.randomUUID(),opportunity_category:'real_estate',title:'SIMULAÇÃO QA — upload superior a 2 MiB e recuperação',reason:'SIMULAÇÃO QA isolada: verificar limites PHP web e supervisão sem efeito jurídico ou divulgação.'});assert.equal(r.status,201);const id=r.data.id;q.proof.opportunity_id=id;q.save();
|
||
async function props(){const r=await q.open(page,`/minhas-oportunidades/${id}/resources`);assert.equal(r.status(),200);const t=await r.text(),enc=t.match(/data-page="([^"]+)"/);return enc&&enc[1].startsWith('{')?JSON.parse(enc[1].replace(/"/g,'"').replace(/&/g,'&').replace(/'/g,"'")).props:JSON.parse(t.match(/<script[^>]*type="application\/json"[^>]*>([\s\S]*?)<\/script>/)[1]).props;}
|
||
// Valid minimal PDF padded with legal comments before xref, no private/reused document.
|
||
function pdf(size){let bytes='%PDF-1.4\n',offset=[0];for(const object of ['<< /Type /Catalog /Pages 2 0 R >>','<< /Type /Pages /Kids [3 0 R] /Count 1 >>','<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] >>']){offset.push(Buffer.byteLength(bytes));bytes+=`${offset.length-1} 0 obj\n${object}\nendobj\n`;}bytes+='% SIMULACAO QA - no legal effect\n';const padding=size-Buffer.byteLength(bytes)-300;bytes+=('%'+ 'Q'.repeat(78)+'\n').repeat(Math.ceil(padding/80));const xref=Buffer.byteLength(bytes);bytes+='xref\n0 4\n0000000000 65535 f \n'+offset.slice(1).map(n=>String(n).padStart(10,'0')+' 00000 n \n').join('')+`trailer\n<< /Size 4 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;return Buffer.from(bytes);}
|
||
const bytes=pdf(2621440),fixture=path.join(DIR,'service-followup-large-qa.pdf');fs.writeFileSync(fixture,bytes);q.proof.upload_bytes=bytes.length;q.proof.upload_sha256=crypto.createHash('sha256').update(bytes).digest('hex');
|
||
q.phase('Upload >2 MiB through visible document form');await props();await page.getByRole('button',{name:'Documentos',exact:true}).click();await page.getByLabel('Título',{exact:true}).fill('SIMULAÇÃO QA — PDF de 2,5 MiB');await page.getByLabel('Classificação documental',{exact:true}).selectOption('restricted');await page.getByLabel('Âmbito de consulta',{exact:true}).selectOption('internal');await page.locator('input[type="file"]').setInputFiles(fixture);await page.getByLabel('Motivo (20–1000 caracteres)',{exact:true}).fill('SIMULAÇÃO QA: validar upload web, scan real e recuperação após interrupção do worker sem duplicações.');const pending=page.waitForResponse(r=>r.request().method()==='POST'&&new URL(r.url()).pathname.endsWith('/resources/documents'));await page.getByRole('button',{name:'Guardar recurso',exact:true}).click();const upload=await pending;assert.equal(upload.status(),201);const resource=(await upload.json()).id;q.proof.resource_id=resource;await props();await page.getByRole('button',{name:'Documentos',exact:true}).click();await q.shot(page,'upload-large-pending-visible');
|
||
function inspect(){return JSON.parse(cp.execFileSync(PHP,[path.join(__dirname,'portal-service-followup-inspect.php'),String(id)],{encoding:'utf8',timeout:30000}));}const before=inspect();assert.equal(before.rows.length,1);assert.equal(before.rows[0].malware_scan_status,'pending');assert.equal(before.jobs.length,1);assert(before.scanner.available);q.proof.before_worker=before;
|
||
const url=`/minhas-oportunidades/${id}/resources/documents/${resource}/download`;assert.equal((await page.request.get(BASE+url)).status(),423);q.proof.checks.large_upload_visible_saved_queued_and_quarantined=true;q.save();
|
||
q.phase('PHP upload and POST limits, rejection without duplicate or partial document');
|
||
async function multipart(size,key){const p=await props();return await page.evaluate(async({url,etag,size,key})=>{const f=new FormData();f.set('etag',etag);f.set('creation_key',key);f.set('reason','SIMULAÇÃO QA: excesso de limite deve ser rejeitado sem persistência parcial ou duplicação.');f.set('payload',JSON.stringify({title:'SIMULAÇÃO QA — excesso',classification:'restricted',visibility:'internal'}));f.set('file',new File([new Uint8Array(size)],'SIMULACAO-QA.pdf',{type:'application/pdf'}));const token=decodeURIComponent(document.cookie.split('; ').find(v=>v.startsWith('XSRF-TOKEN='))?.slice(11)||'');const r=await fetch(url,{method:'POST',headers:{Accept:'application/json','X-XSRF-TOKEN':token},body:f});let data;try{data=await r.json();}catch{data={controlled:false};}return {status:r.status,data};},{url:`/minhas-oportunidades/${id}/resources/documents`,etag:p.etag,size,key});}
|
||
const overUpload=await multipart(20*1048576+1,crypto.randomUUID());assert.equal(overUpload.status,422);q.proof.over_upload={bytes:20*1048576+1,status:overUpload.status,errors:overUpload.data.errors};const overPost=await multipart(25*1048576,crypto.randomUUID());assert.equal(overPost.status,413);q.proof.over_post={bytes:25*1048576,status:overPost.status};assert.deepEqual(inspect().rows,before.rows);assert.equal(inspect().jobs.length,1);q.proof.checks.php_web_limits_reject_without_partial_write=true;
|
||
q.proof.result='passed_upload_preparation';q.save();console.log(JSON.stringify({result:q.proof.result,target:TARGET,opportunity_id:id,upload_bytes:bytes.length,checks:q.proof.checks,active_writes:0}));
|
||
}catch(e){q.proof.result='failed';q.proof.failure=sanitized(e);q.save();console.log(JSON.stringify({result:'failed',phase:q.proof.phase,failure:q.proof.failure}));process.exitCode=1;}finally{if(ctx)await ctx.close();await q.browser.close();}})();
|