// Interop-Test v2: lädt EXAKT den Core aus der ausgelieferten index.html und // prüft Byte-Kompatibilität mit dem Python-CLI (richtungsgetrennte Schlüssel). import { readFileSync, writeFileSync } from 'node:fs'; const U = (p) => new Uint8Array(readFileSync(new URL(p, import.meta.url))); const html = readFileSync(new URL('./index.html', import.meta.url), 'utf8'); const core = html.match(/==CORE START==.*?\*\/([\s\S]*?)\/\*\s*==CORE END==/)[1]; new Function(core)(); const SP = globalThis.SP; let fails = 0; const ok = (c, m) => { console.log((c ? ' ✓ ' : ' ✗ ') + m); if (!c) fails++; }; // A: CLI (send.key) -> Web-Core (recv.key) { const rgb = U('./_a_rgb.bin'); const recv = SP.parseKey(U('../t2/rel_partner_seite/recv.key')); const info = SP.extract(rgb); const plain = SP.otpXor(info.ciphertext, recv.material, info.offset); const text = new TextDecoder().decode(plain); console.log('A) CLI → Web'); ok(SP.sameStream(info.streamId, recv.streamId), 'stream_id passt zum recv.key'); ok(text === 'MsgA vom CLI 🕵️', 'Klartext: ' + JSON.stringify(text)); } // B: Web-Core (send.key) -> CLI (recv.key) { const rgb = U('./_b_rgb.bin'); const send = SP.parseKey(U('../t2/rel_partner_seite/send.key')); const msg = 'MsgB aus dem Browser-Core 🌐'; ok(send.role === SP.ROLE_SEND, 'partner send.key hat Rolle SEND'); const plain = new TextEncoder().encode(msg); const ct = SP.otpXor(plain, send.material, send.sendOffset); const payload = SP.buildStego(send.streamId, send.sendOffset, ct); SP.embed(rgb, payload); writeFileSync(new URL('./_b_out_rgb.bin', import.meta.url), rgb); console.log('B) Web → CLI'); ok(true, `eingebettet (${plain.length} B ab Offset ${send.sendOffset}) → _b_out_rgb.bin`); } process.exit(fails ? 1 : 0);