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 pub fn nsis_args(&self) -> &'static [&'static str] {
37 match self {
41 Self::Passive => &["/P", "/R"],
42 Self::Quiet => &["/S", "/R"],
43 _ => &[],
44 }
45 }
46}
47
48impl Display for WindowsUpdateInstallMode {
49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 write!(
51 f,
52 "{}",
53 match self {
54 Self::BasicUi => "basicUi",
55 Self::Quiet => "quiet",
56 Self::Passive => "passive",
57 }
58 )
59 }
60}
61
62#[derive(Debug, Clone, Deserialize, Default)]
63#[serde(rename_all = "camelCase")]
64pub struct WindowsConfig {
65 #[serde(
67 default,
68 alias = "installer-args",
69 deserialize_with = "deserialize_os_string"
70 )]
71 pub installer_args: Vec<OsString>,
72 #[serde(default, alias = "install-mode")]
76 pub install_mode: WindowsUpdateInstallMode,
77}
78
79fn deserialize_os_string<'de, D>(deserializer: D) -> Result<Vec<OsString>, D::Error>
80where
81 D: Deserializer<'de>,
82{
83 Ok(Vec::<String>::deserialize(deserializer)?
84 .into_iter()
85 .map(OsString::from)
86 .collect::<Vec<_>>())
87}
88
89#[derive(Debug, Clone, Default)]
91pub struct Config {
92 pub dangerous_insecure_transport_protocol: bool,
94 pub dangerous_accept_invalid_certs: bool,
96 pub dangerous_accept_invalid_hostnames: bool,
98 pub endpoints: Vec<Url>,
100 pub pubkey: String,
102 pub windows: Option<WindowsConfig>,
104}
105
106impl<'de> Deserialize<'de> for Config {
107 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108 where
109 D: Deserializer<'de>,
110 {
111 #[derive(Deserialize)]
112 #[serde(rename_all = "camelCase")]
113 pub struct Config {
114 #[serde(default, alias = "dangerous-insecure-transport-protocol")]
115 pub dangerous_insecure_transport_protocol: bool,
116 #[serde(default, alias = "dangerous-accept-invalid-certs")]
117 pub dangerous_accept_invalid_certs: bool,
118 #[serde(default, alias = "dangerous-accept-invalid-hostnames")]
119 pub dangerous_accept_invalid_hostnames: bool,
120 #[serde(default)]
121 pub endpoints: Vec<Url>,
122 pub pubkey: String,
123 pub windows: Option<WindowsConfig>,
124 }
125
126 let config = Config::deserialize(deserializer)?;
127
128 validate_endpoints(
129 &config.endpoints,
130 config.dangerous_insecure_transport_protocol,
131 )
132 .map_err(serde::de::Error::custom)?;
133
134 Ok(Self {
135 dangerous_insecure_transport_protocol: config.dangerous_insecure_transport_protocol,
136 dangerous_accept_invalid_certs: config.dangerous_accept_invalid_certs,
137 dangerous_accept_invalid_hostnames: config.dangerous_accept_invalid_hostnames,
138 endpoints: config.endpoints,
139 pubkey: config.pubkey,
140 windows: config.windows,
141 })
142 }
143}
144
145pub(crate) fn validate_endpoints(
146 endpoints: &[Url],
147 dangerous_insecure_transport_protocol: bool,
148) -> crate::Result<()> {
149 if !dangerous_insecure_transport_protocol {
150 for url in endpoints {
151 if url.scheme() != "https" {
152 #[cfg(debug_assertions)]
153 {
154 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.");
155 eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration");
156 }
157 #[cfg(not(debug_assertions))]
158 return Err(crate::Error::InsecureTransportProtocol);
159 }
160 }
161 }
162
163 Ok(())
164}