mirror of
https://github.com/nab138/isideload.git
synced 2026-03-02 06:26:16 +01:00
176 lines
5.0 KiB
Rust
176 lines
5.0 KiB
Rust
use plist::Dictionary;
|
|
use plist_macro::{plist, plist_to_xml_string};
|
|
use rootcause::prelude::*;
|
|
use serde::de::DeserializeOwned;
|
|
use tracing::warn;
|
|
use uuid::Uuid;
|
|
|
|
use crate::{
|
|
anisette::AnisetteData,
|
|
auth::{
|
|
apple_account::{AppToken, AppleAccount},
|
|
grandslam::GrandSlam,
|
|
},
|
|
dev::structures::{
|
|
DeveloperDevice,
|
|
DeveloperDeviceType::{self, *},
|
|
DeveloperTeam, DevelopmentCertificate, ListCertificatesResponse, ListDevicesResponse,
|
|
ListTeamsResponse,
|
|
},
|
|
util::plist::PlistDataExtract,
|
|
};
|
|
|
|
pub struct DeveloperSession<'a> {
|
|
token: AppToken,
|
|
adsid: String,
|
|
client: &'a GrandSlam,
|
|
anisette_data: &'a AnisetteData,
|
|
}
|
|
|
|
impl<'a> DeveloperSession<'a> {
|
|
pub fn new(
|
|
token: AppToken,
|
|
adsid: String,
|
|
client: &'a GrandSlam,
|
|
anisette_data: &'a AnisetteData,
|
|
) -> Self {
|
|
DeveloperSession {
|
|
token,
|
|
adsid,
|
|
client,
|
|
anisette_data,
|
|
}
|
|
}
|
|
|
|
pub async fn from_account(account: &'a mut AppleAccount) -> Result<Self, Report> {
|
|
let token = account
|
|
.get_app_token("xcode.auth")
|
|
.await
|
|
.context("Failed to get xcode token from Apple account")?;
|
|
|
|
let spd = account
|
|
.spd
|
|
.as_ref()
|
|
.ok_or_else(|| report!("SPD not available, cannot get adsid"))?;
|
|
|
|
Ok(DeveloperSession::new(
|
|
token,
|
|
spd.get_string("adsid")?,
|
|
&account.grandslam_client,
|
|
&account.anisette_data,
|
|
))
|
|
}
|
|
|
|
pub async fn send_developer_request<T: DeserializeOwned>(
|
|
&self,
|
|
url: &str,
|
|
body: impl Into<Option<Dictionary>>,
|
|
) -> Result<T, Report> {
|
|
let body = body.into().unwrap_or_else(|| Dictionary::new());
|
|
|
|
let base = plist!(dict {
|
|
"clientId": "XABBG36SBA",
|
|
"protocolVersion": "QH65B2",
|
|
"requestId": Uuid::new_v4().to_string().to_uppercase(),
|
|
"userLocale": ["en_US"],
|
|
});
|
|
|
|
let body = base.into_iter().chain(body.into_iter()).collect();
|
|
|
|
let text = self
|
|
.client
|
|
.post(url)?
|
|
.body(plist_to_xml_string(&body))
|
|
.header("X-Apple-GS-Token", &self.token.token)
|
|
.header("X-Apple-I-Identity-Id", &self.adsid)
|
|
.headers(self.anisette_data.get_header_map())
|
|
.send()
|
|
.await?
|
|
.error_for_status()
|
|
.context("Developer request failed")?
|
|
.text()
|
|
.await
|
|
.context("Failed to read developer request response text")?;
|
|
|
|
let dict: T = plist::from_bytes(text.as_bytes())
|
|
.context("Failed to parse developer request plist")?;
|
|
|
|
Ok(dict)
|
|
}
|
|
|
|
pub async fn list_teams(&self) -> Result<Vec<DeveloperTeam>, Report> {
|
|
let response: ListTeamsResponse = self
|
|
.send_developer_request(&dev_url("listTeams", Any), None)
|
|
.await
|
|
.context("Failed to list developer teams")?;
|
|
|
|
if response.result_code != 0 {
|
|
warn!(
|
|
"Non-zero list teams response code: {}",
|
|
response.result_code
|
|
)
|
|
};
|
|
|
|
Ok(response.teams)
|
|
}
|
|
|
|
pub async fn list_devices(
|
|
&self,
|
|
team: &DeveloperTeam,
|
|
device_type: impl Into<Option<DeveloperDeviceType>>,
|
|
) -> Result<Vec<DeveloperDevice>, Report> {
|
|
let body = plist!(dict {
|
|
"teamId": &team.team_id,
|
|
});
|
|
|
|
let response: ListDevicesResponse = self
|
|
.send_developer_request(&dev_url("listDevices", device_type), body)
|
|
.await
|
|
.context("Failed to list developer devices")?;
|
|
|
|
if response.result_code != 0 {
|
|
warn!(
|
|
"Non-zero list devices response code: {}",
|
|
response.result_code
|
|
)
|
|
};
|
|
|
|
Ok(response.devices)
|
|
}
|
|
|
|
pub async fn list_all_development_certs(
|
|
&self,
|
|
team: &DeveloperTeam,
|
|
device_type: impl Into<Option<DeveloperDeviceType>>,
|
|
) -> Result<Vec<DevelopmentCertificate>, Report> {
|
|
let body = plist!(dict {
|
|
"teamId": &team.team_id,
|
|
});
|
|
|
|
let response: ListCertificatesResponse = self
|
|
.send_developer_request(&dev_url("listAllDevelopmentCerts", device_type), body)
|
|
.await
|
|
.context("Failed to list development certificates")?;
|
|
|
|
if response.result_code != 0 {
|
|
warn!(
|
|
"Non-zero list development certs response code: {}",
|
|
response.result_code
|
|
)
|
|
};
|
|
|
|
Ok(response.certificates)
|
|
}
|
|
}
|
|
|
|
fn dev_url(endpoint: &str, device_type: impl Into<Option<DeveloperDeviceType>>) -> String {
|
|
format!(
|
|
"https://developerservices2.apple.com/services/QH65B2/{}{}.action?clientId=XABBG36SBA",
|
|
device_type
|
|
.into()
|
|
.unwrap_or(DeveloperDeviceType::Ios)
|
|
.url_segment(),
|
|
endpoint,
|
|
)
|
|
}
|