fieldlens-desktop/scripts/check-signing.mjs
Admin 03b9077c12
Some checks failed
Desktop Release / Bootstrap updater signing key (push) Has been cancelled
Desktop Release / Windows x64 NSIS (push) Has been cancelled
Desktop Release / Linux x64 DEB + AppImage (push) Has been cancelled
Desktop Release / Publish public desktop release (push) Has been cancelled
fix(desktop): configure bundle icons and verified updater signing
2026-09-26 08:24:32 +00:00

41 lines
2.4 KiB
JavaScript

import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { spawnSync } from 'node:child_process';
import { createHash, createPublicKey, verify } from 'node:crypto';
const temp = mkdtempSync(join(tmpdir(), 'fieldlens-signing-'));
try {
if (!process.env.TAURI_SIGNING_PRIVATE_KEY) throw new Error('missing key');
const probe = join(temp, 'probe.txt');
writeFileSync(probe, 'FieldLens updater signing preflight\n', { mode: 0o600 });
const result = spawnSync(process.execPath, [resolve('node_modules/@tauri-apps/cli/tauri.js'), 'signer', 'sign', probe], {
env: process.env, stdio: 'pipe', timeout: 30000,
});
if (result.status !== 0) throw new Error('signing failed');
const config = JSON.parse(readFileSync('src-tauri/tauri.conf.json', 'utf8'));
const publicLines = Buffer.from(config.plugins.updater.pubkey, 'base64').toString().trim().split(/\r?\n/);
const signatureLines = Buffer.from(readFileSync(probe + '.sig', 'utf8').trim(), 'base64').toString().trim().split(/\r?\n/);
const pub = Buffer.from(publicLines[1], 'base64');
const sig = Buffer.from(signatureLines[1], 'base64');
if (pub.length !== 42 || sig.length !== 74 || !pub.subarray(2, 10).equals(sig.subarray(2, 10))) throw new Error('key mismatch');
const key = createPublicKey({
key: Buffer.concat([Buffer.from('302a300506032b6570032100', 'hex'), pub.subarray(10)]),
format: 'der', type: 'spki',
});
const algorithm = sig.subarray(0, 2).toString();
if (!['ED', 'Ed'].includes(algorithm)) throw new Error('unsupported signature');
const message = readFileSync(probe);
const signed = algorithm === 'ED' ? createHash('blake2b512').update(message).digest() : message;
if (!verify(null, signed, key, sig.subarray(10))) throw new Error('invalid signature');
if (!signatureLines[2].startsWith('trusted comment: ')) throw new Error('invalid comment');
const comment = Buffer.from(signatureLines[2].slice('trusted comment: '.length));
if (!verify(null, Buffer.concat([sig.subarray(10), comment]), key, Buffer.from(signatureLines[3], 'base64'))) throw new Error('invalid trusted comment');
console.log('Updater signing preflight passed: key, password and public key match.');
} catch {
console.error('Updater signing preflight failed: check the signing key/password and configured public key.');
process.exitCode = 1;
} finally {
rmSync(temp, { recursive: true, force: true });
}