Add list devices and refactor

This commit is contained in:
nab138
2026-01-28 22:33:51 -05:00
parent 82881aa4e1
commit f01fcc0ac0
9 changed files with 117 additions and 71 deletions

3
Cargo.lock generated
View File

@@ -1071,8 +1071,7 @@ dependencies = [
[[package]] [[package]]
name = "plist-macro" name = "plist-macro"
version = "0.1.3" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/nab138/plist_macro?branch=master#7004b1625aa50044bd381ee5393a9c85cec039d5"
checksum = "8888e02e251eba3258cc58fb79f0d8675c34b3428749e738562d58a0271bf035"
dependencies = [ dependencies = [
"plist", "plist",
] ]

View File

@@ -4,4 +4,5 @@ members = ["examples/minimal","isideload"]
default-members = ["isideload"] default-members = ["isideload"]
[patch.crates-io] [patch.crates-io]
rustls-platform-verifier = { git = "https://github.com/cstkingkey/rustls-platform-verifier", branch = "extra" } rustls-platform-verifier = { git = "https://github.com/cstkingkey/rustls-platform-verifier", branch = "extra" }
plist-macro = { git = "https://github.com/nab138/plist_macro", branch = "master" }

View File

@@ -50,10 +50,19 @@ async fn main() {
.await .await
.expect("Failed to create developer session"); .expect("Failed to create developer session");
let res = dev_session let teams = dev_session
.list_teams() .list_teams()
.await .await
.expect("Failed to list teams"); .expect("Failed to list teams");
let team = teams
.get(0)
.expect("No developer teams available for this account");
let res = dev_session
.list_devices(team, None)
.await
.expect("Failed to list developer devices");
println!("{:#?}", res); println!("{:#?}", res);
} }

View File

@@ -1,4 +1,5 @@
use plist::Dictionary; use plist::Dictionary;
use plist_macro::plist_to_xml_string;
use plist_macro::pretty_print_dictionary; use plist_macro::pretty_print_dictionary;
use reqwest::{ use reqwest::{
Certificate, ClientBuilder, Certificate, ClientBuilder,
@@ -7,11 +8,7 @@ use reqwest::{
use rootcause::prelude::*; use rootcause::prelude::*;
use tracing::debug; use tracing::debug;
use crate::{ use crate::{SideloadError, anisette::AnisetteClientInfo, util::plist::PlistDataExtract};
SideloadError,
anisette::AnisetteClientInfo,
util::plist::{PlistDataExtract, plist_to_xml_string},
};
const APPLE_ROOT: &[u8] = include_bytes!("./apple_root.der"); const APPLE_ROOT: &[u8] = include_bytes!("./apple_root.der");
const URL_BAG: &str = "https://gsa.apple.com/grandslam/GsService2/lookup"; const URL_BAG: &str = "https://gsa.apple.com/grandslam/GsService2/lookup";

View File

@@ -1,7 +1,8 @@
use plist::Dictionary; use plist::Dictionary;
use plist_macro::plist; use plist_macro::{plist, plist_to_xml_string};
use rootcause::prelude::*; use rootcause::prelude::*;
use tracing::debug; use serde::de::DeserializeOwned;
use tracing::warn;
use uuid::Uuid; use uuid::Uuid;
use crate::{ use crate::{
@@ -10,11 +11,12 @@ use crate::{
apple_account::{AppToken, AppleAccount}, apple_account::{AppToken, AppleAccount},
grandslam::GrandSlam, grandslam::GrandSlam,
}, },
dev::{ dev::structures::{
device_type::DeveloperDeviceType, DeveloperDevice,
structures::{DeveloperTeam, ListTeamResponse}, DeveloperDeviceType::{self, *},
DeveloperTeam, ListDevicesResponse, ListTeamsResponse,
}, },
util::plist::{PlistDataExtract, plist_to_xml_string}, util::plist::PlistDataExtract,
}; };
pub struct DeveloperSession<'a> { pub struct DeveloperSession<'a> {
@@ -58,12 +60,12 @@ impl<'a> DeveloperSession<'a> {
)) ))
} }
pub async fn send_developer_request( pub async fn send_developer_request<T: DeserializeOwned>(
&self, &self,
url: &str, url: &str,
body: Option<Dictionary>, body: impl Into<Option<Dictionary>>,
) -> Result<String, Report> { ) -> Result<T, Report> {
let body = body.unwrap_or_else(|| Dictionary::new()); let body = body.into().unwrap_or_else(|| Dictionary::new());
let base = plist!(dict { let base = plist!(dict {
"clientId": "XABBG36SBA", "clientId": "XABBG36SBA",
@@ -89,22 +91,60 @@ impl<'a> DeveloperSession<'a> {
.await .await
.context("Failed to read developer request response text")?; .context("Failed to read developer request response text")?;
// let dict: Dictionary = plist::from_bytes(text.as_bytes()) let dict: T = plist::from_bytes(text.as_bytes())
// .context("Failed to parse developer request plist")?; .context("Failed to parse developer request plist")?;
Ok(text) Ok(dict)
} }
pub async fn list_teams(&self) -> Result<Vec<DeveloperTeam>, Report> { pub async fn list_teams(&self) -> Result<Vec<DeveloperTeam>, Report> {
let res = self let response: ListTeamsResponse = self
.send_developer_request(&DeveloperDeviceType::Any.dev_url("listTeams"), None) .send_developer_request(&dev_url("listTeams", Any), None)
.await?; .await
.context("Failed to list developer teams")?;
let response: ListTeamResponse = plist::from_bytes(res.as_bytes()) if response.result_code != 0 {
.context("Failed to parse list teams response plist")?; warn!(
"Non-zero list teams response code: {}",
debug!("List Teams Response Code: {:?}", response.result_code); response.result_code
)
};
Ok(response.teams) 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)
}
}
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,
)
} }

View File

@@ -1,26 +0,0 @@
#[derive(Debug, Clone)]
pub enum DeveloperDeviceType {
Any,
Ios,
Tvos,
Watchos,
}
impl DeveloperDeviceType {
pub fn url_segment(&self) -> &'static str {
match self {
DeveloperDeviceType::Any => "",
DeveloperDeviceType::Ios => "ios/",
DeveloperDeviceType::Tvos => "tvos/",
DeveloperDeviceType::Watchos => "watchos/",
}
}
pub fn dev_url(&self, endpoint: &str) -> String {
format!(
"https://developerservices2.apple.com/services/QH65B2/{}{}.action?clientId=XABBG36SBA",
self.url_segment(),
endpoint,
)
}
}

