Retrieve certificates

This commit is contained in:
nab138
2026-02-08 22:43:33 -05:00
parent 0509f00257
commit ec9af89d74
10 changed files with 373 additions and 83 deletions

219
Cargo.lock generated
View File

@@ -26,7 +26,7 @@ checksum = "04097e08a47d9ad181c2e1f4a5fabc9ae06ce8839a333ba9a949bcb0d31fd2a3"
dependencies = [
"cipher",
"cpubits",
"cpufeatures",
"cpufeatures 0.2.17",
]
[[package]]
@@ -43,6 +43,15 @@ dependencies = [
"subtle",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.100"
@@ -164,6 +173,16 @@ version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "bcder"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f7c42c9913f68cf9390a225e81ad56a5c515347287eb98baa710090ca1de86d"
dependencies = [
"bytes",
"smallvec",
]
[[package]]
name = "bitflags"
version = "2.10.0"
@@ -254,6 +273,28 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chacha20"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
"rand_core 0.10.0",
]
[[package]]
name = "chrono"
version = "0.4.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
dependencies = [
"iana-time-zone",
"num-traits",
"windows-link",
]
[[package]]
name = "cipher"
version = "0.5.0"
@@ -307,6 +348,12 @@ version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d"
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-oid"
version = "0.10.2"
@@ -354,6 +401,15 @@ dependencies = [
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
@@ -455,13 +511,23 @@ dependencies = [
"zeroize",
]
[[package]]
name = "der"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
"const-oid 0.9.6",
"zeroize",
]
[[package]]
name = "der"
version = "0.8.0-rc.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02c1d73e9668ea6b6a28172aa55f3ebec38507131ce179051c8033b5c6037653"
dependencies = [
"const-oid",
"const-oid 0.10.2",
"pem-rfc7468",
"zeroize",
]
@@ -506,7 +572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b42f1d9edf5207c137646b568a0168ca0ec25b7f9eaf7f9961da51a3d91cea"
dependencies = [
"block-buffer 0.11.0",
"const-oid",
"const-oid 0.10.2",
"crypto-common 0.2.0",
"subtle",
]
@@ -901,6 +967,30 @@ dependencies = [
"windows-registry",
]
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "icu_collections"
version = "2.1.1"
@@ -1082,7 +1172,7 @@ dependencies = [
"pbkdf2",
"plist",
"plist-macro",
"rand",
"rand 0.10.0",
"rcgen",
"reqwest",
"rootcause",
@@ -1096,7 +1186,7 @@ dependencies = [
"tokio-tungstenite",
"tracing",
"uuid",
"x509-parser",
"x509-certificate",
]
[[package]]
@@ -1403,8 +1493,8 @@ version = "0.8.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e"
dependencies = [
"der",
"spki",
"der 0.8.0-rc.10",
"spki 0.8.0-rc.4",
]
[[package]]
@@ -1413,8 +1503,8 @@ version = "0.11.0-rc.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b226d2cc389763951db8869584fd800cbbe2962bf454e2edeb5172b31ee99774"
dependencies = [
"der",
"spki",
"der 0.8.0-rc.10",
"spki 0.8.0-rc.4",
]
[[package]]
@@ -1451,7 +1541,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63641a86fddf4b5274f31c43734458ec7acd3133016dbaa37e4e247e1e9acd46"
dependencies = [
"cpubits",
"cpufeatures",
"cpufeatures 0.2.17",
"universal-hash",
]
@@ -1537,7 +1627,7 @@ dependencies = [
"bytes",
"getrandom 0.3.4",
"lru-slab",
"rand",
"rand 0.9.2",
"ring",
"rustc-hash",
"rustls",
@@ -1588,6 +1678,17 @@ dependencies = [
"rand_core 0.9.5",
]
[[package]]
name = "rand"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
dependencies = [
"chacha20",
"getrandom 0.4.1",
"rand_core 0.10.0",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
@@ -1598,6 +1699,15 @@ dependencies = [
"rand_core 0.9.5",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "rand_core"
version = "0.9.5"
@@ -1709,15 +1819,15 @@ version = "0.10.0-rc.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b342b99544549f37509ed7fd42b0cea04bfd9ce07c16ca56094cf0fbeefbbcd"
dependencies = [
"const-oid",
"const-oid 0.10.2",
"crypto-bigint",
"crypto-primes",
"digest 0.11.0-rc.11",
"pkcs1",
"pkcs8",
"rand_core 0.10.0",
"signature",
"spki",
"signature 3.0.0-rc.10",
"spki 0.8.0-rc.4",
"zeroize",
]
@@ -1935,7 +2045,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"cpufeatures 0.2.17",
"digest 0.10.7",
]
@@ -1946,7 +2056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024"
dependencies = [
"cfg-if",
"cpufeatures",
"cpufeatures 0.2.17",
"digest 0.11.0-rc.11",
]
@@ -1965,6 +2075,15 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"rand_core 0.6.4",
]
[[package]]
name = "signature"
version = "3.0.0-rc.10"
@@ -2003,6 +2122,16 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der 0.7.10",
]
[[package]]
name = "spki"
version = "0.8.0-rc.4"
@@ -2010,7 +2139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8baeff88f34ed0691978ec34440140e1572b68c7dd4a495fd14a3dc1944daa80"
dependencies = [
"base64ct",
"der",
"der 0.8.0-rc.10",
]
[[package]]
@@ -2389,7 +2518,7 @@ dependencies = [
"http",
"httparse",
"log",
"rand",
"rand 0.9.2",
"rustls",
"rustls-pki-types",
"sha1",
@@ -2676,6 +2805,41 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.2.1"
@@ -3036,6 +3200,25 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[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.18",
"zeroize",
]
[[package]]
name = "x509-parser"
version = "0.18.1"

View File

@@ -6,6 +6,12 @@ A Rust library for sideloading iOS applications using an Apple ID. Used in [Cros
This branch is home to isideload-next, the next major version of isideload. It features a redesigned API, improved error handling, better entitlement handling, and more. It is not ready!
## TODO
- [ ] Signing apps
- [ ] Installing apps
- [ ] Remove dependency on ring
## Licensing
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.

View File

@@ -10,4 +10,4 @@ plist-macro = "0.1.3"
tokio = { version = "1.49.0", features = ["rt-multi-thread", "macros"] }
tracing = "0.1.44"
tracing-subscriber = "0.3.22"
idevice = { version = "0.1.52", features = ["usbmuxd"]}
idevice = { version = "0.1.52", features = ["usbmuxd"] }

View File

@@ -42,10 +42,10 @@ async fn main() {
.login(apple_password, get_2fa_code)
.await;
match &account {
Ok(a) => println!("Logged in. {}", a),
Err(e) => panic!("Failed to log in to Apple ID: {:?}", e),
}
// match &account {
// Ok(a) => println!("Logged in. {}", a),
// Err(e) => panic!("Failed to log in to Apple ID: {:?}", e),
// }
let mut account = account.unwrap();
@@ -70,7 +70,7 @@ async fn main() {
.unwrap()
.to_provider(UsbmuxdAddr::from_env_var().unwrap(), "isideload-demo");
let mut sideloader = SideloaderBuilder::new(dev_session)
let mut sideloader = SideloaderBuilder::new(dev_session, apple_id.to_string())
.team_selection(TeamSelection::Prompt(|teams| {
println!("Please select a team:");
for (index, team) in teams.iter().enumerate() {

View File

@@ -23,7 +23,7 @@ reqwest = { version = "0.13.1", features = ["json", "gzip"] }
thiserror = "2.0.17"
async-trait = "0.1.89"
serde = "1.0.228"
rand = "0.9.2"
rand = "0.10.0"
uuid = {version = "1.20.0", features = ["v4"] }
tracing = "0.1.44"
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots"] }
@@ -42,5 +42,5 @@ aes-gcm = "0.11.0-rc.3"
rsa = { version = "0.10.0-rc.15" }
tokio = "1.49.0"
keyring = { version = "3.6.3", features = ["apple-native", "linux-native-sync-persistent", "windows-native"], optional = true }
x509-parser = "0.18.1"
x509-certificate = "0.25"
rcgen = { version = "0.14.7", default-features = false, features = ["aws_lc_rs", "pem"] }

View File

@@ -1,7 +1,7 @@
// Serialization/Desieralization borrowed from https://github.com/SideStore/apple-private-apis/blob/master/omnisette/src/remote_anisette_v3.rs
use plist::Data;
use rand::Rng;
use rand::RngExt;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use sha2::{Digest, Sha256};
use uuid::Uuid;

View File

@@ -26,32 +26,58 @@ impl Display for TeamSelection {
}
}
pub enum MaxCertsBehavior {
/// If the maximum number of certificates is reached, delete all existing certificates and create a new one
Revoke,
/// If the maximum number of certificates is reached, return an error instead of creating a new certificate
Error,
}
pub struct SideloaderBuilder {
team_selection: TeamSelection,
storage: Box<dyn SideloadingStorage>,
developer_session: DeveloperSession,
apple_email: String,
team_selection: Option<TeamSelection>,
max_certs_behavior: Option<MaxCertsBehavior>,
storage: Option<Box<dyn SideloadingStorage>>,
machine_name: Option<String>,
}
impl SideloaderBuilder {
pub fn new(developer_session: DeveloperSession) -> Self {
pub fn new(developer_session: DeveloperSession, apple_email: String) -> Self {
SideloaderBuilder {
team_selection: TeamSelection::First,
storage: Box::new(crate::util::storage::new_storage()),
team_selection: None,
storage: None,
developer_session,
machine_name: None,
apple_email,
max_certs_behavior: None,
}
}
pub fn team_selection(mut self, selection: TeamSelection) -> Self {
self.team_selection = selection;
self.team_selection = Some(selection);
self
}
pub fn storage(mut self, storage: Box<dyn SideloadingStorage>) -> Self {
self.storage = storage;
self.storage = Some(storage);
self
}
pub fn machine_name(mut self, machine_name: String) -> Self {
self.machine_name = Some(machine_name);
self
}
pub fn build(self) -> Sideloader {
Sideloader::new(self.team_selection, self.storage, self.developer_session)
Sideloader::new(
self.developer_session,
self.apple_email,
self.team_selection.unwrap_or(TeamSelection::First),
self.max_certs_behavior.unwrap_or(MaxCertsBehavior::Revoke),
self.machine_name.unwrap_or_else(|| "isideload".to_string()),
self.storage
.unwrap_or_else(|| Box::new(crate::util::storage::new_storage())),
)
}
}

View File

@@ -1,22 +1,27 @@
use rcgen::{CertificateParams, DistinguishedName, DnType, PKCS_RSA_SHA256};
use rcgen::{CertificateParams, DistinguishedName, DnType, KeyPair, PKCS_RSA_SHA256};
use rootcause::prelude::*;
use rsa::{
RsaPrivateKey,
pkcs8::{DecodePrivateKey, EncodePublicKey},
pkcs1::EncodeRsaPublicKey,
pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding},
};
use sha2::{Digest, Sha256};
use tracing::{error, info};
use x509_certificate::X509Certificate;
use crate::{
dev::{
certificates::CertificatesApi, developer_session::DeveloperSession, teams::DeveloperTeam,
},
sideload::builder::MaxCertsBehavior,
util::storage::SideloadingStorage,
};
pub struct CertificateIdentity {
pub machine_id: String,
pub machine_name: String,
pub certificate: X509Certificate,
}
impl CertificateIdentity {
@@ -26,70 +31,82 @@ impl CertificateIdentity {
developer_session: &mut DeveloperSession,
team: &DeveloperTeam,
storage: &dyn SideloadingStorage,
max_certs_behavior: &MaxCertsBehavior,
) -> Result<Self, Report> {
let stored = Self::retrieve_from_storage(
machine_name,
apple_email,
developer_session,
team,
storage,
)
.await;
if let Ok(Some(cert)) = stored {
let pr = Self::retrieve_private_key(apple_email, storage).await?;
let found = Self::find_matching(&pr, machine_name, developer_session, team).await;
if let Ok(Some(cert)) = found {
info!("Found matching certificate");
return Ok(cert);
}
if let Err(e) = stored {
error!("Failed to load stored certificate: {:?}", e);
} else {
info!("No stored certificate found");
if let Err(e) = found {
error!("Failed to check for matching certificate: {:?}", e);
}
todo!("generate CSR")
info!("Requesting new certificate");
Self::request_certificate(
&pr,
machine_name.to_string(),
developer_session,
team,
max_certs_behavior,
)
.await
}
async fn retrieve_from_storage(
machine_name: &str,
async fn retrieve_private_key(
apple_email: &str,
developer_session: &mut DeveloperSession,
team: &DeveloperTeam,
storage: &dyn SideloadingStorage,
) -> Result<Option<Self>, Report> {
) -> Result<RsaPrivateKey, Report> {
let mut hasher = Sha256::new();
hasher.update(apple_email.as_bytes());
let email_hash = hex::encode(hasher.finalize());
let private_key = storage.retrieve(&format!("{}/key", email_hash))?;
if private_key.is_none() {
return Ok(None);
if private_key.is_some() {
return Ok(RsaPrivateKey::from_pkcs8_pem(&private_key.unwrap())?);
}
let private_key = RsaPrivateKey::from_pkcs8_pem(&private_key.unwrap())?;
let public_key_der = private_key.to_public_key().to_public_key_der()?;
let mut rng = rand::rng();
let private_key = RsaPrivateKey::new(&mut rng, 2048)?;
storage.store(
&format!("{}/key", email_hash),
&private_key.to_pkcs8_pem(Default::default())?.to_string(),
)?;
Ok(private_key)
}
async fn find_matching(
private_key: &RsaPrivateKey,
machine_name: &str,
developer_session: &mut DeveloperSession,
team: &DeveloperTeam,
) -> Result<Option<Self>, Report> {
let public_key_der = private_key
.to_public_key()
.to_pkcs1_der()?
.as_bytes()
.to_vec();
for cert in developer_session
.list_ios_certs(team)
.await?
.iter()
.filter(|c| {
c.cert_content.is_some() && c.machine_name.as_deref().unwrap_or("") == machine_name
c.cert_content.is_some()
&& c.machine_name.as_deref().unwrap_or("") == machine_name
&& c.machine_id.is_some()
})
{
let x509_cert =
x509_parser::parse_x509_certificate(cert.cert_content.as_ref().unwrap().as_ref())?;
if x509_cert
.1
.tbs_certificate
.subject_pki
.subject_public_key
.data
== public_key_der.as_ref()
{
X509Certificate::from_der(cert.cert_content.as_ref().unwrap().as_ref())?;
if public_key_der == x509_cert.public_key_data().as_ref() {
return Ok(Some(Self {
machine_id: cert
.machine_id
.clone()
.unwrap_or_else(|| x509_cert.1.tbs_certificate.subject.to_string()),
machine_name: machine_name.to_string(),
machine_id: cert.machine_id.clone().unwrap_or_default(),
machine_name: cert.machine_name.clone().unwrap_or_default(),
certificate: x509_cert,
}));
}
}
@@ -98,16 +115,46 @@ impl CertificateIdentity {
}
async fn request_certificate(
machine_name: &str,
private_key: &RsaPrivateKey,
machine_name: String,
developer_session: &mut DeveloperSession,
team: &DeveloperTeam,
max_certs_behavior: &MaxCertsBehavior,
) -> Result<Self, Report> {
Ok(())
let csr = Self::build_csr(private_key).context("Failed to generate CSR")?;
let request = developer_session
.submit_development_csr(team, csr, machine_name, None)
.await?;
// TODO: Handle max certs behavior properly instead of just always revoking
let apple_certs = developer_session.list_ios_certs(team).await?;
let apple_cert = apple_certs
.iter()
.find(|c| c.certificate_id == Some(request.cert_request_id.clone()))
.ok_or_else(|| report!("Failed to find certificate after submitting CSR"))?;
let x509_cert = X509Certificate::from_der(
apple_cert
.cert_content
.as_ref()
.ok_or_else(|| report!("Certificate content missing"))?
.as_ref(),
)?;
Ok(Self {
machine_id: apple_cert.machine_id.clone().unwrap_or_default(),
machine_name: apple_cert.machine_name.clone().unwrap_or_default(),
certificate: x509_cert,
})
}
fn build_csr(private_key: &RsaPrivateKey) -> Result<String, Report> {
let mut params = CertificateParams::new(vec![])?;
let mut dn = DistinguishedName::new();
dn.push(DnType::CountryName, "US");
dn.push(DnType::StateOrProvinceName, "STATE");
dn.push(DnType::LocalityName, "LOCAL");
@@ -115,6 +162,11 @@ impl CertificateIdentity {
dn.push(DnType::CommonName, "CN");
params.distinguished_name = dn;
Ok(())
let subject_key = KeyPair::from_pkcs8_pem_and_sign_algo(
&private_key.to_pkcs8_pem(LineEnding::LF)?,
&PKCS_RSA_SHA256,
)?;
Ok(params.serialize_request(&subject_key)?.pem()?)
}
}

View File

@@ -4,7 +4,7 @@ use crate::{
devices::DevicesApi,
teams::{DeveloperTeam, TeamsApi},
},
sideload::TeamSelection,
sideload::{TeamSelection, builder::MaxCertsBehavior, certificate::CertificateIdentity},
util::{device::IdeviceInfo, storage::SideloadingStorage},
};
@@ -18,18 +18,27 @@ pub struct Sideloader {
team_selection: TeamSelection,
storage: Box<dyn SideloadingStorage>,
dev_session: DeveloperSession,
machine_name: String,
apple_email: String,
max_certs_behavior: MaxCertsBehavior,
}
impl Sideloader {
pub fn new(
team_selection: TeamSelection,
storage: Box<dyn SideloadingStorage>,
dev_session: DeveloperSession,
apple_email: String,
team_selection: TeamSelection,
max_certs_behavior: MaxCertsBehavior,
machine_name: String,
storage: Box<dyn SideloadingStorage>,
) -> Self {
Sideloader {
team_selection,
storage,
dev_session,
machine_name,
apple_email,
max_certs_behavior,
}
}
@@ -46,6 +55,21 @@ impl Sideloader {
.ensure_device_registered(&team, &device_info.name, &device_info.udid, None)
.await?;
let cert_identity = CertificateIdentity::retrieve(
&self.machine_name,
&self.apple_email,
&mut self.dev_session,
&team,
self.storage.as_ref(),
&self.max_certs_behavior,
)
.await?;
// info!(
// "Using certificate for machine {} with ID {}",
// cert_identity.machine_name, cert_identity.machine_id
// );
Ok(())
}

View File

@@ -1,6 +1,5 @@
use std::{collections::HashMap, sync::Mutex};
use base64::prelude::*;
use rootcause::prelude::*;
pub trait SideloadingStorage: Send + Sync {