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?;
|
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, ¶meters, 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, ¶meters, rules);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user