View File

@@ -1,3 +1,2 @@
pub mod developer_session; pub mod developer_session;
pub mod device_type; pub mod structures;
pub mod structures;

View File

@@ -1,17 +1,52 @@
use serde::Deserialize; use serde::Deserialize;
#[derive(Debug, Clone)]
pub enum DeveloperDeviceType {
Any,
Ios,
Tvos,
Watchos,
}
impl DeveloperDeviceType {
pub fn url_segment(&self) -> &'static str {
match self {
DeveloperDeviceType::Any => "",
DeveloperDeviceType::Ios => "ios/",
DeveloperDeviceType::Tvos => "tvos/",
DeveloperDeviceType::Watchos => "watchos/",
}
}
}
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct DeveloperTeam { pub struct DeveloperTeam {
name: String, pub name: Option<String>,
team_id: String, pub team_id: String,
r#type: String, pub r#type: Option<String>,
status: String, pub status: Option<String>,
} }
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ListTeamResponse { pub struct ListTeamsResponse {
pub teams: Vec<DeveloperTeam>, pub teams: Vec<DeveloperTeam>,
pub result_code: i64, pub result_code: i64,
} }
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct DeveloperDevice {
pub name: String,
pub device_id: String,
pub device_number: String,
pub status: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ListDevicesResponse {
pub devices: Vec<DeveloperDevice>,
pub result_code: i64,
}

View File

@@ -1,15 +1,7 @@
use plist::Dictionary; use plist::Dictionary;
use plist_macro::{plist_to_xml_bytes, plist_value_to_xml_bytes, pretty_print_dictionary}; use plist_macro::pretty_print_dictionary;
use rootcause::prelude::*; use rootcause::prelude::*;
pub fn plist_to_xml_string(p: &Dictionary) -> String {
String::from_utf8(plist_to_xml_bytes(p)).unwrap()
}
pub fn plist_value_to_xml_string(p: &plist::Value) -> String {
String::from_utf8(plist_value_to_xml_bytes(p)).unwrap()
}
pub struct SensitivePlistAttachment { pub struct SensitivePlistAttachment {
pub plist: Dictionary, pub plist: Dictionary,
} }