Files
clawX/scripts/patch-nsis-install-section.mjs

90 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Patch electron-builder's assisted install section so the app-running guard is
* executed in the elevated UAC inner instance as well.
*
* electron-builder skips CHECK_APP_RUNNING for assisted installers when
* UAC_IsInnerInstance is true. Per-machine upgrades run the actual file
* replacement in that inner process, so the old ClawX.exe can remain alive,
* keep $INSTDIR locked, and make the installer appear successful while the old
* files remain installed.
*/
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');
export const INSTALL_SECTION_NSH = join(
ROOT,
'node_modules',
'app-builder-lib',
'templates',
'nsis',
'installSection.nsh',
);
const PATCH_MARKER = 'ClawX-patched-v2: run app-running guard in assisted UAC inner instance';
const ORIGINAL_ASSISTED_CHECK = [
'!else',
' ${ifNot} ${UAC_IsInnerInstance}',
' !insertmacro CHECK_APP_RUNNING',
' ${endif}',
'!endif',
].join('\n');
const PATCHED_ASSISTED_CHECK = [
'!else',
` ; ${PATCH_MARKER}.`,
' ; Per-machine assisted upgrades perform the actual install in the elevated',
' ; UAC inner instance; skipping CHECK_APP_RUNNING there can leave ClawX.exe',
' ; alive and make the installer false-succeed with old files still present.',
' !insertmacro CHECK_APP_RUNNING',
'!endif',
].join('\n');
function isTemplateHealthy(content) {
return content.includes(PATCH_MARKER)
&& content.includes('!insertmacro CHECK_APP_RUNNING')
&& !content.includes([' ${ifNot} ${UAC_IsInnerInstance}', ' !insertmacro CHECK_APP_RUNNING'].join('\n'));
}
/**
* @param {string} [targetPath]
* @returns {boolean}
*/
export function patchNsisInstallSectionTemplate(targetPath = INSTALL_SECTION_NSH) {
if (!existsSync(targetPath)) {
console.warn('[patch-nsis-install-section] installSection.nsh not found, skipping.');
return false;
}
const original = readFileSync(targetPath, 'utf8');
if (isTemplateHealthy(original)) {
return true;
}
if (!original.includes(ORIGINAL_ASSISTED_CHECK)) {
console.warn('[patch-nsis-install-section] Assisted CHECK_APP_RUNNING block not found — template may have changed.');
return false;
}
const patched = original.replace(ORIGINAL_ASSISTED_CHECK, PATCHED_ASSISTED_CHECK);
if (patched === original) {
console.warn('[patch-nsis-install-section] No changes applied.');
return false;
}
writeFileSync(targetPath, patched, 'utf8');
console.log('[patch-nsis-install-section] Patched installSection.nsh (run app guard in assisted UAC inner instance).');
return true;
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
const ok = patchNsisInstallSectionTemplate();
process.exit(ok ? 0 : 1);
}