diff --git a/.changes/updater-allow-downgrades-config.md b/.changes/updater-allow-downgrades-config.md new file mode 100644 index 000000000..365cd956c --- /dev/null +++ b/.changes/updater-allow-downgrades-config.md @@ -0,0 +1,20 @@ +--- +"updater": minor +"updater-js": minor +--- + +**Breaking change:** the `allowDowngrades` option was removed from the `check` command and is now read from the plugin configuration instead. + +Previously any code running in the webview could pass `allowDowngrades: true` to `plugin:updater|check` and relax the version check from "the update must be newer" to "the update must be different", overriding the comparator the application had configured on the Rust side. The flag is now an application-level setting: + +```json +{ + "plugins": { + "updater": { + "allowDowngrades": true + } + } +} +``` + +It defaults to `false`, and is ignored when the application provides its own `Builder::default_version_comparator`, which continues to take precedence. diff --git a/plugins/updater/guest-js/index.ts b/plugins/updater/guest-js/index.ts index d53165eb2..c0f023bbb 100644 --- a/plugins/updater/guest-js/index.ts +++ b/plugins/updater/guest-js/index.ts @@ -22,10 +22,6 @@ interface CheckOptions { * Target identifier for the running application. This is sent to the backend. */ target?: string - /** - * Allow downgrades to previous versions by not checking if the current version is greater than the available version. - */ - allowDowngrades?: boolean } /** Options used when downloading an update */ diff --git a/plugins/updater/src/commands.rs b/plugins/updater/src/commands.rs index edc1b88fb..72684e6d8 100644 --- a/plugins/updater/src/commands.rs +++ b/plugins/updater/src/commands.rs @@ -46,7 +46,6 @@ pub(crate) async fn check( timeout: Option, proxy: Option, target: Option, - allow_downgrades: Option, ) -> Result> { let mut builder = webview.updater_builder(); if let Some(headers) = headers { @@ -64,9 +63,6 @@ pub(crate) async fn check( if let Some(target) = target { builder = builder.target(target); } - if allow_downgrades.unwrap_or(false) { - builder = builder.version_comparator(|current, update| update.version != current); - } let updater = builder.build()?; let update = updater.check().await?; diff --git a/plugins/updater/src/config.rs b/plugins/updater/src/config.rs index 0fa97e8de..9bd941ad5 100644 --- a/plugins/updater/src/config.rs +++ b/plugins/updater/src/config.rs @@ -133,6 +133,19 @@ pub struct Config { /// /// The default value of this flag is `false`. pub require_signed_version: bool, + /// Allow the updater to install a release whose version is not newer than the + /// currently running one, changing the version check from "must be newer" to + /// "must be different". + /// + /// Note that the updater only verifies the signature of the downloaded artifact, + /// not the version advertised by the update endpoint, so enabling this removes the + /// only guard against installing a previously released (and validly signed) version. + /// + /// Ignored when the application sets a custom + /// [`Builder::default_version_comparator`](crate::Builder::default_version_comparator). + /// + /// The default value of this flag is `false`. + pub allow_downgrades: bool, /// The Windows configuration for the updater. pub windows: Option, } @@ -156,6 +169,8 @@ impl<'de> Deserialize<'de> for Config { pub pubkey: String, #[serde(default, alias = "require-signed-version")] pub require_signed_version: bool, + #[serde(default, alias = "allow-downgrades")] + pub allow_downgrades: bool, pub windows: Option, } @@ -174,6 +189,7 @@ impl<'de> Deserialize<'de> for Config { endpoints: config.endpoints, pubkey: config.pubkey, require_signed_version: config.require_signed_version, + allow_downgrades: config.allow_downgrades, windows: config.windows, }) } diff --git a/plugins/updater/src/lib.rs b/plugins/updater/src/lib.rs index adb4c01ce..18f2a11a5 100644 --- a/plugins/updater/src/lib.rs +++ b/plugins/updater/src/lib.rs @@ -98,6 +98,11 @@ impl> UpdaterExt for T { builder.version_comparator = version_comparator.clone(); + // a comparator set by the application takes precedence over the configuration + if builder.version_comparator.is_none() && config.allow_downgrades { + builder = builder.version_comparator(|current, update| update.version != current); + } + #[cfg(any( target_os = "linux", target_os = "dragonfly",