Correct TSS request implementation

This commit is contained in:
Jackson Coxson
2025-02-05 17:32:43 -07:00
parent ab1b999a5e
commit 5615059375
2 changed files with 37 additions and 53 deletions

View File

@@ -116,7 +116,7 @@ impl ImageMounter {
let res = self.idevice.read_plist().await?; let res = self.idevice.read_plist().await?;
match res.get("Status") { match res.get("Status") {
Some(plist::Value::String(s)) => { Some(plist::Value::String(s)) => {
if s.as_str() != "Success" { if s.as_str() != "Complete" {
log::error!("Image send failure: {s:?}"); log::error!("Image send failure: {s:?}");
return Err(IdeviceError::UnexpectedResponse); return Err(IdeviceError::UnexpectedResponse);
} }
@@ -131,8 +131,8 @@ impl ImageMounter {
&mut self, &mut self,
image_type: impl Into<String>, image_type: impl Into<String>,
signature: Vec<u8>, signature: Vec<u8>,
trust_cache: Vec<u8>, trust_cache: Option<Vec<u8>>,
info_plist: plist::Value, info_plist: Option<plist::Value>,
) -> Result<(), IdeviceError> { ) -> Result<(), IdeviceError> {
let image_type = image_type.into(); let image_type = image_type.into();
@@ -140,8 +140,12 @@ impl ImageMounter {
req.insert("Command".into(), "MountImage".into()); req.insert("Command".into(), "MountImage".into());
req.insert("ImageType".into(), image_type.into()); req.insert("ImageType".into(), image_type.into());
req.insert("ImageSignature".into(), plist::Value::Data(signature)); req.insert("ImageSignature".into(), plist::Value::Data(signature));
req.insert("ImageTrustCache".into(), plist::Value::Data(trust_cache)); if let Some(trust_cache) = trust_cache {
req.insert("ImageInfoPlist".into(), info_plist); req.insert("ImageTrustCache".into(), plist::Value::Data(trust_cache));
}
if let Some(info_plist) = info_plist {
req.insert("ImageInfoPlist".into(), info_plist);
}
self.idevice self.idevice
.send_plist(plist::Value::Dictionary(req)) .send_plist(plist::Value::Dictionary(req))
.await?; .await?;
@@ -150,7 +154,7 @@ impl ImageMounter {
match res.get("Status") { match res.get("Status") {
Some(plist::Value::String(s)) => { Some(plist::Value::String(s)) => {
if s.as_str() != "Success" { if s.as_str() != "Complete" {
log::error!("Image send failure: {s:?}"); log::error!("Image send failure: {s:?}");
return Err(IdeviceError::UnexpectedResponse); return Err(IdeviceError::UnexpectedResponse);
} }
@@ -289,13 +293,7 @@ impl ImageMounter {
) -> Result<(), IdeviceError> { ) -> Result<(), IdeviceError> {
self.upload_image("Developer", image, signature.clone()) self.upload_image("Developer", image, signature.clone())
.await?; .await?;
self.mount_image( self.mount_image("Developer", signature, None, None).await?;
"Developer",
signature,
Vec::new(),
plist::Value::Dictionary(plist::Dictionary::new()),
)
.await?;
Ok(()) Ok(())
} }
@@ -337,23 +335,9 @@ impl ImageMounter {
self.upload_image("Personalized", &image, manifest.clone()) self.upload_image("Personalized", &image, manifest.clone())
.await?; .await?;
let mut extras = plist::Dictionary::new();
if let Some(info) = info_plist {
extras.insert("ImageInfoPlist".into(), info);
}
extras.insert(
"ImageTrustCache".into(),
plist::Value::Data(trust_cache.clone()),
);
debug!("Mounting image"); debug!("Mounting image");
self.mount_image( self.mount_image("Personalized", manifest, Some(trust_cache), info_plist)
"Personalized", .await?;
manifest,
trust_cache,
plist::Value::Dictionary(extras),
)
.await?;
Ok(()) Ok(())
} }
@@ -487,6 +471,7 @@ impl ImageMounter {
parameters.insert("ApSupportsImg4".into(), true.into()); parameters.insert("ApSupportsImg4".into(), true.into());
for (key, manifest_item) in manifest { for (key, manifest_item) in manifest {
println!("{key}, {manifest_item:?}");
let manifest_item = match manifest_item { let manifest_item = match manifest_item {
plist::Value::Dictionary(m) => m, plist::Value::Dictionary(m) => m,
_ => { _ => {
@@ -494,15 +479,12 @@ impl ImageMounter {
continue; continue;
} }
}; };
let info = match manifest_item.get("Info") { if manifest_item.get("Info").is_none() {
Some(plist::Value::Dictionary(i)) => i, debug!("Manifest item didn't contain info");
_ => { continue;
debug!("Manifest item didn't contain info"); }
continue;
}
};
match info.get("Trusted") { match manifest_item.get("Trusted") {
Some(plist::Value::Boolean(t)) => { Some(plist::Value::Boolean(t)) => {
if !t { if !t {
debug!("Info item isn't trusted"); debug!("Info item isn't trusted");
@@ -518,11 +500,14 @@ impl ImageMounter {
let mut tss_entry = manifest_item.clone(); let mut tss_entry = manifest_item.clone();
tss_entry.remove("Info"); tss_entry.remove("Info");
if let Some(plist::Value::Dictionary(l)) = manifest.get("LoadableTrustCache") { if let Some(info) = manifest
if let Some(plist::Value::Dictionary(i)) = l.get("Info") { .get("LoadableTrustCache")
if let Some(plist::Value::Array(rules)) = i.get("RestoreRequestRules") { .and_then(|l| l.as_dictionary())
crate::tss::apply_restore_request_rules(&mut tss_entry, &parameters, rules); .and_then(|l| l.get("Info"))
} .and_then(|i| i.as_dictionary())
{
if let Some(plist::Value::Array(rules)) = info.get("RestoreRequestRules") {
crate::tss::apply_restore_request_rules(&mut tss_entry, &parameters, rules);
} }
} }

View File

@@ -9,6 +9,7 @@ use crate::{util::plist_to_bytes, IdeviceError};
const TSS_CLIENT_VERSION_STRING: &str = "libauthinstall-1033.0.2"; const TSS_CLIENT_VERSION_STRING: &str = "libauthinstall-1033.0.2";
const TSS_CONTROLLER_ACTION_URL: &str = "http://gs.apple.com/TSS/controller?action=2"; const TSS_CONTROLLER_ACTION_URL: &str = "http://gs.apple.com/TSS/controller?action=2";
#[derive(Debug)]
pub struct TSSRequest { pub struct TSSRequest {
inner: plist::Dictionary, inner: plist::Dictionary,
} }
@@ -32,6 +33,7 @@ impl TSSRequest {
} }
pub async fn send(&self) -> Result<plist::Value, IdeviceError> { pub async fn send(&self) -> Result<plist::Value, IdeviceError> {
debug!("Sending TSS request: {:#?}", self.inner);
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let res = client let res = client
@@ -75,15 +77,15 @@ pub fn apply_restore_request_rules(
) { ) {
for rule in rules { for rule in rules {
if let plist::Value::Dictionary(rule) = rule { if let plist::Value::Dictionary(rule) = rule {
let mut conditions_fulfulled = true;
let conditions = match rule.get("Conditions") { let conditions = match rule.get("Conditions") {
Some(plist::Value::Dictionary(c)) => c, Some(plist::Value::Dictionary(c)) => c,
_ => { _ => {
warn!("Conditions doesn't exist or wasn't a dictionary!!"); warn!("Conditions doesn't exist or wasn't a dictionary!");
continue; continue;
} }
}; };
let mut conditions_fulfilled = true;
for (key, value) in conditions { for (key, value) in conditions {
let value2 = match key.as_str() { let value2 = match key.as_str() {
"ApRawProductionMode" => parameters.get("ApProductionMode"), "ApRawProductionMode" => parameters.get("ApProductionMode"),
@@ -98,24 +100,20 @@ pub fn apply_restore_request_rules(
} }
}; };
conditions_fulfulled = match value2 { if value2.is_none() || value2 != Some(value) {
Some(value2) => value == value2, conditions_fulfilled = false;
None => false, break; // Stop checking other conditions immediately
};
if !conditions_fulfulled {
break;
} }
} }
if !conditions_fulfulled { if !conditions_fulfilled {
continue; continue;
} }
let actions = match rule.get("Actions") { let actions = match rule.get("Actions") {
Some(plist::Value::Dictionary(a)) => a, Some(plist::Value::Dictionary(a)) => a,
_ => { _ => {
warn!("Actions doesn't exist or wasn't a dictionary!!"); warn!("Actions doesn't exist or wasn't a dictionary!");
continue; continue;
} }
}; };
@@ -132,6 +130,7 @@ pub fn apply_restore_request_rules(
} }
} }
input.remove(key); // Explicitly remove before inserting, like Python
input.insert(key.to_owned(), value.to_owned()); input.insert(key.to_owned(), value.to_owned());
} }
} else { } else {