From 04a0aea0ab9f8750200bc2fe5aff99c1c488082d Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Tue, 24 Sep 2024 18:38:53 +0300 Subject: [PATCH] feat(updater)!: add option to use insecure transport protocol (#1814) --- .changes/updater-endpoints-result.md | 5 ++ .../updater-insecure-transport-protocol.md | 5 ++ plugins/updater/src/config.rs | 72 ++++++++++++------- plugins/updater/src/error.rs | 3 + plugins/updater/src/updater.rs | 11 ++- 5 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 .changes/updater-endpoints-result.md create mode 100644 .changes/updater-insecure-transport-protocol.md diff --git a/.changes/updater-endpoints-result.md b/.changes/updater-endpoints-result.md new file mode 100644 index 00000000..d257d793 --- /dev/null +++ b/.changes/updater-endpoints-result.md @@ -0,0 +1,5 @@ +--- +"updater": patch +--- + +**Breaking change**, Changed `UpdaterBuilder::endpoints` method to return a `Result`. \ No newline at end of file diff --git a/.changes/updater-insecure-transport-protocol.md b/.changes/updater-insecure-transport-protocol.md new file mode 100644 index 00000000..b95aad57 --- /dev/null +++ b/.changes/updater-insecure-transport-protocol.md @@ -0,0 +1,5 @@ +--- +"updater": patch +--- + +Add `dangerousInsecureTransportProtocol` config option to allow using insecure transport protocols, like `http` \ No newline at end of file diff --git a/plugins/updater/src/config.rs b/plugins/updater/src/config.rs index 3c6f5d42..b95c6ae4 100644 --- a/plugins/updater/src/config.rs +++ b/plugins/updater/src/config.rs @@ -91,47 +91,69 @@ where } /// Updater configuration. -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(rename_all = "camelCase")] +#[derive(Debug, Clone, Default)] pub struct Config { + /// Dangerously allow using insecure transport protocols for update endpoints. + pub dangerous_insecure_transport_protocol: bool, /// Updater endpoints. - #[serde(default)] - pub endpoints: Vec, + pub endpoints: Vec, /// Signature public key. pub pubkey: String, /// The Windows configuration for the updater. pub windows: Option, } -/// A URL to an updater server. -/// -/// The URL must use the `https` scheme on production. -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct UpdaterEndpoint(pub Url); - -impl std::fmt::Display for UpdaterEndpoint { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } -} - -impl<'de> Deserialize<'de> for UpdaterEndpoint { +impl<'de> Deserialize<'de> for Config { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - let url = Url::deserialize(deserializer)?; + #[derive(Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct Config { + #[serde(default, alias = "dangerous-insecure-transport-protocol")] + pub dangerous_insecure_transport_protocol: bool, + #[serde(default)] + pub endpoints: Vec, + pub pubkey: String, + pub windows: Option, + } + + let config = Config::deserialize(deserializer)?; - if url.scheme() != "https" { + validate_endpoints( + &config.endpoints, + config.dangerous_insecure_transport_protocol, + ) + .map_err(serde::de::Error::custom)?; + + Ok(Self { + dangerous_insecure_transport_protocol: config.dangerous_insecure_transport_protocol, + endpoints: config.endpoints, + pubkey: config.pubkey, + windows: config.windows, + }) + } +} + +pub(crate) fn validate_endpoints( + endpoints: &[Url], + dangerous_insecure_transport_protocol: bool, +) -> crate::Result<()> { + if !dangerous_insecure_transport_protocol { + for url in endpoints { + #[cfg(debug_assertions)] #[cfg(debug_assertions)] - eprintln!("[\x1b[33mWARNING\x1b[0m] The configured updater endpoint doesn't use `https` protocol. This is allowed in development but will fail in release builds."); + eprintln!("[\x1b[33mWARNING\x1b[0m] The updater endpoint \"{url}\" doesn't use `https` protocol. This is allowed in development but will fail in release builds."); + #[cfg(debug_assertions)] + eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration"); #[cfg(not(debug_assertions))] - return Err(serde::de::Error::custom( - "The configured updater endpoint must use the `https` protocol.", - )); + if url.scheme() != "https" { + return Err(crate::Error::InsecureTransportProtocol); + } } - - Ok(Self(url)) } + + Ok(()) } diff --git a/plugins/updater/src/error.rs b/plugins/updater/src/error.rs index ef435cb5..1f5d6a15 100644 --- a/plugins/updater/src/error.rs +++ b/plugins/updater/src/error.rs @@ -71,6 +71,9 @@ pub enum Error { InvalidHeaderValue(#[from] http::header::InvalidHeaderValue), #[error(transparent)] InvalidHeaderName(#[from] http::header::InvalidHeaderName), + /// The configured updater endpoint must use a secure protocol like `https` + #[error("The configured updater endpoint must use a secure protocol like `https`.")] + InsecureTransportProtocol, #[error(transparent)] Tauri(#[from] tauri::Error), } diff --git a/plugins/updater/src/updater.rs b/plugins/updater/src/updater.rs index 5883bdaa..b1dadd6d 100644 --- a/plugins/updater/src/updater.rs +++ b/plugins/updater/src/updater.rs @@ -148,9 +148,14 @@ impl UpdaterBuilder { self } - pub fn endpoints(mut self, endpoints: Vec) -> Self { + pub fn endpoints(mut self, endpoints: Vec) -> Result { + crate::config::validate_endpoints( + &endpoints, + self.config.dangerous_insecure_transport_protocol, + )?; + self.endpoints.replace(endpoints); - self + Ok(self) } pub fn executable_path>(mut self, p: P) -> Self { @@ -219,7 +224,7 @@ impl UpdaterBuilder { pub fn build(self) -> Result { let endpoints = self .endpoints - .unwrap_or_else(|| self.config.endpoints.iter().map(|e| e.0.clone()).collect()); + .unwrap_or_else(|| self.config.endpoints.clone()); if endpoints.is_empty() { return Err(Error::EmptyEndpoints);