bookworm-smart-assistant/scripts/patches/verify-settings-sig.js

51 lines
1.6 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* verify-settings-sig.js 验证 settings.json HMAC 签名是否一致
*
* 用法:
* node scripts/patches/verify-settings-sig.js # 退出码 0=ok / 1=mismatch
* node scripts/patches/verify-settings-sig.js --quiet # 仅退出码
*/
'use strict';
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const ROOT = path.join(__dirname, '..', '..');
const SETTINGS = path.join(ROOT, 'settings.json');
const SIG_FILE = path.join(ROOT, 'settings.json.sig');
const HMAC_KEY = path.join(ROOT, '.hmac-key');
const QUIET = process.argv.includes('--quiet');
function log(msg) { if (!QUIET) process.stdout.write(msg + '\n'); }
function err(msg) { process.stderr.write(msg + '\n'); }
if (!fs.existsSync(SIG_FILE)) {
err('[FAIL] signature file missing: ' + SIG_FILE);
process.exit(1);
}
if (!fs.existsSync(HMAC_KEY)) {
err('[FAIL] .hmac-key missing');
process.exit(1);
}
const expected = fs.readFileSync(SIG_FILE, 'utf8').trim();
const key = fs.readFileSync(HMAC_KEY, 'utf8').trim();
const content = fs.readFileSync(SETTINGS);
const actual = crypto.createHmac('sha256', key).update(content).digest('hex');
// timing-safe 比较
const ok = expected.length === actual.length &&
crypto.timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(actual, 'hex'));
if (ok) {
log('[OK] settings.json signature valid');
process.exit(0);
} else {
err('[FAIL] settings.json TAMPERED!');
err(' expected: ' + expected.slice(0, 16) + '...' + expected.slice(-16));
err(' actual: ' + actual.slice(0, 16) + '...' + actual.slice(-16));
process.exit(1);
}