Skip to content

Commit

Permalink
fix: fix the signing and notarization process for MacOS packages
Browse files Browse the repository at this point in the history
Closes #131
  • Loading branch information
jan-br committed Jan 20, 2024
1 parent 14f5ae9 commit f08e4b8
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .changes/codesign-and-notarization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"cargo-packager": patch
"@crabnebula/packager": patch
---

Fix the signing and notarization process for MacOS bundles
18 changes: 8 additions & 10 deletions crates/packager/src/codesign/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand All @@ -170,7 +170,7 @@ pub fn try_sign(targets: Vec<SignTarget>, identity: &str, config: &Config) -> cr
&target.path,
identity,
config,
target.is_an_executable,
target.is_native_binary,
packager_keychain,
)?;
}
Expand All @@ -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 \"{}\"",
Expand All @@ -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);
}
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
64 changes: 60 additions & 4 deletions crates/packager/src/package/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,62 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {

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::<Vec<_>>();

// 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()
Expand All @@ -61,7 +117,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {
})
.map(|path| SignTarget {
path,
is_an_executable: false,
is_native_binary: false,
}),
);

Expand All @@ -72,7 +128,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {
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");
Expand All @@ -82,7 +138,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {
std::fs::copy(&bin_path, &dest_path)?;
sign_paths.push(SignTarget {
path: dest_path,
is_an_executable: true,
is_native_binary: true,
});
}

Expand All @@ -95,7 +151,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {
// 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
Expand Down
2 changes: 1 addition & 1 deletion crates/packager/src/package/dmg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub(crate) fn package(ctx: &Context) -> crate::Result<Vec<PathBuf>> {
codesign::try_sign(
vec![codesign::SignTarget {
path: dmg_path.clone(),
is_an_executable: false,
is_native_binary: false,
}],
identity,
config,
Expand Down

0 comments on commit f08e4b8

Please sign in to comment.