aere-cloud-sdk/test/sdk.test.mjs

161 lines
11 KiB
JavaScript

// Testele SDK-ului: rutele contra unui server FALS (deterministe, offline) + verifyWebhook cu
// perechea negativa + o proba VIE optionala contra productiei daca AERE_CHEIE e in mediu.
import assert from 'node:assert';
import crypto from 'node:crypto';
import { AereCloud, AereCloudError, verifyWebhook } from '../index.mjs';
let treceri = 0;
async function test(nume, fn) {
try { await fn(); treceri++; console.log(' OK ' + nume); }
catch (e) { console.log(' ESEC ' + nume + ' — ' + e.message); process.exitCode = 1; }
}
// ---- server fals: raspunde dupa cale, ca sa testam constructia cererii si maparea erorilor ----
function fetchFals(rute) {
return async (url, opts = {}) => {
const u = new URL(url);
const cale = u.pathname.replace(/^\/v1/, ''); // baseUrl de test include /v1
const cheie = opts.method + ' ' + cale + u.search;
const r = rute[cheie] || rute[opts.method + ' ' + cale];
if (!r) return { ok: false, status: 404, json: async () => ({ error: 'not_found' }) };
r._vazut = { headers: opts.headers, body: opts.body ? JSON.parse(opts.body) : undefined };
return { ok: r.status < 400, status: r.status, json: async () => r.corp };
};
}
// AERE-SINTETIC: cheile de mai jos (ak2800.0xAAA.secret, secretul-meu) sunt FICTIVE, pentru
// testul offline; nu sunt chei ale retelei. Marcajul spune portii de secrete exact asta.
const BAZA_TEST = 'https://x.test/v1';
await test('constructorul cere cheia', () => {
assert.throws(() => new AereCloud({}), /apiKey is required/);
});
await test('cheia merge in antetul x-api-key, health e fara cheie', async () => {
const rute = { 'GET /health': { status: 200, corp: { ok: true, chainId: 2800, block: 5 } },
'GET /account': { status: 200, corp: { address: '0xabc', planId: 5 } } };
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-secret', baseUrl: BAZA_TEST, fetch: fetchFals(rute) });
const h = await c.health();
assert.equal(h.block, 5);
assert.equal(rute['GET /health']._vazut.headers['x-api-key'], undefined, 'health nu trimite cheie');
await c.account();
assert.equal(rute['GET /account']._vazut.headers['x-api-key'], 'ak2800.0xAAA.AERE-SINTETIC-secret');
});
await test('rpc impacheteaza corect si ridica eroarea RPC', async () => {
const rute = {
'POST /rpc': { status: 200, corp: { jsonrpc: '2.0', id: 1, result: '0x10' } },
};
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute) });
assert.equal(await c.blockNumber(), 16);
assert.deepEqual(rute['POST /rpc']._vazut.body, { jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [] });
// eroare RPC in plic -> AereCloudError
const rute2 = { 'POST /rpc': { status: 200, corp: { error: { code: -32601, message: 'nope' } } } };
const c2 = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute2) });
await assert.rejects(() => c2.rpc('qbft_proposeValidatorVote'), (e) => e instanceof AereCloudError && e.body.error.code === -32601);
});
await test('un status HTTP de eroare devine AereCloudError cu corpul serverului', async () => {
const rute = { 'POST /pq/verify': { status: 400, corp: { error: 'bad_publicKey', hint: '0x hex' } } };
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute) });
await assert.rejects(() => c.pqVerify({ scheme: 'ml-dsa-44', publicKey: 'nu-e-hex' }),
(e) => e instanceof AereCloudError && e.status === 400 && e.body.error === 'bad_publicKey');
});
await test('rutele de date construiesc corect query-ul', async () => {
const rute = {
'GET /data/anchors?limit=3': { status: 200, corp: { anchors: [] } },
'GET /data/transfers?address=0xBeef&limit=25': { status: 200, corp: { tokenTransfers: [], nativeTransfers: [] } },
};
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute) });
await c.anchors(3);
await c.transfers('0xBeef', 25);
// daca reperele nu s-ar potrivi, fetchFals ar da 404 si _req ar arunca
});
await test('sponsorCreatePqAccount: cale si corp corecte', async () => {
const rute = { 'POST /sponsor/createPqAccount': { status: 200, corp: { txHash: '0xab', account: '0xcd', alreadyDeployed: false } } };
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals(rute) });
const d = await c.sponsorCreatePqAccount('0x09aa', 5);
assert.equal(d.account, '0xcd');
const trimis = rute['POST /sponsor/createPqAccount']._vazut.body; // fetchFals parseaza deja
assert.equal(trimis.salt, 5);
assert.equal(trimis.falconPubKey, '0x09aa');
});
await test('2026-09-17: proof(hash) si readiness(): ruta, cheia doar cand se cere, corpul corect', async () => {
const H = '0x' + 'ab'.repeat(32);
const vazute = [];
const rute = {
['GET /proof/' + H]: { status: 200, corp: { hash: H, notarized: true, finality: 'post-quantum' } },
'POST /pq/readiness': { status: 200, corp: { domain: 'aere.network', score: 75 } },
'GET /pq/readiness/aere.network': { status: 200, corp: { domain: 'aere.network', score: 75, cached: true } },
};
const f = fetchFals(rute);
const spion = async (url, init) => { vazute.push({ url, cheie: !!(init.headers && init.headers['x-api-key']), corp: init.body }); return f(url, init); };
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: spion });
const p = await c.proof(H); assert.equal(p.finality, 'post-quantum'); assert.equal(vazute[0].cheie, true, 'proof cere cheia');
await c.readiness('aere.network'); assert.equal(vazute[1].cheie, false, 'scanarea libera nu trimite cheia'); assert.equal(vazute[1].corp, JSON.stringify({ domain: 'aere.network' }));
await c.readiness('aere.network', { attest: true, fresh: true }); assert.equal(vazute[2].cheie, true, 'atestarea trimite cheia'); assert.deepEqual(JSON.parse(vazute[2].corp), { domain: 'aere.network', fresh: true, attest: true });
const g = await c.readinessReport('aere.network'); assert.equal(g.cached, true); assert.equal(vazute[3].cheie, false);
});
await test('2026-09-18: readinessPerimeter(): ruta cu cheie, corpul poarta doar ce s-a cerut, discover:false se trimite, un 409 de raport incomplet ajunge la apelant', async () => {
const vazute = [];
const f = fetchFals({ 'POST /pq/readiness/perimeter': { status: 200, corp: { domain: 'example.com', summary: { measured: 3, complete: true } } } });
const spion = async (url, init) => { vazute.push({ cheie: !!(init.headers && init.headers['x-api-key']), corp: init.body }); return f(url, init); };
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: spion });
const r = await c.readinessPerimeter('example.com'); assert.equal(r.summary.measured, 3); assert.equal(vazute[0].cheie, true, 'perimetrul cere cheia'); assert.equal(vazute[0].corp, JSON.stringify({ domain: 'example.com' }));
await c.readinessPerimeter('example.com', { hosts: ['api', 'mail.example.com'], discover: false, attest: true });
assert.deepEqual(JSON.parse(vazute[1].corp), { domain: 'example.com', hosts: ['api', 'mail.example.com'], discover: false, attest: true });
await c.readinessPerimeter('example.com', { discover: true }); assert.equal(vazute[2].corp, JSON.stringify({ domain: 'example.com' }), 'discover:true e implicitul, nu se trimite');
const c409 = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: fetchFals({ 'POST /pq/readiness/perimeter': { status: 409, corp: { attestationError: 'perimeter_incomplete' } } }) });
await assert.rejects(() => c409.readinessPerimeter('example.com', { attest: true }), (e) => e.status === 409);
});
await test('2026-09-18: auditExport(): octetii zilei + digestul din antet; verified=true cand octetii dau digestul, FALSE cand nu il dau; cef nu pretinde verificare; un 400 ajunge la apelant', async () => {
const { createHash } = await import('node:crypto');
const corp = Buffer.from('{"t":"2026-09-17T10:00:00.000Z","m":"GET","p":"/v1/account","s":200}\n');
const d = '0x' + createHash('sha256').update(corp).digest('hex');
const raspuns = (octeti, digest, status = 200) => async (url, init) => new Response(octeti, { status, headers: { 'x-aere-digest': digest, 'x-aere-day': '2026-09-17', 'x-aere-entries': '1' } });
const vazute = [];
const c = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: async (u, i) => { vazute.push({ u, cheie: !!i.headers['x-api-key'] }); return raspuns(corp, d)(u, i); } });
const e = await c.auditExport({ day: '2026-09-17' });
assert.equal(e.verified, true); assert.equal(e.digest, d); assert.equal(e.entries, 1); assert.equal(e.text, corp.toString('utf8')); assert.equal(vazute[0].cheie, true);
assert.ok(vazute[0].u.endsWith('/account/audit?format=jsonl&day=2026-09-17'), vazute[0].u);
const stricat = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: raspuns(Buffer.from('alti octeti'), d) });
assert.equal((await stricat.auditExport({ day: '2026-09-17' })).verified, false, 'octeti care nu dau digestul declarat nu au voie sa iasa verified');
const cef = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: raspuns(Buffer.from('CEF:0|x\n'), d) });
assert.equal((await cef.auditExport({ day: '2026-09-17', format: 'cef' })).verified, null, 'pentru cef digestul e al fisierului-sursa, nu al textului primit');
const rau = new AereCloud({ apiKey: 'ak2800.0xAAA.AERE-SINTETIC-s', baseUrl: BAZA_TEST, fetch: async () => new Response(JSON.stringify({ error: 'bad_format' }), { status: 400 }) });
await assert.rejects(() => rau.auditExport({ format: 'xml' }), (x) => x.status === 400);
});
await test('verifyWebhook: semnatura buna trece, una gresita pica, o litera in plus pica', async () => {
const secret = 'AERE-SINTETIC-secretul-meu';
const corp = JSON.stringify({ event: 'pq-anchor', data: { height: 42 } });
const bun = crypto.createHmac('sha256', secret).update(corp).digest('hex'); // ca serverul
assert.equal(await verifyWebhook(corp, bun, secret), true);
assert.equal(await verifyWebhook(corp, bun.slice(0, -1) + (bun.slice(-1) === 'a' ? 'b' : 'a'), secret), false);
assert.equal(await verifyWebhook(corp, bun + 'x', secret), false);
assert.equal(await verifyWebhook(corp + ' ', bun, secret), false, 'corp modificat = alta semnatura');
});
// ---- proba VIE optionala ----
if (process.env.AERE_CHEIE) {
await test('LIVE: health + account + anchors prin productie', async () => {
const c = new AereCloud({ apiKey: process.env.AERE_CHEIE });
const h = await c.health();
assert.equal(h.chainId, 2800);
assert.ok(h.block > 0);
const a = await c.anchors(1);
assert.ok(a.anchors[0].falconSeals >= 6, 'ancora vie sub cvorum');
const acc = await c.account();
assert.ok(acc.usageLast31Days);
});
} else {
console.log(' (sar proba LIVE: AERE_CHEIE nu e in mediu)');
}
console.log('\n' + treceri + ' teste trecute');