mirror of
https://github.com/nab138/isideload.git
synced 2026-03-02 06:26:16 +01:00
Start switching to apple-codesign
This commit is contained in:
2938
Cargo.lock
generated
2938
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -104,6 +104,6 @@ This project is licensed under the MPL-2.0 License. See the [LICENSE](LICENSE) f
|
|||||||
|
|
||||||
- Packages from [`apple-private-apis`](https://github.com/SideStore/apple-private-apis) were used for authentication, but the original project was left unfinished. To support isideload, `apple-private-apis` was forked and modified to add missing features. With permission from the original developers, the fork was published to crates.io until the official project is published.
|
- Packages from [`apple-private-apis`](https://github.com/SideStore/apple-private-apis) were used for authentication, but the original project was left unfinished. To support isideload, `apple-private-apis` was forked and modified to add missing features. With permission from the original developers, the fork was published to crates.io until the official project is published.
|
||||||
|
|
||||||
- [ZSign](https://github.com/zhlynn/zsign) was used for code signing with [custom rust bindings](https://github.com/nab138/zsign-rust)
|
- [apple-codesign](https://crates.io/crates/apple-codesign) was used for code signing, which is licensed under MPL-2.0.
|
||||||
|
|
||||||
- [Sideloader](https://github.com/Dadoum/Sideloader) was used as a reference for how the private API endpoints work
|
- [Sideloader](https://github.com/Dadoum/Sideloader) was used as a reference for how the private API endpoints work
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ edition = "2024"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
isideload = { path = "../../isideload", features = ["vendored-openssl"] }
|
isideload = { path = "../../isideload" }
|
||||||
idevice = { version = "0.1.46", features = ["usbmuxd", "ring"], default-features = false}
|
idevice = { version = "0.1.46", features = ["usbmuxd", "ring"], default-features = false}
|
||||||
tokio = { version = "1.43", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.43", features = ["macros", "rt-multi-thread"] }
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ readme = "../README.md"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
vendored-openssl = ["openssl/vendored", "zsign-rust/vendored-openssl"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
@@ -23,6 +22,12 @@ zip = { version = "4.3", default-features = false, features = ["deflate"] }
|
|||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
sha1 = "0.10"
|
sha1 = "0.10"
|
||||||
idevice = { version = "0.1.46", features = ["afc", "installation_proxy", "ring"], default-features = false }
|
idevice = { version = "0.1.46", features = ["afc", "installation_proxy", "ring"], default-features = false }
|
||||||
openssl = "0.10"
|
|
||||||
zsign-rust = "0.1.6"
|
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
|
apple-codesign = "0.29.0"
|
||||||
|
x509-certificate = "0.25.0"
|
||||||
|
rsa = "0.9"
|
||||||
|
pkcs8 = "0.10"
|
||||||
|
rcgen = "0.13"
|
||||||
|
p12 = "0.6"
|
||||||
|
der = "0.7"
|
||||||
|
rand = "0.8"
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
||||||
|
|
||||||
use hex;
|
use hex;
|
||||||
use openssl::{
|
use rcgen::{CertificateParams, DnType, KeyPair};
|
||||||
hash::MessageDigest,
|
use rsa::pkcs1::EncodeRsaPublicKey;
|
||||||
pkcs12::Pkcs12,
|
use rsa::{
|
||||||
pkey::{PKey, Private},
|
RsaPrivateKey,
|
||||||
rsa::Rsa,
|
pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding},
|
||||||
x509::{X509, X509Name, X509ReqBuilder},
|
|
||||||
};
|
};
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
process::Command,
|
||||||
};
|
};
|
||||||
|
use x509_certificate::X509Certificate;
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::developer_session::{DeveloperDeviceType, DeveloperSession, DeveloperTeam};
|
use crate::developer_session::{DeveloperDeviceType, DeveloperSession, DeveloperTeam};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CertificateIdentity {
|
pub struct CertificateIdentity {
|
||||||
pub certificate: Option<X509>,
|
pub certificate: Option<X509Certificate>,
|
||||||
pub private_key: PKey<Private>,
|
pub private_key: RsaPrivateKey,
|
||||||
pub key_file: PathBuf,
|
pub key_file: PathBuf,
|
||||||
pub cert_file: PathBuf,
|
pub cert_file: PathBuf,
|
||||||
pub machine_name: String,
|
pub machine_name: String,
|
||||||
@@ -46,21 +47,22 @@ impl CertificateIdentity {
|
|||||||
let team = teams
|
let team = teams
|
||||||
.first()
|
.first()
|
||||||
.ok_or(Error::Certificate("No teams found".to_string()))?;
|
.ok_or(Error::Certificate("No teams found".to_string()))?;
|
||||||
|
|
||||||
let private_key = if key_file.exists() {
|
let private_key = if key_file.exists() {
|
||||||
let key_data = fs::read_to_string(&key_file)
|
let key_data = fs::read_to_string(&key_file)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to read key file: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to read key file: {}", e)))?;
|
||||||
PKey::private_key_from_pem(key_data.as_bytes())
|
RsaPrivateKey::from_pkcs8_pem(&key_data)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to load private key: {}", e)))?
|
.map_err(|e| Error::Certificate(format!("Failed to load private key: {}", e)))?
|
||||||
} else {
|
} else {
|
||||||
let rsa = Rsa::generate(2048)
|
let mut rng = rand::thread_rng();
|
||||||
|
let private_key = RsaPrivateKey::new(&mut rng, 2048)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to generate RSA key: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to generate RSA key: {}", e)))?;
|
||||||
let key = PKey::from_rsa(rsa)
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to create private key: {}", e)))?;
|
let pem_data = private_key
|
||||||
let pem_data = key
|
.to_pkcs8_pem(LineEnding::LF)
|
||||||
.private_key_to_pem_pkcs8()
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?;
|
||||||
fs::write(&key_file, pem_data).map_err(Error::Filesystem)?;
|
fs::write(&key_file, pem_data.as_bytes()).map_err(Error::Filesystem)?;
|
||||||
key
|
private_key
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut cert_identity = CertificateIdentity {
|
let mut cert_identity = CertificateIdentity {
|
||||||
@@ -78,9 +80,10 @@ impl CertificateIdentity {
|
|||||||
{
|
{
|
||||||
cert_identity.certificate = Some(cert.clone());
|
cert_identity.certificate = Some(cert.clone());
|
||||||
cert_identity.machine_id = machine_id;
|
cert_identity.machine_id = machine_id;
|
||||||
let cert_pem = cert.to_pem().map_err(|e| {
|
|
||||||
Error::Certificate(format!("Failed to encode certificate to PEM: {}", e))
|
let cert_pem = cert
|
||||||
})?;
|
.encode_pem()
|
||||||
|
.map_err(|e| Error::Certificate(format!("Failed to encode cert: {}", e)))?;
|
||||||
fs::write(&cert_identity.cert_file, cert_pem).map_err(Error::Filesystem)?;
|
fs::write(&cert_identity.cert_file, cert_pem).map_err(Error::Filesystem)?;
|
||||||
|
|
||||||
return Ok(cert_identity);
|
return Ok(cert_identity);
|
||||||
@@ -96,29 +99,35 @@ impl CertificateIdentity {
|
|||||||
&self,
|
&self,
|
||||||
dev_session: &DeveloperSession,
|
dev_session: &DeveloperSession,
|
||||||
team: &DeveloperTeam,
|
team: &DeveloperTeam,
|
||||||
) -> Result<(X509, String), Error> {
|
) -> Result<(X509Certificate, String), Error> {
|
||||||
let certificates = dev_session
|
let certificates = dev_session
|
||||||
.list_all_development_certs(DeveloperDeviceType::Ios, team)
|
.list_all_development_certs(DeveloperDeviceType::Ios, team)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to list certificates: {:?}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to list certificates: {:?}", e)))?;
|
||||||
|
|
||||||
let our_public_key = self
|
let our_public_key_der = self
|
||||||
.private_key
|
.private_key
|
||||||
.public_key_to_der()
|
.to_public_key()
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to get public key: {}", e)))?;
|
.to_pkcs1_der()
|
||||||
|
.map_err(|e| Error::Certificate(format!("Failed to get public key: {}", e)))?
|
||||||
|
.to_vec();
|
||||||
|
|
||||||
for cert in certificates
|
for cert in certificates
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|c| c.machine_name == self.machine_name)
|
.filter(|c| c.machine_name == self.machine_name)
|
||||||
{
|
{
|
||||||
if let Ok(x509_cert) = X509::from_der(&cert.cert_content)
|
if let Ok(x509_cert) = X509Certificate::from_der(&cert.cert_content) {
|
||||||
&& let Ok(cert_public_key) = x509_cert.public_key()
|
let cert_public_key_der: Vec<u8> = x509_cert
|
||||||
&& let Ok(cert_public_key_der) = cert_public_key.public_key_to_der()
|
.tbs_certificate()
|
||||||
&& cert_public_key_der == our_public_key
|
.subject_public_key_info
|
||||||
{
|
.subject_public_key
|
||||||
|
.octets()
|
||||||
|
.collect();
|
||||||
|
if cert_public_key_der == our_public_key_der {
|
||||||
return Ok((x509_cert, cert.machine_id.clone()));
|
return Ok((x509_cert, cert.machine_id.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Err(Error::Certificate(
|
Err(Error::Certificate(
|
||||||
"No matching certificate found".to_string(),
|
"No matching certificate found".to_string(),
|
||||||
))
|
))
|
||||||
@@ -129,47 +138,39 @@ impl CertificateIdentity {
|
|||||||
dev_session: &DeveloperSession,
|
dev_session: &DeveloperSession,
|
||||||
team: &DeveloperTeam,
|
team: &DeveloperTeam,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut req_builder = X509ReqBuilder::new()
|
let mut params = CertificateParams::new(vec!["CN".to_string()])
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to create request builder: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to create params: {}", e)))?;
|
||||||
let mut name_builder = X509Name::builder()
|
params.distinguished_name.push(DnType::CountryName, "US");
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to create name builder: {}", e)))?;
|
params
|
||||||
|
.distinguished_name
|
||||||
|
.push(DnType::StateOrProvinceName, "STATE");
|
||||||
|
params
|
||||||
|
.distinguished_name
|
||||||
|
.push(DnType::LocalityName, "LOCAL");
|
||||||
|
params
|
||||||
|
.distinguished_name
|
||||||
|
.push(DnType::OrganizationName, "ORGNIZATION");
|
||||||
|
params.distinguished_name.push(DnType::CommonName, "CN");
|
||||||
|
|
||||||
name_builder
|
let key_pem = self
|
||||||
.append_entry_by_text("C", "US")
|
.private_key
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set country: {}", e)))?;
|
.to_pkcs8_pem(LineEnding::LF)
|
||||||
name_builder
|
.map_err(|e| Error::Certificate(format!("Failed to encode private key: {}", e)))?;
|
||||||
.append_entry_by_text("ST", "STATE")
|
let key_pair = KeyPair::from_pem(&key_pem)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set state: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to load key pair for CSR: {}", e)))?;
|
||||||
name_builder
|
|
||||||
.append_entry_by_text("L", "LOCAL")
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set locality: {}", e)))?;
|
|
||||||
name_builder
|
|
||||||
.append_entry_by_text("O", "ORGNIZATION")
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set organization: {}", e)))?;
|
|
||||||
name_builder
|
|
||||||
.append_entry_by_text("CN", "CN")
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set common name: {}", e)))?;
|
|
||||||
|
|
||||||
req_builder
|
let csr = params
|
||||||
.set_subject_name(&name_builder.build())
|
.serialize_request(&key_pair)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set subject name: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to generate CSR: {}", e)))?;
|
||||||
req_builder
|
let csr_pem = csr
|
||||||
.set_pubkey(&self.private_key)
|
.pem()
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to set public key: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to encode CSR to PEM: {}", e)))?;
|
||||||
req_builder
|
|
||||||
.sign(&self.private_key, MessageDigest::sha256())
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to sign request: {}", e)))?;
|
|
||||||
|
|
||||||
let csr_pem = req_builder
|
|
||||||
.build()
|
|
||||||
.to_pem()
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to encode CSR: {}", e)))?;
|
|
||||||
|
|
||||||
let certificate_id = dev_session
|
let certificate_id = dev_session
|
||||||
.submit_development_csr(
|
.submit_development_csr(
|
||||||
DeveloperDeviceType::Ios,
|
DeveloperDeviceType::Ios,
|
||||||
team,
|
team,
|
||||||
String::from_utf8_lossy(&csr_pem).to_string(),
|
csr_pem,
|
||||||
self.machine_name.clone(),
|
self.machine_name.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
@@ -196,13 +197,13 @@ impl CertificateIdentity {
|
|||||||
"Certificate not found after submission".to_string(),
|
"Certificate not found after submission".to_string(),
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let certificate = X509::from_der(&apple_cert.cert_content)
|
let certificate = X509Certificate::from_der(&apple_cert.cert_content)
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to parse certificate: {}", e)))?;
|
.map_err(|e| Error::Certificate(format!("Failed to parse certificate: {}", e)))?;
|
||||||
|
|
||||||
// Write certificate to disk
|
// Write certificate to disk
|
||||||
let cert_pem = certificate.to_pem().map_err(|e| {
|
let cert_pem = certificate
|
||||||
Error::Certificate(format!("Failed to encode certificate to PEM: {}", e))
|
.encode_pem()
|
||||||
})?;
|
.map_err(|e| Error::Certificate(format!("Failed to encode cert: {}", e)))?;
|
||||||
fs::write(&self.cert_file, cert_pem).map_err(Error::Filesystem)?;
|
fs::write(&self.cert_file, cert_pem).map_err(Error::Filesystem)?;
|
||||||
|
|
||||||
self.certificate = Some(certificate);
|
self.certificate = Some(certificate);
|
||||||
@@ -228,46 +229,33 @@ impl CertificateIdentity {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let num = cert
|
|
||||||
.serial_number()
|
|
||||||
.to_bn()
|
|
||||||
.map_err(|e| {
|
|
||||||
Error::Certificate(format!("Failed to convert serial number to bn: {}", e))
|
|
||||||
})?
|
|
||||||
.to_hex_str()
|
|
||||||
.map_err(|e| {
|
|
||||||
Error::Certificate(format!(
|
|
||||||
"Failed to convert serial number to hex string: {}",
|
|
||||||
e
|
|
||||||
))
|
|
||||||
})?
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
Ok(num.trim_start_matches("0").to_string())
|
let serial = &cert.tbs_certificate().serial_number;
|
||||||
|
let hex_str = hex::encode(serial.as_slice());
|
||||||
|
|
||||||
|
Ok(hex_str.trim_start_matches("0").to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_pkcs12(&self, password: &str) -> Result<Vec<u8>, Error> {
|
pub fn to_pkcs12(&self, password: &str) -> Result<Vec<u8>, Error> {
|
||||||
let cert = match &self.certificate {
|
let output = Command::new("openssl")
|
||||||
Some(c) => c,
|
.arg("pkcs12")
|
||||||
None => {
|
.arg("-export")
|
||||||
return Err(Error::Certificate(
|
.arg("-inkey")
|
||||||
"No certificate available to create PKCS#12".to_string(),
|
.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)))?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(Error::Certificate(format!(
|
||||||
|
"openssl failed: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let mut pkcs12_builder = Pkcs12::builder();
|
Ok(output.stdout)
|
||||||
pkcs12_builder.pkey(&self.private_key);
|
|
||||||
pkcs12_builder.cert(cert);
|
|
||||||
pkcs12_builder.name("certificate");
|
|
||||||
let pkcs12 = pkcs12_builder
|
|
||||||
.build2(password)
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to create PKCS#12 bundle: {}", e)))?;
|
|
||||||
|
|
||||||
let der_bytes = pkcs12
|
|
||||||
.to_der()
|
|
||||||
.map_err(|e| Error::Certificate(format!("Failed to encode PKCS#12 to DER: {}", e)))?;
|
|
||||||
|
|
||||||
Ok(der_bytes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ pub mod sideload;
|
|||||||
|
|
||||||
use std::io::Error as IOError;
|
use std::io::Error as IOError;
|
||||||
|
|
||||||
|
use apple_codesign::AppleCodesignError;
|
||||||
pub use icloud_auth::{AnisetteConfiguration, AppleAccount};
|
pub use icloud_auth::{AnisetteConfiguration, AppleAccount};
|
||||||
|
|
||||||
use developer_session::DeveloperTeam;
|
use developer_session::DeveloperTeam;
|
||||||
use idevice::IdeviceError;
|
use idevice::IdeviceError;
|
||||||
use thiserror::Error as ThisError;
|
use thiserror::Error as ThisError;
|
||||||
use zsign_rust::ZSignError;
|
|
||||||
|
|
||||||
#[derive(Debug, ThisError)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@@ -33,7 +33,7 @@ pub enum Error {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
IdeviceError(#[from] IdeviceError),
|
IdeviceError(#[from] IdeviceError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ZSignError(#[from] ZSignError),
|
AppleCodesignError(#[from] Box<AppleCodesignError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SideloadLogger: Send + Sync {
|
pub trait SideloadLogger: Send + Sync {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
// This file was made using https://github.com/Dadoum/Sideloader as a reference.
|
||||||
|
|
||||||
|
use apple_codesign::{BundleSigner, SigningSettings};
|
||||||
|
use der::Encode;
|
||||||
use idevice::IdeviceService;
|
use idevice::IdeviceService;
|
||||||
use idevice::lockdown::LockdownClient;
|
use idevice::lockdown::LockdownClient;
|
||||||
use idevice::provider::IdeviceProvider;
|
use idevice::provider::IdeviceProvider;
|
||||||
use zsign_rust::ZSignOptions;
|
|
||||||
|
|
||||||
use crate::application::Application;
|
use crate::application::Application;
|
||||||
use crate::device::install_app;
|
use crate::device::install_app;
|
||||||
@@ -385,18 +386,32 @@ pub async fn sideload_app(
|
|||||||
ext.write_info()?;
|
ext.write_info()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match ZSignOptions::new(app.bundle.bundle_dir.to_str().unwrap())
|
// match ZSignOptions::new(app.bundle.bundle_dir.to_str().unwrap())
|
||||||
.with_cert_file(cert.get_certificate_file_path().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_pkey_file(cert.get_private_key_file_path().to_str().unwrap())
|
||||||
.with_prov_file(profile_path.to_str().unwrap())
|
// .with_prov_file(profile_path.to_str().unwrap())
|
||||||
.sign()
|
// .sign()
|
||||||
{
|
// {
|
||||||
Ok(_) => {}
|
// Ok(_) => {}
|
||||||
Err(e) => {
|
// Err(e) => {
|
||||||
return error_and_return(logger, Error::ZSignError(e));
|
// return error_and_return(logger, Error::ZSignError(e));
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
let mut signer = BundleSigner::new_from_path(&app.bundle.bundle_dir)
|
||||||
|
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||||
|
|
||||||
|
signer
|
||||||
|
.collect_nested_bundles()
|
||||||
|
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||||
|
|
||||||
|
let mut settings = SigningSettings::default();
|
||||||
|
|
||||||
|
settings.set_signing_key(cert.private_key.clone(), cert.certificate.unwrap());
|
||||||
|
|
||||||
|
signer
|
||||||
|
.write_signed_bundle(&app.bundle.bundle_dir, &settings)
|
||||||
|
.map_err(|e| Error::AppleCodesignError(Box::new(e)))?;
|
||||||
logger.log("App signed!");
|
logger.log("App signed!");
|
||||||
|
|
||||||
logger.log("Installing app (Transfer)... 0%");
|
logger.log("Installing app (Transfer)... 0%");
|
||||||
|
|||||||
Reference in New Issue
Block a user