diff options
| author | Tobias Järvelöv <tobias.jarvelov@mullvad.net> | 2025-05-13 14:35:01 +0200 |
|---|---|---|
| committer | Sebastian Holmin <sebastian.holmin@mullvad.net> | 2025-05-28 13:25:41 +0200 |
| commit | 5a0d951c53812b5139ed3c438d044efb519944cc (patch) | |
| tree | 19695cfd1d8eff09644a6a72f70fd115b1e5db64 | |
| parent | d899e07677532afaeb832fa56f6248888791b1d8 (diff) | |
| download | mullvadvpn-5a0d951c53812b5139ed3c438d044efb519944cc.tar.xz mullvadvpn-5a0d951c53812b5139ed3c438d044efb519944cc.zip | |
Add check that path exists before trying to start installer
Otherwise abort the process and emit an error.
| -rw-r--r-- | desktop/packages/mullvad-vpn/src/main/app-upgrade.ts | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts index 6ca33c729f..ff50218d5e 100644 --- a/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts +++ b/desktop/packages/mullvad-vpn/src/main/app-upgrade.ts @@ -1,4 +1,5 @@ import { spawn } from 'child_process'; +import fs from 'fs/promises'; import { tmpdir } from 'os'; import { DaemonAppUpgradeEvent } from '../shared/daemon-rpc-types'; @@ -18,21 +19,14 @@ export default class AppUpgrade { this.daemonRpc.appUpgradeAbort(); }); - IpcMainEventChannel.app.handleUpgradeInstallerStart((verifiedInstallerPath: string) => { + IpcMainEventChannel.app.handleUpgradeInstallerStart(async (verifiedInstallerPath: string) => { try { + await this.checkInstallerPath(verifiedInstallerPath); this.startInstaller(verifiedInstallerPath); - IpcMainEventChannel.app.notifyUpgradeEvent?.({ - type: 'APP_UPGRADE_STATUS_STARTED_INSTALLER', - }); } catch (e) { - IpcMainEventChannel.app.notifyUpgradeError?.('START_INSTALLER_FAILED'); - IpcMainEventChannel.app.notifyUpgradeEvent?.({ - type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', - }); - const error = e as Error; log.error( - `An error occurred when starting installer at path: ${verifiedInstallerPath}. Error: ${error.message}`, + `An error occurred when trying to start the installer: ${verifiedInstallerPath}. Error: ${error.message}`, ); } }); @@ -57,6 +51,33 @@ export default class AppUpgrade { return daemonAppUpgradeEventListener; } + private async checkInstallerPath(verifiedInstallerPath: string) { + try { + // fs.stat throws if the path does not exist + const stat = await fs.stat(verifiedInstallerPath); + // If the path exists, verify that its a file. + if (!stat.isFile()) { + throw new Error('Verified installer path is not a file.'); + } + } catch (e) { + // Let the render process know we encountered an error + IpcMainEventChannel.app.notifyUpgradeError?.('GENERAL_ERROR'); + // If the daemon for some reason doesn't reply with an aborted event we should + // let the render process know which event step to re-start from. + IpcMainEventChannel.app.notifyUpgradeEvent?.({ + type: 'APP_UPGRADE_STATUS_MANUAL_START_INSTALLER', + }); + + // Let the daemon know the we are aborting the upgrade + this.daemonRpc.appUpgradeAbort(); + + const error = e as Error; + throw new Error( + `An error occurred when checking installer at path: ${verifiedInstallerPath}. Error: ${error.message}`, + ); + } + } + private spawnChildMac(verifiedInstallerPath: string) { const child = spawn('open', [verifiedInstallerPath, '--wait-apps'], { detached: true, @@ -95,25 +116,40 @@ export default class AppUpgrade { } private startInstaller(verifiedInstallerPath: string) { - const child = this.spawnChild(verifiedInstallerPath); - - child.once('error', (error) => { - log.error(`An error occurred with the installer: ${error.message}`); - IpcMainEventChannel.app.notifyUpgradeError?.('INSTALLER_FAILED'); + try { + const child = this.spawnChild(verifiedInstallerPath); IpcMainEventChannel.app.notifyUpgradeEvent?.({ - type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', + type: 'APP_UPGRADE_STATUS_STARTED_INSTALLER', }); - }); - child.once('exit', (code) => { - if (code !== 0) { - log.error(`The installer exited unexpectedly with exit code: ${code}`); + child.once('error', (error) => { + log.error(`An error occurred with the installer: ${error.message}`); IpcMainEventChannel.app.notifyUpgradeError?.('INSTALLER_FAILED'); - } + IpcMainEventChannel.app.notifyUpgradeEvent?.({ + type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', + }); + }); + + child.once('exit', (code) => { + if (code !== 0) { + log.error(`The installer exited unexpectedly with exit code: ${code}`); + IpcMainEventChannel.app.notifyUpgradeError?.('INSTALLER_FAILED'); + } + IpcMainEventChannel.app.notifyUpgradeEvent?.({ + type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', + }); + }); + } catch (e) { + IpcMainEventChannel.app.notifyUpgradeError?.('START_INSTALLER_FAILED'); IpcMainEventChannel.app.notifyUpgradeEvent?.({ type: 'APP_UPGRADE_STATUS_EXITED_INSTALLER', }); - }); + + const error = e as Error; + log.error( + `An error occurred when starting installer at path: ${verifiedInstallerPath}. Error: ${error.message}`, + ); + } } } |
