Files
story/web/test/ble-hardware.mjs
T
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

34 lines
2.4 KiB
JavaScript

// Explicit opt-in real-hardware smoke check. Does not submit Wi-Fi or bind an account.
import { spawn } from 'node:child_process';
import { createInterface } from 'node:readline';
import { readFileSync } from 'node:fs';
import ts from 'typescript';
const label = JSON.parse(readFileSync(process.argv[2], 'utf8'));
const compiled = ts.transpileModule(readFileSync(new URL('../src/ble/security2.ts', import.meta.url), 'utf8'), { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext } }).outputText;
const { Security2 } = await import('data:text/javascript;base64,' + Buffer.from(compiled).toString('base64'));
const python = process.env.BLE_PYTHON;
if (!python) throw new Error('Set BLE_PYTHON to the ESP-IDF Python executable');
const child = spawn(python, ['../.tmp-ble-release/ble_bridge.py', 'EchoEar-' + label.device_id.slice(-6)], { stdio: ['pipe','pipe','inherit'] });
const lines = createInterface({ input: child.stdout })[Symbol.asyncIterator]();
async function receive() { const line = await lines.next(); if (line.done) throw new Error('BLE bridge ended'); const result = JSON.parse(line.value); if (result.error) throw new Error(result.error); return result; }
try {
const connected = await receive(); console.log(JSON.stringify(connected));
const security = new Security2();
async function exchange(type, data) {
const header = Buffer.from([type, data.length & 255, data.length >> 8]);
child.stdin.write(JSON.stringify({ frame: Buffer.concat([header, data]).toString('base64') }) + '\n');
const frame = Buffer.from((await receive()).frame,'base64');
if (frame[0] !== type || frame.readUInt16LE(1) + 3 !== frame.length) throw new Error('Invalid device reply');
return frame.subarray(3);
}
await security.handshake(label.device_id, label.setup_password, data => exchange(0, data));
console.log('Real ESP-IDF Security2 handshake verified');
for (const cmd of ['get_info','get_status','get_info','get_status']) {
const raw = Buffer.from(JSON.stringify({ cmd }));
const response = JSON.parse(Buffer.from(await security.decrypt(await exchange(1, await security.encrypt(raw)))).toString());
if (cmd === 'get_info' && response.device_id !== label.device_id) throw new Error('Wrong physical device');
console.log(JSON.stringify({ cmd, response }));
}
security.clear();
} finally { child.stdin.end(JSON.stringify({ close: true }) + '\n'); await new Promise(resolve => child.on('exit', resolve)); }