mirror of
https://github.com/fluxerapp/fluxer.git
synced 2026-09-03 05:10:25 +03:00
fix(desktop): read authenticode sigs with a working pwsh host (#1549)
This commit is contained in:
+80
-9
@@ -1912,6 +1912,29 @@ fn relative_display(root: &Path, path: &Path) -> String {
|
||||
.replace('\\', "/")
|
||||
}
|
||||
|
||||
fn percent_decode_archive_name(name: &str) -> String {
|
||||
if !name.contains('%') {
|
||||
return name.to_string();
|
||||
}
|
||||
let bytes = name.as_bytes();
|
||||
let mut decoded = Vec::with_capacity(bytes.len());
|
||||
let mut index = 0;
|
||||
while index < bytes.len() {
|
||||
if bytes[index] == b'%' && index + 2 < bytes.len() {
|
||||
let high = (bytes[index + 1] as char).to_digit(16);
|
||||
let low = (bytes[index + 2] as char).to_digit(16);
|
||||
if let (Some(high), Some(low)) = (high, low) {
|
||||
decoded.push((high * 16 + low) as u8);
|
||||
index += 3;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
decoded.push(bytes[index]);
|
||||
index += 1;
|
||||
}
|
||||
String::from_utf8(decoded).unwrap_or_else(|_| name.to_string())
|
||||
}
|
||||
|
||||
fn assert_expected_windows_pe_inventory(
|
||||
root: &Path,
|
||||
files: &[PathBuf],
|
||||
@@ -1921,7 +1944,7 @@ fn assert_expected_windows_pe_inventory(
|
||||
let present = files
|
||||
.iter()
|
||||
.filter_map(|path| path.file_name().and_then(OsStr::to_str))
|
||||
.map(ToOwned::to_owned)
|
||||
.map(percent_decode_archive_name)
|
||||
.collect::<BTreeSet<_>>();
|
||||
let expected = expected_windows_pe_inventory(arch, main_exe);
|
||||
let missing = expected
|
||||
@@ -2011,14 +2034,18 @@ fn authenticode_report(files: &[PathBuf]) -> Result<Vec<SignatureRow>> {
|
||||
fs::write(&script_path, authenticode_report_script(&list_path))
|
||||
.with_context(|| format!("Failed to write {}", script_path.display()))?;
|
||||
|
||||
let output = capture(CommandSpec::new("powershell").args([
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
script_path.to_string_lossy().as_ref(),
|
||||
]))?;
|
||||
let output = capture(
|
||||
CommandSpec::new(powershell_host())
|
||||
.args([
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
script_path.to_string_lossy().as_ref(),
|
||||
])
|
||||
.env_remove("PSModulePath"),
|
||||
)?;
|
||||
ensure!(
|
||||
output.status == 0,
|
||||
"Get-AuthenticodeSignature failed with exit code {}",
|
||||
@@ -2029,6 +2056,20 @@ fn authenticode_report(files: &[PathBuf]) -> Result<Vec<SignatureRow>> {
|
||||
parse_authenticode_report(stdout.trim())
|
||||
}
|
||||
|
||||
fn powershell_host() -> &'static str {
|
||||
if which_in_path("pwsh.exe").is_some() || which_in_path("pwsh").is_some() {
|
||||
return "pwsh";
|
||||
}
|
||||
"powershell"
|
||||
}
|
||||
|
||||
fn which_in_path(program: &str) -> Option<PathBuf> {
|
||||
let path = env::var_os("PATH")?;
|
||||
env::split_paths(&path)
|
||||
.map(|directory| directory.join(program))
|
||||
.find(|candidate| candidate.is_file())
|
||||
}
|
||||
|
||||
fn authenticode_report_script(list_path: &Path) -> String {
|
||||
format!(
|
||||
"$ErrorActionPreference = 'Stop'\n\
|
||||
@@ -3772,6 +3813,36 @@ export const CHANNEL_DISPLAY_NAME = BUILD_CHANNEL;\n"
|
||||
assert!(zip.by_name("resources/app.asar").is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn percent_encoded_archive_names_match_their_decoded_inventory_entry() {
|
||||
assert_eq!(
|
||||
percent_decode_archive_name("Fluxer%20Canary.exe"),
|
||||
"Fluxer Canary.exe"
|
||||
);
|
||||
assert_eq!(percent_decode_archive_name("Fluxer.exe"), "Fluxer.exe");
|
||||
assert_eq!(
|
||||
percent_decode_archive_name("win-game-capture.win32-arm64-msvc.node"),
|
||||
"win-game-capture.win32-arm64-msvc.node"
|
||||
);
|
||||
assert_eq!(percent_decode_archive_name("100%.dll"), "100%.dll");
|
||||
assert_eq!(percent_decode_archive_name("a%zz.dll"), "a%zz.dll");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canary_nupkg_inventory_accepts_percent_encoded_main_executable() {
|
||||
let root = Path::new("lib").join("app");
|
||||
let files = expected_windows_pe_inventory("arm64", "Fluxer Canary.exe")
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
if name == "Fluxer Canary.exe" {
|
||||
return root.join("Fluxer%20Canary.exe");
|
||||
}
|
||||
root.join(name)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
assert_expected_windows_pe_inventory(&root, &files, "arm64", "Fluxer Canary.exe").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn known_optional_windows_pe_inventory_never_repeats_a_required_binary() {
|
||||
for arch in ["x64", "arm64"] {
|
||||
|
||||
Reference in New Issue
Block a user