From 2e1b7ee822aeae887c23fde9b25e82564c63039d Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Thu, 6 Mar 2025 15:54:34 -0700 Subject: [PATCH] Implement basic misagent support --- idevice/Cargo.toml | 2 + idevice/src/lib.rs | 2 + idevice/src/misagent.rs | 97 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 idevice/src/misagent.rs diff --git a/idevice/Cargo.toml b/idevice/Cargo.toml index b9739a8..4180e6e 100644 --- a/idevice/Cargo.toml +++ b/idevice/Cargo.toml @@ -40,6 +40,7 @@ core_device_proxy = ["dep:serde_json", "dep:json", "dep:byteorder"] debug_proxy = [] heartbeat = [] installation_proxy = [] +misagent = [] mounter = ["dep:sha2"] usbmuxd = ["tokio/net"] tcp = ["tokio/net"] @@ -58,6 +59,7 @@ full = [ "debug_proxy", "heartbeat", "installation_proxy", + "misagent", "mounter", "usbmuxd", "xpc", diff --git a/idevice/src/lib.rs b/idevice/src/lib.rs index 083725c..27e6328 100644 --- a/idevice/src/lib.rs +++ b/idevice/src/lib.rs @@ -11,6 +11,8 @@ pub mod http2; #[cfg(feature = "installation_proxy")] pub mod installation_proxy; pub mod lockdownd; +#[cfg(feature = "misagent")] +pub mod misagent; #[cfg(feature = "mounter")] pub mod mounter; pub mod pairing_file; diff --git a/idevice/src/misagent.rs b/idevice/src/misagent.rs new file mode 100644 index 0000000..d402269 --- /dev/null +++ b/idevice/src/misagent.rs @@ -0,0 +1,97 @@ +// Jackson Coxson +// Incomplete implementation for installation_proxy + +use log::warn; +use plist::{Dictionary, Value}; + +use crate::{lockdownd::LockdowndClient, Idevice, IdeviceError, IdeviceService}; + +pub struct MisagentClient { + pub idevice: Idevice, +} + +impl IdeviceService for MisagentClient { + fn service_name() -> &'static str { + "com.apple.misagent" + } + + async fn connect( + provider: &dyn crate::provider::IdeviceProvider, + ) -> Result { + let mut lockdown = LockdowndClient::connect(provider).await?; + lockdown + .start_session(&provider.get_pairing_file().await?) + .await?; + let (port, ssl) = lockdown.start_service(Self::service_name()).await?; + + let mut idevice = provider.connect(port).await?; + if ssl { + idevice + .start_session(&provider.get_pairing_file().await?) + .await?; + } + + Ok(Self::new(idevice)) + } +} + +impl MisagentClient { + pub fn new(idevice: Idevice) -> Self { + Self { idevice } + } + + pub async fn install(&mut self, profile: Vec) -> Result<(), IdeviceError> { + let mut req = Dictionary::new(); + req.insert("MessageType".into(), "Install".into()); + req.insert("Profile".into(), plist::Value::Data(profile)); + + // TODO: Determine if there are other types of profiles we can install + req.insert("ProfileType".into(), "Provisioning".into()); + + self.idevice + .send_plist(plist::Value::Dictionary(req)) + .await?; + + let res = self.idevice.read_plist().await?; + + todo!(); + } + + pub async fn remove(&mut self, id: &str) -> Result<(), IdeviceError> { + let mut req = Dictionary::new(); + req.insert("MessageType".into(), "Remove".into()); + req.insert("ProfileID".into(), id.into()); + + // TODO: Determine if there are other types of profiles we can install + req.insert("ProfileType".into(), "Provisioning".into()); + + self.idevice + .send_plist(plist::Value::Dictionary(req)) + .await?; + + let res = self.idevice.read_plist().await?; + todo!() + } + + pub async fn copy_all(&mut self) -> Result, IdeviceError> { + let mut req = Dictionary::new(); + req.insert("MessageType".into(), "CopyAll".into()); + + // TODO: Determine if there are other types of profiles we can install + req.insert("ProfileType".into(), "Provisioning".into()); + + self.idevice + .send_plist(plist::Value::Dictionary(req)) + .await?; + + let mut res = self.idevice.read_plist().await?; + Ok(match res.remove("Payload") { + // TODO: Determine if this is actually an array + Some(plist::Value::Array(a)) => a, + _ => { + warn!("Did not get a payload of provisioning profiles as an array"); + return Err(IdeviceError::UnexpectedResponse); + } + }) + } +}