diff --git a/isideload/src/anisette/mod.rs b/isideload/src/anisette/mod.rs index dd04c94..1894915 100644 --- a/isideload/src/anisette/mod.rs +++ b/isideload/src/anisette/mod.rs @@ -19,7 +19,7 @@ pub struct AnisetteClientInfo { pub struct AnisetteData { machine_id: String, one_time_password: String, - routing_info: String, + pub routing_info: String, device_description: String, device_unique_identifier: String, local_user_id: String, @@ -27,29 +27,29 @@ pub struct AnisetteData { impl AnisetteData { pub fn get_headers(&self, serial: String) -> HashMap { - let dt: DateTime = Utc::now().round_subsecs(0); + // let dt: DateTime = Utc::now().round_subsecs(0); HashMap::from_iter( [ - ( - "X-Apple-I-Client-Time".to_string(), - dt.format("%+").to_string().replace("+00:00", "Z"), - ), - ("X-Apple-I-SRL-NO".to_string(), serial), - ("X-Apple-I-TimeZone".to_string(), "UTC".to_string()), - ("X-Apple-Locale".to_string(), "en_US".to_string()), - ("X-Apple-I-MD-RINFO".to_string(), self.routing_info.clone()), - ("X-Apple-I-MD-LU".to_string(), self.local_user_id.clone()), + // ( + // "X-Apple-I-Client-Time".to_string(), + // dt.format("%+").to_string().replace("+00:00", "Z"), + // ), + // ("X-Apple-I-SRL-NO".to_string(), serial), + // ("X-Apple-I-TimeZone".to_string(), "UTC".to_string()), + // ("X-Apple-Locale".to_string(), "en_US".to_string()), + // ("X-Apple-I-MD-RINFO".to_string(), self.routing_info.clone()), + // ("X-Apple-I-MD-LU".to_string(), self.local_user_id.clone()), ( "X-Mme-Device-Id".to_string(), self.device_unique_identifier.clone(), ), ("X-Apple-I-MD".to_string(), self.one_time_password.clone()), ("X-Apple-I-MD-M".to_string(), self.machine_id.clone()), - ( - "X-Mme-Client-Info".to_string(), - self.device_description.clone(), - ), + // ( + // "X-Mme-Client-Info".to_string(), + // self.device_description.clone(), + // ), ] .into_iter(), ) diff --git a/isideload/src/anisette/remote_v3/mod.rs b/isideload/src/anisette/remote_v3/mod.rs index e87d3cb..ecbe913 100644 --- a/isideload/src/anisette/remote_v3/mod.rs +++ b/isideload/src/anisette/remote_v3/mod.rs @@ -175,18 +175,18 @@ impl RemoteV3AnisetteProvider { "X-Apple-I-MD-LU", HeaderValue::from_str(&hex::encode(state.get_md_lu()))?, ); - headers.insert( - "X-Apple-I-Client-Time", - HeaderValue::from_str( - &Utc::now() - .round_subsecs(0) - .format("%+") - .to_string() - .replace("+00:00", "Z"), - )?, - ); - headers.insert("X-Apple-I-TimeZone", HeaderValue::from_static("UTC")); - headers.insert("X-Apple-Locale", HeaderValue::from_static("en_US")); + // headers.insert( + // "X-Apple-I-Client-Time", + // HeaderValue::from_str( + // &Utc::now() + // .round_subsecs(0) + // .format("%+") + // .to_string() + // .replace("+00:00", "Z"), + // )?, + // ); + // headers.insert("X-Apple-I-TimeZone", HeaderValue::from_static("UTC")); + // headers.insert("X-Apple-Locale", HeaderValue::from_static("en_US")); headers.insert( "X-Mme-Device-Id", HeaderValue::from_str(&state.get_device_id())?, diff --git a/isideload/src/auth/apple_account.rs b/isideload/src/auth/apple_account.rs index e2c08ac..8a75afe 100644 --- a/isideload/src/auth/apple_account.rs +++ b/isideload/src/auth/apple_account.rs @@ -72,7 +72,7 @@ impl AppleAccountBuilder { self } - /// Build the AppleAccount + /// Build the AppleAccount without logging in /// /// # Errors /// Returns an error if the reqwest client cannot be built @@ -118,6 +118,10 @@ impl AppleAccount { /// Build the apple account with the given email /// /// Reccomended to use the AppleAccountBuilder instead + /// # Arguments + /// - `email`: The Apple ID email address + /// - `anisette_provider`: The anisette provider to use + /// - `debug`: DANGER, If true, accept invalid certificates and enable verbose connection pub async fn new( email: &str, mut anisette_provider: Box, @@ -151,6 +155,12 @@ impl AppleAccount { }) } + /// Log in to the Apple ID account + /// # Arguments + /// - `password`: The Apple ID password + /// - `two_factor_callback`: A callback function that returns the two-factor authentication code + /// # Errors + /// Returns an error if the login fails pub async fn login( &mut self, password: &str, @@ -216,6 +226,7 @@ impl AppleAccount { } } + /// Get the user's first and last name associated with the Apple ID pub fn get_name(&self) -> Result<(String, String), Report> { let spd = self .spd @@ -269,6 +280,10 @@ impl AppleAccount { .grandslam_client .get(&submit_code_url)? .headers(self.build_2fa_headers().await?) + .header( + "X-Apple-I-MD-RINFO", + self.anisette_data.routing_info.clone(), + ) .header("security-code", code) .send() .await @@ -321,8 +336,6 @@ impl AppleAccount { "mode": "sms" }); - debug!("{}", body); - let mut headers = self.build_2fa_headers().await?; headers.insert("Content-Type", HeaderValue::from_static("application/json")); headers.insert( @@ -337,14 +350,46 @@ impl AppleAccount { .body(body.to_string()) .send() .await - .context("Failed to submit SMS 2FA code")? - .error_for_status() - .context("SMS 2FA code submission failed")? - .text() - .await - .context("Failed to read SMS 2FA response")?; + .context("Failed to submit SMS 2FA code")?; - debug!("SMS 2FA response: {}", res); + if !res.status().is_success() { + let status = res.status(); + let text = res + .text() + .await + .context("Failed to read SMS 2FA error response text")?; + // try to parse as json, if it fails, just bail with the text + if let Ok(json) = serde_json::from_str::(&text) { + if let Some(service_errors) = json.get("serviceErrors") { + if let Some(first_error) = service_errors.as_array().and_then(|arr| arr.get(0)) + { + let code = first_error + .get("code") + .and_then(|c| c.as_str()) + .unwrap_or("unknown"); + let title = first_error + .get("title") + .and_then(|t| t.as_str()) + .unwrap_or("No title provided"); + let message = first_error + .get("message") + .and_then(|m| m.as_str()) + .unwrap_or("No message provided"); + bail!( + "SMS 2FA code submission failed (code {}): {} - {}", + code, + title, + message + ); + } + } + } + bail!( + "SMS 2FA code submission failed with http status {}: {}", + status, + text + ); + }; Ok(()) } diff --git a/isideload/src/auth/grandslam.rs b/isideload/src/auth/grandslam.rs index 718c617..ee0f4cf 100644 --- a/isideload/src/auth/grandslam.rs +++ b/isideload/src/auth/grandslam.rs @@ -133,15 +133,15 @@ impl GrandSlam { "X-Mme-Client-Info", HeaderValue::from_str(&self.client_info.client_info)?, ); - headers.insert( - "User-Agent", - HeaderValue::from_str(&self.client_info.user_agent)?, - ); - headers.insert("X-Xcode-Version", HeaderValue::from_static("14.2 (14C18)")); - headers.insert( - "X-Apple-App-Info", - HeaderValue::from_static("com.apple.gs.xcode.auth"), - ); + // headers.insert( + // "User-Agent", + // HeaderValue::from_str(&self.client_info.user_agent)?, + // ); + // headers.insert("X-Xcode-Version", HeaderValue::from_static("14.2 (14C18)")); + // headers.insert( + // "X-Apple-App-Info", + // HeaderValue::from_static("com.apple.gs.xcode.auth"), + // ); Ok(headers) }