From f08e4b8972b072617fdb78f11e222427e49ebe8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Brachth=C3=A4user?= Date: Sat, 20 Jan 2024 15:12:54 +0100 Subject: [PATCH] fix: fix the signing and notarization process for MacOS packages Closes #131 --- .changes/codesign-and-notarization.md | 6 +++ crates/packager/src/codesign/macos.rs | 18 ++++---- crates/packager/src/package/app/mod.rs | 64 ++++++++++++++++++++++++-- crates/packager/src/package/dmg/mod.rs | 2 +- 4 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 .changes/codesign-and-notarization.md diff --git a/.changes/codesign-and-notarization.md b/.changes/codesign-and-notarization.md new file mode 100644 index 00000000..79d5b4c1 --- /dev/null +++ b/.changes/codesign-and-notarization.md @@ -0,0 +1,6 @@ +--- +"cargo-packager": patch +"@crabnebula/packager": patch +--- + +Fix the signing and notarization process for MacOS bundles diff --git a/crates/packager/src/codesign/macos.rs b/crates/packager/src/codesign/macos.rs index fd893a8e..04a1e883 100644 --- a/crates/packager/src/codesign/macos.rs +++ b/crates/packager/src/codesign/macos.rs @@ -148,7 +148,7 @@ pub fn delete_keychain() { #[derive(Debug)] pub struct SignTarget { pub path: PathBuf, - pub is_an_executable: bool, + pub is_native_binary: bool, } #[tracing::instrument(level = "trace")] @@ -170,7 +170,7 @@ pub fn try_sign(targets: Vec, identity: &str, config: &Config) -> cr &target.path, identity, config, - target.is_an_executable, + target.is_native_binary, packager_keychain, )?; } @@ -188,8 +188,8 @@ fn sign( path_to_sign: &Path, identity: &str, config: &Config, - is_an_executable: bool, - pcakger_keychain: bool, + is_native_binary: bool, + packager_keychain: bool, ) -> crate::Result<()> { tracing::info!( "Codesigning {} with identity \"{}\"", @@ -199,7 +199,7 @@ fn sign( let mut args = vec!["--force", "-s", identity]; - if pcakger_keychain { + if packager_keychain { args.push("--keychain"); args.push(KEYCHAIN_ID); } @@ -209,14 +209,12 @@ fn sign( args.push(entitlements_path); } - if is_an_executable { + if is_native_binary { args.push("--options"); args.push("runtime"); } - if path_to_sign.is_dir() { - args.push("--deep"); - } + args.push("--timestamp"); Command::new("codesign") .args(args) @@ -275,7 +273,7 @@ pub fn notarize( try_sign( vec![SignTarget { path: zip_path.clone(), - is_an_executable: false, + is_native_binary: false, }], identity, config, diff --git a/crates/packager/src/package/app/mod.rs b/crates/packager/src/package/app/mod.rs index a02be710..e62f38ea 100644 --- a/crates/packager/src/package/app/mod.rs +++ b/crates/packager/src/package/app/mod.rs @@ -52,6 +52,62 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { tracing::debug!("Copying frameworks"); let framework_paths = copy_frameworks_to_bundle(&contents_directory, config)?; + + // All dylib files and native executables should be signed manually + // It is highly discouraged by Apple to use the --deep codesign parameter in larger projects. + // https://developer.apple.com/forums/thread/129980 + for framework_path in &framework_paths { + if let Some(framework_path) = framework_path.to_str() { + // Find all files in the current framework folder + let files = walkdir::WalkDir::new(framework_path) + .into_iter() + .flatten() + .map(|dir| dir.into_path()) + .collect::>(); + + // Filter all files for Mach-O headers. This will target all .dylib and native executable files + for file in files { + let metadata = match std::fs::metadata(&file) { + Ok(f) => f, + Err(err) => { + tracing::warn!("Failed to get metadata for {}: {err}, this file will not be scanned for Mach-O header!", file.display()); + continue; + } + }; + + if !metadata.is_file() { + continue; + } + + let mut open_file = match std::fs::File::open(&file) { + Ok(f) => f, + Err(err) => { + tracing::warn!("Failed to open {} for reading: {err}, this file will not be scanned for Mach-O header!", file.display()); + continue; + } + }; + + let mut buffer = [0; 4]; + std::io::Read::read_exact(&mut open_file, &mut buffer)?; + + const MACH_O_MAGIC_NUMBERS: [u32; 5] = + [0xfeedface, 0xfeedfacf, 0xcafebabe, 0xcefaedfe, 0xcffaedfe]; + + let magic = u32::from_be_bytes(buffer); + + let is_mach = MACH_O_MAGIC_NUMBERS.contains(&magic); + if !is_mach { + continue; + } + + sign_paths.push(SignTarget { + path: file, + is_native_binary: true, + }); + } + } + } + sign_paths.extend( framework_paths .into_iter() @@ -61,7 +117,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { }) .map(|path| SignTarget { path, - is_an_executable: false, + is_native_binary: false, }), ); @@ -72,7 +128,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { let bin_paths = config.copy_external_binaries(&bin_dir)?; sign_paths.extend(bin_paths.into_iter().map(|path| SignTarget { path, - is_an_executable: true, + is_native_binary: true, })); tracing::debug!("Copying binaries"); @@ -82,7 +138,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { std::fs::copy(&bin_path, &dest_path)?; sign_paths.push(SignTarget { path: dest_path, - is_an_executable: true, + is_native_binary: true, }); } @@ -95,7 +151,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { // https://developer.apple.com/forums/thread/701514 sign_paths.push(SignTarget { path: app_bundle_path.clone(), - is_an_executable: true, + is_native_binary: true, }); // Remove extra attributes, which could cause codesign to fail diff --git a/crates/packager/src/package/dmg/mod.rs b/crates/packager/src/package/dmg/mod.rs index fdb99f65..7336c05a 100644 --- a/crates/packager/src/package/dmg/mod.rs +++ b/crates/packager/src/package/dmg/mod.rs @@ -199,7 +199,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result> { codesign::try_sign( vec![codesign::SignTarget { path: dmg_path.clone(), - is_an_executable: false, + is_native_binary: false, }], identity, config,