Skip to content

Commit

Permalink
Merge branch 'develop' into feat/cs/restore-deleted-messages
Browse files Browse the repository at this point in the history
  • Loading branch information
ReagentX committed Apr 26, 2023
2 parents 4b33ff9 + df64228 commit 200b244
Show file tree
Hide file tree
Showing 18 changed files with 635 additions and 212 deletions.
66 changes: 66 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Documentation for the library is located [here](imessage-database/README.md).

### Supported Features

This crate supports every iMessage feature as of MacOS 13.3.1 (22E261):
This crate supports every iMessage feature as of MacOS 13.3.1 (22E261) and iOS 16.4.1 (20E252):

- Multi-part messages
- Replies/Threads
Expand Down
1 change: 1 addition & 0 deletions imessage-database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ version = "0.0.0"
chrono = "0.4.24"
plist = "1.4.3"
rusqlite = {version = "0.29.0", features = ["blob", "bundled"]}
sha1 = "0.10.5"
116 changes: 107 additions & 9 deletions imessage-database/src/tables/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

use rusqlite::{Connection, Error, Error as E, Result, Row, Statement};
use sha1::{Digest, Sha1};
use std::path::{Path, PathBuf};

use crate::{
Expand All @@ -14,6 +15,7 @@ use crate::{
util::{
dirs::home,
output::{done_processing, processing},
platform::Platform,
},
};

Expand Down Expand Up @@ -61,13 +63,8 @@ impl Table for Attachment {

fn extract(attachment: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match attachment {
Ok(attachment) => match attachment {
Ok(att) => Ok(att),
// TODO: When does this occur?
Err(why) => Err(TableError::Attachment(why)),
},
// TODO: When does this occur?
Err(why) => Err(TableError::Attachment(why)),
Ok(Ok(attachment)) => Ok(attachment),
Err(why) | Ok(Err(why)) => Err(TableError::Attachment(why)),
}
}
}
Expand Down Expand Up @@ -210,13 +207,53 @@ impl Attachment {
}
"Attachment missing name metadata!"
}

/// Given a platform and database source, resolve the path for the current attachment
///
/// For MacOS, `db_path` is unused. For iOS, `db_path` is the path to the root of the backup directory.
///
/// iOS Parsing logic source is from [here](https://github.com/nprezant/iMessageBackup/blob/940d001fb7be557d5d57504eb26b3489e88de26e/imessage_backup_tools.py#L83-L85).
pub fn resolved_attachment_path(&self, platform: &Platform, db_path: &Path) -> Option<String> {
if let Some(path_str) = &self.filename {
match platform {
Platform::MacOS => {
if path_str.starts_with('~') {
return Some(path_str.replace('~', &home()));
}
return Some(path_str.to_string());
}
Platform::iOS => {
let input = match path_str.get(2..) {
Some(input) => input,
None => return None,
};

let filename = format!(
"{:x}",
Sha1::digest(format!("MediaDomain-{input}").as_bytes())
);

let directory = match filename.get(0..2) {
Some(dir) => dir,
None => return None,
};

return Some(format!("{}/{directory}/{filename}", db_path.display()));
}
}
}
None
}
}

