// Proba vederii judecatii organizatiei in consola web (consola-web/index.html), intr-un Chromium ADEVARAT (playwright-core + Chromium-ul // instalat de Playwright), pe telefon (390x844, isMobile, cu media queries aplicate) si pe desktop (1440x900), cu reteaua taiata. Iesirile // redate sunt REALE: organizatie.mjs pe pachetul derivat din producatori (fixturi-organizatie.mjs): pachetul bun, acelasi cu un artefact de // identitate stricat, acelasi fara domeniul masinilor, si unul cu un verdict scris de pachet care minte. Cere, pe fiecare latime: pagina cat // ecranul si fara derulare orizontala dupa fiecare redare; verdictul din antet = rezumatul, in culoarea lui; cate o caseta pe domeniu, cu // verdictul DOMENIULUI din iesire; fiecare artefact cu verificatorul lui si amprenta intreaga a dovezii; regula refuzata numita; un domeniu // neprezentat niciodata verde; un pachet brut UNCHECKED; trecerea inapoi la o stare a consolei; nicio eroare de pagina; nicio cerere la retea. // node proba-organizatie-web.mjs [cale index.html] iesire 0 = toate cum trebuia, 1 = una rosie, 2 = nu s-a putut rula (fara browser) import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; import { createRequire } from 'node:module'; import { judecaPachetul, PACK_KIND, CONTEXT_KIND } from './organizatie.mjs'; import { pachetulBun, inlocuieste, vectorul, imparte } from './fixturi-organizatie.mjs'; import { evalueaza } from './consola.mjs'; const AICI = path.dirname(fileURLToPath(import.meta.url)); const PAGINA = path.resolve(process.argv[2] || path.join(AICI, 'consola-web', 'index.html')); const EXE = process.env.CHROME || path.join(os.homedir(), 'AppData', 'Local', 'ms-playwright', 'chromium-1228', 'chrome-win64', 'chrome.exe'); let chromium; try { ({ chromium } = createRequire(import.meta.url)('playwright-core')); } catch { /* mai jos */ } if (!chromium || !fs.existsSync(EXE)) { console.log(`NEMASURAT: lipseste playwright-core (npm i playwright-core, in dosarul acesta sau mai sus) sau Chromium (${EXE}); CHROME= pentru altul`); process.exit(2); } let rele = 0, bune = 0; const cer = (n, c, d = '') => { console.log(` [${c ? 'OK ' : 'RAU '}] ${n}${c || !d ? '' : ' -- ' + d}`); if (c) bune++; else rele++; }; // iesirile reale ale judecatii let F, bun, stricat, faraMasini, minte, consola; try { F = await pachetulBun(); bun = await judecaPachetul(F.pack, { context: F.context }); const s = F.stricate['identity-presentation']; stricat = await judecaPachetul(inlocuieste(F.pack, s.id, s.artifact), { context: F.context }); let p = F.pack; for (const a of F.pack.artifacts.filter((x) => ['device-bundle', 'device-operation-log', 'device-reputation'].includes(x.artifact))) p = inlocuieste(p, a.id, null); faraMasini = await judecaPachetul(p, { context: F.context }); const pm = JSON.parse(JSON.stringify(F.pack)); pm.summary = { verdict: 'VALID' }; minte = await judecaPachetul(pm, { context: F.context }); consola = await evalueaza({ bundle: F.pack.artifacts.find((a) => a.id === 'shield-console-1').input.bundle }); } catch (e) { console.log('NEMASURAT: iesirile de proba nu s-au putut face: ' + e.message); process.exit(2); } // revizia B2 (2026-10-21): iesiri care incearca vederea. Doua EDITATE (nu le scrie unealta: un rezumat VALID peste un domeniu cerut INVALID, un // domeniu VALID peste un artefact INVALID); doua reale cu text lung sau cu marcaj adus de pachet; trei reale despre retea. const clona = (x) => JSON.parse(JSON.stringify(x)); let falsRezumat, falsDomeniu, lung, marcaj, inchis, citiri, testnet; try { falsRezumat = clona(stricat); falsRezumat.summary.verdict = 'VALID'; falsDomeniu = clona(stricat); falsDomeniu.domains.find((d) => d.domain === 'identity').verdict = 'VALID'; const mic = (artifacts, extra = {}) => ({ v: 1, kind: PACK_KIND, artifacts, ...extra }); lung = await judecaPachetul(mic([{ id: 'o', artifact: 'k'.repeat(400), input: {} }], { organization: 'O'.repeat(300), verdict: 'V'.repeat(400) }), { require: ['identity'] }); marcaj = await judecaPachetul(mic([{ id: 'o', artifact: '', input: {} }], { organization: '', verdict: '' }), { require: ['identity'] }); const n = vectorul('envelope/notarized-28001.valid'), ni = imparte('envelope', n.input); const vechi = process.env.AERE_CONFORMANCE_RPC_28001; process.env.AERE_CONFORMANCE_RPC_28001 = 'http://127.0.0.1:9'; try { inchis = await judecaPachetul(mic([{ id: 'notar', artifact: 'envelope', input: ni.pack }]), { context: { v: 1, kind: CONTEXT_KIND, byArtifact: { notar: ni.context } }, online: true, require: ['proofs'] }); } finally { if (vechi === undefined) delete process.env.AERE_CONFORMANCE_RPC_28001; else process.env.AERE_CONFORMANCE_RPC_28001 = vechi; } const dvz = vectorul('device-bundle/notarization-not-read.partial'), di = imparte('device-bundle', dvz.input); citiri = await judecaPachetul(mic([{ id: 'dev', artifact: 'device-bundle', input: di.pack }]), { context: { v: 1, kind: CONTEXT_KIND, byArtifact: { dev: di.context } }, online: true, require: ['devices'] }); // finalitatea pe un testnet: forma pe care o scrie unealta cand citeste 28001 (proba-organizatie --online o masoara pe lant) testnet = clona(bun); testnet.network = { online: true, needed: [], readings: [], unmeasured: [], finality: [{ id: 'envelope-1', chain: 28001, testnet: true }] }; } catch (e) { console.log('NEMASURAT: iesirile de proba ale reviziei nu s-au putut face: ' + e.message); process.exit(2); } if (!(inchis.network.unmeasured.length === 1 && citiri.network.readings.length === 1 && lung.unjudged.length === 1 && marcaj.unjudged.length === 1)) { console.log(`NEMASURAT: iesirile de proba ale reviziei nu sunt cele asteptate (${JSON.stringify(inchis.network)}, ${JSON.stringify(citiri.network)})`); process.exit(2); } const RULE = F.stricate['identity-presentation'].failed[0]; if (!(bun.summary.verdict === 'PARTIAL' && stricat.summary.verdict === 'INVALID' && faraMasini.summary.verdict === 'NOT_MEASURED' && minte.selfReport.suspect.length && consola.verdict === 'OK')) { console.log(`NEMASURAT: iesirile de proba nu sunt cele asteptate (${bun.summary.verdict}, ${stricat.summary.verdict}, ${faraMasini.summary.verdict}, ${minte.selfReport.suspect.length}, ${consola.verdict})`); process.exit(2); } const CLS = { VALID: 'ok', PARTIAL: 'warn', NOT_MEASURED: 'warn', NOT_PRESENTED: 'dim', INVALID: 'bad' }; const browser = await chromium.launch({ executablePath: EXE, headless: true }); try { for (const vp of [{ w: 390, h: 844, mobil: true }, { w: 1440, h: 900, mobil: false }]) { const et = `${vp.w}px`; const ctx = await browser.newContext({ viewport: { width: vp.w, height: vp.h }, deviceScaleFactor: 1, isMobile: vp.mobil, hasTouch: vp.mobil }); const page = await ctx.newPage(); const erori = []; const cereri = []; const eroriRedare = []; page.on('console', (m) => { if (m.type() === 'error' && !/ERR_(BLOCKED|FAILED|INTERNET|NAME)|net::|Failed to load resource/.test(m.text())) erori.push(m.text().slice(0, 160)); }); page.on('pageerror', (e) => erori.push('pageerror: ' + String(e.message).slice(0, 160))); await page.route('**/*', (r) => { const u = r.request().url(); if (u.startsWith('file:')) return r.continue(); cereri.push(u); return r.abort(); }); await page.goto(pathToFileURL(PAGINA).href, { waitUntil: 'load' }); const lipeste = async (o) => { try { await page.fill('#in', typeof o === 'string' ? o : JSON.stringify(o), { timeout: 10000 }); await page.click('#render', { timeout: 5000 }); } catch (e) { cer(`${et}: campul si butonul Render se pot folosi`, false, String(e.message).split('\n')[0].slice(0, 140)); return null; } const st = await page.evaluate(() => { const q = (s) => document.querySelector(s); const qa = (s) => [...document.querySelectorAll(s)]; return { iw: window.innerWidth, sw: document.documentElement.scrollWidth, perr: q('#perr').hidden ? null : q('#perr').textContent, vtext: q('#vtext').textContent, vcls: q('#verdict').className, hostlab: q('#hostlab').textContent, org: !q('#orgsec').hidden, consola: !q('#sec-chain').hidden && !q('#sec-ladder').hidden && !q('#sec-mig').hidden, alert: q('#alert').textContent, tiles: qa('#tiles .tile').map((t) => t.textContent), retea: (() => { const t = qa('#tiles .tile').find((x) => /^Network/.test(x.textContent)); return t ? { text: t.textContent, stripe: t.querySelector('.stripe').className, v: t.querySelector('.v').textContent } : null; })(), host: q('#host').textContent, xss: window.__xss === undefined ? null : window.__xss, injectate: qa('#alert *, #host *, #domains *, #tiles *').filter((e) => ['IMG', 'SCRIPT', 'IFRAME'].includes(e.tagName)).length, carduri: qa('#domains .dcard').map((c) => ({ domain: c.dataset.domain, verdict: c.dataset.verdict, np: c.classList.contains('np'), pill: c.querySelector('.dhead .pill') ? { text: c.querySelector('.dhead .pill').textContent, cls: c.querySelector('.dhead .pill').className } : null, reguli: c.querySelector(':scope > .arules') ? c.querySelector(':scope > .arules').textContent : '', randuri: [...c.querySelectorAll('.arow')].map((r) => ({ id: r.dataset.id, verdict: r.dataset.verdict, text: r.textContent, dig: r.querySelector('.adig .hval') ? r.querySelector('.adig .hval').textContent : '', reguli: r.querySelector('.arules') ? r.querySelector('.arules').textContent : '', lata: r.scrollWidth > r.clientWidth + 1 })) })), }; }); if (st.perr) eroriRedare.push(st.perr.slice(0, 160)); return st; }; const lat = (s, nume) => cer(`${et}: ${nume}: pagina cat ecranul (${s && s.iw}) si fara derulare orizontala (${s && s.sw})`, s && s.iw === vp.w && s.sw <= vp.w, JSON.stringify(s && { iw: s.iw, sw: s.sw })); // 1) pachetul bun const a = await lipeste(bun); if (a) { lat(a, 'judecata buna'); cer(`${et}: verdictul din antet e rezumatul (${bun.summary.verdict}), in culoarea lui, si eticheta spune "organization"`, a.vtext === bun.summary.verdict && a.vcls.includes(CLS[bun.summary.verdict]) && a.hostlab === 'organization', `${a.vtext} ${a.vcls} ${a.hostlab}`); cer(`${et}: sectiunile consolei ascunse, sectiunea domeniilor aratata`, a.org && !a.consola, `org ${a.org}, consola ${a.consola}`); const peDomeniu = bun.domains.every((d) => { const c = a.carduri.find((x) => x.domain === d.domain); return c && c.verdict === d.verdict && c.pill && c.pill.cls.includes(CLS[d.verdict]); }); cer(`${et}: cate o caseta pe domeniu (${bun.domains.length}), fiecare cu verdictul domeniului din iesire, in culoarea lui`, a.carduri.length === bun.domains.length && peDomeniu, JSON.stringify(a.carduri.map((c) => [c.domain, c.verdict, c.pill && c.pill.text]))); const toate = a.carduri.flatMap((c) => c.randuri); const cuDovada = bun.artifacts.every((r) => { const x = toate.find((y) => y.id === r.id); return x && x.verdict === r.verdict && x.dig === r.inputSha256 && x.text.includes(r.verifier.module); }); cer(`${et}: fiecare artefact (${bun.artifacts.length}) cu verdictul lui, verificatorul care l-a judecat si amprenta intreaga a dovezii`, toate.length === bun.artifacts.length && cuDovada, `${toate.length} randuri`); cer(`${et}: niciun rand de artefact mai lat decat caseta lui`, toate.every((r) => !r.lata), toate.filter((r) => r.lata).map((r) => r.id).join(',')); cer(`${et}: motivul rezumatului e aratat`, a.alert.includes(bun.summary.reason.slice(0, 40)), a.alert.slice(0, 120)); cer(`${et}: o iesire reala nu e numita contradictorie (nicio alarma falsa a corectiei de mai jos)`, !/contradicts itself/.test(a.alert), a.alert.slice(0, 160)); } // 2) un artefact de identitate stricat const b = await lipeste(stricat); if (b) { lat(b, 'judecata cu un artefact stricat'); const ci = b.carduri.find((c) => c.domain === 'identity'); const ri = ci && ci.randuri.find((r) => r.id === F.stricate['identity-presentation'].id); cer(`${et}: rezumatul INVALID in culoarea rea; domeniul identity INVALID (rau), cu regula ${RULE} numita pe caseta si pe artefact`, b.vtext === 'INVALID' && b.vcls.includes('bad') && ci && ci.verdict === 'INVALID' && ci.pill.cls.includes('bad') && ci.reguli.includes(RULE) && ri && ri.reguli.includes(RULE), JSON.stringify({ v: b.vtext, ci: ci && { v: ci.verdict, p: ci.pill, r: ci.reguli } })); } // 3) un domeniu neprezentat const c = await lipeste(faraMasini); if (c) { lat(c, 'judecata fara domeniul masinilor'); const cd = c.carduri.find((x) => x.domain === 'devices'); cer(`${et}: domeniul neprezentat aratat NOT PRESENTED, palid, niciodata in culoarea buna; caseta "Domains presented" spune 7/8`, cd && cd.np && cd.verdict === 'NOT_PRESENTED' && cd.pill.text === 'NOT PRESENTED' && !cd.pill.cls.includes('ok') && !cd.randuri.length && c.tiles.some((t) => /Domains presented7\/8/.test(t)) && c.vtext === 'NOT MEASURED', JSON.stringify({ cd, tiles: c.tiles, v: c.vtext })); } // 4) un verdict scris de pachet care minte const d = await lipeste(minte); if (d) cer(`${et}: verdictul scris de pachet e aratat ca suspect si ignorat, nu ca verdict`, d.vtext === minte.summary.verdict && /Suspect self-report, ignored: the pack says pack\.summary\.verdict = VALID/.test(d.alert), d.alert.slice(0, 160)); // revizia B2: o iesire editata nu e aratata mai bine decat o dau propriile ei randuri const g1 = await lipeste(falsRezumat); if (g1) cer(`${et}: o iesire editata cu rezumatul VALID peste un domeniu cerut INVALID: antetul arata INVALID (rau) si spune ca iesirea se contrazice`, g1.vtext === 'INVALID' && g1.vcls.includes('bad') && /contradicts itself/.test(g1.alert), JSON.stringify({ v: g1.vtext, c: g1.vcls, a: g1.alert.slice(0, 120) })); const g2 = await lipeste(falsDomeniu); if (g2) { const ci = g2.carduri.find((c) => c.domain === 'identity'); cer(`${et}: o iesire editata cu domeniul identity VALID peste un artefact INVALID: caseta lui arata INVALID (rau), nu VALID`, ci && ci.verdict === 'INVALID' && ci.pill.cls.includes('bad') && !ci.pill.cls.includes('ok') && g2.vtext === 'INVALID' && /contradicts itself/.test(g2.alert), JSON.stringify({ ci: ci && [ci.verdict, ci.pill], v: g2.vtext })); } // tot ce vine din pachet e text: un marcaj nu devine element const g3 = await lipeste(marcaj); if (g3) cer(`${et}: un marcaj adus de pachet (numele organizatiei, felul, verdictul scris) e aratat ca text, nu devine element si nu ruleaza`, g3.xss === null && g3.injectate === 0 && g3.host.includes('/.test(g3.alert), JSON.stringify({ xss: g3.xss, n: g3.injectate, host: g3.host.slice(0, 60) })); // reteaua: "read" in culoarea buna numai cand s-a citit tot ce se cerea; citirile celui care verifica si un testnet sunt spuse const g4 = await lipeste(inchis), g5 = await lipeste(citiri), g6 = await lipeste(testnet); if (g4 && g5 && g6) cer(`${et}: caseta retelei: lantul necitit e "partly read" (galben), citirile celui care verifica si finalitatea pe testnet sunt numite, niciuna in verde`, g4.retea && g4.retea.v === 'partly read' && g4.retea.stripe.includes('s-warn') && /could not be read for 1/.test(g4.retea.text) && g5.retea && g5.retea.stripe.includes('s-warn') && /relying party's own readings/.test(g5.retea.text) && g6.retea && g6.retea.stripe.includes('s-warn') && /testnet \(chain 28001\)/.test(g6.retea.text), JSON.stringify([g4.retea, g5.retea, g6.retea])); // text lung fara spatii adus de pachet: nicio derulare orizontala (pana azi felul necunoscut de 400 de caractere facea pagina de 3138 px pe telefon) const g7 = await lipeste(lung); if (g7) lat(g7, 'text lung fara spatii adus de pachet (felul, verdictul scris, numele organizatiei)'); // 5) un pachet brut const e = await lipeste(F.pack); if (e) { lat(e, 'pachetul brut'); cer(`${et}: un pachet brut lipit e UNCHECKED, cu nota, si nicio caseta de domeniu judecata`, e.vtext === 'UNCHECKED' && e.vcls.includes('bad') && /checks nothing/.test(e.alert) && !e.carduri.length, JSON.stringify({ v: e.vtext, n: e.carduri.length })); } // 6) inapoi la o stare a consolei: vederea consolei revine, a organizatiei se ascunde const f = await lipeste(consola); if (f) cer(`${et}: o stare a consolei dupa o judecata a organizatiei: sectiunile consolei revin, domeniile se ascund, eticheta spune "host"`, f.vtext === 'OK' && f.consola && !f.org && f.hostlab === 'host', JSON.stringify({ v: f.vtext, c: f.consola, o: f.org })); cer(`${et}: nicio iesire reala nu a dat un mesaj de eroare la redare (campul de eroare ascuns de fiecare data)`, !eroriRedare.length, eroriRedare.join(' | ')); cer(`${et}: nicio eroare de consola sau de pagina`, !erori.length, erori.join(' | ')); cer(`${et}: nicio cerere in afara fisierului a ajuns la retea (${cereri.length} cerute, toate refuzate: fonturile)`, cereri.every((u) => /fonts\.(googleapis|gstatic)\.com/.test(u)), cereri.join(', ')); if (process.env.CAPTURI) { fs.mkdirSync(process.env.CAPTURI, { recursive: true }); for (const [n, o] of [['bun', bun], ['stricat', stricat], ['fara-masini', faraMasini]]) { await lipeste(o); await page.screenshot({ path: path.join(process.env.CAPTURI, `organizatie-${n}-${vp.w}.png`), fullPage: true }); } } await ctx.close(); } } finally { await browser.close(); } console.log(`\norganizatie-web: ${bune}/${bune + rele} cum trebuia (Chromium ${path.basename(path.dirname(path.dirname(EXE)))})`); process.exitCode = rele ? 1 : 0;