mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 22:46:14 +01:00
Add companion proxy support
This commit is contained in:
@@ -3,7 +3,7 @@ name = "idevice"
|
||||
description = "A Rust library to interact with services on iOS devices."
|
||||
authors = ["Jackson Coxson"]
|
||||
version = "0.1.37"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
documentation = "https://docs.rs/idevice"
|
||||
repository = "https://github.com/jkcoxson/idevice"
|
||||
@@ -62,6 +62,7 @@ ring = ["rustls/ring", "tokio-rustls/ring"]
|
||||
|
||||
afc = ["dep:chrono"]
|
||||
amfi = []
|
||||
companion_proxy = []
|
||||
core_device = ["xpc", "dep:uuid"]
|
||||
core_device_proxy = ["dep:serde_json", "dep:json", "dep:byteorder"]
|
||||
crashreportcopymobile = ["afc"]
|
||||
@@ -95,6 +96,7 @@ xpc = ["dep:indexmap", "dep:uuid"]
|
||||
full = [
|
||||
"afc",
|
||||
"amfi",
|
||||
"companion_proxy",
|
||||
"core_device",
|
||||
"core_device_proxy",
|
||||
"crashreportcopymobile",
|
||||
|
||||
@@ -660,6 +660,10 @@ pub enum IdeviceError {
|
||||
FfiInvalidString = -61,
|
||||
#[error("buffer passed is too small - needs {0}, got {1}")]
|
||||
FfiBufferTooSmall(usize, usize) = -62,
|
||||
#[error("unsupported watch key")]
|
||||
UnsupportedWatchKey = -63,
|
||||
#[error("malformed command")]
|
||||
MalformedCommand = -64,
|
||||
}
|
||||
|
||||
impl IdeviceError {
|
||||
@@ -683,6 +687,8 @@ impl IdeviceError {
|
||||
"UserDeniedPairing" => Some(Self::UserDeniedPairing),
|
||||
#[cfg(feature = "pair")]
|
||||
"PasswordProtected" => Some(Self::PasswordProtected),
|
||||
"UnsupportedWatchKey" => Some(Self::UnsupportedWatchKey),
|
||||
"MalformedCommand" => Some(Self::MalformedCommand),
|
||||
"InternalError" => {
|
||||
let detailed_error = context
|
||||
.get("DetailedError")
|
||||
@@ -806,6 +812,8 @@ impl IdeviceError {
|
||||
IdeviceError::FfiInvalidArg => -60,
|
||||
IdeviceError::FfiInvalidString => -61,
|
||||
IdeviceError::FfiBufferTooSmall(_, _) => -62,
|
||||
IdeviceError::UnsupportedWatchKey => -63,
|
||||
IdeviceError::MalformedCommand => -64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
150
idevice/src/services/companion_proxy.rs
Normal file
150
idevice/src/services/companion_proxy.rs
Normal file
@@ -0,0 +1,150 @@
|
||||
//! Companion Proxy is Apple's bridge to connect to the Apple Watch
|
||||
|
||||
use log::warn;
|
||||
|
||||
use crate::{Idevice, IdeviceError, IdeviceService, RsdService, obf};
|
||||
|
||||
pub struct CompanionProxy {
|
||||
idevice: Idevice,
|
||||
}
|
||||
|
||||
pub struct CompanionProxyStream {
|
||||
proxy: CompanionProxy,
|
||||
}
|
||||
|
||||
impl IdeviceService for CompanionProxy {
|
||||
fn service_name() -> std::borrow::Cow<'static, str> {
|
||||
obf!("com.apple.companion_proxy")
|
||||
}
|
||||
|
||||
async fn from_stream(idevice: Idevice) -> Result<Self, crate::IdeviceError> {
|
||||
Ok(Self::new(idevice))
|
||||
}
|
||||
}
|
||||
|
||||
impl RsdService for CompanionProxy {
|
||||
fn rsd_service_name() -> std::borrow::Cow<'static, str> {
|
||||
obf!("com.apple.companion_proxy.shim.remote")
|
||||
}
|
||||
|
||||
async fn from_stream(stream: Box<dyn crate::ReadWrite>) -> Result<Self, crate::IdeviceError> {
|
||||
let mut idevice = Idevice::new(stream, "");
|
||||
idevice.rsd_checkin().await?;
|
||||
Ok(Self::new(idevice))
|
||||
}
|
||||
}
|
||||
|
||||
impl CompanionProxy {
|
||||
pub fn new(idevice: Idevice) -> Self {
|
||||
Self { idevice }
|
||||
}
|
||||
|
||||
pub async fn get_device_registry(&mut self) -> Result<Vec<String>, IdeviceError> {
|
||||
let command = crate::plist!({
|
||||
"Command": "GetDeviceRegistry"
|
||||
});
|
||||
|
||||
self.idevice.send_plist(command).await?;
|
||||
let res = self.idevice.read_plist().await?;
|
||||
let list = match res.get("PairedDevicesArray").and_then(|x| x.as_array()) {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
warn!("Didn't get PairedDevicesArray array");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
};
|
||||
|
||||
let mut res = Vec::new();
|
||||
for l in list {
|
||||
if let plist::Value::String(l) = l {
|
||||
res.push(l.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub async fn listen_for_devices(mut self) -> Result<CompanionProxyStream, IdeviceError> {
|
||||
let command = crate::plist!({
|
||||
"Command": "StartListeningForDevices"
|
||||
});
|
||||
self.idevice.send_plist(command).await?;
|
||||
|
||||
Ok(CompanionProxyStream { proxy: self })
|
||||
}
|
||||
|
||||
pub async fn get_value(
|
||||
&mut self,
|
||||
udid: impl Into<String>,
|
||||
key: impl Into<String>,
|
||||
) -> Result<plist::Value, IdeviceError> {
|
||||
let udid = udid.into();
|
||||
let key = key.into();
|
||||
let command = crate::plist!({
|
||||
"Command": "GetValueFromRegistry",
|
||||
"GetValueGizmoUDIDKey": udid,
|
||||
"GetValueKeyKey": key.clone()
|
||||
});
|
||||
self.idevice.send_plist(command).await?;
|
||||
let mut res = self.idevice.read_plist().await?;
|
||||
if let Some(v) = res
|
||||
.remove("RetrievedValueDictionary")
|
||||
.and_then(|x| x.into_dictionary())
|
||||
.and_then(|mut x| x.remove(&key))
|
||||
{
|
||||
Ok(v)
|
||||
} else {
|
||||
Err(IdeviceError::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start_forwarding_service_port(
|
||||
&mut self,
|
||||
port: u16,
|
||||
service_name: Option<&str>,
|
||||
options: Option<plist::Dictionary>,
|
||||
) -> Result<u16, IdeviceError> {
|
||||
let command = crate::plist!({
|
||||
"Command": "StartForwardingServicePort",
|
||||
"GizmoRemotePortNumber": port,
|
||||
"IsServiceLowPriority": false,
|
||||
"PreferWifi": false,
|
||||
"ForwardedServiceName":? service_name,
|
||||
:<? options,
|
||||
});
|
||||
self.idevice.send_plist(command).await?;
|
||||
let res = self.idevice.read_plist().await?;
|
||||
if let Some(p) = res
|
||||
.get("CompanionProxyServicePort")
|
||||
.and_then(|x| x.as_unsigned_integer())
|
||||
{
|
||||
Ok(p as u16)
|
||||
} else {
|
||||
Err(IdeviceError::UnexpectedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn stop_forwarding_service_port(&mut self, port: u16) -> Result<(), IdeviceError> {
|
||||
let command = crate::plist!({
|
||||
"Command": "StopForwardingServicePort",
|
||||
"GizmoRemotePortNumber": port
|
||||
});
|
||||
|
||||
self.idevice.send_plist(command).await?;
|
||||
let res = self.idevice.read_plist().await?;
|
||||
if let Some(c) = res.get("Command").and_then(|x| x.as_string())
|
||||
&& (c == "ComandSuccess" || c == "CommandSuccess")
|
||||
// Apple you spelled this wrong, adding the right spelling just in case you fix it smh
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(IdeviceError::UnexpectedResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CompanionProxyStream {
|
||||
pub async fn next(&mut self) -> Result<plist::Dictionary, IdeviceError> {
|
||||
self.proxy.idevice.read_plist().await
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
pub mod afc;
|
||||
#[cfg(feature = "amfi")]
|
||||
pub mod amfi;
|
||||
#[cfg(feature = "companion_proxy")]
|
||||
pub mod companion_proxy;
|
||||
#[cfg(feature = "core_device")]
|
||||
pub mod core_device;
|
||||
#[cfg(feature = "core_device_proxy")]
|
||||
|
||||
Reference in New Issue
Block a user