130 lines
13 KiB
JavaScript
130 lines
13 KiB
JavaScript
// Actual authorized HTTP action in Chromium. Login/MFA are entered locally by the existing user.
|
|
// No stored credentials, OTP generation, TLS bypass, test fixtures or direct active SQL writes.
|
|
const fs=require('node:fs'),path=require('node:path'),assert=require('node:assert/strict'),crypto=require('node:crypto');
|
|
const {chromium}=require('C:/Users/macbook/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright');
|
|
const ROOT=path.resolve(__dirname,'..'),DIR=path.join(ROOT,'storage/app/private/investmoz-v2/portal-audit');
|
|
const BASE='https://portal-investidor.test',INSTALL='/management/opportunity-resources-install/organization-country';
|
|
const manifest=JSON.parse(fs.readFileSync(path.join(ROOT,'outputs/investmoz-portal-stability-20261011/manifesto-candidata.json')));
|
|
assert.equal(manifest.delivery_revision,'485ee04c40b2754ab668f48fd84d8559fb19a8b98f4b9af50fc0517bb488ca76');
|
|
const fresh=JSON.parse(fs.readFileSync(JSON.parse(fs.readFileSync(path.join(DIR,'stability-active-backup-latest.json'))).path));
|
|
const statusFile=path.join(DIR,'stability-active-browser-status.json'),commandFile=path.join(DIR,'stability-active-browser-command.json');
|
|
const proof={at:new Date().toISOString(),origin:BASE,code_hash:manifest.country_installation_fingerprint,delivery_revision:manifest.delivery_revision,
|
|
navigation:[],assets:{},mixed_requests:[],javascript_errors:[],cookies:[],tls:[],criteria:{},credentials_or_MFA_recorded:false};
|
|
const write=()=>fs.writeFileSync(statusFile,JSON.stringify(proof,null,2));
|
|
const pending=[];let context,page,browser,lastCommand=null,done=false;
|
|
async function makeContext(){
|
|
context=await browser.newContext({viewport:{width:1280,height:900},locale:'pt-MZ',ignoreHTTPSErrors:false});page=await context.newPage();page.setDefaultTimeout(20000);
|
|
page.on('pageerror',e=>{proof.javascript_errors.push({path:new URL(page.url()).pathname,type:e.name,message:e.message.split('\n')[0].slice(0,250)});write();});
|
|
page.on('request',r=>{const u=new URL(r.url());if(u.protocol==='http:')proof.mixed_requests.push({origin:u.origin,path:u.pathname});});
|
|
page.on('response',r=>{const u=new URL(r.url());if(u.origin!==BASE)return;
|
|
if(r.request().isNavigationRequest() || ['/login','/two-factor-challenge',INSTALL,'/logout'].includes(u.pathname))
|
|
proof.navigation.push({path:u.pathname,method:r.request().method(),status:r.status(),location:r.headers().location??null});
|
|
if(u.pathname.startsWith('/build/'))pending.push((async()=>{const bytes=await r.body(),key=u.pathname.slice(7);const digest=crypto.createHash('sha256').update(bytes).digest('hex');proof.assets[key]={status:r.status(),sha256:digest,matches:digest===manifest.revision_input.assets[key]};})().catch(()=>{}));
|
|
if(r.request().isNavigationRequest())pending.push((async()=>{const t=await r.securityDetails();if(t)proof.tls.push({path:u.pathname,...t});})().catch(()=>{}));
|
|
});
|
|
}
|
|
async function inspect(){
|
|
await Promise.allSettled(pending);
|
|
proof.path=new URL(page.url()).pathname;
|
|
proof.runtime=await page.evaluate(()=>({secureContext:isSecureContext,subtle:typeof crypto.subtle,randomUUID:typeof crypto.randomUUID}));
|
|
proof.cookies=(await context.cookies(BASE)).map(c=>({name:c.name,domain:c.domain,path:c.path,secure:c.secure,httpOnly:c.httpOnly,sameSite:c.sameSite}));
|
|
assert(proof.runtime.secureContext && proof.runtime.subtle==='object','Actual secure context unavailable');
|
|
assert(proof.cookies.filter(c=>c.name==='portal_investidor_https').every(c=>c.secure&&c.httpOnly&&c.path==='/'&&c.sameSite==='Lax'&&c.domain==='portal-investidor.test'),'Actual session cookie attributes differ');
|
|
assert.equal(proof.mixed_requests.length,0);assert.equal(proof.javascript_errors.length,0);
|
|
for(const asset of Object.values(proof.assets))assert(asset.status===200&&asset.matches,'Actual production asset mismatch');
|
|
proof.login_form_visible=await page.locator('#email').isVisible();
|
|
proof.MFA_form_visible=proof.path==='/two-factor-challenge';
|
|
if(!proof.login_form_visible && !proof.MFA_form_visible){
|
|
const preview=await page.evaluate(async url=>{const r=await fetch(url,{headers:{Accept:'application/json'}});return {status:r.status,value:r.ok?await r.json():null};},INSTALL);
|
|
proof.preview_HTTP_status=preview.status;
|
|
if(preview.status===200){
|
|
const p=preview.value;
|
|
proof.preview=Object.fromEntries(['target','code_hash','migration','ready','consistent','installed','hash','backupDate','dependencies','operationKey','actionUrl'].map(k=>[k,p[k]]));
|
|
assert.equal(p.target.database,'investemoz');assert.equal(Number(p.target.port),5432);assert.equal(p.code_hash,manifest.country_installation_fingerprint);
|
|
assert.equal(p.backupDate,fresh.verified_at,'Preview backup differs');
|
|
assert.equal(p.migration,'2026_10_10_050000_extend_organization_country');assert(p.consistent&&p.ready);
|
|
assert.match(p.operationKey,/^[0-9a-f-]{36}$/i);
|
|
proof.criteria.actual_authenticated_preview_corresponds=true;
|
|
}
|
|
}
|
|
proof.phase=proof.login_form_visible?'awaiting_existing_manager_login':proof.MFA_form_visible?'awaiting_local_MFA':'observed_authenticated_page';
|
|
proof.at=new Date().toISOString();write();
|
|
console.log(JSON.stringify({phase:proof.phase,path:proof.path,preview_status:proof.preview_HTTP_status,
|
|
preview:proof.preview?{target:proof.preview.target,code_hash:proof.preview.code_hash,installed:proof.preview.installed,ready:proof.preview.ready,hash:proof.preview.hash}:null}));
|
|
}
|
|
async function historyCheck(name){
|
|
const h=await page.evaluate(()=>({encrypted:history.state?.page instanceof ArrayBuffer,plain:!!history.state?.page && !(history.state.page instanceof ArrayBuffer)}));
|
|
assert(h.encrypted&&!h.plain,'Actual private history is not encrypted');proof.criteria[name]=true;
|
|
}
|
|
(async()=>{
|
|
browser=await chromium.launch({headless:false,executablePath:'C:/Users/macbook/AppData/Local/ms-playwright/chromium-1243/chrome-win64/chrome.exe'});
|
|
await makeContext();await page.goto(BASE+INSTALL,{waitUntil:'networkidle'});await inspect();
|
|
let observedPath=proof.path;
|
|
while(!done){
|
|
await new Promise(r=>setTimeout(r,1200));
|
|
if(page.isClosed()){proof.phase='browser_closed_without_application';write();break;}
|
|
if(new URL(page.url()).pathname!==observedPath){observedPath=new URL(page.url()).pathname;await inspect();}
|
|
if(!fs.existsSync(commandFile))continue;
|
|
const command=JSON.parse(fs.readFileSync(commandFile));if(command.id===lastCommand)continue;lastCommand=command.id;
|
|
assert.equal(command.delivery_revision,manifest.delivery_revision,'Command delivery differs');
|
|
try{
|
|
if(command.action==='inspect')await inspect();
|
|
else if(command.action==='apply'){
|
|
await page.goto(BASE+INSTALL,{waitUntil:'networkidle'});await inspect();
|
|
assert.equal(proof.preview.hash,command.preview_hash,'Preview differs; stop before apply');
|
|
assert(!proof.preview.installed&&proof.preview.ready&&proof.preview.consistent);
|
|
await page.getByLabel('Fundamentação da instalação',{exact:true}).fill('Ativação exclusiva COUNTRY02, entrega 485ee04c40b2 e código 162daff6ce08, autorizada pelo responsável em 11/10/2026; somente 050000, duas colunas, sem criar entidades ou instalar outros pacotes.');
|
|
await page.getByLabel('Confirmo a aplicação deste plano',{exact:true}).check();
|
|
const originalRequest=page.waitForRequest(r=>r.method()==='POST'&&new URL(r.url()).pathname===INSTALL);
|
|
const applied=page.waitForResponse(r=>r.request().method()==='POST'&&new URL(r.url()).pathname===INSTALL);
|
|
await page.getByRole('button',{name:'Aplicar extensão do país',exact:true}).click();
|
|
const sent=await originalRequest;const submitted=sent.postDataJSON(),csrf=sent.headers()['x-xsrf-token'];
|
|
assert(csrf && submitted.idempotency_key,'Authenticated CSRF/key missing');
|
|
const response=await applied;proof.application_POST_status=response.status();assert([302,303].includes(response.status()),'Unexpected application response');
|
|
await page.waitForLoadState('networkidle');await inspect();assert(proof.preview.installed);
|
|
await page.getByRole('button',{name:'Aplicar extensão do país',exact:true}).isDisabled().then(v=>assert(v));
|
|
const replay=await page.evaluate(async({url,body,token})=>{
|
|
const send=async data=>{const r=await fetch(url,{method:'POST',headers:{Accept:'application/json','Content-Type':'application/json','X-XSRF-TOKEN':token},credentials:'same-origin',body:JSON.stringify(data)});return {status:r.status,value:r.ok?await r.json():null};};
|
|
const same=await send(body);const changed=await send({...body,reason:body.reason+' Conte?do diferente para confirmar rejei??o da mesma chave.'});return {same,changed_status:changed.status};
|
|
},{url:INSTALL,body:submitted,token:csrf});
|
|
assert.equal(replay.same.status,200);assert.equal(replay.same.value.migration,'2026_10_10_050000_extend_organization_country');
|
|
assert.equal(replay.same.value.new_columns,2);assert.equal(replay.same.value.new_tables,0);assert.equal(replay.changed_status,409);
|
|
proof.criteria.same_attempt_returns_original_receipt=true;proof.criteria.same_key_changed_content_rejected=true;
|
|
proof.repetition={same_status:200,changed_status:409,credentials_or_payload_recorded:false};
|
|
proof.criteria.authenticated_UI_application_visible=true;proof.phase='installed_country_disabled';write();
|
|
}else if(command.action==='profile'){
|
|
await page.goto(BASE+'/investidor/profile',{waitUntil:'networkidle'});await page.getByRole('heading',{name:'Perfil de investimento e empresas',exact:true}).waitFor();
|
|
await historyCheck('actual_private_history_encrypted');
|
|
const p=await page.evaluate(async()=>{const r=await fetch('/api/v1/investment/profile',{headers:{Accept:'application/json'}});const d=r.ok?await r.json():null;
|
|
return {status:r.status,available:d?.organizationCountryAvailable,organization_count:d?.organizations?.length,
|
|
company_count:d?.companies?.length,account_version:d?.account?.version};});
|
|
proof.profile=p;proof.criteria.profile_available_and_empty_master_explained=p.available===true&&p.organization_count===0;
|
|
assert.equal(p.status,200);assert.equal(p.available,true);assert.equal(p.organization_count,0);
|
|
await page.getByText('Sem representação organizacional registada para esta conta.',{exact:true}).waitFor();
|
|
await page.reload({waitUntil:'networkidle'});await historyCheck('refresh_history_encrypted');
|
|
proof.criteria.refresh_recovers_authorized_profile=true;
|
|
await page.getByRole('link',{name:'Voltar à área do investidor',exact:true}).click();await page.waitForURL(BASE+'/investidor/manifestacoes');
|
|
await page.goBack({waitUntil:'networkidle'});await page.getByRole('heading',{name:'Perfil de investimento e empresas',exact:true}).waitFor();await historyCheck('back_history_encrypted');
|
|
await page.goForward({waitUntil:'networkidle'});await page.waitForURL(BASE+'/investidor/manifestacoes');
|
|
await page.goBack({waitUntil:'networkidle'});await page.getByRole('heading',{name:'Perfil de investimento e empresas',exact:true}).waitFor();
|
|
proof.criteria.back_forward_authorized_profile=true;await inspect();
|
|
}else if(command.action==='logout'){
|
|
const response=page.waitForResponse(r=>r.request().method()==='POST'&&new URL(r.url()).pathname==='/logout');
|
|
await page.getByRole('button',{name:'Terminar sessão',exact:true}).first().click();assert([302,303].includes((await response).status()),'Unexpected logout response');
|
|
await page.waitForURL(BASE+'/',{waitUntil:'networkidle'});
|
|
const code=await page.evaluate(async()=>{const r=await fetch('/api/v1/investment/profile',{headers:{Accept:'application/json'}});return r.status;});
|
|
assert.equal(code,401);proof.criteria.logout_revokes_private_API=true;
|
|
await page.goBack({waitUntil:'networkidle'});await page.getByRole('heading',{name:'Log in to your account',exact:true}).waitFor();
|
|
assert(!(await page.getByRole('heading',{name:'Perfil de investimento e empresas',exact:true}).isVisible()));
|
|
proof.criteria.back_after_logout_does_not_recover_private_profile=true;proof.logout_API_status=code;await inspect();
|
|
}else if(command.action==='new-session'){
|
|
await context.close();await makeContext();await page.goto(BASE+'/investidor/profile',{waitUntil:'networkidle'});
|
|
proof.criteria.new_browser_session_requires_login=await page.locator('#email').isVisible();await inspect();
|
|
}else if(command.action==='close'){done=true;proof.phase='browser_closed';write();}
|
|
else throw new Error('Unknown authorized browser action');
|
|
proof.last_command={id:command.id,action:command.action,result:'passed'};write();console.log(JSON.stringify(proof.last_command));
|
|
}catch(error){proof.last_command={id:command.id,action:command.action,result:'stopped',error_type:error.name};write();console.log(JSON.stringify(proof.last_command));}
|
|
}
|
|
await context.close();await browser.close();
|
|
})().catch(error=>{proof.phase='stopped_before_further_action';proof.error_type=error.name;write();console.error(JSON.stringify({phase:proof.phase,error_type:error.name}));process.exitCode=1;});
|