diff --git a/.changes/updater-endpoint-version-encoded.md b/.changes/updater-endpoint-version-encoded.md new file mode 100644 index 00000000..8445c5e3 --- /dev/null +++ b/.changes/updater-endpoint-version-encoded.md @@ -0,0 +1,5 @@ +--- +'updater': 'patch' +--- + +Encode `+` when making updater requests which can be cause incorrectly interpolating the endpoint when using `{{current_version}}` in the endpoint where the current version contains a build number, for example `1.8.0+1`. diff --git a/Cargo.lock b/Cargo.lock index 5b1125d4..403aff98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7120,6 +7120,7 @@ dependencies = [ "http", "infer", "minisign-verify", + "percent-encoding", "reqwest", "semver", "serde", diff --git a/plugins/updater/Cargo.toml b/plugins/updater/Cargo.toml index 000a7b34..a9830446 100644 --- a/plugins/updater/Cargo.toml +++ b/plugins/updater/Cargo.toml @@ -37,6 +37,7 @@ semver = { version = "1", features = ["serde"] } futures-util = "0.3" tempfile = "3" infer = "0.16" +percent-encoding = "2.3" [target."cfg(target_os = \"windows\")".dependencies] zip = { version = "2", default-features = false, optional = true } diff --git a/plugins/updater/src/updater.rs b/plugins/updater/src/updater.rs index 51a18729..5883bdaa 100644 --- a/plugins/updater/src/updater.rs +++ b/plugins/updater/src/updater.rs @@ -16,6 +16,7 @@ use base64::Engine; use futures_util::StreamExt; use http::HeaderName; use minisign_verify::{PublicKey, Signature}; +use percent_encoding::{AsciiSet, CONTROLS}; use reqwest::{ header::{HeaderMap, HeaderValue}, ClientBuilder, StatusCode, @@ -322,17 +323,20 @@ impl Updater { // https://releases.myapp.com/update/darwin/aarch64/1.0.0 // The main objective is if the update URL is defined via the Cargo.toml // the URL will be generated dynamically + let version = self.current_version.to_string(); + let version = version.as_bytes(); + const CONTROLS_ADD: &AsciiSet = &CONTROLS.add(b'+'); + let encoded_version = percent_encoding::percent_encode(version, CONTROLS_ADD); + let encoded_version = encoded_version.to_string(); + let url: Url = url .to_string() // url::Url automatically url-encodes the path components - .replace( - "%7B%7Bcurrent_version%7D%7D", - &self.current_version.to_string(), - ) + .replace("%7B%7Bcurrent_version%7D%7D", &encoded_version) .replace("%7B%7Btarget%7D%7D", &self.target) .replace("%7B%7Barch%7D%7D", self.arch) // but not query parameters - .replace("{{current_version}}", &self.current_version.to_string()) + .replace("{{current_version}}", &encoded_version) .replace("{{target}}", &self.target) .replace("{{arch}}", self.arch) .parse()?;