diff --git a/idevice/Cargo.toml b/idevice/Cargo.toml index f005d49..7c0fc65 100644 --- a/idevice/Cargo.toml +++ b/idevice/Cargo.toml @@ -88,6 +88,7 @@ full = [ "debug_proxy", "dvt", "heartbeat", + "house_arrest", "installation_proxy", "misagent", "mobile_image_mounter", diff --git a/idevice/src/services/house_arrest.rs b/idevice/src/services/house_arrest.rs index 1127165..ab1cc15 100644 --- a/idevice/src/services/house_arrest.rs +++ b/idevice/src/services/house_arrest.rs @@ -90,7 +90,9 @@ impl HouseArrestClient { self.vend(bundle_id, "VendContainer".into()).await } - /// Requests access to the app's Documents directory over AFC + /// Requests access to the app's Documents directory over AFC. + /// Note that you can only access the /Documents directory. Permission will be denied + /// otherwise. /// /// # Arguments /// * `bundle_id` - The bundle identifier of the target app (e.g., "com.example.MyApp") diff --git a/tools/src/afc.rs b/tools/src/afc.rs index fe090fb..c8a979a 100644 --- a/tools/src/afc.rs +++ b/tools/src/afc.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use clap::{value_parser, Arg, Command}; use idevice::{ afc::{opcode::AfcFopenMode, AfcClient}, + house_arrest::HouseArrestClient, IdeviceService, }; @@ -15,7 +16,7 @@ async fn main() { env_logger::init(); let matches = Command::new("afc") - .about("Start a tunnel") + .about("Manage files on the device") .arg( Arg::new("host") .long("host") @@ -33,6 +34,20 @@ async fn main() { .value_name("UDID") .help("UDID of the device (overrides host/pairing file)"), ) + .arg( + Arg::new("documents") + .long("documents") + .value_name("BUNDLE_ID") + .help("Read the documents from a bundle. Note that when vending documents, you can only access files in /Documents") + .global(true), + ) + .arg( + Arg::new("container") + .long("container") + .value_name("BUNDLE_ID") + .help("Read the container contents of a bundle") + .global(true), + ) .arg( Arg::new("about") .long("about") @@ -101,9 +116,26 @@ async fn main() { return; } }; - let mut afc_client = AfcClient::connect(&*provider) - .await - .expect("Unable to connect to misagent"); + + let mut afc_client = if let Some(bundle_id) = matches.get_one::("container") { + let h = HouseArrestClient::connect(&*provider) + .await + .expect("Failed to connect to house arrest"); + h.vend_container(bundle_id) + .await + .expect("Failed to vend container") + } else if let Some(bundle_id) = matches.get_one::("documents") { + let h = HouseArrestClient::connect(&*provider) + .await + .expect("Failed to connect to house arrest"); + h.vend_documents(bundle_id) + .await + .expect("Failed to vend documents") + } else { + AfcClient::connect(&*provider) + .await + .expect("Unable to connect to misagent") + }; if let Some(matches) = matches.subcommand_matches("list") { let path = matches.get_one::("path").expect("No path passed");