From 59985f9b92af4651446beb716d01d4cfe5f65989 Mon Sep 17 00:00:00 2001 From: nab138 Date: Fri, 13 Feb 2026 09:01:33 -0500 Subject: [PATCH] Modify bundle for altstore/sidestore/sidstore+lc --- isideload/Cargo.toml | 5 +-- isideload/src/sideload/application.rs | 53 +++++++++++++++++++++++++ isideload/src/sideload/cert_identity.rs | 6 ++- isideload/src/sideload/sideloader.rs | 11 +++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/isideload/Cargo.toml b/isideload/Cargo.toml index a03ecf4..5cb6fc9 100644 --- a/isideload/Cargo.toml +++ b/isideload/Cargo.toml @@ -14,7 +14,6 @@ readme = "../README.md" default = ["install", "keyring-storage"] install = ["dep:idevice"] keyring-storage = ["keyring"] -p12 = ["dep:p12-keystore"] # Unfortunately, dependencies are kinda a mess rn, since this requires a beta version of the srp crate. # Once that becomes stable, hopefuly duplicate dependencies should clean up.\ @@ -44,10 +43,10 @@ cbc = { version = "0.2.0-rc.3", features = ["alloc"] } aes = "0.9.0-rc.4" aes-gcm = "0.11.0-rc.3" rsa = { version = "0.10.0-rc.15" } -tokio = "1.49.0" +tokio = { version = "1.49.0", features = ["fs"] } keyring = { version = "3.6.3", features = ["apple-native", "linux-native-sync-persistent", "windows-native"], optional = true } # TODO: Fork to update dependencies (doubt it will ever be updated) x509-certificate = "0.25" rcgen = { version = "0.14.7", default-features = false, features = ["aws_lc_rs", "pem"] } -p12-keystore = { optional = true, version = "0.2.0" } +p12-keystore = "0.2.0" zip = { version = "7.4", default-features = false, features = ["deflate"] } \ No newline at end of file diff --git a/isideload/src/sideload/application.rs b/isideload/src/sideload/application.rs index 129dd08..692d37f 100644 --- a/isideload/src/sideload/application.rs +++ b/isideload/src/sideload/application.rs @@ -7,10 +7,12 @@ use crate::dev::developer_session::DeveloperSession; use crate::dev::teams::DeveloperTeam; use crate::sideload::builder::ExtensionsBehavior; use crate::sideload::bundle::Bundle; +use crate::sideload::cert_identity::CertificateIdentity; use rootcause::option_ext::OptionExt; use rootcause::prelude::*; use std::fs::File; use std::path::PathBuf; +use tokio::io::AsyncWriteExt; use zip::ZipArchive; pub struct Application { @@ -206,6 +208,57 @@ impl Application { Ok(app_ids) } + + pub async fn apply_special_app_behavior( + &mut self, + special: &Option, + group_identifier: &str, + cert: &CertificateIdentity, + ) -> Result<(), Report> { + if special.is_none() { + return Ok(()); + } + let special = special.as_ref().unwrap(); + + if special == &SpecialApp::SideStoreLc + || special == &SpecialApp::SideStore + || special == &SpecialApp::AltStore + { + self.bundle.app_info.insert( + "ALTAppGroups".to_string(), + plist::Value::Array(vec![plist::Value::String(group_identifier.to_string())]), + ); + + let target_bundle = + match special { + SpecialApp::SideStoreLc => self.bundle.frameworks_mut().iter_mut().find(|fw| { + fw.bundle_identifier().unwrap_or("") == "com.SideStore.SideStore" + }), + _ => Some(&mut self.bundle), + }; + + if let Some(target_bundle) = target_bundle { + target_bundle.app_info.insert( + "ALTCertificateID".to_string(), + plist::Value::String(cert.get_serial_number()), + ); + + let p12_bytes = cert + .as_p12(&cert.machine_id) + .await + .context("Failed to encode cert as p12")?; + let alt_cert_path = target_bundle.bundle_dir.join("ALTCertificate.p12"); + + let mut file = tokio::fs::File::create(&alt_cert_path) + .await + .context("Failed to create ALTCertificate.p12")?; + file.write_all(&p12_bytes) + .await + .context("Failed to write ALTCertificate.p12")?; + } + } + Ok(()) + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/isideload/src/sideload/cert_identity.rs b/isideload/src/sideload/cert_identity.rs index 29873ac..e8a4f09 100644 --- a/isideload/src/sideload/cert_identity.rs +++ b/isideload/src/sideload/cert_identity.rs @@ -1,3 +1,4 @@ +use hex::ToHex; use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, PKCS_RSA_SHA256}; use rootcause::prelude::*; use rsa::{ @@ -31,7 +32,6 @@ pub struct CertificateIdentity { impl CertificateIdentity { // This implementation was "heavily inspired" by Impactor (https://github.com/khcrysalis/Impactor/blob/main/crates/plume_core/src/utils/certificate.rs) // It's a little messy and I will clean it up when the rust crypto ecosystem gets through it's next release cycle and I can reduce duplicate dependencies - #[cfg(feature = "p12")] /// Exports the certificate and private key as a PKCS#12 archive /// If you plan to import into SideStore/AltStore, use the machine id as the password pub async fn as_p12(&self, password: &str) -> Result, Report> { @@ -61,6 +61,10 @@ impl CertificateIdentity { Ok(p12) } + pub fn get_serial_number(&self) -> String { + self.certificate.serial_number_asn1().encode_hex() + } + pub async fn retrieve( machine_name: &str, apple_email: &str, diff --git a/isideload/src/sideload/sideloader.rs b/isideload/src/sideload/sideloader.rs index f8e808e..f8ded2a 100644 --- a/isideload/src/sideload/sideloader.rs +++ b/isideload/src/sideload/sideloader.rs @@ -129,11 +129,22 @@ impl Sideloader { // TODO: Increased memory entitlement } + app.apply_special_app_behavior(&special, &group_identifier, &cert_identity) + .await?; + let provisioning_profile = self .dev_session .download_team_provisioning_profile(&team, &main_app_id, None) .await?; + app.bundle.write_info()?; + for ext in app.bundle.app_extensions_mut() { + ext.write_info()?; + } + for ext in app.bundle.frameworks_mut() { + ext.write_info()?; + } + Ok(()) }