Dadoum commited on 2026-09-28 01:52:24
Showing 3 changed files, with 42 additions and 12 deletions.
| ... | ... |
@@ -131,6 +131,7 @@ pub enum AuthOutcome {
|
| 131 | 131 |
SecondaryActionRequired(Option<ServerProvidedData>, String), |
| 132 | 132 |
AnisetteResyncRequired(Vec<u8>), |
| 133 | 133 |
AnisetteReprovisionRequired, |
| 134 |
+ /// Opaque `idata` to pass to `url_switch` with the original bag lookup URL. |
|
| 134 | 135 |
UrlSwitchingRequired(String), |
| 135 | 136 |
} |
| 136 | 137 |
|
| ... | ... |
@@ -271,7 +271,7 @@ pub async fn sync_machine( |
| 271 | 271 |
.ok_or(SyncError::URLNotFound)?; |
| 272 | 272 |
|
| 273 | 273 |
let sync_machine_request_builder = |
| 274 |
- http_session.simple_request_builder(Method::GET, mid_sync_machine_url); |
|
| 274 |
+ http_session.simple_request_builder(Method::POST, mid_sync_machine_url); |
|
| 275 | 275 |
|
| 276 | 276 |
let mut sync_machine_request_body = Vec::<u8>::new(); |
| 277 | 277 |
plist::to_writer_xml(&mut sync_machine_request_body, &sync_machine_request_plist) |
| ... | ... |
@@ -283,6 +283,8 @@ pub async fn sync_machine( |
| 283 | 283 |
.send() |
| 284 | 284 |
.await |
| 285 | 285 |
.map_err(SyncError::Network)? |
| 286 |
+ .error_for_status() |
|
| 287 |
+ .map_err(SyncError::Network)? |
|
| 286 | 288 |
.bytes() |
| 287 | 289 |
.await |
| 288 | 290 |
.map_err(SyncError::Network)?; |
| ... | ... |
@@ -290,13 +292,38 @@ pub async fn sync_machine( |
| 290 | 292 |
let sync_machine_response_plist: Dictionary = |
| 291 | 293 |
plist::from_bytes(&sync_machine_response).map_err(SyncError::Parsing)?; |
| 292 | 294 |
|
| 293 |
- sync_machine_response_plist |
|
| 295 |
+ let response = sync_machine_response_plist |
|
| 294 | 296 |
.get("Response")
|
| 295 |
- .and_then(|response| response.as_dictionary()) |
|
| 296 |
- .and_then(|response| response.get("Status"))
|
|
| 297 |
- .and_then(|response| response.as_dictionary()) |
|
| 298 |
- .map(|status| parse_status(status).map_err(SyncError::Apple)) |
|
| 299 |
- .ok_or(SyncError::ResponseStructure( |
|
| 300 |
- sync_machine_response_plist.clone(), |
|
| 301 |
- ))? |
|
| 297 |
+ .and_then(Value::as_dictionary) |
|
| 298 |
+ .ok_or_else(|| SyncError::ResponseStructure(sync_machine_response_plist.clone()))?; |
|
| 299 |
+ let status = response |
|
| 300 |
+ .get("Status")
|
|
| 301 |
+ .and_then(Value::as_dictionary) |
|
| 302 |
+ .ok_or_else(|| SyncError::ResponseStructure(sync_machine_response_plist.clone()))?; |
|
| 303 |
+ let code = status |
|
| 304 |
+ .get("ec")
|
|
| 305 |
+ .and_then(Value::as_signed_integer) |
|
| 306 |
+ .ok_or_else(|| SyncError::ResponseStructure(sync_machine_response_plist.clone()))?; |
|
| 307 |
+ if code != 0 {
|
|
| 308 |
+ return Err(SyncError::Apple(AppleError {
|
|
| 309 |
+ code, |
|
| 310 |
+ message: status |
|
| 311 |
+ .get("em")
|
|
| 312 |
+ .and_then(Value::as_string) |
|
| 313 |
+ .unwrap_or("Unknown synchronization error")
|
|
| 314 |
+ .to_owned(), |
|
| 315 |
+ })); |
|
| 316 |
+ } |
|
| 317 |
+ |
|
| 318 |
+ if let Some(routing_info) = response.get("X-Apple-I-MD-RINFO") {
|
|
| 319 |
+ let routing_info = routing_info |
|
| 320 |
+ .as_unsigned_integer() |
|
| 321 |
+ .or_else(|| routing_info.as_string()?.parse().ok()) |
|
| 322 |
+ .ok_or_else(|| SyncError::ResponseStructure(sync_machine_response_plist.clone()))?; |
|
| 323 |
+ adi_proxy |
|
| 324 |
+ .set_idms_routing(GRANDSLAM_DSID, routing_info) |
|
| 325 |
+ .map_err(SyncError::ADI)?; |
|
| 326 |
+ } |
|
| 327 |
+ |
|
| 328 |
+ Ok(()) |
|
| 302 | 329 |
} |
| ... | ... |
@@ -29,14 +29,16 @@ impl Display for URLSwitchingError {
|
| 29 | 29 |
|
| 30 | 30 |
impl Error for URLSwitchingError {}
|
| 31 | 31 |
|
| 32 |
+/// Fetches a replacement URL bag from the original bag lookup URL. |
|
| 33 |
+/// `idata` is the opaque data from `AuthOutcome::UrlSwitchingRequired`, not a URL. |
|
| 32 | 34 |
pub async fn url_switch( |
| 33 | 35 |
http_session: &mut HTTPSession<'_>, |
| 34 |
- url: &str, |
|
| 36 |
+ bag_lookup_url: &str, |
|
| 35 | 37 |
idata: &str, |
| 36 | 38 |
) -> Result<(), URLSwitchingError> {
|
| 37 | 39 |
let url_bag_response = http_session |
| 38 |
- .request_builder(Method::GET, url) |
|
| 39 |
- .query(&[("idata", idata.to_string())])
|
|
| 40 |
+ .request_builder(Method::GET, bag_lookup_url) |
|
| 41 |
+ .query(&[("idata", idata)])
|
|
| 40 | 42 |
.send() |
| 41 | 43 |
.await |
| 42 | 44 |
.map_err(URLSwitchingError::Reqwest)? |
| 43 | 45 |