fix: codesign doesn't sign frameworks or sidecar, closes #7690 (#7774)

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
This commit is contained in:
Trey Smith
2023-09-15 11:09:10 -04:00
committed by GitHub
parent 2f8881c010
commit dcdbe3eb6c
18 changed files with 322 additions and 54 deletions

View File

@@ -23,9 +23,9 @@
// files into the `Contents` directory of the bundle.
use super::{
super::common,
super::common::{self, CommandExt},
icon::create_icns_file,
sign::{notarize, notarize_auth, sign},
sign::{notarize, notarize_auth, sign, SignTarget},
};
use crate::Settings;
@@ -33,8 +33,10 @@ use anyhow::Context;
use log::{info, warn};
use std::{
ffi::OsStr,
fs,
path::{Path, PathBuf},
process::Command,
};
/// Bundles the project.
@@ -65,6 +67,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
let resources_dir = bundle_directory.join("Resources");
let bin_dir = bundle_directory.join("MacOS");
let mut sign_paths = Vec::new();
let bundle_icon_file: Option<PathBuf> =
{ create_icns_file(&resources_dir, settings).with_context(|| "Failed to create app icon")? };
@@ -72,20 +75,52 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
create_info_plist(&bundle_directory, bundle_icon_file, settings)
.with_context(|| "Failed to create Info.plist")?;
copy_frameworks_to_bundle(&bundle_directory, settings)
let framework_paths = copy_frameworks_to_bundle(&bundle_directory, settings)
.with_context(|| "Failed to bundle frameworks")?;
sign_paths.extend(
framework_paths
.into_iter()
.filter(|p| {
let ext = p.extension();
ext == Some(OsStr::new("framework")) || ext == Some(OsStr::new("dylib"))
})
.map(|path| SignTarget {
path,
is_an_executable: false,
}),
);
settings.copy_resources(&resources_dir)?;
settings
let bin_paths = settings
.copy_binaries(&bin_dir)
.with_context(|| "Failed to copy external binaries")?;
sign_paths.extend(bin_paths.into_iter().map(|path| SignTarget {
path,
is_an_executable: true,
}));
copy_binaries_to_bundle(&bundle_directory, settings)?;
let bin_paths = copy_binaries_to_bundle(&bundle_directory, settings)?;
sign_paths.extend(bin_paths.into_iter().map(|path| SignTarget {
path,
is_an_executable: true,
}));
if let Some(identity) = &settings.macos().signing_identity {
// Sign frameworks and sidecar binaries first, per apple, signing must be done inside out
// https://developer.apple.com/forums/thread/701514
sign_paths.push(SignTarget {
path: app_bundle_path.clone(),
is_an_executable: true,
});
// Remove extra attributes, which could cause codesign to fail
// https://developer.apple.com/library/archive/qa/qa1940/_index.html
remove_extra_attr(&app_bundle_path)?;
// sign application
sign(app_bundle_path.clone(), identity, settings, true)?;
sign(sign_paths, identity, settings)?;
// notarization is required for distribution
match notarize_auth() {
Ok(auth) => {
@@ -100,15 +135,30 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
Ok(vec![app_bundle_path])
}
fn remove_extra_attr(app_bundle_path: &Path) -> crate::Result<()> {
Command::new("xattr")
.arg("-cr")
.arg(app_bundle_path)
.output_ok()
.context("failed to remove extra attributes from app bundle")?;
Ok(())
}
// Copies the app's binaries to the bundle.
fn copy_binaries_to_bundle(bundle_directory: &Path, settings: &Settings) -> crate::Result<()> {
fn copy_binaries_to_bundle(
bundle_directory: &Path,
settings: &Settings,
) -> crate::Result<Vec<PathBuf>> {
let mut paths = Vec::new();
let dest_dir = bundle_directory.join("MacOS");
for bin in settings.binaries() {
let bin_path = settings.binary_path(bin);
common::copy_file(&bin_path, &dest_dir.join(bin.name()))
let dest_path = dest_dir.join(bin.name());
common::copy_file(&bin_path, &dest_path)
.with_context(|| format!("Failed to copy binary from {:?}", bin_path))?;
paths.push(dest_path);
}
Ok(())
Ok(paths)
}
// Creates the Info.plist file.
@@ -208,7 +258,12 @@ fn copy_framework_from(dest_dir: &Path, framework: &str, src_dir: &Path) -> crat
}
// Copies the macOS application bundle frameworks to the .app
fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> crate::Result<()> {
fn copy_frameworks_to_bundle(
bundle_directory: &Path,
settings: &Settings,
) -> crate::Result<Vec<PathBuf>> {
let mut paths = Vec::new();
let frameworks = settings
.macos()
.frameworks
@@ -216,7 +271,7 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
.cloned()
.unwrap_or_default();
if frameworks.is_empty() {
return Ok(());
return Ok(paths);
}
let dest_dir = bundle_directory.join("Frameworks");
fs::create_dir_all(bundle_directory)
@@ -227,7 +282,9 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
let src_name = src_path
.file_name()
.expect("Couldn't get framework filename");
common::copy_dir(&src_path, &dest_dir.join(src_name))?;
let dest_path = dest_dir.join(src_name);
common::copy_dir(&src_path, &dest_path)?;
paths.push(dest_path);
continue;
} else if framework.ends_with(".dylib") {
let src_path = PathBuf::from(framework);
@@ -238,7 +295,9 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
)));
}
let src_name = src_path.file_name().expect("Couldn't get library filename");
common::copy_file(&src_path, &dest_dir.join(src_name))?;
let dest_path = dest_dir.join(src_name);
common::copy_file(&src_path, &dest_path)?;
paths.push(dest_path);
continue;
} else if framework.contains('/') {
return Err(crate::Error::GenericError(format!(
@@ -265,5 +324,5 @@ fn copy_frameworks_to_bundle(bundle_directory: &Path, settings: &Settings) -> cr
framework
)));
}
Ok(())
Ok(paths)
}

