1#![doc = include_str!("../README.md")]
2#![warn(missing_debug_implementations)]
3#![warn(missing_copy_implementations)]
4#[cfg(all(feature = "pair", feature = "rustls"))]
7mod ca;
8pub mod cursor;
9mod obfuscation;
10pub mod pairing_file;
11pub mod provider;
12#[cfg(feature = "rustls")]
13mod sni;
14#[cfg(feature = "tunnel_tcp_stack")]
15pub mod tcp;
16#[cfg(feature = "tss")]
17pub mod tss;
18#[cfg(feature = "tunneld")]
19pub mod tunneld;
20#[cfg(feature = "usbmuxd")]
21pub mod usbmuxd;
22pub mod utils;
23#[cfg(feature = "xpc")]
24pub mod xpc;
25
26pub mod services;
27pub use services::*;
28
29#[cfg(feature = "xpc")]
30pub use xpc::RemoteXpcClient;
31
32use plist_macro::{plist, pretty_print_dictionary, pretty_print_plist};
33use provider::{IdeviceProvider, RsdProvider};
34#[cfg(feature = "rustls")]
35use rustls::{crypto::CryptoProvider, pki_types::ServerName};
36use std::{
37 io::{self, BufWriter},
38 sync::Arc,
39};
40use thiserror::Error;
41use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
42use tracing::{debug, trace};
43
44use crate::services::lockdown::LockdownClient;
45
46pub trait ReadWrite: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug {}
54
55impl<T: AsyncRead + AsyncWrite + Unpin + Send + Sync + std::fmt::Debug> ReadWrite for T {}
57
58pub trait IdeviceService: Sized {
63 fn service_name() -> std::borrow::Cow<'static, str>;
65
66 #[allow(async_fn_in_trait)]
76 async fn connect(provider: &dyn IdeviceProvider) -> Result<Self, IdeviceError> {
77 let mut lockdown = LockdownClient::connect(provider).await?;
78
79 #[cfg(feature = "openssl")]
80 let legacy = lockdown
81 .get_value(Some("ProductVersion"), None)
82 .await
83 .ok()
84 .as_ref()
85 .and_then(|x| x.as_string())
86 .and_then(|x| x.split(".").next())
87 .and_then(|x| x.parse::<u8>().ok())
88 .map(|x| x < 5)
89 .unwrap_or(false);
90
91 #[cfg(not(feature = "openssl"))]
92 let legacy = false;
93
94 lockdown
95 .start_session(&provider.get_pairing_file().await?)
96 .await?;
97 let udid_value = match lockdown.get_value(Some("UniqueDeviceID"), None).await {
99 Ok(v) => v.as_string().map(|s| s.to_string()),
100 Err(_) => None,
101 };
102
103 let (port, ssl) = lockdown.start_service(Self::service_name()).await?;
104
105 let mut idevice = provider.connect(port).await?;
106 if ssl {
107 idevice
108 .start_session(&provider.get_pairing_file().await?, legacy)
109 .await?;
110 }
111
112 if let Some(udid) = udid_value {
113 idevice.set_udid(udid);
114 }
115
116 Self::from_stream(idevice).await
117 }
118
119 #[allow(async_fn_in_trait)]
120 async fn from_stream(idevice: Idevice) -> Result<Self, IdeviceError>;
121}
122
123#[cfg(feature = "rsd")]
124pub trait RsdService: Sized {
125 fn rsd_service_name() -> std::borrow::Cow<'static, str>;
126 fn from_stream(
127 stream: Box<dyn ReadWrite>,
128 ) -> impl std::future::Future<Output = Result<Self, IdeviceError>> + Send;
129 fn connect_rsd(
130 provider: &mut impl RsdProvider,
131 handshake: &mut rsd::RsdHandshake,
132 ) -> impl std::future::Future<Output = Result<Self, IdeviceError>>
133 where
134 Self: crate::RsdService,
135 {
136 handshake.connect(provider)
137 }
138}
139
140pub type IdeviceSocket = Box<dyn ReadWrite>;
145
146#[derive(Debug)]
151pub struct Idevice {
152 socket: Option<Box<dyn ReadWrite>>,
154 label: String,
156 udid: Option<String>,
158}
159
160impl Idevice {
161 pub fn new(socket: Box<dyn ReadWrite>, label: impl Into<String>) -> Self {
167 Self {
168 socket: Some(socket),
169 label: label.into(),
170 udid: None,
171 }
172 }
173
174 pub fn get_socket(self) -> Option<Box<dyn ReadWrite>> {
175 self.socket
176 }
177
178 pub fn set_udid(&mut self, udid: impl Into<String>) {
180 self.udid = Some(udid.into());
181 }
182
183 pub fn udid(&self) -> Option<&str> {
185 self.udid.as_deref()
186 }
187
188 pub async fn get_type(&mut self) -> Result<String, IdeviceError> {
198 let req = plist!({
199 "Label": self.label.clone(),
200 "Request": "QueryType",
201 });
202 self.send_plist(req).await?;
203
204 let message: plist::Dictionary = self.read_plist().await?;
205 match message.get("Type") {
206 Some(m) => Ok(plist::from_value(m)?),
207 None => Err(IdeviceError::UnexpectedResponse),
208 }
209 }
210
211 pub async fn rsd_checkin(&mut self) -> Result<(), IdeviceError> {
218 let req = plist!({
219 "Label": self.label.clone(),
220 "ProtocolVersion": "2",
221 "Request": "RSDCheckin",
222 });
223
224 self.send_plist(req).await?;
225 let res = self.read_plist().await?;
226 match res.get("Request").and_then(|x| x.as_string()) {
227 Some(r) => {
228 if r != "RSDCheckin" {
229 return Err(IdeviceError::UnexpectedResponse);
230 }
231 }
232 None => return Err(IdeviceError::UnexpectedResponse),
233 }
234
235 let res = self.read_plist().await?;
236 match res.get("Request").and_then(|x| x.as_string()) {
237 Some(r) => {
238 if r != "StartService" {
239 return Err(IdeviceError::UnexpectedResponse);
240 }
241 }
242 None => return Err(IdeviceError::UnexpectedResponse),
243 }
244
245 Ok(())
246 }
247
248 async fn send_plist(&mut self, message: plist::Value) -> Result<(), IdeviceError> {
256 if let Some(socket) = &mut self.socket {
257 debug!("Sending plist: {}", pretty_print_plist(&message));
258
259 let buf = Vec::new();
260 let mut writer = BufWriter::new(buf);
261 message.to_writer_xml(&mut writer)?;
262 let message = writer.into_inner().unwrap();
263 let message = String::from_utf8(message)?;
264 let len = message.len() as u32;
265 socket.write_all(&len.to_be_bytes()).await?;
266 socket.write_all(message.as_bytes()).await?;
267 socket.flush().await?;
268 Ok(())
269 } else {
270 Err(IdeviceError::NoEstablishedConnection)
271 }
272 }
273
274 async fn send_bplist(&mut self, message: plist::Value) -> Result<(), IdeviceError> {
282 if let Some(socket) = &mut self.socket {
283 debug!("Sending plist: {}", pretty_print_plist(&message));
284
285 let buf = Vec::new();
286 let mut writer = BufWriter::new(buf);
287 message.to_writer_binary(&mut writer)?;
288 let message = writer.into_inner().unwrap();
289 let len = message.len() as u32;
290 socket.write_all(&len.to_be_bytes()).await?;
291 socket.write_all(&message).await?;
292 socket.flush().await?;
293 Ok(())
294 } else {
295 Err(IdeviceError::NoEstablishedConnection)
296 }
297 }
298
299 pub async fn send_raw(&mut self, message: &[u8]) -> Result<(), IdeviceError> {
307 self.send_raw_with_progress(message, |_| async {}, ()).await
308 }
309
310 pub async fn send_raw_vectored(
318 &mut self,
319 bufs: &[std::io::IoSlice<'_>],
320 ) -> Result<(), IdeviceError> {
321 if let Some(socket) = &mut self.socket {
322 let mut curr_idx = 0;
323 let mut curr_offset = 0;
324
325 while curr_idx < bufs.len() {
326 let mut iovec = Vec::new();
327 let mut accumulated_len = 0;
328 let max_chunk = 1024 * 64;
329
330 let first_avail = bufs[curr_idx].len() - curr_offset;
332 let to_take_first = std::cmp::min(first_avail, max_chunk);
333 iovec.push(std::io::IoSlice::new(
334 &bufs[curr_idx][curr_offset..curr_offset + to_take_first],
335 ));
336 accumulated_len += to_take_first;
337
338 let mut temp_idx = curr_idx + 1;
340 while temp_idx < bufs.len() && accumulated_len < max_chunk {
341 let needed = max_chunk - accumulated_len;
342 let avail = bufs[temp_idx].len();
343 let take = std::cmp::min(avail, needed);
344 iovec.push(std::io::IoSlice::new(&bufs[temp_idx][..take]));
345 accumulated_len += take;
346 temp_idx += 1;
347 }
348
349 let n = socket.write_vectored(&iovec).await?;
350 if n == 0 {
351 return Err(io::Error::new(
352 io::ErrorKind::WriteZero,
353 "failed to write whole buffer",
354 )
355 .into());
356 }
357
358 let mut advanced = n;
360 while advanced > 0 && curr_idx < bufs.len() {
361 let available = bufs[curr_idx].len() - curr_offset;
362 if advanced < available {
363 curr_offset += advanced;
364 advanced = 0;
365 } else {
366 advanced -= available;
367 curr_idx += 1;
368 curr_offset = 0;
369 }
370 }
371 }
372 socket.flush().await?;
373 Ok(())
374 } else {
375 Err(IdeviceError::NoEstablishedConnection)
376 }
377 }
378
379 pub async fn send_raw_with_progress<Fut, S>(
393 &mut self,
394 message: &[u8],
395 callback: impl Fn(((usize, usize), S)) -> Fut,
396 state: S,
397 ) -> Result<(), IdeviceError>
398 where
399 Fut: std::future::Future<Output = ()>,
400 S: Clone,
401 {
402 if let Some(socket) = &mut self.socket {
403 let message_parts = message.chunks(1024 * 64);
404 let part_len = message_parts.len() - 1;
405
406 for (i, part) in message_parts.enumerate() {
407 trace!("Writing {i}/{part_len}");
408 socket.write_all(part).await?;
409 callback(((i, part_len), state.clone())).await;
410 }
411 socket.flush().await?;
412 Ok(())
413 } else {
414 Err(IdeviceError::NoEstablishedConnection)
415 }
416 }
417
418 pub async fn read_raw(&mut self, len: usize) -> Result<Vec<u8>, IdeviceError> {
429 if let Some(socket) = &mut self.socket {
430 let mut buf = vec![0; len];
431 socket.read_exact(&mut buf).await?;
432 Ok(buf)
433 } else {
434 Err(IdeviceError::NoEstablishedConnection)
435 }
436 }
437
438 pub async fn read_any(&mut self, max_size: u32) -> Result<Vec<u8>, IdeviceError> {
449 if let Some(socket) = &mut self.socket {
450 let mut buf = vec![0; max_size as usize];
451 let len = socket.read(&mut buf).await?;
452 Ok(buf[..len].to_vec())
453 } else {
454 Err(IdeviceError::NoEstablishedConnection)
455 }
456 }
457
458 async fn read_plist(&mut self) -> Result<plist::Dictionary, IdeviceError> {
466 let res = self.read_plist_value().await?;
467 let res: plist::Dictionary = plist::from_value(&res)?;
468 debug!("Received plist: {}", pretty_print_dictionary(&res));
469
470 if let Some(e) = res.get("Error") {
471 let e = match e {
472 plist::Value::String(e) => e.to_string(),
473 plist::Value::Integer(e) => {
474 if let Some(error_string) = res.get("ErrorString").and_then(|x| x.as_string()) {
475 error_string.to_string()
476 } else {
477 e.to_string()
478 }
479 }
480 _ => {
481 tracing::error!("Error is not a string or integer from read_plist: {e:?}");
482 return Err(IdeviceError::UnexpectedResponse);
483 }
484 };
485 if let Some(e) = IdeviceError::from_device_error_type(e.as_str(), &res) {
486 return Err(e);
487 } else {
488 let msg =
489 if let Some(desc) = res.get("ErrorDescription").and_then(|x| x.as_string()) {
490 format!("{} ({})", e, desc)
491 } else {
492 e
493 };
494 return Err(IdeviceError::UnknownErrorType(msg));
495 }
496 }
497 Ok(res)
498 }
499
500 async fn read_plist_value(&mut self) -> Result<plist::Value, IdeviceError> {
501 if let Some(socket) = &mut self.socket {
502 debug!("Reading response size");
503 let mut buf = [0u8; 4];
504 socket.read_exact(&mut buf).await?;
505 let len = u32::from_be_bytes(buf);
506 let mut buf = vec![0; len as usize];
507 socket.read_exact(&mut buf).await?;
508 let res: plist::Value = plist::from_bytes(&buf)?;
509 Ok(res)
510 } else {
511 Err(IdeviceError::NoEstablishedConnection)
512 }
513 }
514
515 #[cfg(feature = "syslog_relay")]
516 async fn read_until_delim(
517 &mut self,
518 delimiter: &[u8],
519 ) -> Result<Option<bytes::BytesMut>, IdeviceError> {
520 if let Some(socket) = &mut self.socket {
521 let mut buffer = bytes::BytesMut::with_capacity(1024);
522 let mut temp = [0u8; 1024];
523
524 loop {
525 let n = socket.read(&mut temp).await?;
526 if n == 0 {
527 if buffer.is_empty() {
528 return Ok(None); } else {
530 return Ok(Some(buffer)); }
532 }
533
534 buffer.extend_from_slice(&temp[..n]);
535
536 if let Some(pos) = buffer.windows(delimiter.len()).position(|w| w == delimiter) {
537 let mut line = buffer.split_to(pos + delimiter.len());
538 line.truncate(line.len() - delimiter.len()); return Ok(Some(line));
540 }
541 }
542 } else {
543 Err(IdeviceError::NoEstablishedConnection)
544 }
545 }
546
547 pub async fn start_session(
555 &mut self,
556 pairing_file: &pairing_file::PairingFile,
557 legacy: bool,
558 ) -> Result<(), IdeviceError> {
559 #[cfg(feature = "rustls")]
560 {
561 if legacy {
562 tracing::warn!(
563 "Compiled with rustls, but connecting to legacy device! rustls does not support old SSL, this will fail."
564 );
565 }
566
567 if CryptoProvider::get_default().is_none() {
568 let crypto_provider: CryptoProvider = {
570 #[cfg(all(feature = "ring", not(feature = "aws-lc")))]
571 {
572 debug!("Using ring crypto backend");
573 rustls::crypto::ring::default_provider()
574 }
575
576 #[cfg(all(feature = "aws-lc", not(feature = "ring")))]
577 {
578 debug!("Using aws-lc crypto backend");
579 rustls::crypto::aws_lc_rs::default_provider()
580 }
581
582 #[cfg(not(any(feature = "ring", feature = "aws-lc")))]
583 {
584 compile_error!(
585 "No crypto backend was selected! Specify an idevice feature for a crypto backend"
586 );
587 }
588
589 #[cfg(all(feature = "ring", feature = "aws-lc"))]
590 {
591 debug!("Using ring crypto backend, because both were passed");
595 tracing::warn!(
596 "Both ring && aws-lc are selected as idevice crypto backends!"
597 );
598 rustls::crypto::ring::default_provider()
599 }
600 };
601
602 if let Err(e) = CryptoProvider::install_default(crypto_provider) {
603 tracing::error!("Failed to set crypto provider: {e:?}");
607 }
608 }
609 let config = sni::create_client_config(pairing_file)?;
610 let connector = tokio_rustls::TlsConnector::from(Arc::new(config));
611
612 let socket = self.socket.take().unwrap();
613 let socket = connector
614 .connect(ServerName::try_from("Device").unwrap(), socket)
615 .await?;
616
617 self.socket = Some(Box::new(socket));
618
619 Ok(())
620 }
621 #[cfg(all(feature = "openssl", not(feature = "rustls")))]
622 {
623 let mut connector =
624 openssl::ssl::SslConnector::builder(openssl::ssl::SslMethod::tls())?;
625 if legacy {
626 connector.set_min_proto_version(Some(openssl::ssl::SslVersion::SSL3))?;
627 connector.set_max_proto_version(Some(openssl::ssl::SslVersion::TLS1))?;
628 connector.set_cipher_list("ALL:!aNULL:!eNULL:@SECLEVEL=0")?;
629 connector.set_options(openssl::ssl::SslOptions::ALLOW_UNSAFE_LEGACY_RENEGOTIATION);
630 }
631
632 let mut connector = connector.build().configure()?.into_ssl("ur mom")?;
633
634 connector.set_certificate(&pairing_file.host_certificate)?;
635 connector.set_private_key(&pairing_file.host_private_key)?;
636 connector.set_verify(openssl::ssl::SslVerifyMode::empty());
637 let socket = self.socket.take().unwrap();
638 let mut ssl_stream = tokio_openssl::SslStream::new(connector, socket)?;
639 std::pin::Pin::new(&mut ssl_stream).connect().await?;
640 self.socket = Some(Box::new(ssl_stream));
641
642 Ok(())
643 }
644 }
645}
646
647#[derive(Error, Debug)]
649#[repr(i32)]
650#[non_exhaustive]
651pub enum IdeviceError {
652 #[error("device socket io failed")]
653 Socket(#[from] io::Error) = -1,
654 #[cfg(feature = "rustls")]
655 #[error("PEM parse failed")]
656 PemParseFailed(#[from] rustls::pki_types::pem::Error) = -2,
657
658 #[cfg(feature = "rustls")]
659 #[error("TLS error")]
660 Rustls(#[from] rustls::Error) = -3,
661 #[cfg(all(feature = "openssl", not(feature = "rustls")))]
662 #[error("TLS error")]
663 Rustls(#[from] openssl::ssl::Error) = -3,
664
665 #[cfg(feature = "rustls")]
666 #[error("TLS verifiction build failed")]
667 TlsBuilderFailed(#[from] rustls::server::VerifierBuilderError) = -4,
668 #[cfg(all(feature = "openssl", not(feature = "rustls")))]
669 #[error("TLS verifiction build failed")]
670 TlsBuilderFailed(#[from] openssl::error::ErrorStack) = -4,
671
672 #[error("io on plist")]
673 Plist(#[from] plist::Error) = -5,
674 #[error("can't convert bytes to utf8")]
675 Utf8(#[from] std::string::FromUtf8Error) = -6,
676 #[error("unexpected response from device")]
677 UnexpectedResponse = -7,
678 #[error("this request was prohibited")]
679 GetProhibited = -8,
680 #[error("no SSL session is active")]
681 SessionInactive = -9,
682 #[error("device does not have pairing file")]
683 InvalidHostID = -10,
684 #[error("no established connection")]
685 NoEstablishedConnection = -11,
686 #[error("device went to sleep")]
687 HeartbeatSleepyTime = -12,
688 #[error("heartbeat timeout")]
689 HeartbeatTimeout = -13,
690 #[error("not found")]
691 NotFound = -14,
692 #[error("service not found")]
693 ServiceNotFound = -15,
694 #[error("CDTunnel packet too short")]
695 CdtunnelPacketTooShort = -16,
696 #[error("CDTunnel packet invalid magic")]
697 CdtunnelPacketInvalidMagic = -17,
698 #[error("Proclaimed packet size does not match actual size")]
699 PacketSizeMismatch = -18,
700
701 #[cfg(feature = "core_device_proxy")]
702 #[error("JSON serialization failed")]
703 Json(#[from] serde_json::Error) = -19,
704
705 #[error("device not found")]
706 DeviceNotFound = -20,
707
708 #[error("device lockded")]
709 DeviceLocked = -21,
710
711 #[error("device refused connection")]
712 UsbConnectionRefused = -22,
713 #[error("bad command")]
714 UsbBadCommand = -23,
715 #[error("bad device")]
716 UsbBadDevice = -24,
717 #[error("usb bad version")]
718 UsbBadVersion = -25,
719
720 #[error("bad build manifest")]
721 BadBuildManifest = -26,
722 #[error("image not mounted")]
723 ImageNotMounted = -27,
724
725 #[cfg(feature = "pair")]
726 #[error("pairing trust dialog pending")]
727 PairingDialogResponsePending = -28,
728
729 #[cfg(feature = "pair")]
730 #[error("user denied pairing trust")]
731 UserDeniedPairing = -29,
732
733 #[cfg(feature = "pair")]
734 #[error("device is locked")]
735 PasswordProtected = -30,
736
737 #[cfg(feature = "misagent")]
738 #[error("misagent operation failed")]
739 MisagentFailure = -31,
740
741 #[cfg(feature = "installation_proxy")]
742 #[error("installation proxy operation failed")]
743 InstallationProxyOperationFailed(String) = -32,
744
745 #[cfg(feature = "afc")]
746 #[error("afc error: {0}")]
747 Afc(#[from] afc::errors::AfcError) = -33,
748
749 #[cfg(feature = "afc")]
750 #[error("unknown afc opcode")]
751 UnknownAfcOpcode = -34,
752
753 #[cfg(feature = "afc")]
754 #[error("invalid afc magic")]
755 InvalidAfcMagic = -35,
756
757 #[cfg(feature = "afc")]
758 #[error("missing file attribute")]
759 AfcMissingAttribute = -36,
760
761 #[cfg(feature = "crashreportcopymobile")]
762 #[error("crash report mover sent the wrong response")]
763 CrashReportMoverBadResponse(Vec<u8>) = -37,
764
765 #[cfg(any(feature = "tss", feature = "tunneld"))]
766 #[error("http reqwest error")]
767 Reqwest(#[from] reqwest::Error) = -38,
768
769 #[error("internal error")]
770 InternalError(String) = -39,
771
772 #[cfg(feature = "xpc")]
773 #[error("unknown http frame type")]
774 UnknownFrame(u8) = -40,
775
776 #[cfg(feature = "xpc")]
777 #[error("unknown http setting type")]
778 UnknownHttpSetting(u16) = -41,
779
780 #[cfg(feature = "xpc")]
781 #[error("Unintialized stream ID")]
782 UninitializedStreamId = -42,
783
784 #[cfg(feature = "xpc")]
785 #[error("unknown XPC type")]
786 UnknownXpcType(u32) = -43,
787
788 #[cfg(feature = "xpc")]
789 #[error("malformed XPC message")]
790 MalformedXpc = -44,
791
792 #[cfg(feature = "xpc")]
793 #[error("invalid XPC magic")]
794 InvalidXpcMagic = -45,
795
796 #[cfg(feature = "xpc")]
797 #[error("unexpected XPC version")]
798 UnexpectedXpcVersion = -46,
799
800 #[cfg(feature = "xpc")]
801 #[error("invalid C string")]
802 InvalidCString = -47,
803
804 #[cfg(feature = "xpc")]
805 #[error("stream reset")]
806 HttpStreamReset = -48,
807
808 #[cfg(feature = "xpc")]
809 #[error("go away packet received")]
810 HttpGoAway(String) = -49,
811
812 #[cfg(feature = "dvt")]
813 #[error("NSKeyedArchive error")]
814 NsKeyedArchiveError(#[from] ns_keyed_archive::ConverterError) = -50,
815
816 #[cfg(feature = "dvt")]
817 #[error("Unknown aux value type")]
818 UnknownAuxValueType(u32) = -51,
819
820 #[cfg(feature = "dvt")]
821 #[error("unknown channel")]
822 UnknownChannel(u32) = -52,
823
824 #[error("cannot parse string as IpAddr")]
825 AddrParseError(#[from] std::net::AddrParseError) = -53,
826
827 #[cfg(feature = "dvt")]
828 #[error("disable memory limit failed")]
829 DisableMemoryLimitFailed = -54,
830
831 #[error("not enough bytes, expected {1}, got {0}")]
832 NotEnoughBytes(usize, usize) = -55,
833
834 #[error("failed to parse bytes as valid utf8")]
835 Utf8Error = -56,
836
837 #[cfg(any(
838 feature = "debug_proxy",
839 all(feature = "afc", feature = "installation_proxy")
840 ))]
841 #[error("invalid argument passed")]
842 InvalidArgument = -57,
843
844 #[error("unknown error `{0}` returned from device")]
845 UnknownErrorType(String) = -59,
846
847 #[error("invalid arguments were passed")]
848 FfiInvalidArg = -60,
849 #[error("invalid string was passed")]
850 FfiInvalidString = -61,
851 #[error("buffer passed is too small - needs {0}, got {1}")]
852 FfiBufferTooSmall(usize, usize) = -62,
853 #[error("unsupported watch key")]
854 UnsupportedWatchKey = -63,
855 #[error("malformed command")]
856 MalformedCommand = -64,
857 #[error("integer overflow")]
858 IntegerOverflow = -65,
859 #[error("canceled by user")]
860 CanceledByUser = -66,
861
862 #[cfg(feature = "installation_proxy")]
863 #[error("malformed package archive: {0}")]
864 MalformedPackageArchive(#[from] async_zip::error::ZipError) = -67,
865
866 #[error("Developer mode is not enabled")]
867 DeveloperModeNotEnabled = -68,
868
869 #[cfg(feature = "notification_proxy")]
870 #[error("notification proxy died")]
871 NotificationProxyDeath = -69,
872
873 #[cfg(feature = "installation_proxy")]
874 #[error("Application verification failed: {0}")]
875 ApplicationVerificationFailed(String) = -70,
876}
877
878impl IdeviceError {
879 fn from_device_error_type(e: &str, context: &plist::Dictionary) -> Option<Self> {
888 if e.contains("NSDebugDescription=Canceled by user.") {
889 return Some(Self::CanceledByUser);
890 } else if e.contains("Developer mode is not enabled.") {
891 return Some(Self::DeveloperModeNotEnabled);
892 }
893 match e {
894 "GetProhibited" => Some(Self::GetProhibited),
895 "InvalidHostID" => Some(Self::InvalidHostID),
896 "SessionInactive" => Some(Self::SessionInactive),
897 "DeviceLocked" => Some(Self::DeviceLocked),
898 #[cfg(feature = "pair")]
899 "PairingDialogResponsePending" => Some(Self::PairingDialogResponsePending),
900 #[cfg(feature = "pair")]
901 "UserDeniedPairing" => Some(Self::UserDeniedPairing),
902 #[cfg(feature = "pair")]
903 "PasswordProtected" => Some(Self::PasswordProtected),
904 "UnsupportedWatchKey" => Some(Self::UnsupportedWatchKey),
905 "MalformedCommand" => Some(Self::MalformedCommand),
906 "InternalError" => {
907 let detailed_error = context
908 .get("DetailedError")
909 .and_then(|d| d.as_string())
910 .unwrap_or("No context")
911 .to_string();
912
913 if detailed_error.contains("There is no matching entry in the device map for") {
914 Some(Self::ImageNotMounted)
915 } else {
916 Some(Self::InternalError(detailed_error))
917 }
918 }
919 #[cfg(feature = "installation_proxy")]
920 "ApplicationVerificationFailed" => {
921 let msg = context
922 .get("ErrorDescription")
923 .and_then(|x| x.as_string())
924 .unwrap_or("No context")
925 .to_string();
926 Some(Self::ApplicationVerificationFailed(msg))
927 }
928 _ => None,
929 }
930 }
931
932 pub fn code(&self) -> i32 {
933 match self {
934 IdeviceError::Socket(_) => -1,
935 #[cfg(feature = "rustls")]
936 IdeviceError::PemParseFailed(_) => -2,
937 IdeviceError::Rustls(_) => -3,
938 IdeviceError::TlsBuilderFailed(_) => -4,
939 IdeviceError::Plist(_) => -5,
940 IdeviceError::Utf8(_) => -6,
941 IdeviceError::UnexpectedResponse => -7,
942 IdeviceError::GetProhibited => -8,
943 IdeviceError::SessionInactive => -9,
944 IdeviceError::InvalidHostID => -10,
945 IdeviceError::NoEstablishedConnection => -11,
946 IdeviceError::HeartbeatSleepyTime => -12,
947 IdeviceError::HeartbeatTimeout => -13,
948 IdeviceError::NotFound => -14,
949 IdeviceError::ServiceNotFound => -15,
950 IdeviceError::CdtunnelPacketTooShort => -16,
951 IdeviceError::CdtunnelPacketInvalidMagic => -17,
952 IdeviceError::PacketSizeMismatch => -18,
953
954 #[cfg(feature = "core_device_proxy")]
955 IdeviceError::Json(_) => -19,
956
957 IdeviceError::DeviceNotFound => -20,
958 IdeviceError::DeviceLocked => -21,
959 IdeviceError::UsbConnectionRefused => -22,
960 IdeviceError::UsbBadCommand => -23,
961 IdeviceError::UsbBadDevice => -24,
962 IdeviceError::UsbBadVersion => -25,
963 IdeviceError::BadBuildManifest => -26,
964 IdeviceError::ImageNotMounted => -27,
965
966 #[cfg(feature = "pair")]
967 IdeviceError::PairingDialogResponsePending => -28,
968 #[cfg(feature = "pair")]
969 IdeviceError::UserDeniedPairing => -29,
970 #[cfg(feature = "pair")]
971 IdeviceError::PasswordProtected => -30,
972
973 #[cfg(feature = "misagent")]
974 IdeviceError::MisagentFailure => -31,
975
976 #[cfg(feature = "installation_proxy")]
977 IdeviceError::InstallationProxyOperationFailed(_) => -32,
978
979 #[cfg(feature = "afc")]
980 IdeviceError::Afc(_) => -33,
981 #[cfg(feature = "afc")]
982 IdeviceError::UnknownAfcOpcode => -34,
983 #[cfg(feature = "afc")]
984 IdeviceError::InvalidAfcMagic => -35,
985 #[cfg(feature = "afc")]
986 IdeviceError::AfcMissingAttribute => -36,
987
988 #[cfg(feature = "crashreportcopymobile")]
989 IdeviceError::CrashReportMoverBadResponse(_) => -37,
990
991 #[cfg(any(feature = "tss", feature = "tunneld"))]
992 IdeviceError::Reqwest(_) => -38,
993
994 IdeviceError::InternalError(_) => -39,
995
996 #[cfg(feature = "xpc")]
997 IdeviceError::UnknownFrame(_) => -40,
998 #[cfg(feature = "xpc")]
999 IdeviceError::UnknownHttpSetting(_) => -41,
1000 #[cfg(feature = "xpc")]
1001 IdeviceError::UninitializedStreamId => -42,
1002 #[cfg(feature = "xpc")]
1003 IdeviceError::UnknownXpcType(_) => -43,
1004 #[cfg(feature = "xpc")]
1005 IdeviceError::MalformedXpc => -44,
1006 #[cfg(feature = "xpc")]
1007 IdeviceError::InvalidXpcMagic => -45,
1008 #[cfg(feature = "xpc")]
1009 IdeviceError::UnexpectedXpcVersion => -46,
1010 #[cfg(feature = "xpc")]
1011 IdeviceError::InvalidCString => -47,
1012 #[cfg(feature = "xpc")]
1013 IdeviceError::HttpStreamReset => -48,
1014 #[cfg(feature = "xpc")]
1015 IdeviceError::HttpGoAway(_) => -49,
1016
1017 #[cfg(feature = "dvt")]
1018 IdeviceError::NsKeyedArchiveError(_) => -50,
1019 #[cfg(feature = "dvt")]
1020 IdeviceError::UnknownAuxValueType(_) => -51,
1021 #[cfg(feature = "dvt")]
1022 IdeviceError::UnknownChannel(_) => -52,
1023
1024 IdeviceError::AddrParseError(_) => -53,
1025
1026 #[cfg(feature = "dvt")]
1027 IdeviceError::DisableMemoryLimitFailed => -54,
1028
1029 IdeviceError::NotEnoughBytes(_, _) => -55,
1030 IdeviceError::Utf8Error => -56,
1031
1032 #[cfg(any(
1033 feature = "debug_proxy",
1034 all(feature = "afc", feature = "installation_proxy")
1035 ))]
1036 IdeviceError::InvalidArgument => -57,
1037
1038 IdeviceError::UnknownErrorType(_) => -59,
1039 IdeviceError::FfiInvalidArg => -60,
1040 IdeviceError::FfiInvalidString => -61,
1041 IdeviceError::FfiBufferTooSmall(_, _) => -62,
1042 IdeviceError::UnsupportedWatchKey => -63,
1043 IdeviceError::MalformedCommand => -64,
1044 IdeviceError::IntegerOverflow => -65,
1045 IdeviceError::CanceledByUser => -66,
1046
1047 #[cfg(feature = "installation_proxy")]
1048 IdeviceError::MalformedPackageArchive(_) => -67,
1049 IdeviceError::DeveloperModeNotEnabled => -68,
1050
1051 #[cfg(feature = "notification_proxy")]
1052 IdeviceError::NotificationProxyDeath => -69,
1053
1054 #[cfg(feature = "installation_proxy")]
1055 IdeviceError::ApplicationVerificationFailed(_) => -70,
1056 }
1057 }
1058}