idevice/services/
companion_proxy.rs

1//! Companion Proxy is Apple's bridge to connect to the Apple Watch
2
3use log::warn;
4
5use crate::{Idevice, IdeviceError, IdeviceService, RsdService, obf};
6
7pub struct CompanionProxy {
8    idevice: Idevice,
9}
10
11pub struct CompanionProxyStream {
12    proxy: CompanionProxy,
13}
14
15impl IdeviceService for CompanionProxy {
16    fn service_name() -> std::borrow::Cow<'static, str> {
17        obf!("com.apple.companion_proxy")
18    }
19
20    async fn from_stream(idevice: Idevice) -> Result<Self, crate::IdeviceError> {
21        Ok(Self::new(idevice))
22    }
23}
24
25impl RsdService for CompanionProxy {
26    fn rsd_service_name() -> std::borrow::Cow<'static, str> {
27        obf!("com.apple.companion_proxy.shim.remote")
28    }
29
30    async fn from_stream(stream: Box<dyn crate::ReadWrite>) -> Result<Self, crate::IdeviceError> {
31        let mut idevice = Idevice::new(stream, "");
32        idevice.rsd_checkin().await?;
33        Ok(Self::new(idevice))
34    }
35}
36
37impl CompanionProxy {
38    pub fn new(idevice: Idevice) -> Self {
39        Self { idevice }
40    }
41
42    pub async fn get_device_registry(&mut self) -> Result<Vec<String>, IdeviceError> {
43        let command = crate::plist!({
44            "Command": "GetDeviceRegistry"
45        });
46
47        self.idevice.send_plist(command).await?;
48        let res = self.idevice.read_plist().await?;
49        let list = match res.get("PairedDevicesArray").and_then(|x| x.as_array()) {
50            Some(l) => l,
51            None => {
52                warn!("Didn't get PairedDevicesArray array");
53                return Err(IdeviceError::UnexpectedResponse);
54            }
55        };
56
57        let mut res = Vec::new();
58        for l in list {
59            if let plist::Value::String(l) = l {
60                res.push(l.to_owned());
61            }
62        }
63
64        Ok(res)
65    }
66
67    pub async fn listen_for_devices(mut self) -> Result<CompanionProxyStream, IdeviceError> {
68        let command = crate::plist!({
69            "Command": "StartListeningForDevices"
70        });
71        self.idevice.send_plist(command).await?;
72
73        Ok(CompanionProxyStream { proxy: self })
74    }
75
76    pub async fn get_value(
77        &mut self,
78        udid: impl Into<String>,
79        key: impl Into<String>,
80    ) -> Result<plist::Value, IdeviceError> {
81        let udid = udid.into();
82        let key = key.into();
83        let command = crate::plist!({
84            "Command": "GetValueFromRegistry",
85            "GetValueGizmoUDIDKey": udid,
86            "GetValueKeyKey": key.clone()
87        });
88        self.idevice.send_plist(command).await?;
89        let mut res = self.idevice.read_plist().await?;
90        if let Some(v) = res
91            .remove("RetrievedValueDictionary")
92            .and_then(|x| x.into_dictionary())
93            .and_then(|mut x| x.remove(&key))
94        {
95            Ok(v)
96        } else {
97            Err(IdeviceError::NotFound)
98        }
99    }
100
101    pub async fn start_forwarding_service_port(
102        &mut self,
103        port: u16,
104        service_name: Option<&str>,
105        options: Option<plist::Dictionary>,
106    ) -> Result<u16, IdeviceError> {
107        let command = crate::plist!({
108            "Command": "StartForwardingServicePort",
109            "GizmoRemotePortNumber": port,
110            "IsServiceLowPriority": false,
111            "PreferWifi": false,
112            "ForwardedServiceName":? service_name,
113            :<? options,
114        });
115        self.idevice.send_plist(command).await?;
116        let res = self.idevice.read_plist().await?;
117        if let Some(p) = res
118            .get("CompanionProxyServicePort")
119            .and_then(|x| x.as_unsigned_integer())
120        {
121            Ok(p as u16)
122        } else {
123            Err(IdeviceError::UnexpectedResponse)
124        }
125    }
126
127    pub async fn stop_forwarding_service_port(&mut self, port: u16) -> Result<(), IdeviceError> {
128        let command = crate::plist!({
129           "Command": "StopForwardingServicePort",
130            "GizmoRemotePortNumber": port
131        });
132
133        self.idevice.send_plist(command).await?;
134        let res = self.idevice.read_plist().await?;
135        if let Some(c) = res.get("Command").and_then(|x| x.as_string())
136            && (c == "ComandSuccess" || c == "CommandSuccess")
137        // Apple you spelled this wrong, adding the right spelling just in case you fix it smh
138        {
139            Ok(())
140        } else {
141            Err(IdeviceError::UnexpectedResponse)
142        }
143    }
144}
145
146impl CompanionProxyStream {
147    pub async fn next(&mut self) -> Result<plist::Dictionary, IdeviceError> {
148        self.proxy.idevice.read_plist().await
149    }
150}