73 lines
4.6 KiB
JavaScript
73 lines
4.6 KiB
JavaScript
// Proba de cost: inventarul trebuie sa ramana LINIAR pe fisiere facute anume (2026-09-29, revizuirea adversariala). Formele vechi
|
|
// ale cautarii PEM, ale literalului regex JS, ale docstring-ului Python, ale rezolvarii variabilelor si ale variabilei atribuite
|
|
// in Java costau patratic: un singur fisier de 1 MB (marimea maxima implicita) tinea scanarea minute intregi.
|
|
// Fiecare caz se scaneaza la doua marimi, a doua de 4 ori prima (64 si 256 KB; PEM 256 KB si 1 MB), fiecare intr-un proces
|
|
// separat cu termen; liniar inseamna ~4x, patratic ~16x. Verdict pe caz: VERDE daca t2 <= 6 * t1 + 250 ms si t2 < 10 s; ROSU
|
|
// altfel (si la depasirea termenului).
|
|
// node test/proba-timp.mjs [--doar caz1,caz2] -> 0 toate verzi, 1 unul rosu, 2 STRICAT (o masurare nu a pornit)
|
|
// Modulul masurat se schimba cu CRYPTO_INVENTORY_MODULE=<cale>/inventar.mjs (asa il foloseste controlul negativ).
|
|
import { mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
import { join, resolve, dirname } from 'node:path';
|
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { tmpdir } from 'node:os';
|
|
|
|
const AICI = dirname(fileURLToPath(import.meta.url));
|
|
const CALE_MODUL = process.env.CRYPTO_INVENTORY_MODULE ? resolve(process.env.CRYPTO_INVENTORY_MODULE) : join(AICI, '..', 'inventar.mjs');
|
|
const TERMEN_MS = 20000;
|
|
|
|
// unitatea se repeta pana la marime; '@' se inlocuieste cu un contor (nume distincte)
|
|
export const CAZURI = {
|
|
// pem: cautarea sfarsitului e nativa (indexOf), deci forma patratica se vede abia spre marimea maxima implicita
|
|
'pem.txt': ['-----BEGIN CERTIFICATE-----AAAA\n', 256, 1024],
|
|
'py-triplu.py': 'x="""a"""+',
|
|
'py-linie.py': 'hashlib.new(x)+',
|
|
'js-regex.js': '=/[',
|
|
'js-linie.js': 'crypto.createHash(x)+',
|
|
'js-func.js': 'crypto.createHash(q)\nfunction (',
|
|
'java-linie.java': 'Cipher.getInstance(x)+',
|
|
'java-kpg.java': 'k = KeyPairGenerator.getInstance("EC")+',
|
|
};
|
|
|
|
const marimi = (nume) => (Array.isArray(CAZURI[nume]) ? CAZURI[nume].slice(1) : [64, 256]);
|
|
const unitate = (nume) => (Array.isArray(CAZURI[nume]) ? CAZURI[nume][0] : CAZURI[nume]);
|
|
const genereaza = (unit, kb) => unit.repeat(Math.max(1, Math.floor((kb * 1024) / unit.length)));
|
|
|
|
const arg = (f) => { const i = process.argv.indexOf(f); return i >= 0 ? process.argv[i + 1] : null; };
|
|
|
|
if (arg('--caz')) {
|
|
// copilul: scaneaza un singur fisier si tipareste milisecundele
|
|
const nume = arg('--caz'); const kb = Number(arg('--kb'));
|
|
const inv = await import(pathToFileURL(CALE_MODUL).href);
|
|
const d = mkdtempSync(join(tmpdir(), 'ci-timp-'));
|
|
try {
|
|
writeFileSync(join(d, nume), genereaza(unitate(nume), kb));
|
|
const t0 = process.hrtime.bigint();
|
|
const rez = inv.scan(d);
|
|
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
if (rez.stats.filesSeen !== 1 || rez.stats.codeFilesTotal + rez.stats.textFilesPemOnly !== 1) throw new Error('fisierul nu a fost citit');
|
|
console.log(JSON.stringify({ ms }));
|
|
} finally { rmSync(d, { recursive: true, force: true }); }
|
|
} else {
|
|
const doar = arg('--doar') ? arg('--doar').split(',') : Object.keys(CAZURI);
|
|
const masoara = (nume, kb) => {
|
|
const r = spawnSync(process.execPath, [fileURLToPath(import.meta.url), '--caz', nume, '--kb', String(kb)], { encoding: 'utf8', timeout: TERMEN_MS, env: process.env });
|
|
if (r.error && r.error.code === 'ETIMEDOUT') return { termen: true };
|
|
try { return { ms: JSON.parse((r.stdout || '').trim().split('\n').pop()).ms }; } catch { return { stricat: `cod ${r.status}: ${(r.stderr || '').trim().split('\n').slice(-1)[0]}` }; }
|
|
};
|
|
let rosii = 0, stricate = 0;
|
|
for (const nume of doar) {
|
|
if (!CAZURI[nume]) { stricate++; console.log(`STRICAT ${nume}: caz necunoscut`); continue; }
|
|
const [k1, k2] = marimi(nume);
|
|
const a = masoara(nume, k1);
|
|
const b = a.ms !== undefined ? masoara(nume, k2) : a.termen ? {} : { stricat: `nemasurat (${k1} KB a cazut)` };
|
|
if (a.stricat || b.stricat) { stricate++; console.log(`STRICAT ${nume}: ${a.stricat || b.stricat}`); continue; }
|
|
if (a.termen || b.termen) { rosii++; console.log(`ROSU ${nume}: peste ${TERMEN_MS / 1000} s la ${a.termen ? k1 : k2} KB`); continue; }
|
|
const ok = b.ms <= 6 * a.ms + 250 && b.ms < 10000;
|
|
if (!ok) rosii++;
|
|
console.log(`${ok ? 'VERDE ' : 'ROSU '} ${nume.padEnd(16)} ${String(k1).padStart(4)} KB ${a.ms.toFixed(0).padStart(6)} ms | ${String(k2).padStart(4)} KB ${b.ms.toFixed(0).padStart(6)} ms x${(b.ms / Math.max(a.ms, 1)).toFixed(1)}`);
|
|
}
|
|
console.log(`\ncostul inventarului: ${doar.length - rosii - stricate}/${doar.length} liniare, ${rosii} rosii, ${stricate} stricate (modul: ${CALE_MODUL})`);
|
|
process.exitCode = stricate ? 2 : rosii ? 1 : 0;
|
|
}
|