Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions src/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ use crate::download::{
use crate::ensure_and_debug_assert_eq;
use crate::ephemeral::{Timer as EphemeralTimer, start_chat_ephemeral_timers};
use crate::events::EventType;
use crate::key;
use crate::key::{Fingerprint, self_fingerprint};
use crate::location;
use crate::log::{LogExt, warn};
use crate::logged_debug_assert;
use crate::message::{self, Message, MessageState, MsgId, Viewtype};
use crate::mimefactory;
use crate::mimefactory::{MimeFactory, RenderedEmail};
use crate::mimeparser::SystemMessage;
use crate::param::{Param, Params};
Expand Down Expand Up @@ -2766,6 +2768,10 @@ async fn render_mime_message_and_pre_message(
msg: &mut Message,
mimefactory: MimeFactory,
) -> Result<(Option<RenderedEmail>, RenderedEmail)> {
let from_addr = context.get_primary_self_addr().await?;
let public_key = key::load_self_public_key(context).await?;
let secret_key = key::load_self_secret_key(context).await?;

let needs_pre_message = msg.viewtype.has_file()
&& mimefactory.will_be_encrypted() // unencrypted is likely email, we don't want to spam by sending multiple messages
&& msg
Expand All @@ -2782,15 +2788,31 @@ async fn render_mime_message_and_pre_message(

let mut mimefactory_post_msg = mimefactory.clone();
mimefactory_post_msg.set_as_post_message();
let rendered_msg = Box::pin(mimefactory_post_msg.render(context))
let (queued_msg, side_effects) = Box::pin(mimefactory_post_msg.into_queued_mail(context))
.await
.context("Failed to render post-message")?;

let rendered_msg = mimefactory::render_queued_mail(
queued_msg,
&public_key,
&secret_key,
from_addr.clone(),
side_effects,
)?;

let mut mimefactory_pre_msg = mimefactory;
mimefactory_pre_msg.set_as_pre_message_for(&rendered_msg);
let rendered_pre_msg = Box::pin(mimefactory_pre_msg.render(context))
.await
.context("pre-message failed to render")?;
let (queued_pre_msg, pre_side_effects) =
Box::pin(mimefactory_pre_msg.into_queued_mail(context))
.await
.context("pre-message failed to render")?;
let rendered_pre_msg = mimefactory::render_queued_mail(
queued_pre_msg,
&public_key,
&secret_key,
from_addr,
pre_side_effects,
)?;

if rendered_pre_msg.message.len() > PRE_MSG_SIZE_WARNING_THRESHOLD {
warn!(
Expand All @@ -2803,7 +2825,16 @@ async fn render_mime_message_and_pre_message(

Ok((Some(rendered_pre_msg), rendered_msg))
} else {
Ok((None, Box::pin(mimefactory.render(context)).await?))
let (queued_msg, side_effects) = Box::pin(mimefactory.into_queued_mail(context)).await?;
let rendered_msg = mimefactory::render_queued_mail(
queued_msg,
&public_key,
&secret_key,
from_addr,
side_effects,
)?;

Ok((None, rendered_msg))
}
}

Expand Down Expand Up @@ -2848,7 +2879,6 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
return Err(err);
}
};
let attach_selfavatar = mimefactory.attach_selfavatar;
let mut recipients = mimefactory.recipients();

// Default Webxdc integrations are hidden messages and must not be sent out:
Expand Down Expand Up @@ -2930,22 +2960,30 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -

let now = time();

if let Some(last_added_location_timestamp) = rendered_msg.last_added_location_timestamp {
if let Some(last_added_location_timestamp) =
rendered_msg.side_effects.last_added_location_timestamp
{
location::set_kml_sent_timestamp(context, msg.chat_id, last_added_location_timestamp)
.await?;
}

if attach_selfavatar && let Err(err) = msg.chat_id.set_selfavatar_timestamp(context, now).await
if rendered_msg.side_effects.avatar_is_attached
|| rendered_pre_msg
.as_ref()
.is_some_and(|msg| msg.side_effects.avatar_is_attached)
{
error!(context, "Failed to set selfavatar timestamp: {err:#}.");
msg.chat_id
.set_selfavatar_timestamp(context, now)
.await
.context("Failed to set selfavatar timestamp")?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this changed from just logging an error in the background to aborting create_send_msg_jobs?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that the reason is that if one SQL statement errors, then there is usually not much point in continuing to try using the database (except there is a syntax error in the SQL statement, but then every test touching this code would fail)

}

if rendered_msg.is_encrypted {
msg.param.set_int(Param::GuaranteeE2ee, 1);
} else {
msg.param.remove(Param::GuaranteeE2ee);
}
msg.subject.clone_from(&rendered_msg.subject);
msg.subject.clone_from(&rendered_msg.side_effects.subject);
// Sort the message to the bottom. Employ `msgs_index7` to compute `timestamp`.
context
.sql
Expand Down Expand Up @@ -2977,7 +3015,7 @@ WHERE id=?
let trans_fn = |t: &mut rusqlite::Transaction| {
let mut row_ids = Vec::<i64>::new();

if let Some(sync_ids) = rendered_msg.sync_ids_to_delete {
if let Some(sync_ids) = rendered_msg.side_effects.sync_ids_to_delete {
t.execute(
&format!("DELETE FROM multi_device_sync WHERE id IN ({sync_ids})"),
(),
Expand Down
6 changes: 4 additions & 2 deletions src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,9 @@ pub(crate) async fn download_msg(
delete_from_available_post_msgs(context, &rfc724_mid).await?;
return Ok(None);
};
Box::pin(session.fetch_single_msg(context, &server_folder, server_uid, rfc724_mid)).await?;
session
.fetch_single_msg(context, &server_folder, server_uid, rfc724_mid)
.await?;

let bcc_self = context.get_config_bool(Config::BccSelf).await?;
if ephemeral::should_delete_all_downloaded_messages(bcc_self, session.is_chatmail()) {
Expand Down Expand Up @@ -204,7 +206,7 @@ impl Session {
let (sender, receiver) = async_channel::unbounded();
{
let _fetch_msgs_lock_guard = context.fetch_msgs_mutex.lock().await;
self.fetch_many_msgs(context, folder, vec![uid], &uid_message_ids, sender)
Box::pin(self.fetch_many_msgs(context, folder, vec![uid], &uid_message_ids, sender))
Comment thread
link2xt marked this conversation as resolved.
.await?;
}
if receiver.recv().await.is_err() {
Expand Down
100 changes: 2 additions & 98 deletions src/e2ee.rs
Original file line number Diff line number Diff line change
@@ -1,105 +1,9 @@
//! End-to-end encryption support.

use std::io::Cursor;

use anyhow::Result;
use mail_builder::mime::MimePart;

use crate::aheader::{Aheader, EncryptPreference};
use crate::context::Context;
use crate::key::{SignedPublicKey, load_self_public_key, load_self_secret_key};
use crate::pgp::{self, SeipdVersion};

#[derive(Debug)]
pub struct EncryptHelper {
pub addr: String,
pub public_key: SignedPublicKey,
}

impl EncryptHelper {
pub async fn new(context: &Context) -> Result<EncryptHelper> {
let addr = context.get_primary_self_addr().await?;
let public_key = load_self_public_key(context).await?;

Ok(EncryptHelper { addr, public_key })
}

pub fn get_aheader(&self) -> Aheader {
Aheader {
addr: self.addr.clone(),
public_key: self.public_key.clone(),
prefer_encrypt: EncryptPreference::Mutual,
verified: false,
}
}

/// Tries to encrypt the passed in `mail`.
pub async fn encrypt(
self,
context: &Context,
keyring: Vec<SignedPublicKey>,
mail_to_encrypt: MimePart<'static>,
compress: bool,
seipd_version: SeipdVersion,
) -> Result<String> {
let mut raw_message = Vec::new();
let cursor = Cursor::new(&mut raw_message);
mail_to_encrypt.clone().write_part(cursor).ok();

let ctext = self
.encrypt_raw(context, keyring, raw_message, compress, seipd_version)
.await?;
Ok(ctext)
}

pub async fn encrypt_raw(
self,
context: &Context,
keyring: Vec<SignedPublicKey>,
raw_message: Vec<u8>,
compress: bool,
seipd_version: SeipdVersion,
) -> Result<String> {
let sign_key = load_self_secret_key(context).await?;
let ctext =
pgp::pk_encrypt(raw_message, keyring, sign_key, compress, seipd_version).await?;

Ok(ctext)
}

/// Symmetrically encrypt the message. This is used for broadcast channels.
/// `shared secret` is the secret that will be used for symmetric encryption.
pub async fn encrypt_symmetrically(
self,
context: &Context,
shared_secret: &str,
mail_to_encrypt: MimePart<'static>,
compress: bool,
sign: bool,
) -> Result<String> {
let sign_key = if sign {
Some(load_self_secret_key(context).await?)
} else {
None
};

let shared_secret = shared_secret.to_string();
let mut raw_message = Vec::new();
let cursor = Cursor::new(&mut raw_message);
mail_to_encrypt.clone().write_part(cursor).ok();

let ctext = tokio::task::spawn_blocking(move || {
pgp::symm_encrypt_message(raw_message, sign_key, shared_secret, compress)
})
.await??;

Ok(ctext)
}
}

#[cfg(test)]
mod tests {
use super::*;
use anyhow::Result;

use crate::chat;
use crate::chat::send_text_msg;
use crate::config::Config;
Expand Down
Loading