diff --git a/Cargo.lock b/Cargo.lock index aeb2b4fb4..0526d1706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,7 +99,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures_codec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures_codec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "imap-proto 0.9.1 (git+https://github.com/djc/tokio-imap)", "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1116,7 +1116,7 @@ dependencies = [ [[package]] name = "futures_codec" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3483,7 +3483,7 @@ dependencies = [ "checksum futures-timer 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a1de7508b218029b0f01662ed8f61b1c964b3ae99d6f25462d0f55a595109df6" "checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76" "checksum futures-util-preview 0.3.0-alpha.19 (registry+https://github.com/rust-lang/crates.io-index)" = "5ce968633c17e5f97936bd2797b6e38fb56cf16a7422319f7ec2e30d3c470e8d" -"checksum futures_codec 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b4043054a6220de5dc5c814eb82ab6fd7cd2b6574a844406f651ec688cfa6fcc" +"checksum futures_codec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "793d2283ff61ffff52d51cc631be0c8e75370d96056a38e09f124a67263913da" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" diff --git a/src/e2ee.rs b/src/e2ee.rs index d510a623c..f48dc8452 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -10,7 +10,6 @@ use crate::context::Context; use crate::error::*; use crate::key::*; use crate::keyring::*; -use crate::mimefactory::MimeFactory; use crate::peerstate::*; use crate::pgp; use crate::securejoin::handle_degrade_event; @@ -89,19 +88,17 @@ impl EncryptHelper { } /// Tries to encrypt the passed in `mail`. - pub fn try_encrypt( + pub fn encrypt( &mut self, - factory: &mut MimeFactory, + context: &Context, e2ee_guaranteed: bool, min_verified: PeerstateVerifiedStatus, do_gossip: bool, - mut mail: lettre_email::Email, - imffields_unprotected: Vec, + mut mail_to_encrypt: lettre_email::PartBuilder, peerstates: &[(Option, &str)], - ) -> Result<(lettre_email::Email, bool)> { - let context = &factory.context; + ) -> Result { let mut keyring = Keyring::default(); - let mut gossip_headers: Vec = Vec::with_capacity(factory.recipients_addr.len()); + let mut gossip_headers: Vec = Vec::with_capacity(peerstates.len()); for (peerstate, addr) in peerstates .iter() @@ -129,109 +126,16 @@ impl EncryptHelper { key }; - // encrypt message - use lettre_email::{EmailBuilder, MimeMessage, PartBuilder}; - - // let mut part_to_encrypt: lettre::SendableEmail = mail.into().to_string()?.into_bytes(); - - let mut mail_to_encrypt = EmailBuilder::new(); - + // Add gossip headers for header in &gossip_headers { mail_to_encrypt = mail_to_encrypt.header(("Autocrypt-Gossip", header)); } - // memoryhole headers: move some headers into encrypted part + let raw_message = mail_to_encrypt.build().as_string().into_bytes(); - // while !cur.is_null() { - // let field = (*cur).data as *mut mailimf_field; - // let mut move_to_encrypted = false; + let ctext = pgp::pk_encrypt(&raw_message, &keyring, sign_key.as_ref())?; - // if !field.is_null() { - // if (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int { - // move_to_encrypted = true; - // } else if (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int { - // let opt_field = (*field).fld_data.fld_optional_field; - // if !opt_field.is_null() && !(*opt_field).fld_name.is_null() { - // let fld_name = to_string_lossy((*opt_field).fld_name); - // if fld_name.starts_with("Secure-Join") - // || (fld_name.starts_with("Chat-") && fld_name != "Chat-Version") - // { - // move_to_encrypted = true; - // } - // } - // } - // } - - // if move_to_encrypted { - // mailimf_fields_add(imffields_encrypted, field); - // cur = clist_delete((*imffields_unprotected).fld_list, cur); - // } else { - // cur = (*cur).next; - // } - // } - - // let subject = mailimf_subject_new("...".strdup()); - // mailimf_fields_add(imffields_unprotected, mailimf_field_new_subject(subject)); - - // wrapmime::append_ct_param( - // (*part_to_encrypt).mm_content_type, - // "protected-headers", - // "v1", - // )?; - // let plain = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char); - // let mut col = 0; - // mailmime_write_mem(plain, &mut col, message_to_encrypt); - // mailmime_free(message_to_encrypt); - - // ensure!( - // !(*plain).str_0.is_null() && (*plain).len > 0, - // "could not write/allocate" - // ); - - // let ctext = pgp::pk_encrypt( - // std::slice::from_raw_parts((*plain).str_0 as *const u8, (*plain).len), - // &keyring, - // sign_key.as_ref(), - // ); - // mmap_string_free(plain); - - // let ctext_v = ctext?; - - // // create MIME-structure that will contain the encrypted text - // let mut encrypted_part = new_data_part( - // ptr::null_mut(), - // 0 as libc::size_t, - // "multipart/encrypted", - // MAILMIME_MECHANISM_BASE64, - // )?; - // let content = (*encrypted_part).mm_content_type; - // wrapmime::append_ct_param(content, "protocol", "application/pgp-encrypted")?; - - // let version_mime = new_data_part( - // VERSION_CONTENT.as_mut_ptr() as *mut libc::c_void, - // strlen(VERSION_CONTENT.as_mut_ptr()), - // "application/pgp-encrypted", - // MAILMIME_MECHANISM_7BIT, - // )?; - // mailmime_smart_add_part(encrypted_part, version_mime); - - // // we assume that ctext_v is not dropped until the end - // // of this if-scope - // let ctext_part = new_data_part( - // ctext_v.as_ptr() as *mut libc::c_void, - // ctext_v.len(), - // "application/octet-stream", - // MAILMIME_MECHANISM_7BIT, - // )?; - - // mailmime_smart_add_part(encrypted_part, ctext_part); - // (*in_out_message).mm_data.mm_message.mm_msg_mime = encrypted_part; - // (*encrypted_part).mm_parent = in_out_message; - - // let gossiped = !&gossip_headers.is_empty(); - // factory.finalize_mime_message(true, gossiped)?; - - Ok((mail_to_encrypt.build()?, true)) + Ok(ctext) } } diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 1b36ce2f7..6462a3bcb 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -300,13 +300,9 @@ impl<'a> MimeFactory<'a> { "Invalid use of mimefactory-object." ); - let context = &self.context; - let peerstates = self.peerstates_for_recipients()?; let e2ee_guranteed = self.is_e2ee_guranteed()?; - let mut encrypt_helper = EncryptHelper::new(&context)?; - let should_encrypt = - encrypt_helper.should_encrypt(self.context, e2ee_guranteed, &peerstates)?; + let mut encrypt_helper = EncryptHelper::new(self.context)?; // Headers that are encrypted // - Chat-*, except Chat-Version @@ -400,23 +396,62 @@ impl<'a> MimeFactory<'a> { unprotected_headers.push(Header::new("Autocrypt".into(), aheader)); } + protected_headers.push(Header::new("Subject".into(), subject)); + + let peerstates = self.peerstates_for_recipients()?; + let should_encrypt = + encrypt_helper.should_encrypt(self.context, e2ee_guranteed, &peerstates)?; + let mut outer_message = if should_encrypt && force_plaintext == 0 { for header in protected_headers.into_iter() { message = message.header(header); } - let mut outer_message = PartBuilder::new(); + // Manual Content-Type only works with https://github.com/niax/rust-email/pull/51 + // At the moment the boundary will not be inserted. + let mut outer_message = PartBuilder::new().header(( + "Content-Type".to_string(), + "multipart/encrypted; protocol=\"application/pgp-encrypted\"".to_string(), + )); + for header in unprotected_headers.into_iter() { outer_message = outer_message.header(header); } - // if let Some(encrypted) = encrypt_helper.try_encrypt( - // self, - // e2ee_guaranteed, - // min_verified, - // do_gossip, - // message, - // imffields_unprotected, - // )? { + + let encrypted = encrypt_helper.encrypt( + self.context, + e2ee_guranteed, + min_verified, + do_gossip, + message, + &peerstates, + )?; + + outer_message = outer_message + .child( + // Autocrypt part 1 + PartBuilder::new() + .content_type(&"application/pgp-encrypted".parse::().unwrap()) + .header(("Content-Description", "PGP/MIME version identification")) + .body("Version: 1") + .build(), + ) + .child( + // Autocrypt part 2 + PartBuilder::new() + .content_type( + &"application/octet-stream; name=\"encrypted.asc\"" + .parse::() + .unwrap(), + ) + .header(("Content-Description", "OpenPGP encrypted message")) + .header(("Content-Disposition", "inline; filename=\"encrypted.asc\"")) + .body(encrypted) + .build(), + ) + .header(("Subject".to_string(), "...".to_string())); + + self.finalize_mime_message(true, do_gossip && !peerstates.is_empty())?; outer_message } else { @@ -434,8 +469,7 @@ impl<'a> MimeFactory<'a> { outer_message = outer_message .header(Header::new_with_value("To".into(), to).unwrap()) - .header(Header::new_with_value("From".into(), vec![from]).unwrap()) - .header(Header::new("Subject".into(), subject)); + .header(Header::new_with_value("From".into(), vec![from]).unwrap()); // TODO // self.envelope = Some(Envelope::new(Some(from), to).expect("setting from"));