Files
Investidor-V2/tools/portal-stability-activation-transport.cjs
T
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

43 lines
5.4 KiB
JavaScript

// Verify the authorized running Apache/vhosts and Chromium trust without credentials or fixtures.
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 manifest=JSON.parse(fs.readFileSync(path.join(ROOT,'outputs/investmoz-portal-stability-20261011/manifesto-candidata.json')));
const proof={at:new Date().toISOString(),delivery_revision:manifest.delivery_revision,origin:'https://portal-investidor.test',assets:{},mixed_requests:[],errors:[],credentials_or_secrets_recorded:false};
let browser;
(async()=>{
const redirect=await fetch('http://portal-investidor.test/login?deployment=485ee04c40b2',{redirect:'manual'});
proof.http_get={status:redirect.status,location:redirect.headers.get('location')};
assert.equal(redirect.status,308);assert.equal(proof.http_get.location,'https://portal-investidor.test/login?deployment=485ee04c40b2');
const denied=await fetch('http://portal-investidor.test/login',{method:'POST',redirect:'manual'});
proof.http_post={status:denied.status};assert.equal(denied.status,405);
// Existing Laragon default vhost; phpinfo is parsed only in memory. Never save its body/environment.
const home=await fetch('http://127.0.0.1/');const homeText=await home.text();
proof.default_vhost={status:home.status,laragon_visible:/Laragon/i.test(homeText)};
assert.equal(home.status,200);assert(proof.default_vhost.laragon_visible);
const info=await fetch('http://127.0.0.1/?q=info');const html=await info.text();
const clean=s=>s.replace(/<[^>]*>/g,' ').replace(/&nbsp;|&#039;|&quot;|&amp;/g,' ').replace(/\s+/g,' ').trim();
const rows=[...html.matchAll(/<tr[^>]*>([\s\S]*?)<\/tr>/gi)].map(m=>[...m[1].matchAll(/<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi)].map(c=>clean(c[1])));
const value=name=>rows.find(r=>r[0]===name)?.[1];
proof.PHP={status:info.status,version:html.match(/PHP Version\s+([\d.]+)/)?.[1],sapi:value('Server API'),curl_support:value('cURL support'),curl_version:value('cURL Information'),extensions:{}};
assert.equal(info.status,200);assert.equal(proof.PHP.version,'8.5.11');assert.match(proof.PHP.sapi,/^Apache 2(?:\.0)? Handler$/);assert.equal(proof.PHP.curl_support,'enabled');
for(const [key,label] of Object.entries({pgsql:'PostgreSQL Support',pdo_pgsql:'PDO Driver for PostgreSQL',openssl:'OpenSSL support',fileinfo:'fileinfo support',mbstring:'Multibyte Support',zip:'Zip'})){
const cell=value(label);proof.PHP.extensions[key]=cell??null;
assert(cell && /enabled|PostgreSQL/i.test(cell),'Required PHP extension unavailable: '+key);
}
browser=await chromium.launch({headless:true,executablePath:'C:/Users/macbook/AppData/Local/ms-playwright/chromium-1243/chrome-win64/chrome.exe'});
const context=await browser.newContext({ignoreHTTPSErrors:false,locale:'pt-MZ'});const page=await context.newPage();const pending=[];
page.on('pageerror',e=>proof.errors.push({type:e.name}));
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===proof.origin&&u.pathname.startsWith('/build/'))pending.push((async()=>{const name=u.pathname.slice(7);const digest=crypto.createHash('sha256').update(await r.body()).digest('hex');proof.assets[name]={status:r.status(),sha256:digest,matches:manifest.revision_input.assets[name]===digest};})());});
const response=await page.goto(proof.origin+'/login',{waitUntil:'networkidle'});await page.locator('#email').waitFor();await Promise.all(pending);
proof.HTTPS_status=response.status();proof.certificate=await response.securityDetails();
proof.runtime=await page.evaluate(()=>({secureContext:isSecureContext,subtle:typeof crypto.subtle,randomUUID:typeof crypto.randomUUID}));
proof.cookies=(await context.cookies(proof.origin)).map(c=>({name:c.name,domain:c.domain,path:c.path,secure:c.secure,httpOnly:c.httpOnly,sameSite:c.sameSite}));
assert.equal(response.status(),200);assert(proof.runtime.secureContext&&proof.runtime.subtle==='object');assert.equal(proof.errors.length,0);assert.equal(proof.mixed_requests.length,0);
const session=proof.cookies.find(c=>c.name==='portal_investidor_https');assert(session?.secure&&session.httpOnly&&session.path==='/'&&session.sameSite==='Lax'&&session.domain==='portal-investidor.test');
assert(Object.keys(proof.assets).length>0);for(const a of Object.values(proof.assets))assert(a.status===200&&a.matches);
proof.result='passed';fs.writeFileSync(path.join(DIR,'stability-active-transport.json'),JSON.stringify(proof,null,2));
console.log(JSON.stringify({result:proof.result,revision:proof.delivery_revision.slice(0,12),PHP:proof.PHP,HTTPS_status:proof.HTTPS_status,secure_context:true,trusted_without_TLS_bypass:true,default_vhost:proof.default_vhost,assets_checked:Object.keys(proof.assets).length,mixed_content:0}));
})().catch(error=>{proof.result='stopped';proof.error_type=error.name;fs.writeFileSync(path.join(DIR,'stability-active-transport.json'),JSON.stringify(proof,null,2));console.error(JSON.stringify({result:'stopped',error_type:error.name,message:error.name==='AssertionError'?error.message.split('\n')[0]:undefined}));process.exitCode=1;}).finally(async()=>{if(browser)await browser.close();});