tauri_plugin_updater/
config.rs1use std::{ffi::OsString, fmt::Display};
6
7use serde::{Deserialize, Deserializer};
8use url::Url;
9
10#[derive(Debug, PartialEq, Eq, Clone, Deserialize)]
12#[serde(rename_all = "camelCase")]
13#[derive(Default)]
14pub enum WindowsUpdateInstallMode {
15 BasicUi,
17 Quiet,
20 #[default]
22 Passive,
23}
24
25impl WindowsUpdateInstallMode {
26 pub fn msiexec_args(&self) -> &'static [&'static str] {
28 match self {
29 Self::BasicUi => &["/qb+"],
30 Self::Quiet => &["/quiet"],
31 Self::Passive => &["/passive"],
32 }
33 }
34
35 #[cfg(windows)]
36 pub(crate) fn msi_restart_after_install_args(&self) -> &'static [&'static str] {
37 &["AUTOLAUNCHAPP=True"]
38 }
39
40 pub fn nsis_args(&self) -> &'static [&'static str] {
42 match self {
46 Self::Passive => &["/P"],
47 Self::Quiet => &["/S"],
48 _ => &[],
49 }
50 }
51
52 #[cfg(windows)]
53 pub(crate) fn nsis_restart_after_install_args(&self) -> &'static [&'static str] {
54 match self {
55 Self::BasicUi => &[],
56 _ => &["/R"],
57 }
58 }
59}
60
61impl Display for WindowsUpdateInstallMode {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(
64 f,
65 "{}",
66 match self {
67 Self::BasicUi => "basicUi",
68 Self::Quiet => "quiet",
69 Self::Passive => "passive",
70 }
71 )
72 }
73}
74
75#[derive(Debug, Clone, Deserialize, Default)]
76#[serde(rename_all = "camelCase")]
77pub struct WindowsConfig {
78 #[serde(
82 default,
83 alias = "installer-args",
84 deserialize_with = "deserialize_os_string"
85 )]
86 pub installer_args: Vec<OsString>,
87 #[serde(default, alias = "install-mode")]
91 pub install_mode: WindowsUpdateInstallMode,
92}
93
94fn deserialize_os_string<'de, D>(deserializer: D) -> Result<Vec<OsString>, D::Error>
95where
96 D: Deserializer<'de>,
97{
98 Ok(Vec::<String>::deserialize(deserializer)?
99 .into_iter()
100 .map(OsString::from)
101 .collect::<Vec<_>>())
102}
103
104#[derive(Debug, Clone, Default)]
106pub struct Config {
107 pub dangerous_insecure_transport_protocol: bool,
109 pub dangerous_accept_invalid_certs: bool,
111 pub dangerous_accept_invalid_hostnames: bool,
113 pub endpoints: Vec<Url>,
115 pub pubkey: String,
117 pub require_signed_version: bool,
136 pub allow_downgrades: bool,
149 pub windows: Option<WindowsConfig>,
151}
152
153impl<'de> Deserialize<'de> for Config {
154 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155 where
156 D: Deserializer<'de>,
157 {
158 #[derive(Deserialize)]
159 #[serde(rename_all = "camelCase")]
160 pub struct Config {
161 #[serde(default, alias = "dangerous-insecure-transport-protocol")]
162 pub dangerous_insecure_transport_protocol: bool,
163 #[serde(default, alias = "dangerous-accept-invalid-certs")]
164 pub dangerous_accept_invalid_certs: bool,
165 #[serde(default, alias = "dangerous-accept-invalid-hostnames")]
166 pub dangerous_accept_invalid_hostnames: bool,
167 #[serde(default)]
168 pub endpoints: Vec<Url>,
169 pub pubkey: String,
170 #[serde(default, alias = "require-signed-version")]
171 pub require_signed_version: bool,
172 #[serde(default, alias = "allow-downgrades")]
173 pub allow_downgrades: bool,
174 pub windows: Option<WindowsConfig>,
175 }
176
177 let config = Config::deserialize(deserializer)?;
178
179 validate_endpoints(
180 &config.endpoints,
181 config.dangerous_insecure_transport_protocol,
182 )
183 .map_err(serde::de::Error::custom)?;
184
185 Ok(Self {
186 dangerous_insecure_transport_protocol: config.dangerous_insecure_transport_protocol,
187 dangerous_accept_invalid_certs: config.dangerous_accept_invalid_certs,
188 dangerous_accept_invalid_hostnames: config.dangerous_accept_invalid_hostnames,
189 endpoints: config.endpoints,
190 pubkey: config.pubkey,
191 require_signed_version: config.require_signed_version,
192 allow_downgrades: config.allow_downgrades,
193 windows: config.windows,
194 })
195 }
196}
197
198pub(crate) fn validate_endpoints(
199 endpoints: &[Url],
200 dangerous_insecure_transport_protocol: bool,
201) -> crate::Result<()> {
202 if !dangerous_insecure_transport_protocol {
203 for url in endpoints {
204 if url.scheme() != "https" {
205 #[cfg(debug_assertions)]
206 {
207 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.");
208 eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration");
209 }
210 #[cfg(not(debug_assertions))]
211 return Err(crate::Error::InsecureTransportProtocol);
212 }
213 }
214 }
215
216 Ok(())
217}