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