View File

@@ -153,7 +153,14 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result<
// Sign DMG if needed
if let Some(identity) = &settings.macos().signing_identity {
super::sign::sign(dmg_path.clone(), identity, settings, false)?;
super::sign::sign(
vec![super::sign::SignTarget {
path: dmg_path.clone(),
is_an_executable: false,
}],
identity,
settings,
)?;
}
Ok(Bundled {

View File

@@ -144,13 +144,13 @@ pub fn delete_keychain() {
.output_ok();
}
pub fn sign(
path_to_sign: PathBuf,
identity: &str,
settings: &Settings,
is_an_executable: bool,
) -> crate::Result<()> {
info!(action = "Signing"; "{} with identity \"{}\"", path_to_sign.display(), identity);
pub struct SignTarget {
pub path: PathBuf,
pub is_an_executable: bool,
}
pub fn sign(targets: Vec<SignTarget>, identity: &str, settings: &Settings) -> crate::Result<()> {
info!(action = "Signing"; "with identity \"{}\"", identity);
let setup_keychain = if let (Some(certificate_encoded), Some(certificate_password)) = (
var_os("APPLE_CERTIFICATE"),
@@ -164,20 +164,24 @@ pub fn sign(
false
};
let res = try_sign(
path_to_sign,
identity,
settings,
is_an_executable,
setup_keychain,
);
info!("Signing app bundle...");
for target in targets {
try_sign(
target.path,
identity,
settings,
target.is_an_executable,
setup_keychain,
)?;
}
if setup_keychain {
// delete the keychain again after signing
delete_keychain();
}
res
Ok(())
}
fn try_sign(
@@ -187,6 +191,8 @@ fn try_sign(
is_an_executable: bool,
tauri_keychain: bool,
) -> crate::Result<()> {
info!(action = "Signing"; "{}", path_to_sign.display());
let mut args = vec!["--force", "-s", identity];
if tauri_keychain {
@@ -205,13 +211,9 @@ fn try_sign(
args.push("runtime");
}
if path_to_sign.is_dir() {
args.push("--deep");
}
Command::new("codesign")
.args(args)
.arg(path_to_sign.to_string_lossy().to_string())
.arg(path_to_sign)
.output_ok()
.context("failed to sign app")?;
@@ -260,7 +262,14 @@ pub fn notarize(
// sign the zip file
if let Some(identity) = &settings.macos().signing_identity {
sign(zip_path.clone(), identity, settings, false)?;
sign(
vec![SignTarget {
path: zip_path.clone(),
is_an_executable: false,
}],
identity,
settings,
)?;
};
let notarize_args = vec![

View File

@@ -761,7 +761,11 @@ impl Settings {
}
/// Copies external binaries to a path.
pub fn copy_binaries(&self, path: &Path) -> crate::Result<()> {
///
/// Returns the list of destination paths.
pub fn copy_binaries(&self, path: &Path) -> crate::Result<Vec<PathBuf>> {
let mut paths = Vec::new();
for src in self.external_binaries() {
let src = src?;
let dest = path.join(
@@ -771,9 +775,10 @@ impl Settings {
.to_string_lossy()
.replace(&format!("-{}", self.target), ""),
);
common::copy_file(&src, dest)?;
common::copy_file(&src, &dest)?;
paths.push(dest);
}
Ok(())
Ok(paths)
}
/// Copies resources to a path.