diff --git a/node_modules/app-builder-lib/out/asar/asarUtil.js b/node_modules/app-builder-lib/out/asar/asarUtil.js index 7f37444..1a85145 100644 --- a/node_modules/app-builder-lib/out/asar/asarUtil.js +++ b/node_modules/app-builder-lib/out/asar/asarUtil.js @@ -31,10 +31,16 @@ class AsarPackager { } await (0, promises_1.mkdir)(path.dirname(this.outFile), { recursive: true }); const unpackedFileIndexMap = new Map(); - for (const fileSet of fileSets) { + const orderedFileSets = [ + // Write dependencies first to minimize offset changes to asar header + ...fileSets.slice(1), + // Finish with the app files that change most often + fileSets[0] + ].map(orderFileSet); + for (const fileSet of orderedFileSets) { unpackedFileIndexMap.set(fileSet, await this.createPackageFromFiles(fileSet, packager.info)); } - await this.writeAsarFile(fileSets, unpackedFileIndexMap); + await this.writeAsarFile(orderedFileSets, unpackedFileIndexMap); } async createPackageFromFiles(fileSet, packager) { const metadata = fileSet.metadata; @@ -238,4 +244,47 @@ function copyFileOrData(fileCopier, data, source, destination, stats) { return (0, promises_1.writeFile)(destination, data); } } +function orderFileSet(fileSet) { + const filesAndIndices = Array.from(fileSet.files.entries()); + filesAndIndices.sort(([, a], [, b]) => { + if (a === b) { + return 0; + } + // Place addons last because their signature change + const isAAddon = a.endsWith('.node'); + const isBAddon = b.endsWith('.node'); + if (isAAddon && !isBAddon) { + return 1; + } + if (isBAddon && !isAAddon) { + return -1; + } + // Otherwise order by name + return a < b ? -1 : 1; + }); + let transformedFiles; + if (fileSet.transformedFiles) { + transformedFiles = new Map(); + const indexMap = new Map(); + for (const [newIndex, [oldIndex,]] of filesAndIndices.entries()) { + indexMap.set(oldIndex, newIndex); + } + for (const [oldIndex, value] of fileSet.transformedFiles) { + const newIndex = indexMap.get(oldIndex); + if (newIndex === undefined) { + const file = fileSet.files[oldIndex]; + throw new Error(`Internal error: ${file} was lost while ordering asar`); + } + transformedFiles.set(newIndex, value); + } + } + const { src, destination, metadata, } = fileSet; + return { + src, + destination, + metadata, + files: filesAndIndices.map(([, file]) => file), + transformedFiles, + }; +} //# sourceMappingURL=asarUtil.js.map \ No newline at end of file diff --git a/node_modules/app-builder-lib/out/electron/ElectronFramework.js b/node_modules/app-builder-lib/out/electron/ElectronFramework.js index 2b09620..739e296 100644 --- a/node_modules/app-builder-lib/out/electron/ElectronFramework.js +++ b/node_modules/app-builder-lib/out/electron/ElectronFramework.js @@ -9,6 +9,7 @@ const path = require("path"); const index_1 = require("../index"); const pathManager_1 = require("../util/pathManager"); const electronMac_1 = require("./electronMac"); +const electronWin_1 = require("./electronWin"); const electronVersion_1 = require("./electronVersion"); const fs = require("fs/promises"); const injectFFMPEG_1 = require("./injectFFMPEG"); @@ -39,6 +40,9 @@ async function beforeCopyExtraFiles(options) { else if (packager.platform === index_1.Platform.WINDOWS) { const executable = path.join(appOutDir, `${packager.appInfo.productFilename}.exe`); await (0, fs_extra_1.rename)(path.join(appOutDir, `${electronBranding.projectName}.exe`), executable); + if (options.asarIntegrity) { + await (0, electronWin_1.addWinAsarIntegrity)(executable, options.asarIntegrity); + } } else { await (0, electronMac_1.createMacApp)(packager, appOutDir, options.asarIntegrity, options.platformName === "mas"); diff --git a/node_modules/app-builder-lib/out/electron/electronWin.js b/node_modules/app-builder-lib/out/electron/electronWin.js new file mode 100644 index 0000000..f198807 --- /dev/null +++ b/node_modules/app-builder-lib/out/electron/electronWin.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.addWinAsarIntegrity = void 0; +const promises_1 = require("fs/promises"); +const cjs_1 = require("resedit/cjs"); +const builder_util_1 = require("builder-util"); +/** @internal */ +async function addWinAsarIntegrity(executablePath, asarIntegrity) { + const resedit = await (0, cjs_1.load)(); + const buffer = await (0, promises_1.readFile)(executablePath); + const executable = resedit.NtExecutable.from(buffer); + const resource = resedit.NtExecutableResource.from(executable); + const versionInfo = resedit.Resource.VersionInfo.fromEntries(resource.entries); + if (versionInfo.length !== 1) { + throw new Error(`Failed to parse version info in ${executablePath}`); + } + const languages = versionInfo[0].getAllLanguagesForStringValues(); + if (languages.length !== 1) { + throw new Error(`Failed to locate languages in ${executablePath}`); + } + // See: https://github.com/electron/packager/blob/00d20b99cf4aa4621103dbbd09ff7de7d2f7f539/src/resedit.ts#L124 + const integrityList = Array.from(Object.entries(asarIntegrity)).map(([file, { algorithm: alg, hash: value }]) => ({ + file, + alg, + value, + })); + resource.entries.push({ + type: "INTEGRITY", + id: "ELECTRONASAR", + bin: Buffer.from(JSON.stringify(integrityList)), + lang: languages[0].lang, + codepage: languages[0].codepage, + }); + resource.outputResource(executable); + await (0, promises_1.writeFile)(executablePath, Buffer.from(executable.generate())); + builder_util_1.log.info({ executablePath }, "updating asar integrity executable resource"); +} +exports.addWinAsarIntegrity = addWinAsarIntegrity; +//# sourceMappingURL=electronWin.js.map diff --git a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js index c3f1000..62bd27c 100644 --- a/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js +++ b/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js @@ -100,7 +100,7 @@ class LinuxTargetHelper { // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables const execCodes = ["%f", "%u", "%F", "%U"]; if (executableArgs == null || executableArgs.findIndex(arg => execCodes.includes(arg)) === -1) { - exec += " %U"; + exec += " --no-sandbox %U"; } } const desktopMeta = { diff --git a/node_modules/app-builder-lib/templates/linux/after-install.tpl b/node_modules/app-builder-lib/templates/linux/after-install.tpl index 65e7326..29a8c44 100644 --- a/node_modules/app-builder-lib/templates/linux/after-install.tpl +++ b/node_modules/app-builder-lib/templates/linux/after-install.tpl @@ -10,9 +10,6 @@ else ln -sf '/opt/${sanitizedProductName}/${executable}' '/usr/bin/${executable}' fi -# SUID chrome-sandbox for Electron 5+ -chmod 4755 '/opt/${sanitizedProductName}/chrome-sandbox' || true - if hash update-mime-database 2>/dev/null; then update-mime-database /usr/share/mime || true fi diff --git a/node_modules/app-builder-lib/templates/nsis/include/allowOnlyOneInstallerInstance.nsh b/node_modules/app-builder-lib/templates/nsis/include/allowOnlyOneInstallerInstance.nsh index fe5d45c..8bb2bf4 100644 --- a/node_modules/app-builder-lib/templates/nsis/include/allowOnlyOneInstallerInstance.nsh +++ b/node_modules/app-builder-lib/templates/nsis/include/allowOnlyOneInstallerInstance.nsh @@ -43,6 +43,7 @@ !else # find process owned by current user nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | %SYSTEMROOT%\System32\find.exe "${_FILE}"` + nsExec::Exec `"$SYSDIR\cmd.exe" /c tasklist /FI "USERNAME eq %USERNAME%" /FI "IMAGENAME eq ${_FILE}" /FO csv | "$SYSDIR\find.exe" "${_FILE}"` Pop ${_ERR} !endif !macroend @@ -73,7 +74,7 @@ !ifdef INSTALL_MODE_PER_ALL_USERS nsExec::Exec `taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"` !else - nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"` + nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"` !endif # to ensure that files are not "in-use" Sleep 300 @@ -91,7 +92,7 @@ !ifdef INSTALL_MODE_PER_ALL_USERS nsExec::Exec `taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid"` !else - nsExec::Exec `%SYSTEMROOT%\System32\cmd.exe /c taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"` + nsExec::Exec `"$SYSDIR\cmd.exe" /c taskkill /f /im "${APP_EXECUTABLE_FILENAME}" /fi "PID ne $pid" /fi "USERNAME eq %USERNAME%"` !endif !insertmacro FIND_PROCESS "${APP_EXECUTABLE_FILENAME}" $R0 ${If} $R0 == 0 diff --git a/node_modules/app-builder-lib/templates/nsis/include/installer.nsh b/node_modules/app-builder-lib/templates/nsis/include/installer.nsh index 34e91df..73bfffc 100644 --- a/node_modules/app-builder-lib/templates/nsis/include/installer.nsh +++ b/node_modules/app-builder-lib/templates/nsis/include/installer.nsh @@ -90,7 +90,13 @@ ${if} $installMode == "all" SetShellVarContext current ${endif} - !insertmacro copyFile "$EXEPATH" "$LOCALAPPDATA\${APP_INSTALLER_STORE_FILE}" + # SIGNAL CHANGE START + # This file is needed for electron-builder's native incremental updates, + # but we have our own system so no need to place it. Clean it up instead. + # + # !insertmacro copyFile "$EXEPATH" "$LOCALAPPDATA\${APP_INSTALLER_STORE_FILE}" + RMDir /r /REBOOTOK "$LOCALAPPDATA\signal-desktop-updater" + # SIGNAL CHANGE END ${if} $installMode == "all" SetShellVarContext all ${endif} diff --git a/node_modules/app-builder-lib/templates/nsis/installSection.nsh b/node_modules/app-builder-lib/templates/nsis/installSection.nsh index 053772f..7981a4e 100644 --- a/node_modules/app-builder-lib/templates/nsis/installSection.nsh +++ b/node_modules/app-builder-lib/templates/nsis/installSection.nsh @@ -22,11 +22,38 @@ StrCpy $appExe "$INSTDIR\${APP_EXECUTABLE_FILENAME}" SpiderBanner::Show /MODERN !endif + # Set text (1000 is the id of text element of SpiderBanner) FindWindow $0 "#32770" "" $hwndparent FindWindow $0 "#32770" "" $hwndparent $0 - GetDlgItem $0 $0 1000 - SendMessage $0 ${WM_SETTEXT} 0 "STR:$(installing)" + GetDlgItem $1 $0 1000 + SendMessage $1 ${WM_SETTEXT} 0 "STR:$(installing)" + + # Set header image compatible with "ManifestDPIAware" mode. + !ifdef HEADER_ICO + # Convert 24 Dialog Units to pixels: + # See https://github.com/mozilla/gecko-dev/blob/8de0e699002872d969aebf1bc8407e5c839a4472/toolkit/mozapps/installer/windows/nsis/common.nsh#L8801 + + # rect = LPRect { .left = 0, .top = 0, .right = 24, .bottom = 0 } + # See https://nsis.sourceforge.io/Docs/System/System.html#faq + System::Call "*(i 0, i 0, i 24, i 0) p.r1" + + # Call `MapDialogRect(window, &rect)` + System::Call `user32::MapDialogRect(p $0, p r1)` + + # rect.right now contains the converted value (24du => ?px). + # Place `rect.right` into `r2` + System::Call "*$1(i, i, i.r2, i)" + System::Free $1 + + # Load image and pass `r2` as both width and height, get the image handle + # back to `r2` register. + System::Call `user32::LoadImage(i 0, t "$PLUGINSDIR\installerHeaderico.ico", i ${IMAGE_ICON}, i r2, i r2, i ${LR_LOADFROMFILE}) i.r2` + + # 1025 is the id of the icon of SpiderBanner. + GetDlgItem $1 $0 1025 + SendMessage $1 ${STM_SETIMAGE} ${IMAGE_ICON} $2 + !endif StrCpy $1 $hwndparent System::Call 'user32::ShutdownBlockReasonCreate(${SYSTYPE_PTR}r1, w "$(installing)")' ${endif}