#[cfg(test)]
mod tests {
use crate::tables::attachment::{Attachment, MediaType};
use crate::{
tables::attachment::{Attachment, MediaType},
util::platform::Platform,
};

use std::path::Path;
use std::path::{Path, PathBuf};

fn sample_attachment() -> Attachment {
Attachment {
Expand Down Expand Up @@ -303,4 +340,65 @@ mod tests {
attachment.filename = None;
assert_eq!(attachment.filename(), "Attachment missing name metadata!");
}

#[test]
fn can_get_resolved_path_macos() {
let db_path = PathBuf::from("fake_root");
let attachment = sample_attachment();

assert_eq!(
attachment.resolved_attachment_path(&Platform::MacOS, &db_path),
Some("a/b/c.png".to_string())
);
}

#[test]
fn can_get_resolved_path_macos_raw() {
let db_path = PathBuf::from("fake_root");
let mut attachment = sample_attachment();
attachment.filename = Some("~/a/b/c.png".to_string());

assert!(
attachment
.resolved_attachment_path(&Platform::MacOS, &db_path)
.unwrap()
.len()
> attachment.filename.unwrap().len()
);
}

#[test]
fn can_get_resolved_path_ios() {
let db_path = PathBuf::from("fake_root");
let attachment = sample_attachment();

assert_eq!(
attachment.resolved_attachment_path(&Platform::iOS, &db_path),
Some("fake_root/41/41746ffc65924078eae42725c979305626f57cca".to_string())
);
}

#[test]
fn cant_get_missing_resolved_path_macos() {
let db_path = PathBuf::from("fake_root");
let mut attachment = sample_attachment();
attachment.filename = None;

assert_eq!(
attachment.resolved_attachment_path(&Platform::MacOS, &db_path),
None
);
}

#[test]
fn cant_get_missing_resolved_path_ios() {
let db_path = PathBuf::from("fake_root");
let mut attachment = sample_attachment();
attachment.filename = None;

assert_eq!(
attachment.resolved_attachment_path(&Platform::iOS, &db_path),
None
);
}
}
9 changes: 2 additions & 7 deletions imessage-database/src/tables/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,8 @@ impl Table for Chat {

fn extract(chat: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match chat {
Ok(chat) => match chat {
Ok(ch) => Ok(ch),
// TODO: When does this occur?
Err(why) => Err(TableError::Chat(why)),
},
// TODO: When does this occur?
Err(why) => Err(TableError::Chat(why)),
Ok(Ok(chat)) => Ok(chat),
Err(why) | Ok(Err(why)) => Err(TableError::Chat(why)),
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions imessage-database/src/tables/chat_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,8 @@ impl Table for ChatToHandle {

fn extract(chat_to_handle: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match chat_to_handle {
Ok(chat_to_handle) => match chat_to_handle {
Ok(c2h) => Ok(c2h),
// TODO: When does this occur?
Err(why) => Err(TableError::ChatToHandle(why)),
},
// TODO: When does this occur?
Err(why) => Err(TableError::ChatToHandle(why)),
Ok(Ok(chat_to_handle)) => Ok(chat_to_handle),
Err(why) | Ok(Err(why)) => Err(TableError::ChatToHandle(why)),
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions imessage-database/src/tables/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,8 @@ impl Table for Handle {

fn extract(handle: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match handle {
Ok(handle) => match handle {
Ok(hdl) => Ok(hdl),
// TODO: When does this occur?
Err(why) => Err(TableError::Handle(why)),
},
// TODO: When does this occur?
Err(why) => Err(TableError::Handle(why)),
Ok(Ok(handle)) => Ok(handle),
Err(why) | Ok(Err(why)) => Err(TableError::Handle(why)),
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions imessage-database/src/tables/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,8 @@ impl Table for Message {

fn extract(message: Result<Result<Self, Error>, Error>) -> Result<Self, TableError> {
match message {
Ok(message) => match message {
Ok(msg) => Ok(msg),
// TODO: When does this occur?
Err(why) => Err(TableError::Messages(why)),
},
// TODO: When does this occur?
Err(why) => Err(TableError::Messages(why)),
Ok(Ok(message)) => Ok(message),
Err(why) | Ok(Err(why)) => Err(TableError::Messages(why)),
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions imessage-database/src/tables/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,10 @@ pub const ME: &str = "Me";
pub const YOU: &str = "You";
/// Name used for contacts or chats where the name cannot be discovered
pub const UNKNOWN: &str = "Unknown";
/// Default location for the Messages database
pub const DEFAULT_PATH: &str = "Library/Messages/chat.db";
/// Default location for the Messages database on MacOS
pub const DEFAULT_PATH_MACOS: &str = "Library/Messages/chat.db";
/// Default location for the Messages database in an unencrypted iOS backup
pub const DEFAULT_PATH_IOS: &str = "3d/3d0d7e5fb2ce288813306e4d4636395e047a3d28";
/// Chat name reserved for messages that do not belong to a chat in the table
pub const ORPHANED: &str = "orphaned";
/// Maximum length a filename can be
Expand Down
6 changes: 3 additions & 3 deletions imessage-database/src/util/dirs.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*!
Contains functions that generate the correct path to the default iMessage database location.
Contains functions that generate the correct path to the default iMessage database location
*/

use std::{env::var, path::PathBuf};

use crate::tables::table::DEFAULT_PATH;
use crate::tables::table::DEFAULT_PATH_MACOS;

/// Get the user's home directory (MacOS only)
///
Expand Down Expand Up @@ -34,5 +34,5 @@ pub fn home() -> String {
/// println!("{path:?}");
/// ```
pub fn default_db_path() -> PathBuf {
PathBuf::from(format!("{}/{DEFAULT_PATH}", home()))
PathBuf::from(format!("{}/{DEFAULT_PATH_MACOS}", home()))
}
1 change: 1 addition & 0 deletions imessage-database/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
pub mod dates;
pub mod dirs;
pub mod output;
pub mod platform;
pub mod plist;
pub mod query_context;
pub mod streamtyped;
2 changes: 1 addition & 1 deletion imessage-database/src/util/output.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
Contains method to emit a loading message while we do other work.
Contains method to emit a loading message while we do other work
*/

use std::io::{stdout, Write};
Expand Down
Loading

0 comments on commit 200b244

Please sign in to comment.