#!/usr/bin/env node
// OTA firmware signing tool. No npm dependencies required.
// Usage:
//   node sign.js keygen            # generate private.pem + print public key #define
//   node sign.js sign firmware.bin # append 64-byte ECDSA-P256 signature

'use strict';

const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

function usage() {
  console.error('Usage:');
  console.error('  node sign.js keygen              # generate key pair');
  console.error('  node sign.js sign FIRMWARE.bin   # sign firmware');
  process.exit(1);
}

// DER-encoded ECDSA signature -> raw 64-byte R||S
function derToRaw(der) {
  let i = 2;              // skip SEQUENCE tag + length
  i++;                    // skip INTEGER tag
  const rLen = der[i++];
  const r = der.slice(i, i + rLen); i += rLen;
  i++;                    // skip INTEGER tag
  const sLen = der[i++];
  const s = der.slice(i, i + sLen);
  return Buffer.concat([to32(r), to32(s)]);
}

// Normalize a DER integer to exactly 32 bytes (strip leading 0x00, zero-pad)
function to32(b) {
  while (b.length > 32 && b[0] === 0) b = b.slice(1);
  const out = Buffer.alloc(32, 0);
  b.copy(out, 32 - b.length);
  return out;
}

function keygen() {
  const { privateKey, publicKey } = crypto.generateKeyPairSync('ec', {
    namedCurve: 'P-256',
  });

  fs.writeFileSync('private.pem', privateKey.export({ type: 'pkcs8', format: 'pem' }));
  console.log('Wrote private.pem  (keep secret, never ship in firmware)');

  // SPKI DER for P-256 ends with: 04 [X 32 bytes] [Y 32 bytes]
  // We want the raw 64-byte X||Y (no 0x04 prefix) for mg_uecc_verify
  const spki = publicKey.export({ type: 'spki', format: 'der' });
  const raw = spki.slice(-64);

  const hex = Array.from(raw).map(b => '0x' + b.toString(16).padStart(2, '0'));
  const rows = [];
  for (let i = 0; i < 64; i += 8)
    rows.push('  ' + hex.slice(i, i + 8).join(', '));

  console.log('\nAdd to your mongoose_config.h:');
  console.log(`#define MG_OTA_PUBLIC_KEY { \\\n${rows.join(', \\\n')}, \\\n}`);
}

function sign(firmware, privateKeyFile = 'private.pem') {
  const fw = fs.readFileSync(firmware);
  const privateKey = crypto.createPrivateKey(fs.readFileSync(privateKeyFile));
  const derSig = crypto.sign('SHA256', fw, privateKey);
  const raw = derToRaw(derSig);  // 64 bytes: R||S

  const dot = firmware.lastIndexOf('.');
  const out = dot >= 0
    ? firmware.slice(0, dot) + '.signed' + firmware.slice(dot)
    : firmware + '.signed';

  fs.writeFileSync(out, Buffer.concat([fw, raw, Buffer.from('MGSG')]));
  console.log(`Signed: ${out}  (${fw.length} bytes firmware + 64 bytes signature + 4 bytes magic)`);
}

const [,, cmd, arg1, arg2] = process.argv;
if      (cmd === 'keygen')          keygen();
else if (cmd === 'sign' && arg1)    sign(arg1, arg2);
else                                usage();
