34 lines
2.4 KiB
JavaScript
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)); }
|