pacenotes_installer/
elevation.rs1const RESTARTED: &str = "--restarted";
6const LANGUAGE: &str = "--language";
7const FOLDER: &str = "--folder";
8const SECRET: &str = "--secret";
9const PASSED_ON: [&str; 2] = ["--server", "--cache"];
11
12#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct Restart {
15 pub language: crate::i18n::Language,
16 pub folder: String,
17 pub secret: String,
20}
21
22impl Restart {
23 pub fn from_args() -> Option<Restart> {
25 let arguments: Vec<String> = std::env::args().skip(1).collect();
26 Restart::parse(&arguments)
27 }
28
29 fn parse(arguments: &[String]) -> Option<Restart> {
30 if !arguments.iter().any(|argument| argument == RESTARTED) {
31 return None;
32 }
33 let value = |flag: &str| {
34 let at = arguments.iter().position(|argument| argument == flag)?;
35 arguments.get(at + 1).cloned()
36 };
37 Some(Restart {
38 language: crate::i18n::Language::from_tag(&value(LANGUAGE)?)?,
39 folder: value(FOLDER)?,
40 secret: value(SECRET).unwrap_or_default(),
41 })
42 }
43
44 fn command_line(&self, passed_on: &[(&str, String)]) -> String {
47 let mut arguments = vec![
48 RESTARTED.to_string(),
49 LANGUAGE.to_string(),
50 self.language.tag().to_string(),
51 FOLDER.to_string(),
52 self.folder.clone(),
53 SECRET.to_string(),
54 self.secret.clone(),
55 ];
56 for (flag, value) in passed_on {
57 arguments.push(flag.to_string());
58 arguments.push(value.clone());
59 }
60 arguments
61 .iter()
62 .map(|argument| quote(argument))
63 .collect::<Vec<_>>()
64 .join(" ")
65 }
66}
67
68pub fn is_elevated() -> bool {
71 unsafe {
72 let mut token: windows_sys::Win32::Foundation::HANDLE = core::ptr::null_mut();
73 if windows_sys::Win32::System::Threading::OpenProcessToken(
74 windows_sys::Win32::System::Threading::GetCurrentProcess(),
75 windows_sys::Win32::Security::TOKEN_QUERY,
76 &mut token,
77 ) == 0
78 {
79 return false;
80 }
81 let mut elevation = windows_sys::Win32::Security::TOKEN_ELEVATION { TokenIsElevated: 0 };
82 let mut written = 0u32;
83 let read = windows_sys::Win32::Security::GetTokenInformation(
84 token,
85 windows_sys::Win32::Security::TokenElevation,
86 &mut elevation as *mut _ as *mut core::ffi::c_void,
87 core::mem::size_of::<windows_sys::Win32::Security::TOKEN_ELEVATION>() as u32,
88 &mut written,
89 );
90 windows_sys::Win32::Foundation::CloseHandle(token);
91 read != 0 && elevation.TokenIsElevated != 0
92 }
93}
94
95pub fn restart_elevated(owner: windows_sys::Win32::Foundation::HWND, restart: &Restart) -> bool {
98 let Ok(exe) = std::env::current_exe() else {
99 return false;
100 };
101 let passed_on: Vec<(&str, String)> = PASSED_ON
102 .iter()
103 .filter_map(|flag| Some((*flag, crate::argument_after(flag)?)))
104 .collect();
105 let verb = crate::i18n::to_wide("runas");
106 let file = crate::i18n::to_wide(&exe.to_string_lossy());
107 let parameters = crate::i18n::to_wide(&restart.command_line(&passed_on));
108 let started = unsafe {
109 windows_sys::Win32::UI::Shell::ShellExecuteW(
110 owner,
111 verb.as_ptr(),
112 file.as_ptr(),
113 parameters.as_ptr(),
114 core::ptr::null(),
115 windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL,
116 )
117 };
118 started as isize > 32
120}
121
122fn quote(argument: &str) -> String {
125 if !argument.is_empty() && !argument.contains([' ', '\t', '"']) {
126 return argument.to_string();
127 }
128 let mut quoted = String::from('"');
129 let mut backslashes = 0;
131 for character in argument.chars() {
132 if character == '"' {
133 quoted.push_str(&"\\".repeat(backslashes + 1));
134 }
135 backslashes = if character == '\\' {
136 backslashes + 1
137 } else {
138 0
139 };
140 quoted.push(character);
141 }
142 quoted.push_str(&"\\".repeat(backslashes));
143 quoted.push('"');
144 quoted
145}
146
147#[cfg(test)]
148mod tests;