From eacd36a4ea4d6a14a73f414981fb5a8af7dfdafe Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Tue, 10 Mar 2026 14:14:58 +0200 Subject: [PATCH] refactor(macos-sign): use base64 crate instead of Command (#15038) * refactor(macos-sign): use base64 crate instead of Command * add base64 crate as a dependency * add change file --------- Co-authored-by: Lucas Nogueira --- .changes/base64.md | 5 ++++ Cargo.lock | 1 + crates/tauri-macos-sign/Cargo.toml | 1 + crates/tauri-macos-sign/src/lib.rs | 41 +++++++++++------------------- 4 files changed, 22 insertions(+), 26 deletions(-) create mode 100644 .changes/base64.md diff --git a/.changes/base64.md b/.changes/base64.md new file mode 100644 index 000000000..2fb599bab --- /dev/null +++ b/.changes/base64.md @@ -0,0 +1,5 @@ +--- +"tauri-macos-sign": patch:enhance +--- + +Do not rely on system base64 CLI to decode certificates. diff --git a/Cargo.lock b/Cargo.lock index ffa7c32f7..8b9b0da50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8712,6 +8712,7 @@ name = "tauri-macos-sign" version = "2.3.3" dependencies = [ "apple-codesign", + "base64 0.22.1", "chrono", "dirs 6.0.0", "log", diff --git a/crates/tauri-macos-sign/Cargo.toml b/crates/tauri-macos-sign/Cargo.toml index af15c66fa..fa4c429fd 100644 --- a/crates/tauri-macos-sign/Cargo.toml +++ b/crates/tauri-macos-sign/Cargo.toml @@ -25,3 +25,4 @@ log = { version = "0.4.21", features = ["kv"] } apple-codesign = { version = "0.27", default-features = false } chrono = "0.4" p12 = "0.6" +base64 = "0.22" diff --git a/crates/tauri-macos-sign/src/lib.rs b/crates/tauri-macos-sign/src/lib.rs index 87e30fdee..c6e93821a 100644 --- a/crates/tauri-macos-sign/src/lib.rs +++ b/crates/tauri-macos-sign/src/lib.rs @@ -64,6 +64,8 @@ pub enum Error { }, #[error("failed to encode DER: {error}")] FailedToEncodeDER { error: std::io::Error }, + #[error("failed to decode base64 certificate: {0}")] + Base64Decode(base64::DecodeError), #[error("certificate missing common name")] CertificateMissingCommonName, #[error("certificate missing organization unit for common name {common_name}")] @@ -329,36 +331,23 @@ impl NotarytoolCmdExt for Command { } } -fn decode_base64(base64: &OsStr, out_path: &Path) -> Result<()> { - let tmp_dir = tempfile::tempdir().map_err(Error::TempDir)?; +fn decode_base64(base64_input: &OsStr, out_path: &Path) -> Result<()> { + use base64::Engine; - let src_path = tmp_dir.path().join("src"); - let base64 = base64 + let input = base64_input .to_str() - .expect("failed to convert base64 to string") - .as_bytes(); + .expect("failed to convert base64 to string"); - // as base64 contain whitespace decoding may be broken - // https://github.com/marshallpierce/rust-base64/issues/105 - // we'll use builtin base64 command from the OS - std::fs::write(&src_path, base64).map_err(|error| Error::Fs { - context: "failed to write base64 to temp file", - path: src_path.clone(), - error, - })?; + // strip whitespace before decoding + let cleaned: String = input.chars().filter(|c| !c.is_ascii_whitespace()).collect(); - assert_command( - std::process::Command::new("base64") - .arg("--decode") - .arg("-i") - .arg(&src_path) - .arg("-o") - .arg(out_path) - .piped(), - "failed to decode certificate", - ) - .map_err(|error| Error::CommandFailed { - command: "base64 --decode".to_string(), + let decoded = base64::engine::general_purpose::STANDARD + .decode(&cleaned) + .map_err(Error::Base64Decode)?; + + std::fs::write(out_path, &decoded).map_err(|error| Error::Fs { + context: "failed to write decoded certificate", + path: out_path.to_path_buf(), error, })?;