-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iOS cli option #113
iOS cli option #113
Conversation
set to false for test cases
Really cool work, thank you for the contribution. This is the most detailed pull request I have ever seen! I will take a closer look soon; I left a small comment in the meantime. |
.unwrap_or_else(|| self.config.options.db_path.display().to_string()); | ||
// <db_path>/<hash[0..2]>/<hash>/<filename> > <filename> allows for copy-paste conversion | ||
format!("{}/{}/{} > {}", db_path_os_string, &hash[0..2], hash, | ||
filename.rsplit_once("/").unwrap().1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use unwrap()
in runtime code; I try to reserve it for tests only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, would this be better?
format!("{}/{}/{} > {}", db_path_os_string, &hash[0..2], hash,
filename.rsplit_once("/").map(|(_, x)| x).unwrap_or_else(|| "Could not get filename")
or we could reflow the logic so it goes ios, macos, error in the match
match &attachment.filename {
Some(filename) if self.config.options.ios => {
// iOS rehash the filename to a path in the backup
let salt = "MediaDomain-";
let hash = format!("{:x}", Sha1::digest(
format!("{}{}", salt, &filename[2..]).as_bytes()
));
// attempting to escape spaces in the path for easier copy-paste
let db_path_os_string = self.config.options.db_path.to_str()
.map(|s| s.replace(" ", r#"\ "#))
.unwrap_or_else(|| self.config.options.db_path.display().to_string());
// <db_path>/<hash[0..2]>/<hash>/<filename> > <filename> allows for copy-paste conversion
Ok(format!("{}/{}/{} > {}", db_path_os_string, &hash[0..2], hash,
filename.rsplit_once("/").map(|(_, x)| x).unwrap_or_else(|| "Could not get filename")))
}
// macOS uses the filename as the path
Some(filename) => Ok(filename.to_string()),
None => Err(attachment.filename()),
}
and we could always swap out the "Could not get a filename" with just a plain old error like so
match filename.rsplit_once("/") {
Some((_, filename)) => Ok(format!("{}/{}/{} > {}", db_path_os_string, &hash[0..2], hash, filename)),
None => Err(attachment.filename()),
}
or returning it "macOS" style, which is the path from the internal iPhone file system
match filename.rsplit_once("/") {
Some((_, filename)) => Ok(format!("{}/{}/{} > {}", db_path_os_string, &hash[0..2], hash, filename)),
None => Ok(filename.to_string()),
}
again I'm not entirely sure how you want the program to handle it or what syntactic style you prefer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
I think the logic for the iOS parsing should be split out somewhere so that it can be tested separately.
-
I think this whole block will be a lot cleaner once we use an enum instead of a
bool
here, so I will wait to review it until that changes.
If it makes things easier, I can merge this current branch into another feature branch and make all of these fixes myself. You've done a lot of work here; since I'm going to reorganize some of this anyway I may as well also build these requested fixes. If you just wrap up the enum aspect, I will merge this and clean the rest up in my own way. |
I fixed up a lot of the little things (the unwraps, removing the unused constant, made the ios error message more clear) and im currently in progress on the enum. Ill push everything that I have by the end of today (~4:00 AM Wednesday (GMT)). |
also updated runtime tests to include ImportPlatform enum, but they remain unused
using in txt.rs left very verbose in for changes
not entirely sure how errors should be handled
Alright, I took a swing at creating the enum and impl for it. Hopefully it makes the reorganizing easier for you. I would love to see how this feature ends up looking in the end as this was my first time writing "production" rust. Thank you for your help and insight, I learned a lot! |
This is really good work, you should be proud of it! |
Adding full support for iOS backups
The Problem
So I noticed in multiple reddit threads people were asking you if this tool could be used on iOS backups.[1] [2]
I also wanted to do this, but the first issue is "where is the
chat.db
file?" How does one extract the chat info, attachments, etc when the backup has nonsense hashed file names? Building off of this, how can we retain most of the core code while still allowing backups from iOS? It shouldn't be tedious either and should work from any backup location as people might use Finder, iMazing, or an external drive which all store the backup in different locations.Finding
chat.db
From my limited testing and thanks to @nprezant's work 5 years ago, it seems that iOS backups keep their chat.db file in the same location:
$PATH_TO_BACKUP/3d/3d0d7e5fb2ce288813306e4d4636395e047a3d28
. After finding this I did a test run and found that the messages backed up no problem but there were no attachmentsNotice that all the file paths are paths from the iOS system, meaning that all the attachments are stored somewhere in the backup, they are just hidden by the hash.
If all you want is texts from your iPhone run the following
Finding 'contacts.db'
One thing I also found that might prove helpful for issues like #61 is a
contacts.db
stored at:$PATH_TO_BACKUP/31/31bb7ba8914766d4ba40d6dfb6113c8b614be442
Since the hash is a consistent pattern, these two file locations shouldn't change, but there is no guarantee.
The Hash
How the files are hashed from "original path" -> "hashed path" is as follows:
so for example,
Thanks again to nprazent
The
SHA1
hash requires the crate sha1 v0.10.5 to be added to the `Cargo.toml'3aa1620
imessage-exporter/imessage-exporter/Cargo.toml
Line 19 in 3aa1620
--ios
CLI ArgumentSince the backup exists in its own little world, and I didn't want to rewrite a lot of the reader and exporter, I thought the best option was to add a
--ios
flag which requires the-p, --db-path
to point to the folder holding the iOS backup. So this would beLibrary/Application\ Support/MobileSync/Backup/<backup-version>
This is what the help dialogue says for the option
imessage-exporter/imessage-exporter/src/app/options.rs
Lines 39 to 58 in 592973c
imessage-exporter/imessage-exporter/src/app/options.rs
Line 71 in 592973c
imessage-exporter/imessage-exporter/src/app/options.rs
Lines 286 to 292 in 8b25dc2
Validating the path
I found that the best way to validate the path was to check for the aforementioned chat.db.
imessage-exporter/imessage-exporter/src/app/options.rs
Lines 119 to 127 in 592973c
The value for the path is a public constant, and while I was at it I added the contact.db file location as well in case it's used later, even though it is unused code
imessage-exporter/imessage-exporter/src/app/options.rs
Lines 14 to 17 in 592973c
Establishing the database connection
Since the iOS Backup lives in its own directory, the path of the
chat.db
needs to be appended to the path to the iOS backup. However, if the iOS option is not enabled, then the path should remain the same.imessage-exporter/imessage-exporter/src/app/runtime.rs
Lines 168 to 174 in ae0b29b
HTML Exporter
Since the HTML Exporter already has
resolved_attachment_path
to resolve the relative path, simply adding a control flow statement to determine which path is used was all that was necessary. If theios
flag is true, then the path to the attachment from the database will be rehashed to find its location in the backup. This seemed to work perfectly and attachments were appearing in the html files no problems.imessage-exporter/imessage-exporter/src/exporters/html.rs
Lines 404 to 415 in 034c908
The exporter properly creates the
Attachments
folder, where each subdirectory uses thechat_id
and each file name is the "original" file name and not the "hashed" one.TXT Exporter
I thought it fitting I should still update the TXT Exporter using these file paths, as the ones it would display were files that did not exist on the machine.
Possible improvements
--ios
arugment location, I put it at the end, but probably having it appear closer to the front would be better-p
argument should be used with it\
. I made sure to add that back in for the TXT export, but having the option to shave it off would be nice as I am sure many people will "drop" their iOS backup directory into the terminal and not know they have to remove the escape character for the path to read properlyThanks again to @nprezant and their repo iMessageBackup
and yes the emojis are non negotiable 😜