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")]
13pub enum WindowsUpdateInstallMode {
14 BasicUi,
16 Quiet,
19 Passive,
21}
22
23impl WindowsUpdateInstallMode {
24 pub fn msiexec_args(&self) -> &'static [&'static str] {
26 match self {
27 Self::BasicUi => &["/qb+"],
28 Self::Quiet => &["/quiet"],
29 Self::Passive => &["/passive"],
30 }
31 }
32
33 pub fn nsis_args(&self) -> &'static [&'static str] {
35 match self {
39 Self::Passive => &["/P", "/R"],
40 Self::Quiet => &["/S", "/R"],
41 _ => &[],
42 }
43 }
44}
45
46impl Display for WindowsUpdateInstallMode {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 write!(
49 f,
50 "{}",
51 match self {
52 Self::BasicUi => "basicUi",
53 Self::Quiet => "quiet",
54 Self::Passive => "passive",
55 }
56 )
57 }
58}
59
60impl Default for WindowsUpdateInstallMode {
61 fn default() -> Self {
62 Self::Passive
63 }
64}
65
66#[derive(Debug, Clone, Deserialize, Default)]
67#[serde(rename_all = "camelCase")]
68pub struct WindowsConfig {
69 #[serde(
71 default,
72 alias = "installer-args",
73 deserialize_with = "deserialize_os_string"
74 )]
75 pub installer_args: Vec<OsString>,
76 #[serde(default, alias = "install-mode")]
80 pub install_mode: WindowsUpdateInstallMode,
81}
82
83fn deserialize_os_string<'de, D>(deserializer: D) -> Result<Vec<OsString>, D::Error>
84where
85 D: Deserializer<'de>,
86{
87 Ok(Vec::<String>::deserialize(deserializer)?
88 .into_iter()
89 .map(OsString::from)
90 .collect::<Vec<_>>())
91}
92
93#[derive(Debug, Clone, Default)]
95pub struct Config {
96 pub dangerous_insecure_transport_protocol: 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)]
117 pub endpoints: Vec<Url>,
118 pub pubkey: String,
119 pub windows: Option<WindowsConfig>,
120 }
121
122 let config = Config::deserialize(deserializer)?;
123
124 validate_endpoints(
125 &config.endpoints,
126 config.dangerous_insecure_transport_protocol,
127 )
128 .map_err(serde::de::Error::custom)?;
129
130 Ok(Self {
131 dangerous_insecure_transport_protocol: config.dangerous_insecure_transport_protocol,
132 endpoints: config.endpoints,
133 pubkey: config.pubkey,
134 windows: config.windows,
135 })
136 }
137}
138
139pub(crate) fn validate_endpoints(
140 endpoints: &[Url],
141 dangerous_insecure_transport_protocol: bool,
142) -> crate::Result<()> {
143 if !dangerous_insecure_transport_protocol {
144 for url in endpoints {
145 if url.scheme() != "https" {
146 #[cfg(debug_assertions)]
147 {
148 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.");
149 eprintln!("[\x1b[33mWARNING\x1b[0m] if this is a desired behavior, you can enable `dangerousInsecureTransportProtocol` in the plugin configuration");
150 }
151 #[cfg(not(debug_assertions))]
152 return Err(crate::Error::InsecureTransportProtocol);
153 }
154 }
155 }
156
157 Ok(())
158}