Major Changes
-
Feat(updater): add
verifyUpdateFiletoAppUpdater, and rename the NSIS Authenticode verification interface#10239317fc9e@LemonexeAppUpdater.verifyUpdateFilelets an app run its own verification of an update file before that file is allowed to become installable. The default implementation is a stub that immediately succeeds. It runs on every path that can lead to an install — right after a fresh download (while the file still sits under a temporary name, so an unverified file is never executable under its real name), when an update downloaded by an earlier session is reused from the cache, and before an install-on-next-launch spawns the cached installer. On failure the file is deleted and anERR_UPDATER_INVALID_UPDATE_FILEerror is emitted. Assigningnullrestores the default.The NSIS Authenticode verification interface now returns an unambiguous result object instead of the
null-means-success /string-means-error convention:type VerifyUpdateFileResult = | { response: "success" } | { response: "failure"; message: string };
BREAKING CHANGE:
NsisUpdater.verifyUpdateCodeSignatureis deprecated in favour ofverifyUpdateFileAuthenticodeSignature, which differs in return type. The old name is kept as a compatibility shim that translates in both directions and shall be removed in electron-builder v28.// Before autoUpdater.verifyUpdateCodeSignature = async (publisherNames, path) => isValid ? null : "why it failed"; // After autoUpdater.verifyUpdateFileAuthenticodeSignature = async ( publisherNames, path ) => isValid ? { response: "success" } : { response: "failure", message: "why it failed" };
BREAKING CHANGE: the protected
NsisUpdater._verifyUpdateCodeSignaturemember is renamed to_verifyUpdateFileAuthenticodeSignatureand takes the new return type. A deprecated accessor under the old name forwards to it, so a subclass that assignsthis._verifyUpdateCodeSignaturekeeps working; a subclass that redeclares it as a class field shadows the accessor and must be migrated.BREAKING CHANGE: the protected
BaseUpdater.verifyInstallerSignatureOnLaunchreturnsPromise<VerifyUpdateFileResult>instead ofPromise<string | null>. An override that resolvesnullto mean "verified" now reports every install-on-next-launch as unsigned; return{ response: "success" }instead. (This member was introduced earlier in the same v27 pre-release cycle, so only apps on a 7.0.0-alpha are affected.) -
Feat!: electron-updater sends update-feed credentials only to downloads on the feed's origin. With the generic, s3, spaces, r2, keygen, bitbucket, github and gitlab providers, a download on another origin than the feed (scheme, host or port) — an absolute
files[].urlorpackages.<arch>.pathinlatest*.yml, a GitLab release asset link, and the blockmaps and differential range requests derived from them — is requested without the credential headers fromrequestHeaders/addAuthHeader(headers such asAuthorization, the same set that is removed on a cross-origin redirect) and without the feed URL's query string. Such a URL keeps its own query string, so pre-signed URLs work. With every provider, including custom ones, a URL that electron-updater resolves against the feed URL (such as afiles[].urlor a blockmap) gets the feed query only on the feed's origin; as on redirects, anhttp→httpsupgrade of the feed host on the default ports keeps the headers and the query. Downloads on the feed origin are unchanged, and the old blockmap from an app-setpreviousBlockmapBaseUrlOverridekeeps the credentials on that origin. If yourlatest*.ymlpoints downloads at another origin that needs these credentials, serve the files from the feed origin or use pre-signed URLs. The NSIS web-package differential download now uses the same per-download headers as other downloads. A custom provider that does not extend a built-in one must declareProvider.feedBaseUrl— its feed URL (the credential headers then only go to that origin) ornull(the request headers go to every download URL) — when the download headers include a credential header: if it does not,downloadUpdate()fails withERR_UPDATER_FEED_BASE_URL_NOT_DECLAREDbefore any download request. The first download that loses the credential headers, and the first that does not get the feed query, each log a warning once per updater, naming the headers, the query parameters and the origins (never their values), with a link to the migration guide;ERR_UPDATER_FEED_BASE_URL_NOT_DECLAREDlinks it too. New APIs:Provider.feedBaseUrl(undefined, not declared, by default),HttpExecutor.sensitiveHeaderNames,HttpExecutor.removeCrossOriginSensitiveHeadersandHttpExecutor.isCrossOrigin.#10270ec9135d@mmaietta -
Feat!: NSIS web-installer updates are rejected unless
disableWebInstallerisfalse(the v27 grace period is removed; cached and install-on-next-launch web updates re-verify the web package), and the nsis-web installer verifies--package-fileand versioned package downloads against its built-in SHA-512 hashes (opt out withnsisWeb.allowUnverifiedAppPackage). SetdisableWebInstallerbefore the app is ready: a pending install-on-next-launch web update is checked against it at appready#10264c8ca1ac@mmaietta
Minor Changes
- Feat(updater): optional
files[].blockMapUrlinlatest*.ymlnames a file's blockmap URL (e.g. a separately pre-signed one) instead of${url}.blockmapwith the file URL's query string. A relative value resolves likeurl(against the feed URL); an absolute URL is used as-is, with its own host and query string. It gets the feed query and credential headers only on the feed's origin. With ablockMapUrl, the old blockmap is not derived from the new file's URL: it comes from the local cache, else frompreviousBlockmapBaseUrlOverride, else that update is downloaded in full (which caches the new blockmap). The manifest signature coversblockMapUrlwhen present, as an extra field on the file record, so manifests without it canonicalize and verify exactly as before; an electron-updater without this change refuses a signed manifest that has one. electron-builder does not write it. The private GitHub and GitLab providers, which resolve files from the release assets, ignore it.#10270ec9135d@mmaietta
Patch Changes
- Fix: report accurate differential download progress deltas
#1011858e5d2e@OskarEichler - Feat!: a code-signed Windows build that writes
app-update.yml(annsis,nsis-weborelectronUpdaterAwareappxtarget with a publish configuration, including one inferred from a GitHubrepository) now fails with anInvalidConfigurationErrorwhen its publisher name cannot be determined: any customwin.sign.signhook withoutwin.sign.publisherName(its publisher name is never derived from a certificate, not even one in the config —certificateFile,certificateSubjectName,certificateSha1,cscLink— or fromWIN_CSC_LINK/CSC_LINK, because the hook may sign with another one), or a certificate without a Common Name (including a certificate-store subject, which no longer yields an undefined publisher name). Setwin.sign.publisherNameto the subject of the signing certificate (copy it from a binary your hook already signed), or setwin.verifyUpdateCodeSignature: falseonly if your updates are not Authenticode-signed or you don't use electron-updater. Error and warning messages now namewin.sign.publisherNameinstead of the removedwin.publisherName.#10264c8ca1ac@mmaietta - Fix(updater): pass the web installer package to
verifyUpdateFileaspackageFilePathwhen a pending web update is installed on next launch#10264c8ca1ac@mmaietta - Fix: handle background download rejections from
checkForUpdatesAndNotify#10113c10345f@OskarEichler - Fix(updater): pass the NSIS install directory (
installDirectory,/D=) as the last installer argument, after--package-file#10264c8ca1ac@mmaietta - Chore: replace ESLint and Prettier with oxlint and oxfmt
#10240a578e53@claude - Fix: reject traversal segments as update cache filenames
#10127e832c81@OskarEichler - Fix(updater): the warning about
disableWebInstallerset tofalsefor a full-installer update is logged only when the app set it; for the default of an install made by an nsis-web installer an info line says that web-installer updates needdisableWebInstaller = falseafter that update#10264c8ca1ac@mmaietta - Feat!: the nsis-web installer verifies and installs its own copy of a local app package. A package passed via
--package-file(electron-updater does this for updates) or found next to the installer is first copied into the installer's own temporary directory; the checksum is computed on that copy and that copy is what is extracted. WithnsisWeb.allowUnverifiedAppPackagea package passed via--package-fileis still copied, but not verified. The local package file is now left in place (the installer's copy is moved into the app's update cache instead), and the installation is aborted (exit code2) if a--package-filepackage cannot be copied; a package found next to the installer that cannot be copied is ignored and the package is downloaded, as when its checksum doesn't match. electron-updater removes the package it passed via--package-filefrom itspendingcache directory at startup once the app runs the version of that update (update-info.jsonrecords the version of a web installer update for this); the package of an update that is not installed yet, or whose install failed, is kept.#10264c8ca1ac@mmaietta