diff --git a/Cargo.lock b/Cargo.lock index 1bf6410..af26310 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1071,8 +1071,7 @@ dependencies = [ [[package]] name = "plist-macro" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8888e02e251eba3258cc58fb79f0d8675c34b3428749e738562d58a0271bf035" +source = "git+https://github.com/nab138/plist_macro?branch=master#7004b1625aa50044bd381ee5393a9c85cec039d5" dependencies = [ "plist", ] diff --git a/Cargo.toml b/Cargo.toml index 9dc06e1..5fb16d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ members = ["examples/minimal","isideload"] default-members = ["isideload"] [patch.crates-io] -rustls-platform-verifier = { git = "https://github.com/cstkingkey/rustls-platform-verifier", branch = "extra" } \ No newline at end of file +rustls-platform-verifier = { git = "https://github.com/cstkingkey/rustls-platform-verifier", branch = "extra" } +plist-macro = { git = "https://github.com/nab138/plist_macro", branch = "master" } \ No newline at end of file diff --git a/examples/minimal/src/main.rs b/examples/minimal/src/main.rs index 9a3a305..af4497f 100644 --- a/examples/minimal/src/main.rs +++ b/examples/minimal/src/main.rs @@ -50,10 +50,19 @@ async fn main() { .await .expect("Failed to create developer session"); - let res = dev_session + let teams = dev_session .list_teams() .await .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); } diff --git a/isideload/src/auth/grandslam.rs b/isideload/src/auth/grandslam.rs index 71d1800..44133fa 100644 --- a/isideload/src/auth/grandslam.rs +++ b/isideload/src/auth/grandslam.rs @@ -1,4 +1,5 @@ use plist::Dictionary; +use plist_macro::plist_to_xml_string; use plist_macro::pretty_print_dictionary; use reqwest::{ Certificate, ClientBuilder, @@ -7,11 +8,7 @@ use reqwest::{ use rootcause::prelude::*; use tracing::debug; -use crate::{ - SideloadError, - anisette::AnisetteClientInfo, - util::plist::{PlistDataExtract, plist_to_xml_string}, -}; +use crate::{SideloadError, anisette::AnisetteClientInfo, util::plist::PlistDataExtract}; const APPLE_ROOT: &[u8] = include_bytes!("./apple_root.der"); const URL_BAG: &str = "https://gsa.apple.com/grandslam/GsService2/lookup"; diff --git a/isideload/src/dev/developer_session.rs b/isideload/src/dev/developer_session.rs index 7966817..ff1eb2a 100644 --- a/isideload/src/dev/developer_session.rs +++ b/isideload/src/dev/developer_session.rs @@ -1,7 +1,8 @@ use plist::Dictionary; -use plist_macro::plist; +use plist_macro::{plist, plist_to_xml_string}; use rootcause::prelude::*; -use tracing::debug; +use serde::de::DeserializeOwned; +use tracing::warn; use uuid::Uuid; use crate::{ @@ -10,11 +11,12 @@ use crate::{ apple_account::{AppToken, AppleAccount}, grandslam::GrandSlam, }, - dev::{ - device_type::DeveloperDeviceType, - structures::{DeveloperTeam, ListTeamResponse}, + dev::structures::{ + DeveloperDevice, + DeveloperDeviceType::{self, *}, + DeveloperTeam, ListDevicesResponse, ListTeamsResponse, }, - util::plist::{PlistDataExtract, plist_to_xml_string}, + util::plist::PlistDataExtract, }; pub struct DeveloperSession<'a> { @@ -58,12 +60,12 @@ impl<'a> DeveloperSession<'a> { )) } - pub async fn send_developer_request( + pub async fn send_developer_request( &self, url: &str, - body: Option, - ) -> Result { - let body = body.unwrap_or_else(|| Dictionary::new()); + body: impl Into>, + ) -> Result { + let body = body.into().unwrap_or_else(|| Dictionary::new()); let base = plist!(dict { "clientId": "XABBG36SBA", @@ -89,22 +91,60 @@ impl<'a> DeveloperSession<'a> { .await .context("Failed to read developer request response text")?; - // let dict: Dictionary = plist::from_bytes(text.as_bytes()) - // .context("Failed to parse developer request plist")?; + let dict: T = plist::from_bytes(text.as_bytes()) + .context("Failed to parse developer request plist")?; - Ok(text) + Ok(dict) } pub async fn list_teams(&self) -> Result, Report> { - let res = self - .send_developer_request(&DeveloperDeviceType::Any.dev_url("listTeams"), None) - .await?; + let response: ListTeamsResponse = self + .send_developer_request(&dev_url("listTeams", Any), None) + .await + .context("Failed to list developer teams")?; - let response: ListTeamResponse = plist::from_bytes(res.as_bytes()) - .context("Failed to parse list teams response plist")?; - - debug!("List Teams Response Code: {:?}", response.result_code); + 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>, + ) -> Result, 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>) -> String { + format!( + "https://developerservices2.apple.com/services/QH65B2/{}{}.action?clientId=XABBG36SBA", + device_type + .into() + .unwrap_or(DeveloperDeviceType::Ios) + .url_segment(), + endpoint, + ) } diff --git a/isideload/src/dev/device_type.rs b/isideload/src/dev/device_type.rs deleted file mode 100644 index bcc5fb5..0000000 --- a/isideload/src/dev/device_type.rs +++ /dev/null @@ -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, - ) - } -} diff --git a/isideload/src/dev/mod.rs b/isideload/src/dev/mod.rs index 11420e3..1a66810 100644 --- a/isideload/src/dev/mod.rs +++ b/isideload/src/dev/mod.rs @@ -1,3 +1,2 @@ pub mod developer_session; -pub mod device_type; -pub mod structures; \ No newline at end of file +pub mod structures; diff --git a/isideload/src/dev/structures.rs b/isideload/src/dev/structures.rs index 1516cd5..39e8851 100644 --- a/isideload/src/dev/structures.rs +++ b/isideload/src/dev/structures.rs @@ -1,17 +1,52 @@ 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)] #[serde(rename_all = "camelCase")] pub struct DeveloperTeam { - name: String, - team_id: String, - r#type: String, - status: String, + pub name: Option, + pub team_id: String, + pub r#type: Option, + pub status: Option, } #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] -pub struct ListTeamResponse { +pub struct ListTeamsResponse { pub teams: Vec, 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, +} + +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ListDevicesResponse { + pub devices: Vec, + pub result_code: i64, +} diff --git a/isideload/src/util/plist.rs b/isideload/src/util/plist.rs index 35528cb..c02e0bc 100644 --- a/isideload/src/util/plist.rs +++ b/isideload/src/util/plist.rs @@ -1,15 +1,7 @@ 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::*; -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 plist: Dictionary, }