mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 06:26:15 +01:00
Correct TSS request implementation
This commit is contained in:
@@ -116,7 +116,7 @@ impl ImageMounter {
|
||||
let res = self.idevice.read_plist().await?;
|
||||
match res.get("Status") {
|
||||
Some(plist::Value::String(s)) => {
|
||||
if s.as_str() != "Success" {
|
||||
if s.as_str() != "Complete" {
|
||||
log::error!("Image send failure: {s:?}");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
@@ -131,8 +131,8 @@ impl ImageMounter {
|
||||
&mut self,
|
||||
image_type: impl Into<String>,
|
||||
signature: Vec<u8>,
|
||||
trust_cache: Vec<u8>,
|
||||
info_plist: plist::Value,
|
||||
trust_cache: Option<Vec<u8>>,
|
||||
info_plist: Option<plist::Value>,
|
||||
) -> Result<(), IdeviceError> {
|
||||
let image_type = image_type.into();
|
||||
|
||||
@@ -140,8 +140,12 @@ impl ImageMounter {
|
||||
req.insert("Command".into(), "MountImage".into());
|
||||
req.insert("ImageType".into(), image_type.into());
|
||||
req.insert("ImageSignature".into(), plist::Value::Data(signature));
|
||||
if let Some(trust_cache) = trust_cache {
|
||||
req.insert("ImageTrustCache".into(), plist::Value::Data(trust_cache));
|
||||
}
|
||||
if let Some(info_plist) = info_plist {
|
||||
req.insert("ImageInfoPlist".into(), info_plist);
|
||||
}
|
||||
self.idevice
|
||||
.send_plist(plist::Value::Dictionary(req))
|
||||
.await?;
|
||||
@@ -150,7 +154,7 @@ impl ImageMounter {
|
||||
|
||||
match res.get("Status") {
|
||||
Some(plist::Value::String(s)) => {
|
||||
if s.as_str() != "Success" {
|
||||
if s.as_str() != "Complete" {
|
||||
log::error!("Image send failure: {s:?}");
|
||||
return Err(IdeviceError::UnexpectedResponse);
|
||||
}
|
||||
@@ -289,13 +293,7 @@ impl ImageMounter {
|
||||
) -> Result<(), IdeviceError> {
|
||||
self.upload_image("Developer", image, signature.clone())
|
||||
.await?;
|
||||
self.mount_image(
|
||||
"Developer",
|
||||
signature,
|
||||
Vec::new(),
|
||||
plist::Value::Dictionary(plist::Dictionary::new()),
|
||||
)
|
||||
.await?;
|
||||
self.mount_image("Developer", signature, None, None).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -337,22 +335,8 @@ impl ImageMounter {
|
||||
self.upload_image("Personalized", &image, manifest.clone())
|
||||
.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");
|
||||
self.mount_image(
|
||||
"Personalized",
|
||||
manifest,
|
||||
trust_cache,
|
||||
plist::Value::Dictionary(extras),
|
||||
)
|
||||
self.mount_image("Personalized", manifest, Some(trust_cache), info_plist)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
@@ -487,6 +471,7 @@ impl ImageMounter {
|
||||
parameters.insert("ApSupportsImg4".into(), true.into());
|
||||
|
||||
for (key, manifest_item) in manifest {
|
||||
println!("{key}, {manifest_item:?}");
|
||||
let manifest_item = match manifest_item {
|
||||
plist::Value::Dictionary(m) => m,
|
||||
_ => {
|
||||
@@ -494,15 +479,12 @@ impl ImageMounter {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let info = match manifest_item.get("Info") {
|
||||
Some(plist::Value::Dictionary(i)) => i,
|
||||
_ => {
|
||||
if manifest_item.get("Info").is_none() {
|
||||
debug!("Manifest item didn't contain info");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match info.get("Trusted") {
|
||||
match manifest_item.get("Trusted") {
|
||||
Some(plist::Value::Boolean(t)) => {
|
||||
if !t {
|
||||
debug!("Info item isn't trusted");
|
||||
@@ -518,13 +500,16 @@ impl ImageMounter {
|
||||
let mut tss_entry = manifest_item.clone();
|
||||
tss_entry.remove("Info");
|
||||
|
||||
if let Some(plist::Value::Dictionary(l)) = manifest.get("LoadableTrustCache") {
|
||||
if let Some(plist::Value::Dictionary(i)) = l.get("Info") {
|
||||
if let Some(plist::Value::Array(rules)) = i.get("RestoreRequestRules") {
|
||||
if let Some(info) = manifest
|
||||
.get("LoadableTrustCache")
|
||||
.and_then(|l| l.as_dictionary())
|
||||
.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, ¶meters, rules);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if manifest_item.get("Digest").is_none() {
|
||||
tss_entry.insert("Digest".into(), plist::Value::Data(vec![]));
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{util::plist_to_bytes, IdeviceError};
|
||||
const TSS_CLIENT_VERSION_STRING: &str = "libauthinstall-1033.0.2";
|
||||
const TSS_CONTROLLER_ACTION_URL: &str = "http://gs.apple.com/TSS/controller?action=2";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TSSRequest {
|
||||
inner: plist::Dictionary,
|
||||
}
|
||||
@@ -32,6 +33,7 @@ impl TSSRequest {
|
||||
}
|
||||
|
||||
pub async fn send(&self) -> Result<plist::Value, IdeviceError> {
|
||||
debug!("Sending TSS request: {:#?}", self.inner);
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let res = client
|
||||
@@ -75,15 +77,15 @@ pub fn apply_restore_request_rules(
|
||||
) {
|
||||
for rule in rules {
|
||||
if let plist::Value::Dictionary(rule) = rule {
|
||||
let mut conditions_fulfulled = true;
|
||||
let conditions = match rule.get("Conditions") {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
let mut conditions_fulfilled = true;
|
||||
for (key, value) in conditions {
|
||||
let value2 = match key.as_str() {
|
||||
"ApRawProductionMode" => parameters.get("ApProductionMode"),
|
||||
@@ -98,24 +100,20 @@ pub fn apply_restore_request_rules(
|
||||
}
|
||||
};
|
||||
|
||||
conditions_fulfulled = match value2 {
|
||||
Some(value2) => value == value2,
|
||||
None => false,
|
||||
};
|
||||
|
||||
if !conditions_fulfulled {
|
||||
break;
|
||||
if value2.is_none() || value2 != Some(value) {
|
||||
conditions_fulfilled = false;
|
||||
break; // Stop checking other conditions immediately
|
||||
}
|
||||
}
|
||||
|
||||
if !conditions_fulfulled {
|
||||
if !conditions_fulfilled {
|
||||
continue;
|
||||
}
|
||||
|
||||
let actions = match rule.get("Actions") {
|
||||
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;
|
||||
}
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user