Skip to content

Commit

Permalink
Merge pull request #329 from crepererum-oss/crepererum/issue259
Browse files Browse the repository at this point in the history
feat: allow ignoring new/non-decryptable mails
  • Loading branch information
crepererum authored Dec 8, 2024
2 parents 7bc582a + d4b6a6f commit 85a7a42
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 8 deletions.
19 changes: 19 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ uuid = { version = "1.11.0", features = ["v4"] }
assert_cmd = "2.0.16"
hex-literal = "0.4.1"
insta = "1.41.1"
predicates = "3.1.2"
similar-asserts = "1.6.0"
tempfile = "3"

Expand Down
31 changes: 25 additions & 6 deletions src/mails.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ impl Mail {
client: &Client,
session: &Session,
folder: &Folder,
ignore_new_mails: bool,
) -> impl Stream<Item = Result<Arc<Self>>> {
let group_keys = Arc::clone(&session.group_keys);
let folder_id = folder.id.clone();
Expand All @@ -69,18 +70,36 @@ impl Mail {
let group_keys = Arc::clone(&group_keys);
let folder_id = folder_id.clone();
async move {
let mail = Self::decode(m, &group_keys, folder_id)?;
Ok(Arc::new(mail))
Self::decode(m, &group_keys, folder_id)
}
})
.try_filter_map(move |mail| async move {
match mail {
Some(mail) => Ok(Some(Arc::new(mail))),
None if ignore_new_mails => Ok(None),
None => bail!("Folder contains new mail that has not been decoded before. Use the official app and view the folder to decode the data, or pass --ignore-new-mails to skip new emails."),
}
})
}

fn decode(resp: MailReponse, group_keys: &GroupKeys, folder_id: String) -> Result<Self> {
/// Decode [`MailReponse`].
///
/// Returns [`None`] if no encryption key is set. This usually happens when the mail was NOT
/// processed via the official app yet.
fn decode(
resp: MailReponse,
group_keys: &GroupKeys,
folder_id: String,
) -> Result<Option<Self>> {
let Some(key) = resp.owner_enc_session_key else {
return Ok(None);
};

let session_key = decrypt_key(
group_keys
.get(&resp.owner_group)
.context("getting owner group key")?,
resp.owner_enc_session_key,
key,
)
.context("decrypting session key")?;

Expand All @@ -100,7 +119,7 @@ impl Mail {
}
};

Ok(Self {
Ok(Some(Self {
folder_id,
mail_id: resp.id[1].clone(),
archive_id,
Expand All @@ -111,7 +130,7 @@ impl Mail {
subject,
sender,
attachments: resp.attachments,
})
}))
}

pub(crate) fn ui_url(&self) -> String {
Expand Down
11 changes: 10 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use tracing::{debug, info};
#[cfg(test)]
use assert_cmd as _;
#[cfg(test)]
use predicates as _;
#[cfg(test)]
use similar_asserts as _;
#[cfg(test)]
use tempfile as _;
Expand Down Expand Up @@ -79,6 +81,13 @@ struct DownloadCLIConfig {
/// Target path.
#[clap(long, action)]
path: PathBuf,

/// Ignore new mails that cannot be decrypted (yet).
///
/// Use the official app to view and respective folder. This will convert the mail data to a
/// format that we can read.
#[clap(long, action)]
ignore_new_mails: bool,
}

/// Command
Expand Down Expand Up @@ -149,7 +158,7 @@ async fn exec_cmd(client: &Client, session: &Session, cmd: Command) -> Result<()
.context("folder not found")?;
debug!(mails = folder.mails.as_str(), "download mails from folder");

Mail::list(client, session, &folder)
Mail::list(client, session, &folder, cfg.ignore_new_mails)
.map(|mail| {
let cfg = &cfg;

Expand Down
2 changes: 1 addition & 1 deletion src/proto/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ pub(crate) struct MailReponse {
pub(crate) _format: Format<0>,

#[serde(rename = "_ownerEncSessionKey")]
pub(crate) owner_enc_session_key: EncryptedKey,
pub(crate) owner_enc_session_key: Option<EncryptedKey>,

#[serde(rename = "_ownerGroup")]
pub(crate) owner_group: String,
Expand Down
30 changes: 30 additions & 0 deletions tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,34 @@ mod integration {
similar_asserts::assert_eq!(actual_content, expected_content);
}
}

#[test]
fn test_new_mail_without_flag() {
let path = TempDir::new().unwrap();

let mut cmd = cmd();
cmd.arg("-vv")
.arg("download")
.arg("--folder=Inbox")
.arg("--path")
.arg(path.path())
.assert()
.failure()
.stderr(predicates::str::contains("--ignore-new-mails"));
}

#[test]
fn test_new_mail_with_flag() {
let path = TempDir::new().unwrap();

let mut cmd = cmd();
cmd.arg("-vv")
.arg("download")
.arg("--folder=Inbox")
.arg("--path")
.arg(path.path())
.arg("--ignore-new-mails")
.assert()
.success();
}
}

0 comments on commit 85a7a42

Please sign in to comment.