mirror of
https://github.com/chatmail/core.git
synced 2026-09-22 04:58:47 +03:00
refactor: extract shared pieces for non-chat messages
No functional changes: Add a relay_addrs helper, share the protected headers and self-key rendering of non-chat messages, and move insert_into_smtp from securejoin to smtp.
This commit is contained in:
@@ -10,6 +10,8 @@ use deltachat_contact_tools::sanitize_bidi_characters;
|
||||
use iroh_gossip::proto::TopicId;
|
||||
use mail_builder::headers::HeaderType;
|
||||
use mail_builder::headers::address::Address;
|
||||
use mail_builder::headers::raw::Raw;
|
||||
use mail_builder::headers::text::Text;
|
||||
use mail_builder::mime::MimePart;
|
||||
use tokio::fs;
|
||||
|
||||
@@ -32,7 +34,7 @@ use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::Param;
|
||||
use crate::peer_channels::{create_iroh_header, get_iroh_topic_for_msg};
|
||||
use crate::pgp::{SeipdVersion, addresses_from_public_key, pubkey_supports_seipdv2};
|
||||
use crate::pgp::{SeipdVersion, addresses_from_public_key, pubkey_supports_seipdv2, relay_addrs};
|
||||
use crate::simplify::escape_message_footer_marks;
|
||||
use crate::stock_str;
|
||||
use crate::tools::{IsNoneOrEmpty, create_outgoing_rfc724_mid, remove_subject_prefix, time};
|
||||
@@ -578,9 +580,7 @@ impl MimeFactory {
|
||||
|
||||
let public_key = SignedPublicKey::from_slice(&public_key_bytes)?;
|
||||
|
||||
let relays =
|
||||
addresses_from_public_key(&public_key).unwrap_or_else(|| vec![addr.clone()]);
|
||||
recipients.extend(relays);
|
||||
recipients.extend(relay_addrs(&public_key, &addr));
|
||||
to.push((authname, addr.clone()));
|
||||
|
||||
Encryption::Asymmetric {
|
||||
@@ -897,7 +897,7 @@ impl MimeFactory {
|
||||
}
|
||||
} else if contact.is_key_contact() {
|
||||
let encryption_pubkeys = if let Some(key) = contact.public_key(context).await? {
|
||||
recipients = addresses_from_public_key(&key).unwrap_or_else(|| vec![addr.clone()]);
|
||||
recipients = relay_addrs(&key, &addr);
|
||||
vec![(addr.clone(), key)]
|
||||
} else {
|
||||
Vec::new()
|
||||
@@ -2439,6 +2439,42 @@ fn b_encode(value: &str) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the headers to place into the encrypted part
|
||||
/// of messages that are not part of a chat.
|
||||
async fn non_chat_protected_headers(
|
||||
context: &Context,
|
||||
subject: &str,
|
||||
) -> Result<Vec<(&'static str, HeaderType<'static>)>> {
|
||||
let date = chrono::DateTime::<chrono::Utc>::from_timestamp(time(), 0)
|
||||
.unwrap()
|
||||
.to_rfc2822();
|
||||
let mut headers = vec![
|
||||
("To", Address::new_list(vec![hidden_recipients()]).into()),
|
||||
("Date", Raw::new(date).into()),
|
||||
("Subject", Text::new(subject.to_string()).into()),
|
||||
];
|
||||
// Automatic Response headers <https://www.rfc-editor.org/rfc/rfc3834>
|
||||
if context.get_config_bool(Config::Bot).await? {
|
||||
headers.push(("Auto-Submitted", Raw::new("auto-generated").into()));
|
||||
}
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
/// Renders `queued_mail` for SMTP with the own key pair and primary address.
|
||||
async fn render_with_self_key(context: &Context, queued_mail: QueuedMail) -> Result<String> {
|
||||
let public_key = key::load_self_public_key(context).await?;
|
||||
let secret_key = key::load_self_secret_key(context).await?;
|
||||
let from_addr = context.get_primary_self_addr().await?;
|
||||
let rendered_mail = render_queued_mail(
|
||||
queued_mail,
|
||||
&public_key,
|
||||
&secret_key,
|
||||
from_addr,
|
||||
RenderSideEffects::default(),
|
||||
)?;
|
||||
Ok(rendered_mail.message)
|
||||
}
|
||||
|
||||
pub(crate) async fn render_symm_encrypted_securejoin_message(
|
||||
context: &Context,
|
||||
step: &str,
|
||||
@@ -2451,81 +2487,29 @@ pub(crate) async fn render_symm_encrypted_securejoin_message(
|
||||
|
||||
let message: MimePart<'static> = MimePart::new("text/plain", "Secure-Join");
|
||||
|
||||
let mut headers = Vec::<(&'static str, HeaderType<'static>)>::new();
|
||||
|
||||
let to: Vec<Address<'static>> = vec![hidden_recipients()];
|
||||
headers.push((
|
||||
"To",
|
||||
mail_builder::headers::address::Address::new_list(to.clone()).into(),
|
||||
));
|
||||
|
||||
let timestamp = time();
|
||||
let date = chrono::DateTime::<chrono::Utc>::from_timestamp(timestamp, 0)
|
||||
.unwrap()
|
||||
.to_rfc2822();
|
||||
headers.push(("Date", mail_builder::headers::raw::Raw::new(date).into()));
|
||||
|
||||
headers.push((
|
||||
"Subject",
|
||||
mail_builder::headers::text::Text::new("Secure-Join".to_string()).into(),
|
||||
));
|
||||
|
||||
// Automatic Response headers <https://www.rfc-editor.org/rfc/rfc3834>
|
||||
if context.get_config_bool(Config::Bot).await? {
|
||||
headers.push((
|
||||
"Auto-Submitted",
|
||||
mail_builder::headers::raw::Raw::new("auto-generated".to_string()).into(),
|
||||
));
|
||||
}
|
||||
|
||||
headers.push((
|
||||
"Secure-Join",
|
||||
mail_builder::headers::raw::Raw::new(step.to_string()).into(),
|
||||
));
|
||||
|
||||
headers.push((
|
||||
"Secure-Join-Auth",
|
||||
mail_builder::headers::text::Text::new(auth.to_string()).into(),
|
||||
));
|
||||
let mut headers = non_chat_protected_headers(context, "Secure-Join").await?;
|
||||
headers.push(("Secure-Join", Raw::new(step.to_string()).into()));
|
||||
headers.push(("Secure-Join-Auth", Text::new(auth.to_string()).into()));
|
||||
|
||||
let message = add_headers_to_encrypted_part(message, headers);
|
||||
|
||||
// Disable compression for SecureJoin to ensure
|
||||
// there are no compression side channels
|
||||
// leaking information about the tokens.
|
||||
let should_compress = false;
|
||||
|
||||
// Only sign the message if we attach the pubkey.
|
||||
let should_sign = should_attach_pubkey;
|
||||
|
||||
let raw_message = part_to_bytes(message);
|
||||
|
||||
let queued_mail = QueuedMail {
|
||||
raw_message,
|
||||
raw_message: part_to_bytes(message),
|
||||
display_name: String::new(),
|
||||
rfc724_mid: rfc724_mid.to_string(),
|
||||
encryption: Encryption::Symmetric {
|
||||
shared_secret: shared_secret.to_string(),
|
||||
},
|
||||
should_attach_pubkey,
|
||||
should_sign,
|
||||
should_compress,
|
||||
// Only sign the message if we attach the pubkey.
|
||||
should_sign: should_attach_pubkey,
|
||||
// Disable compression for SecureJoin to ensure
|
||||
// there are no compression side channels
|
||||
// leaking information about the tokens.
|
||||
should_compress: false,
|
||||
};
|
||||
|
||||
let public_key = key::load_self_public_key(context).await?;
|
||||
let secret_key = key::load_self_secret_key(context).await?;
|
||||
let side_effects = RenderSideEffects::default();
|
||||
|
||||
let from_addr = context.get_primary_self_addr().await?;
|
||||
let rendered_mail = render_queued_mail(
|
||||
queued_mail,
|
||||
&public_key,
|
||||
&secret_key,
|
||||
from_addr,
|
||||
side_effects,
|
||||
)?;
|
||||
|
||||
Ok(rendered_mail.message)
|
||||
render_with_self_key(context, queued_mail).await
|
||||
}
|
||||
|
||||
/// Renders MIME part into a vector of bytes.
|
||||
|
||||
@@ -452,6 +452,12 @@ pub(crate) fn addresses_from_public_key(public_key: &SignedPublicKey) -> Option<
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the addresses to reach the owner of `public_key`,
|
||||
/// falling back to `addr` if the key carries no relay list.
|
||||
pub(crate) fn relay_addrs(public_key: &SignedPublicKey, addr: &str) -> Vec<String> {
|
||||
addresses_from_public_key(public_key).unwrap_or_else(|| vec![addr.to_string()])
|
||||
}
|
||||
|
||||
/// Returns true if public key advertises SEIPDv2 feature.
|
||||
pub(crate) fn pubkey_supports_seipdv2(public_key: &SignedPublicKey) -> bool {
|
||||
// If any Direct Key Signature or any User ID signature has SEIPDv2 feature,
|
||||
|
||||
@@ -16,11 +16,12 @@ use crate::key;
|
||||
use crate::key::{DcKey, Fingerprint, load_self_public_key, self_fingerprint};
|
||||
use crate::log::LogExt as _;
|
||||
use crate::log::warn;
|
||||
use crate::message::{self, Message, MsgId, Viewtype};
|
||||
use crate::message::{self, Message, Viewtype};
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
use crate::param::Param;
|
||||
use crate::qr::check_qr;
|
||||
use crate::securejoin::bob::JoinerProgress;
|
||||
use crate::smtp::insert_into_smtp;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::{create_id, create_outgoing_rfc724_mid, time};
|
||||
use crate::{SecurejoinSource, mimefactory, stats};
|
||||
@@ -743,24 +744,6 @@ pub(crate) async fn handle_securejoin_handshake(
|
||||
}
|
||||
}
|
||||
|
||||
async fn insert_into_smtp(
|
||||
context: &Context,
|
||||
rfc724_mid: &str,
|
||||
recipients: &str,
|
||||
rendered_message: String,
|
||||
msg_id: MsgId,
|
||||
) -> Result<(), Error> {
|
||||
context
|
||||
.sql
|
||||
.execute(
|
||||
"INSERT INTO smtp (rfc724_mid, recipients, mime, msg_id)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
(&rfc724_mid, &recipients, &rendered_message, msg_id),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Observe self-sent Securejoin message.
|
||||
///
|
||||
/// In a multi-device-setup, there may be other devices that "see" the handshake messages.
|
||||
|
||||
@@ -16,9 +16,8 @@ use crate::message::{self, Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::pgp::addresses_from_public_key;
|
||||
use crate::securejoin::{
|
||||
ContactId, encrypted_and_signed, insert_into_smtp, verify_sender_by_fingerprint,
|
||||
};
|
||||
use crate::securejoin::{ContactId, encrypted_and_signed, verify_sender_by_fingerprint};
|
||||
use crate::smtp::insert_into_smtp;
|
||||
use crate::stock_str;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::{create_outgoing_rfc724_mid, time};
|
||||
|
||||
19
src/smtp.rs
19
src/smtp.rs
@@ -327,6 +327,25 @@ pub(crate) async fn smtp_send(
|
||||
status
|
||||
}
|
||||
|
||||
/// Inserts a rendered message into the `smtp` table for sending.
|
||||
pub(crate) async fn insert_into_smtp(
|
||||
context: &Context,
|
||||
rfc724_mid: &str,
|
||||
recipients: &str,
|
||||
rendered_message: String,
|
||||
msg_id: MsgId,
|
||||
) -> Result<(), Error> {
|
||||
context
|
||||
.sql
|
||||
.execute(
|
||||
"INSERT INTO smtp (rfc724_mid, recipients, mime, msg_id)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
(&rfc724_mid, &recipients, &rendered_message, msg_id),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sends message identified by `smtp` table rowid over SMTP connection.
|
||||
///
|
||||
/// Removes row if the message should not be retried, otherwise increments retry count.
|
||||
|
||||
Reference in New Issue
Block a user