mirror of
https://github.com/nab138/isideload.git
synced 2026-03-02 06:26:16 +01:00
im questioning everything I thought I knew about this stuff
This commit is contained in:
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -155,7 +155,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.17",
|
||||
"x509-certificate 0.24.0",
|
||||
"x509-certificate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -246,7 +246,7 @@ dependencies = [
|
||||
"widestring",
|
||||
"windows-sys 0.59.0",
|
||||
"x509",
|
||||
"x509-certificate 0.24.0",
|
||||
"x509-certificate",
|
||||
"xml-rs",
|
||||
"yasna",
|
||||
"zeroize",
|
||||
@@ -294,7 +294,7 @@ dependencies = [
|
||||
"signature 2.2.0",
|
||||
"thiserror 2.0.17",
|
||||
"url",
|
||||
"x509-certificate 0.24.0",
|
||||
"x509-certificate",
|
||||
"xml-rs",
|
||||
"xz2",
|
||||
]
|
||||
@@ -1390,7 +1390,7 @@ dependencies = [
|
||||
"reqwest 0.12.24",
|
||||
"ring",
|
||||
"signature 2.2.0",
|
||||
"x509-certificate 0.24.0",
|
||||
"x509-certificate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2504,12 +2504,10 @@ name = "isideload"
|
||||
version = "0.1.21"
|
||||
dependencies = [
|
||||
"apple-codesign",
|
||||
"der 0.7.10",
|
||||
"hex",
|
||||
"idevice",
|
||||
"nab138_icloud_auth",
|
||||
"p12",
|
||||
"pkcs8 0.10.2",
|
||||
"plist",
|
||||
"rand 0.8.5",
|
||||
"rcgen",
|
||||
@@ -2517,8 +2515,9 @@ dependencies = [
|
||||
"serde",
|
||||
"sha1",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"uuid",
|
||||
"x509-certificate 0.25.0",
|
||||
"x509-certificate",
|
||||
"zip 4.6.1",
|
||||
]
|
||||
|
||||
@@ -5437,25 +5436,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x509-certificate"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca9eb9a0c822c67129d5b8fcc2806c6bc4f50496b420825069a440669bcfbf7f"
|
||||
dependencies = [
|
||||
"bcder",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"der 0.7.10",
|
||||
"hex",
|
||||
"pem",
|
||||
"ring",
|
||||
"signature 2.2.0",
|
||||
"spki 0.7.3",
|
||||
"thiserror 2.0.17",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.28"
|
||||
|
||||
@@ -58,7 +58,9 @@ async fn main() {
|
||||
let dev_session = DeveloperSession::new(Arc::new(account));
|
||||
|
||||
// You can change the machine name, store directory (for certs, anisette data, & provision files), and logger
|
||||
let config = SideloadConfiguration::default().set_machine_name("isideload-demo".to_string());
|
||||
let config = SideloadConfiguration::default()
|
||||
.set_machine_name("isideload-demo".to_string())
|
||||
.set_force_sidestore(true);
|
||||
|
||||
sideload_app(&provider, &dev_session, app_path, config)
|
||||
.await
|
||||
|
||||
@@ -24,10 +24,9 @@ sha1 = "0.10"
|
||||
idevice = { version = "0.1.46", features = ["afc", "installation_proxy", "ring"], default-features = false }
|
||||
thiserror = "2"
|
||||
apple-codesign = "0.29.0"
|
||||
x509-certificate = "0.25.0"
|
||||
x509-certificate = "0.24.0"
|
||||
rsa = "0.9"
|
||||
pkcs8 = "0.10"
|
||||
rcgen = "0.13"
|
||||
p12 = "0.6"
|
||||
der = "0.7"
|
||||
rand = "0.8"
|
||||
tokio = "1.48.0"
|
||||
p12 = "0.6.3"
|
||||
|
||||
@@ -7,12 +7,13 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Bundle {
|
||||
pub app_info: Dictionary,
|
||||
pub bundle_dir: PathBuf,
|
||||
|
||||
pub bundle_type: BundleType,
|
||||
app_extensions: Vec<Bundle>,
|
||||
_frameworks: Vec<Bundle>,
|
||||
frameworks: Vec<Bundle>,
|
||||
_libraries: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -79,9 +80,15 @@ impl Bundle {
|
||||
|
||||
Ok(Bundle {
|
||||
app_info,
|
||||
bundle_type: BundleType::from_extension(
|
||||
bundle_path
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.unwrap_or(""),
|
||||
),
|
||||
bundle_dir: bundle_path,
|
||||
app_extensions,
|
||||
_frameworks: frameworks,
|
||||
frameworks,
|
||||
_libraries: libraries,
|
||||
})
|
||||
}
|
||||
@@ -125,6 +132,15 @@ impl Bundle {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn embedded_bundles(&self) -> Vec<&Bundle> {
|
||||
let mut bundles = Vec::new();
|
||||
bundles.extend(self.app_extensions.iter());
|
||||
bundles.extend(self.frameworks.iter());
|
||||
bundles.push(self);
|
||||
bundles.sort_by_key(|b| b.bundle_dir.components().count());
|
||||
bundles
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_bundle(condition: bool, msg: &str) -> Result<(), Error> {
|
||||
@@ -178,3 +194,23 @@ fn find_dylibs(dir: &Path, bundle_root: &Path) -> Result<Vec<String>, Error> {
|
||||
collect_dylibs(dir, bundle_root, &mut libraries)?;
|
||||
Ok(libraries)
|
||||
}
|
||||
|
||||
// Borrowed from https://github.com/khcrysalis/PlumeImpactor/blob/main/crates/utils/src/bundle.rs
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BundleType {
|
||||
App,
|
||||
AppExtension,
|
||||
Framework,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl BundleType {
|
||||
pub fn from_extension(ext: &str) -> Self {
|
||||
match ext {
|
||||
"app" => BundleType::App,
|
||||
"appex" => BundleType::AppExtension,
|
||||
"framework" => BundleType::Framework,
|
||||
_ => BundleType::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
||||
|
||||
use apple_codesign::SigningSettings;
|
||||
use hex;
|
||||
use rcgen::{CertificateParams, DnType, KeyPair};
|
||||
use rsa::pkcs1::EncodeRsaPublicKey;
|
||||
use rsa::{
|
||||
RsaPrivateKey,
|
||||
pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding},
|
||||
@@ -11,16 +11,16 @@ use sha1::{Digest, Sha1};
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
use x509_certificate::X509Certificate;
|
||||
use x509_certificate::{CapturedX509Certificate, InMemorySigningKeyPair, Sign, X509Certificate};
|
||||
|
||||
use crate::Error;
|
||||
use crate::developer_session::{DeveloperDeviceType, DeveloperSession, DeveloperTeam};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct CertificateIdentity {
|
||||
pub certificate: Option<X509Certificate>,
|
||||
pub key_pair: InMemorySigningKeyPair,
|
||||
pub private_key: RsaPrivateKey,
|
||||
pub key_file: PathBuf,
|
||||
pub cert_file: PathBuf,
|
||||
@@ -65,8 +65,17 @@ impl CertificateIdentity {
|
||||
private_key
|
||||
};
|
||||
|
||||
let key_pair = InMemorySigningKeyPair::from_pkcs8_der(
|
||||
private_key
|
||||
.to_pkcs8_der()
|
||||
.map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?
|
||||
.as_bytes(),
|
||||
)
|
||||
.map_err(|e| Error::Certificate(format!("Failed to decode private key: {}", e)))?;
|
||||
|
||||
let mut cert_identity = CertificateIdentity {
|
||||
certificate: None,
|
||||
key_pair,
|
||||
private_key,
|
||||
key_file,
|
||||
cert_file,
|
||||
@@ -105,12 +114,7 @@ impl CertificateIdentity {
|
||||
.await
|
||||
.map_err(|e| Error::Certificate(format!("Failed to list certificates: {:?}", e)))?;
|
||||
|
||||
let our_public_key_der = self
|
||||
.private_key
|
||||
.to_public_key()
|
||||
.to_pkcs1_der()
|
||||
.map_err(|e| Error::Certificate(format!("Failed to get public key: {}", e)))?
|
||||
.to_vec();
|
||||
let our_public_key_der = self.key_pair.public_key_data().to_vec();
|
||||
|
||||
for cert in certificates
|
||||
.iter()
|
||||
@@ -233,29 +237,65 @@ impl CertificateIdentity {
|
||||
let serial = &cert.tbs_certificate().serial_number;
|
||||
let hex_str = hex::encode(serial.as_slice());
|
||||
|
||||
Ok(hex_str.trim_start_matches("0").to_string())
|
||||
Ok(hex_str.trim_start_matches("0").to_string().to_uppercase())
|
||||
}
|
||||
|
||||
pub fn to_pkcs12(&self, password: &str) -> Result<Vec<u8>, Error> {
|
||||
let output = Command::new("openssl")
|
||||
.arg("pkcs12")
|
||||
.arg("-export")
|
||||
.arg("-inkey")
|
||||
.arg(&self.key_file)
|
||||
.arg("-in")
|
||||
.arg(&self.cert_file)
|
||||
.arg("-passout")
|
||||
.arg(format!("pass:{}", password))
|
||||
.output()
|
||||
.map_err(|e| Error::Certificate(format!("Failed to execute openssl: {}", e)))?;
|
||||
let cert = self
|
||||
.certificate
|
||||
.as_ref()
|
||||
.ok_or(Error::Certificate("Certificate not found".to_string()))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(Error::Certificate(format!(
|
||||
"openssl failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
)));
|
||||
let cert_der = cert
|
||||
.encode_der()
|
||||
.map_err(|e| Error::Certificate(format!("Failed to encode certificate: {}", e)))?;
|
||||
|
||||
let key_der = self
|
||||
.private_key
|
||||
.to_pkcs8_der()
|
||||
.map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?;
|
||||
|
||||
let pfx = p12::PFX::new(
|
||||
&cert_der,
|
||||
key_der.as_bytes(),
|
||||
None,
|
||||
password,
|
||||
&self.machine_name,
|
||||
)
|
||||
.ok_or(Error::Certificate("Failed to create PKCS#12".to_string()))?;
|
||||
|
||||
Ok(pfx.to_der())
|
||||
}
|
||||
|
||||
Ok(output.stdout)
|
||||
pub fn to_signing_settings(&self) -> Result<SigningSettings<'_>, Error> {
|
||||
let mut settings = SigningSettings::default();
|
||||
|
||||
let certificate = self
|
||||
.certificate
|
||||
.as_ref()
|
||||
.ok_or(Error::Certificate("Certificate not found".to_string()))?;
|
||||
|
||||
settings.set_signing_key(
|
||||
&self.key_pair,
|
||||
CapturedX509Certificate::from_der(
|
||||
certificate.encode_der().map_err(|e| {
|
||||
Error::Certificate(format!("Failed to encode certificate: {}", e))
|
||||
})?,
|
||||
)
|
||||
.map_err(|e| {
|
||||
Error::Certificate(format!("Failed to create captured certificate: {}", e))
|
||||
})?,
|
||||
);
|
||||
settings.chain_apple_certificates();
|
||||
settings.set_for_notarization(false);
|
||||
settings.set_shallow(true);
|
||||
settings.set_team_id_from_signing_certificate().ok_or({
|
||||
Error::Certificate("Failed to set team ID from signing certificate".to_string())
|
||||
})?;
|
||||
settings
|
||||
.set_time_stamp_url("http://timestamp.apple.com/ts01")
|
||||
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,3 +724,56 @@ pub struct ProvisioningProfile {
|
||||
pub _name: String,
|
||||
pub encoded_profile: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ProvisioningProfile {
|
||||
// TODO: I'm not sure if this is the proper way to parse this but it works so...
|
||||
pub fn profile_plist(&self) -> Result<plist::Dictionary, Error> {
|
||||
let start_marker = b"<?xml";
|
||||
let end_marker = b"</plist>";
|
||||
|
||||
let start = self
|
||||
.encoded_profile
|
||||
.windows(start_marker.len())
|
||||
.position(|w| w == start_marker)
|
||||
.ok_or_else(|| {
|
||||
Error::Generic("Failed to find start of plist in provisioning profile".to_string())
|
||||
})?;
|
||||
|
||||
let end = self
|
||||
.encoded_profile
|
||||
.windows(end_marker.len())
|
||||
.position(|w| w == end_marker)
|
||||
.ok_or_else(|| {
|
||||
Error::Generic("Failed to find end of plist in provisioning profile".to_string())
|
||||
})?
|
||||
+ end_marker.len();
|
||||
|
||||
plist::from_bytes::<plist::Dictionary>(&self.encoded_profile[start..end]).map_err(|e| {
|
||||
Error::Generic(format!("Failed to parse provisioning profile plist: {}", e))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn entitlements_xml(&self) -> Result<String, Error> {
|
||||
let profile_plist = self.profile_plist()?;
|
||||
let entitlements = profile_plist.get("Entitlements").ok_or_else(|| {
|
||||
Error::Generic("No Entitlements found in provisioning profile".to_string())
|
||||
})?;
|
||||
let mut buf = vec![];
|
||||
entitlements.to_writer_xml(&mut buf).map_err(|e| {
|
||||
Error::Generic(format!(
|
||||
"Failed to convert entitlements to XML for codesigning: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
let entitlements = std::str::from_utf8(&buf)
|
||||
.map_err(|e| {
|
||||
Error::Generic(format!(
|
||||
"Failed to convert entitlements to UTF-8 for codesigning: {}",
|
||||
e
|
||||
))
|
||||
})?
|
||||
.to_string();
|
||||
|
||||
Ok(entitlements)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,16 +55,12 @@ impl SideloadLogger for DefaultLogger {
|
||||
|
||||
/// Sideload configuration options.
|
||||
pub struct SideloadConfiguration<'a> {
|
||||
/// An arbitrary machine name to appear on the certificate (e.x. "YCode")
|
||||
pub machine_name: String,
|
||||
/// Logger for reporting progress and errors
|
||||
pub logger: &'a dyn SideloadLogger,
|
||||
/// Directory used to store intermediate artifacts (profiles, certs, etc.). This directory will not be cleared at the end.
|
||||
pub store_dir: std::path::PathBuf,
|
||||
/// Whether or not to revoke the certificate immediately after installation
|
||||
pub revoke_cert: bool,
|
||||
/// Whether or not to force SideStore App Group (fixes LiveContainer+SideStore issues)
|
||||
pub force_sidestore_app_group: bool,
|
||||
pub force_sidestore: bool,
|
||||
pub skip_register_extensions: bool,
|
||||
}
|
||||
|
||||
impl Default for SideloadConfiguration<'_> {
|
||||
@@ -80,32 +76,48 @@ impl<'a> SideloadConfiguration<'a> {
|
||||
logger: &DefaultLogger,
|
||||
store_dir: std::env::current_dir().unwrap(),
|
||||
revoke_cert: false,
|
||||
force_sidestore_app_group: false,
|
||||
force_sidestore: false,
|
||||
skip_register_extensions: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// An arbitrary machine name to appear on the certificate (e.x. "CrossCode")
|
||||
pub fn set_machine_name(mut self, machine_name: String) -> Self {
|
||||
self.machine_name = machine_name;
|
||||
self
|
||||
}
|
||||
|
||||
/// Logger for reporting progress and errors
|
||||
pub fn set_logger(mut self, logger: &'a dyn SideloadLogger) -> Self {
|
||||
self.logger = logger;
|
||||
self
|
||||
}
|
||||
|
||||
/// Directory used to store intermediate artifacts (profiles, certs, etc.). This directory will not be cleared at the end.
|
||||
pub fn set_store_dir(mut self, store_dir: std::path::PathBuf) -> Self {
|
||||
self.store_dir = store_dir;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether or not to revoke the certificate immediately after installation
|
||||
#[deprecated(
|
||||
since = "0.1.0",
|
||||
note = "Certificates will now be placed in SideStore automatically so there is no need to revoke"
|
||||
)]
|
||||
pub fn set_revoke_cert(mut self, revoke_cert: bool) -> Self {
|
||||
self.revoke_cert = revoke_cert;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_force_sidestore_app_group(mut self, force: bool) -> Self {
|
||||
self.force_sidestore_app_group = force;
|
||||
/// Whether or not to treat the app as SideStore (fixes LiveContainer+SideStore issues)
|
||||
pub fn set_force_sidestore(mut self, force: bool) -> Self {
|
||||
self.force_sidestore = force;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether or not to skip registering app extensions (save app IDs, default true)
|
||||
pub fn set_skip_register_extensions(mut self, skip: bool) -> Self {
|
||||
self.skip_register_extensions = skip;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
||||
|
||||
use apple_codesign::{BundleSigner, SigningSettings};
|
||||
use der::Encode;
|
||||
use apple_codesign::{SettingsScope, UnifiedSigner};
|
||||
use idevice::IdeviceService;
|
||||
use idevice::lockdown::LockdownClient;
|
||||
use idevice::provider::IdeviceProvider;
|
||||
|
||||
use crate::application::Application;
|
||||
use crate::developer_session::ProvisioningProfile;
|
||||
use crate::device::install_app;
|
||||
use crate::{DeveloperTeam, Error, SideloadConfiguration, SideloadLogger};
|
||||
use crate::{
|
||||
certificate::CertificateIdentity,
|
||||
developer_session::{DeveloperDeviceType, DeveloperSession},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::{io::Write, path::PathBuf};
|
||||
|
||||
fn error_and_return(logger: &dyn SideloadLogger, error: Error) -> Result<(), Error> {
|
||||
@@ -106,7 +107,8 @@ pub async fn sideload_app(
|
||||
};
|
||||
|
||||
let mut app = Application::new(app_path)?;
|
||||
let is_sidestore = app.bundle.bundle_identifier().unwrap_or("") == "com.SideStore.SideStore";
|
||||
let is_sidestore = config.force_sidestore
|
||||
|| app.bundle.bundle_identifier().unwrap_or("") == "com.SideStore.SideStore";
|
||||
let main_app_bundle_id = match app.bundle.bundle_identifier() {
|
||||
Some(id) => id.to_string(),
|
||||
None => {
|
||||
@@ -255,7 +257,7 @@ pub async fn sideload_app(
|
||||
|
||||
let group_identifier = format!(
|
||||
"group.{}",
|
||||
if config.force_sidestore_app_group {
|
||||
if config.force_sidestore {
|
||||
format!("com.SideStore.SideStore.{}", team.team_id)
|
||||
} else {
|
||||
main_app_id_str.clone()
|
||||
@@ -321,7 +323,7 @@ pub async fn sideload_app(
|
||||
matching_app_groups[0].clone()
|
||||
};
|
||||
|
||||
//let mut provisioning_profiles: HashMap<String, ProvisioningProfile> = HashMap::new();
|
||||
let mut provisioning_profiles: HashMap<String, ProvisioningProfile> = HashMap::new();
|
||||
for app_id in app_ids {
|
||||
let assign_res = dev_session
|
||||
.assign_application_group_to_app_id(
|
||||
@@ -334,26 +336,8 @@ pub async fn sideload_app(
|
||||
if assign_res.is_err() {
|
||||
return error_and_return(logger, assign_res.err().unwrap());
|
||||
}
|
||||
// let provisioning_profile = match account
|
||||
// // This doesn't seem right to me, but it's what Sideloader does... Shouldn't it be downloading the provisioning profile for this app ID, not the main?
|
||||
// .download_team_provisioning_profile(DeveloperDeviceType::Ios, &team, &main_app_id)
|
||||
// .await
|
||||
// {
|
||||
// Ok(pp /* tee hee */) => pp,
|
||||
// Err(e) => {
|
||||
// return emit_error_and_return(
|
||||
// &window,
|
||||
// &format!("Failed to download provisioning profile: {:?}", e),
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
// provisioning_profiles.insert(app_id.identifier.clone(), provisioning_profile);
|
||||
}
|
||||
|
||||
logger.log("Successfully registered app groups");
|
||||
|
||||
let provisioning_profile = match dev_session
|
||||
.download_team_provisioning_profile(DeveloperDeviceType::Ios, &team, &main_app_id)
|
||||
.download_team_provisioning_profile(DeveloperDeviceType::Ios, &team, &app_id)
|
||||
.await
|
||||
{
|
||||
Ok(pp /* tee hee */) => pp,
|
||||
@@ -361,10 +345,12 @@ pub async fn sideload_app(
|
||||
return error_and_return(logger, e);
|
||||
}
|
||||
};
|
||||
provisioning_profiles.insert(app_id.identifier.clone(), provisioning_profile);
|
||||
}
|
||||
|
||||
let profile_path = config
|
||||
.store_dir
|
||||
.join(format!("{}.mobileprovision", main_app_id_str));
|
||||
logger.log("Successfully registered app groups");
|
||||
|
||||
let profile_path = app.bundle.bundle_dir.join("embedded.mobileprovision");
|
||||
|
||||
if profile_path.exists() {
|
||||
std::fs::remove_file(&profile_path).map_err(Error::Filesystem)?;
|
||||
@@ -386,37 +372,53 @@ pub async fn sideload_app(
|
||||
ext.write_info()?;
|
||||
}
|
||||
|
||||
// match ZSignOptions::new(app.bundle.bundle_dir.to_str().unwrap())
|
||||
// .with_cert_file(cert.get_certificate_file_path().to_str().unwrap())
|
||||
// .with_pkey_file(cert.get_private_key_file_path().to_str().unwrap())
|
||||
// .with_prov_file(profile_path.to_str().unwrap())
|
||||
// .sign()
|
||||
// {
|
||||
// Ok(_) => {}
|
||||
// Err(e) => {
|
||||
// return error_and_return(logger, Error::ZSignError(e));
|
||||
// }
|
||||
// };
|
||||
// Collect owned bundle identifiers and directories so we don't capture `app` or `logger` by reference in the blocking thread.
|
||||
let embedded_bundles_info: Vec<(String, PathBuf)> = app
|
||||
.bundle
|
||||
.embedded_bundles()
|
||||
.iter()
|
||||
.map(|bundle| {
|
||||
(
|
||||
bundle.bundle_identifier().unwrap_or("Unknown").to_string(),
|
||||
bundle.bundle_dir.clone(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let main_bundle_dir = app.bundle.bundle_dir.clone();
|
||||
|
||||
let mut signer = BundleSigner::new_from_path(&app.bundle.bundle_dir)
|
||||
// Log bundle signing messages outside the blocking closure to avoid capturing non-'static references.
|
||||
for (id, _) in &embedded_bundles_info {
|
||||
logger.log(&format!("Signing bundle: {}", id));
|
||||
}
|
||||
|
||||
// Move owned data (cert, provisioning_profile, embedded_bundles_info) into the blocking task.
|
||||
tokio::task::spawn_blocking(move || {
|
||||
for (_id, bundle_dir) in embedded_bundles_info {
|
||||
// Recreate settings for each bundle so ownership is clear and we don't move settings across iterations.
|
||||
let mut settings = cert.to_signing_settings()?;
|
||||
settings
|
||||
.set_entitlements_xml(
|
||||
SettingsScope::Main,
|
||||
provisioning_profile.entitlements_xml()?,
|
||||
)
|
||||
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||
|
||||
let signer = UnifiedSigner::new(settings);
|
||||
|
||||
signer
|
||||
.collect_nested_bundles()
|
||||
.sign_path_in_place(&bundle_dir)
|
||||
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||
}
|
||||
Ok::<(), Error>(())
|
||||
})
|
||||
.await
|
||||
.map_err(|e| Error::Generic(format!("Signing task failed: {}", e)))??;
|
||||
|
||||
let mut settings = SigningSettings::default();
|
||||
logger.log("Sucessfully signed app");
|
||||
|
||||
settings.set_signing_key(cert.private_key.clone(), cert.certificate.unwrap());
|
||||
logger.log("Installing app... 0%");
|
||||
|
||||
signer
|
||||
.write_signed_bundle(&app.bundle.bundle_dir, &settings)
|
||||
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||
logger.log("App signed!");
|
||||
|
||||
logger.log("Installing app (Transfer)... 0%");
|
||||
|
||||
let res = install_app(device_provider, &app.bundle.bundle_dir, |percentage| {
|
||||
let res = install_app(device_provider, &main_bundle_dir, |percentage| {
|
||||
logger.log(&format!("Installing app... {}%", percentage));
|
||||
})
|
||||
.await;
|
||||
@@ -424,12 +426,12 @@ pub async fn sideload_app(
|
||||
return error_and_return(logger, e);
|
||||
}
|
||||
|
||||
if config.revoke_cert {
|
||||
dev_session
|
||||
.revoke_development_cert(DeveloperDeviceType::Ios, &team, &cert.get_serial_number()?)
|
||||
.await?;
|
||||
logger.log("Certificate revoked");
|
||||
}
|
||||
// if config.revoke_cert {
|
||||
// dev_session
|
||||
// .revoke_development_cert(DeveloperDeviceType::Ios, &team, &cert.get_serial_number()?)
|
||||
// .await?;
|
||||
// logger.log("Certificate revoked");
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user