mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
fix(desktop): drop orphaned Squirrel uninstall entry (#2885)
This commit is contained in:
1 parent
70e1ce682a
commit
242ed3a934
3 files changed
+95
-1
No files matched your search
@@ -6,7 +6,8 @@ export const DESKTOP_APP_NAME = BUILD_CHANNEL === 'canary' ? 'Fluxer Canary' : '
|
|||||||
export const MACOS_BUNDLE_ID = BUILD_CHANNEL === 'canary' ? 'app.fluxer.canary' : 'app.fluxer';
|
export const MACOS_BUNDLE_ID = BUILD_CHANNEL === 'canary' ? 'app.fluxer.canary' : 'app.fluxer';
|
||||||
export const LINUX_DESKTOP_ENTRY_ID = BUILD_CHANNEL === 'canary' ? 'fluxer-canary' : 'fluxer';
|
export const LINUX_DESKTOP_ENTRY_ID = BUILD_CHANNEL === 'canary' ? 'fluxer-canary' : 'fluxer';
|
||||||
export const WINDOWS_SHORTCUT_AUTHOR = 'Fluxer Platform AB';
|
export const WINDOWS_SHORTCUT_AUTHOR = 'Fluxer Platform AB';
|
||||||
const WINDOWS_VELOPACK_ID = BUILD_CHANNEL === 'canary' ? 'fluxer_desktop_canary' : 'fluxer_desktop';
|
export const WINDOWS_VELOPACK_ID = BUILD_CHANNEL === 'canary' ? 'fluxer_desktop_canary' : 'fluxer_desktop';
|
||||||
|
export const WINDOWS_LEGACY_SQUIRREL_ID = 'fluxer_app';
|
||||||
export const WINDOWS_APP_USER_MODEL_ID = BUILD_CHANNEL === 'canary' ? 'Fluxer.Fluxer.Canary' : 'Fluxer.Fluxer';
|
export const WINDOWS_APP_USER_MODEL_ID = BUILD_CHANNEL === 'canary' ? 'Fluxer.Fluxer.Canary' : 'Fluxer.Fluxer';
|
||||||
export const WINDOWS_LEGACY_APP_USER_MODEL_IDS = [`velopack.${WINDOWS_VELOPACK_ID}`];
|
export const WINDOWS_LEGACY_APP_USER_MODEL_IDS = [`velopack.${WINDOWS_VELOPACK_ID}`];
|
||||||
export const WINDOWS_TOAST_ACTIVATOR_CLSID =
|
export const WINDOWS_TOAST_ACTIVATOR_CLSID =
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {execFile} from 'node:child_process';
|
||||||
|
import fs from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import {WINDOWS_LEGACY_SQUIRREL_ID, WINDOWS_VELOPACK_ID} from '@electron/common/DesktopIdentity';
|
||||||
|
import log from 'electron-log';
|
||||||
|
|
||||||
|
const UNINSTALL_REGISTRY_KEY = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall';
|
||||||
|
|
||||||
|
interface RegResult {
|
||||||
|
status: number;
|
||||||
|
stdout: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function runReg(args: Array<string>): Promise<RegResult> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
execFile('reg.exe', args, {encoding: 'utf8', windowsHide: true}, (error, stdout) => {
|
||||||
|
if (!error) {
|
||||||
|
resolve({status: 0, stdout});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof error.code === 'number') {
|
||||||
|
resolve({status: error.code, stdout});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeWindowsPath(target: string): string {
|
||||||
|
return path.resolve(target).replace(/\\+$/, '').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRunningFromMigratedSquirrelRoot(): boolean {
|
||||||
|
const localAppData = process.env.LOCALAPPDATA;
|
||||||
|
if (!localAppData) return false;
|
||||||
|
const currentDir = path.dirname(process.execPath);
|
||||||
|
if (path.basename(currentDir).toLowerCase() !== 'current') return false;
|
||||||
|
const rootAppDir = path.dirname(currentDir);
|
||||||
|
if (normalizeWindowsPath(rootAppDir) !== normalizeWindowsPath(path.join(localAppData, WINDOWS_LEGACY_SQUIRREL_ID))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return fs.existsSync(path.join(rootAppDir, 'Update.exe'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function uninstallKey(appId: string): string {
|
||||||
|
return `${UNINSTALL_REGISTRY_KEY}\\${appId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseInstallLocation(stdout: string): string | null {
|
||||||
|
const match = stdout.match(/^\s*InstallLocation\s+REG_(?:EXPAND_)?SZ\s+(.*?)\s*$/im);
|
||||||
|
return match ? match[1] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function velopackEntryDescribesLegacyRoot(): Promise<boolean> {
|
||||||
|
const {status, stdout} = await runReg(['query', uninstallKey(WINDOWS_VELOPACK_ID), '/v', 'InstallLocation']);
|
||||||
|
if (status !== 0) return false;
|
||||||
|
const installLocation = parseInstallLocation(stdout);
|
||||||
|
if (!installLocation) return false;
|
||||||
|
return path.basename(installLocation.replace(/\\+$/, '')).toLowerCase() === WINDOWS_LEGACY_SQUIRREL_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeLegacySquirrelUninstallEntryAsync(): Promise<void> {
|
||||||
|
const legacyKey = uninstallKey(WINDOWS_LEGACY_SQUIRREL_ID);
|
||||||
|
const legacyEntry = await runReg(['query', legacyKey]);
|
||||||
|
if (legacyEntry.status !== 0) return;
|
||||||
|
if (!(await velopackEntryDescribesLegacyRoot())) {
|
||||||
|
log.info('[LegacyUninstallEntry] Keeping the Squirrel uninstall entry, no Velopack entry describes this install');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const removal = await runReg(['delete', legacyKey, '/f']);
|
||||||
|
if (removal.status !== 0) {
|
||||||
|
log.warn('[LegacyUninstallEntry] Failed to remove the Squirrel uninstall entry', {status: removal.status});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info('[LegacyUninstallEntry] Removed the Squirrel uninstall entry', {key: legacyKey});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeLegacySquirrelUninstallEntry(): void {
|
||||||
|
if (process.platform !== 'win32') return;
|
||||||
|
if (!isRunningFromMigratedSquirrelRoot()) return;
|
||||||
|
removeLegacySquirrelUninstallEntryAsync().catch((error: unknown) => {
|
||||||
|
log.warn('[LegacyUninstallEntry] Failed to clean up the Squirrel uninstall entry', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -75,6 +75,7 @@ import {
|
|||||||
setQuitting,
|
setQuitting,
|
||||||
showWindow,
|
showWindow,
|
||||||
} from '@electron/main/Window';
|
} from '@electron/main/Window';
|
||||||
|
import {removeLegacySquirrelUninstallEntry} from '@electron/main/WindowsLegacyUninstallEntry';
|
||||||
import {removeFluxerVulkanLayerRegistrations} from '@electron/main/WindowsVulkanLayerCleanup';
|
import {removeFluxerVulkanLayerRegistrations} from '@electron/main/WindowsVulkanLayerCleanup';
|
||||||
import {app, dialog, netLog} from 'electron';
|
import {app, dialog, netLog} from 'electron';
|
||||||
import log from 'electron-log';
|
import log from 'electron-log';
|
||||||
@@ -361,6 +362,11 @@ if (launchConfigurationError) {
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
log.error('[Init] Failed to remove stale Vulkan layer registrations:', error);
|
log.error('[Init] Failed to remove stale Vulkan layer registrations:', error);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
runStartupPhase('legacy-uninstall-entry-cleanup', removeLegacySquirrelUninstallEntry);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
log.error('[Init] Failed to remove the legacy Squirrel uninstall entry:', error);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
runStartupPhase('native-screen-capture-handlers', registerNativeScreenCaptureHandlers);
|
runStartupPhase('native-screen-capture-handlers', registerNativeScreenCaptureHandlers);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
Reference in new issue
Block a user