mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 21:06:31 +03:00
fix: Always pass the correct sort timestamp to ChatId::set_protection() (#5088)
Before in some places it was correctly calculated by passing the "sent" timestamp to `calc_sort_timestamp()`, but in other places just the system time was used. In some complex scenarios like #5088 (restoration of a backup made before a contact verification) it led to wrong sort timestamps of protection messages and also messages following by them. But to reduce number of args passed to functions needing to calculate the sort timestamp, add message timestamps to `struct MimeMessage` which is anyway passed everywhere.
This commit is contained in:
25
src/chat.rs
25
src/chat.rs
@@ -36,7 +36,7 @@ use crate::mimefactory::MimeFactory;
|
|||||||
use crate::mimeparser::SystemMessage;
|
use crate::mimeparser::SystemMessage;
|
||||||
use crate::param::{Param, Params};
|
use crate::param::{Param, Params};
|
||||||
use crate::peerstate::Peerstate;
|
use crate::peerstate::Peerstate;
|
||||||
use crate::receive_imf::ReceivedMsg;
|
use crate::receive_imf::{calc_sort_timestamp, ReceivedMsg};
|
||||||
use crate::smtp::send_msg_to_smtp;
|
use crate::smtp::send_msg_to_smtp;
|
||||||
use crate::sql;
|
use crate::sql;
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
@@ -578,7 +578,7 @@ impl ChatId {
|
|||||||
///
|
///
|
||||||
/// `timestamp_sort` is used as the timestamp of the added message
|
/// `timestamp_sort` is used as the timestamp of the added message
|
||||||
/// and should be the timestamp of the change happening.
|
/// and should be the timestamp of the change happening.
|
||||||
pub(crate) async fn set_protection(
|
async fn set_protection_for_timestamp_sort(
|
||||||
self,
|
self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
protect: ProtectionStatus,
|
protect: ProtectionStatus,
|
||||||
@@ -600,6 +600,22 @@ impl ChatId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets protection and sends or adds a message.
|
||||||
|
///
|
||||||
|
/// `timestamp_sent` is the "sent" timestamp of a message caused the protection state change.
|
||||||
|
pub(crate) async fn set_protection(
|
||||||
|
self,
|
||||||
|
context: &Context,
|
||||||
|
protect: ProtectionStatus,
|
||||||
|
timestamp_sent: i64,
|
||||||
|
contact_id: Option<ContactId>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let sort_to_bottom = true;
|
||||||
|
let ts = calc_sort_timestamp(context, timestamp_sent, self, sort_to_bottom, false).await?;
|
||||||
|
self.set_protection_for_timestamp_sort(context, protect, ts, contact_id)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the 1:1 chat with the given address to ProtectionStatus::Protected,
|
/// Sets the 1:1 chat with the given address to ProtectionStatus::Protected,
|
||||||
/// and posts a `SystemMessage::ChatProtectionEnabled` into it.
|
/// and posts a `SystemMessage::ChatProtectionEnabled` into it.
|
||||||
///
|
///
|
||||||
@@ -607,6 +623,7 @@ impl ChatId {
|
|||||||
pub(crate) async fn set_protection_for_contact(
|
pub(crate) async fn set_protection_for_contact(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
contact_id: ContactId,
|
contact_id: ContactId,
|
||||||
|
timestamp: i64,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let chat_id = ChatId::create_for_contact_with_blocked(context, contact_id, Blocked::Yes)
|
let chat_id = ChatId::create_for_contact_with_blocked(context, contact_id, Blocked::Yes)
|
||||||
.await
|
.await
|
||||||
@@ -615,7 +632,7 @@ impl ChatId {
|
|||||||
.set_protection(
|
.set_protection(
|
||||||
context,
|
context,
|
||||||
ProtectionStatus::Protected,
|
ProtectionStatus::Protected,
|
||||||
smeared_time(context),
|
timestamp,
|
||||||
Some(contact_id),
|
Some(contact_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -3258,7 +3275,7 @@ pub async fn create_group_chat(
|
|||||||
|
|
||||||
if protect == ProtectionStatus::Protected {
|
if protect == ProtectionStatus::Protected {
|
||||||
chat_id
|
chat_id
|
||||||
.set_protection(context, protect, timestamp, None)
|
.set_protection_for_timestamp_sort(context, protect, timestamp, None)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//! # MIME message parsing module.
|
//! # MIME message parsing module.
|
||||||
|
|
||||||
|
use std::cmp::min;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -37,8 +38,8 @@ use crate::simplify::{simplify, SimplifiedText};
|
|||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
use crate::sync::SyncItems;
|
use crate::sync::SyncItems;
|
||||||
use crate::tools::{
|
use crate::tools::{
|
||||||
create_smeared_timestamp, get_filemeta, parse_receive_headers, strip_rtlo_characters,
|
create_smeared_timestamp, get_filemeta, parse_receive_headers, smeared_time,
|
||||||
truncate_by_lines,
|
strip_rtlo_characters, truncate_by_lines,
|
||||||
};
|
};
|
||||||
use crate::{location, tools};
|
use crate::{location, tools};
|
||||||
|
|
||||||
@@ -118,6 +119,12 @@ pub(crate) struct MimeMessage {
|
|||||||
|
|
||||||
/// Whether the contact sending this should be marked as bot.
|
/// Whether the contact sending this should be marked as bot.
|
||||||
pub(crate) is_bot: bool,
|
pub(crate) is_bot: bool,
|
||||||
|
|
||||||
|
/// When the message was received, in secs since epoch.
|
||||||
|
pub(crate) timestamp_rcvd: i64,
|
||||||
|
/// Sender timestamp in secs since epoch. Allowed to be in the future due to unsynchronized
|
||||||
|
/// clocks, but not too much.
|
||||||
|
pub(crate) timestamp_sent: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -386,6 +393,12 @@ impl MimeMessage {
|
|||||||
// Auto-submitted is also set by holiday-notices so we also check `chat-version`
|
// Auto-submitted is also set by holiday-notices so we also check `chat-version`
|
||||||
let is_bot = headers.contains_key("auto-submitted") && headers.contains_key("chat-version");
|
let is_bot = headers.contains_key("auto-submitted") && headers.contains_key("chat-version");
|
||||||
|
|
||||||
|
let timestamp_rcvd = smeared_time(context);
|
||||||
|
let timestamp_sent = headers
|
||||||
|
.get(HeaderDef::Date.get_headername())
|
||||||
|
.and_then(|value| mailparse::dateparse(value).ok())
|
||||||
|
.map_or(timestamp_rcvd, |value| min(value, timestamp_rcvd + 60));
|
||||||
|
|
||||||
let mut parser = MimeMessage {
|
let mut parser = MimeMessage {
|
||||||
parts: Vec::new(),
|
parts: Vec::new(),
|
||||||
headers,
|
headers,
|
||||||
@@ -415,6 +428,8 @@ impl MimeMessage {
|
|||||||
decoded_data: Vec::new(),
|
decoded_data: Vec::new(),
|
||||||
hop_info,
|
hop_info,
|
||||||
is_bot,
|
is_bot,
|
||||||
|
timestamp_rcvd,
|
||||||
|
timestamp_sent,
|
||||||
};
|
};
|
||||||
|
|
||||||
match partial {
|
match partial {
|
||||||
@@ -1630,13 +1645,7 @@ impl MimeMessage {
|
|||||||
/// Handle reports
|
/// Handle reports
|
||||||
/// (MDNs = Message Disposition Notification, the message was read
|
/// (MDNs = Message Disposition Notification, the message was read
|
||||||
/// and NDNs = Non delivery notification, the message could not be delivered)
|
/// and NDNs = Non delivery notification, the message could not be delivered)
|
||||||
pub async fn handle_reports(
|
pub async fn handle_reports(&self, context: &Context, from_id: ContactId, parts: &[Part]) {
|
||||||
&self,
|
|
||||||
context: &Context,
|
|
||||||
from_id: ContactId,
|
|
||||||
sent_timestamp: i64,
|
|
||||||
parts: &[Part],
|
|
||||||
) {
|
|
||||||
for report in &self.mdn_reports {
|
for report in &self.mdn_reports {
|
||||||
for original_message_id in report
|
for original_message_id in report
|
||||||
.original_message_id
|
.original_message_id
|
||||||
@@ -1644,7 +1653,7 @@ impl MimeMessage {
|
|||||||
.chain(&report.additional_message_ids)
|
.chain(&report.additional_message_ids)
|
||||||
{
|
{
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
handle_mdn(context, from_id, original_message_id, sent_timestamp).await
|
handle_mdn(context, from_id, original_message_id, self.timestamp_sent).await
|
||||||
{
|
{
|
||||||
warn!(context, "Could not handle MDN: {err:#}.");
|
warn!(context, "Could not handle MDN: {err:#}.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,19 +172,10 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
Ok(mime_parser) => mime_parser,
|
Ok(mime_parser) => mime_parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
let rcvd_timestamp = smeared_time(context);
|
|
||||||
|
|
||||||
// Sender timestamp is allowed to be a bit in the future due to
|
|
||||||
// unsynchronized clocks, but not too much.
|
|
||||||
let sent_timestamp = mime_parser
|
|
||||||
.get_header(HeaderDef::Date)
|
|
||||||
.and_then(|value| mailparse::dateparse(value).ok())
|
|
||||||
.map_or(rcvd_timestamp, |value| min(value, rcvd_timestamp + 60));
|
|
||||||
|
|
||||||
crate::peerstate::maybe_do_aeap_transition(context, &mut mime_parser).await?;
|
crate::peerstate::maybe_do_aeap_transition(context, &mut mime_parser).await?;
|
||||||
if let Some(peerstate) = &mime_parser.decryption_info.peerstate {
|
if let Some(peerstate) = &mime_parser.decryption_info.peerstate {
|
||||||
peerstate
|
peerstate
|
||||||
.handle_fingerprint_change(context, sent_timestamp)
|
.handle_fingerprint_change(context, mime_parser.timestamp_sent)
|
||||||
.await?;
|
.await?;
|
||||||
// When peerstate is set to Mutual, it's saved immediately to not lose that fact in case
|
// When peerstate is set to Mutual, it's saved immediately to not lose that fact in case
|
||||||
// of an error. Otherwise we don't save peerstate until get here to reduce the number of
|
// of an error. Otherwise we don't save peerstate until get here to reduce the number of
|
||||||
@@ -284,7 +275,7 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
received_msg = Some(ReceivedMsg {
|
received_msg = Some(ReceivedMsg {
|
||||||
chat_id: DC_CHAT_ID_TRASH,
|
chat_id: DC_CHAT_ID_TRASH,
|
||||||
state: MessageState::InSeen,
|
state: MessageState::InSeen,
|
||||||
sort_timestamp: sent_timestamp,
|
sort_timestamp: mime_parser.timestamp_sent,
|
||||||
msg_ids: vec![msg_id],
|
msg_ids: vec![msg_id],
|
||||||
needs_delete_job: res == securejoin::HandshakeMessage::Done,
|
needs_delete_job: res == securejoin::HandshakeMessage::Done,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -313,8 +304,6 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
incoming,
|
incoming,
|
||||||
&to_ids,
|
&to_ids,
|
||||||
rfc724_mid,
|
rfc724_mid,
|
||||||
sent_timestamp,
|
|
||||||
rcvd_timestamp,
|
|
||||||
from_id,
|
from_id,
|
||||||
seen || replace_partial_download.is_some(),
|
seen || replace_partial_download.is_some(),
|
||||||
is_partial_download,
|
is_partial_download,
|
||||||
@@ -328,7 +317,7 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !from_id.is_special() {
|
if !from_id.is_special() {
|
||||||
contact::update_last_seen(context, from_id, sent_timestamp).await?;
|
contact::update_last_seen(context, from_id, mime_parser.timestamp_sent).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update gossiped timestamp for the chat if someone else or our other device sent
|
// Update gossiped timestamp for the chat if someone else or our other device sent
|
||||||
@@ -345,9 +334,9 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
context,
|
context,
|
||||||
"Received message contains Autocrypt-Gossip for all members of {chat_id}, updating timestamp."
|
"Received message contains Autocrypt-Gossip for all members of {chat_id}, updating timestamp."
|
||||||
);
|
);
|
||||||
if chat_id.get_gossiped_timestamp(context).await? < sent_timestamp {
|
if chat_id.get_gossiped_timestamp(context).await? < mime_parser.timestamp_sent {
|
||||||
chat_id
|
chat_id
|
||||||
.set_gossiped_timestamp(context, sent_timestamp)
|
.set_gossiped_timestamp(context, mime_parser.timestamp_sent)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,7 +373,11 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
if let Some(avatar_action) = &mime_parser.user_avatar {
|
if let Some(avatar_action) = &mime_parser.user_avatar {
|
||||||
if from_id != ContactId::UNDEFINED
|
if from_id != ContactId::UNDEFINED
|
||||||
&& context
|
&& context
|
||||||
.update_contacts_timestamp(from_id, Param::AvatarTimestamp, sent_timestamp)
|
.update_contacts_timestamp(
|
||||||
|
from_id,
|
||||||
|
Param::AvatarTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
if let Err(err) = contact::set_profile_image(
|
if let Err(err) = contact::set_profile_image(
|
||||||
@@ -405,7 +398,11 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
if !mime_parser.is_mailinglist_message()
|
if !mime_parser.is_mailinglist_message()
|
||||||
&& from_id != ContactId::UNDEFINED
|
&& from_id != ContactId::UNDEFINED
|
||||||
&& context
|
&& context
|
||||||
.update_contacts_timestamp(from_id, Param::StatusTimestamp, sent_timestamp)
|
.update_contacts_timestamp(
|
||||||
|
from_id,
|
||||||
|
Param::StatusTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
if let Err(err) = contact::set_status(
|
if let Err(err) = contact::set_status(
|
||||||
@@ -454,7 +451,7 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
context.new_msgs_notify.notify_one();
|
context.new_msgs_notify.notify_one();
|
||||||
|
|
||||||
mime_parser
|
mime_parser
|
||||||
.handle_reports(context, from_id, sent_timestamp, &mime_parser.parts)
|
.handle_reports(context, from_id, &mime_parser.parts)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
from_id.mark_bot(context, mime_parser.is_bot).await?;
|
from_id.mark_bot(context, mime_parser.is_bot).await?;
|
||||||
@@ -525,8 +522,6 @@ async fn add_parts(
|
|||||||
incoming: bool,
|
incoming: bool,
|
||||||
to_ids: &[ContactId],
|
to_ids: &[ContactId],
|
||||||
rfc724_mid: &str,
|
rfc724_mid: &str,
|
||||||
sent_timestamp: i64,
|
|
||||||
rcvd_timestamp: i64,
|
|
||||||
from_id: ContactId,
|
from_id: ContactId,
|
||||||
seen: bool,
|
seen: bool,
|
||||||
is_partial_download: Option<u32>,
|
is_partial_download: Option<u32>,
|
||||||
@@ -665,7 +660,6 @@ async fn add_parts(
|
|||||||
from_id,
|
from_id,
|
||||||
to_ids,
|
to_ids,
|
||||||
&verified_encryption,
|
&verified_encryption,
|
||||||
sent_timestamp,
|
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
@@ -711,7 +705,6 @@ async fn add_parts(
|
|||||||
group_changes_msgs = apply_group_changes(
|
group_changes_msgs = apply_group_changes(
|
||||||
context,
|
context,
|
||||||
mime_parser,
|
mime_parser,
|
||||||
sent_timestamp,
|
|
||||||
group_chat_id,
|
group_chat_id,
|
||||||
from_id,
|
from_id,
|
||||||
to_ids,
|
to_ids,
|
||||||
@@ -729,7 +722,6 @@ async fn add_parts(
|
|||||||
allow_creation,
|
allow_creation,
|
||||||
mailinglist_header,
|
mailinglist_header,
|
||||||
mime_parser,
|
mime_parser,
|
||||||
sent_timestamp,
|
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
@@ -740,7 +732,7 @@ async fn add_parts(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(chat_id) = chat_id {
|
if let Some(chat_id) = chat_id {
|
||||||
apply_mailinglist_changes(context, mime_parser, sent_timestamp, chat_id).await?;
|
apply_mailinglist_changes(context, mime_parser, chat_id).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if contact renaming is prevented (for mailinglists and bots),
|
// if contact renaming is prevented (for mailinglists and bots),
|
||||||
@@ -826,11 +818,13 @@ async fn add_parts(
|
|||||||
// The message itself will be sorted under the device message since the device
|
// The message itself will be sorted under the device message since the device
|
||||||
// message is `MessageState::InNoticed`, which means that all following
|
// message is `MessageState::InNoticed`, which means that all following
|
||||||
// messages are sorted under it.
|
// messages are sorted under it.
|
||||||
let sort_timestamp =
|
|
||||||
calc_sort_timestamp(context, sent_timestamp, chat_id, true, incoming)
|
|
||||||
.await?;
|
|
||||||
chat_id
|
chat_id
|
||||||
.set_protection(context, new_protection, sort_timestamp, Some(from_id))
|
.set_protection(
|
||||||
|
context,
|
||||||
|
new_protection,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
Some(from_id),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -898,7 +892,6 @@ async fn add_parts(
|
|||||||
from_id,
|
from_id,
|
||||||
to_ids,
|
to_ids,
|
||||||
&verified_encryption,
|
&verified_encryption,
|
||||||
sent_timestamp,
|
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
@@ -936,7 +929,6 @@ async fn add_parts(
|
|||||||
group_changes_msgs = apply_group_changes(
|
group_changes_msgs = apply_group_changes(
|
||||||
context,
|
context,
|
||||||
mime_parser,
|
mime_parser,
|
||||||
sent_timestamp,
|
|
||||||
chat_id,
|
chat_id,
|
||||||
from_id,
|
from_id,
|
||||||
to_ids,
|
to_ids,
|
||||||
@@ -1025,8 +1017,14 @@ async fn add_parts(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let in_fresh = state == MessageState::InFresh;
|
let in_fresh = state == MessageState::InFresh;
|
||||||
let sort_timestamp =
|
let sort_timestamp = calc_sort_timestamp(
|
||||||
calc_sort_timestamp(context, sent_timestamp, chat_id, false, incoming).await?;
|
context,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
chat_id,
|
||||||
|
false,
|
||||||
|
incoming,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Apply ephemeral timer changes to the chat.
|
// Apply ephemeral timer changes to the chat.
|
||||||
//
|
//
|
||||||
@@ -1056,7 +1054,11 @@ async fn add_parts(
|
|||||||
"Ignoring ephemeral timer change to {ephemeral_timer:?} for chat {chat_id} to avoid rollback.",
|
"Ignoring ephemeral timer change to {ephemeral_timer:?} for chat {chat_id} to avoid rollback.",
|
||||||
);
|
);
|
||||||
} else if chat_id
|
} else if chat_id
|
||||||
.update_timestamp(context, Param::EphemeralSettingsTimestamp, sent_timestamp)
|
.update_timestamp(
|
||||||
|
context,
|
||||||
|
Param::EphemeralSettingsTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
if let Err(err) = chat_id
|
if let Err(err) = chat_id
|
||||||
@@ -1259,7 +1261,7 @@ async fn add_parts(
|
|||||||
match ephemeral_timer {
|
match ephemeral_timer {
|
||||||
EphemeralTimer::Disabled => 0,
|
EphemeralTimer::Disabled => 0,
|
||||||
EphemeralTimer::Enabled { duration } => {
|
EphemeralTimer::Enabled { duration } => {
|
||||||
rcvd_timestamp.saturating_add(duration.into())
|
mime_parser.timestamp_rcvd.saturating_add(duration.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1312,8 +1314,8 @@ RETURNING id
|
|||||||
if trash { ContactId::UNDEFINED } else { from_id },
|
if trash { ContactId::UNDEFINED } else { from_id },
|
||||||
if trash { ContactId::UNDEFINED } else { to_id },
|
if trash { ContactId::UNDEFINED } else { to_id },
|
||||||
sort_timestamp,
|
sort_timestamp,
|
||||||
sent_timestamp,
|
mime_parser.timestamp_sent,
|
||||||
rcvd_timestamp,
|
mime_parser.timestamp_rcvd,
|
||||||
typ,
|
typ,
|
||||||
state,
|
state,
|
||||||
is_dc_message,
|
is_dc_message,
|
||||||
@@ -1485,7 +1487,7 @@ async fn save_locations(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn calc_sort_timestamp(
|
pub(crate) async fn calc_sort_timestamp(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
message_timestamp: i64,
|
message_timestamp: i64,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
@@ -1620,7 +1622,6 @@ async fn create_or_lookup_group(
|
|||||||
from_id: ContactId,
|
from_id: ContactId,
|
||||||
to_ids: &[ContactId],
|
to_ids: &[ContactId],
|
||||||
verified_encryption: &VerifiedEncryption,
|
verified_encryption: &VerifiedEncryption,
|
||||||
timestamp: i64,
|
|
||||||
) -> Result<Option<(ChatId, Blocked)>> {
|
) -> Result<Option<(ChatId, Blocked)>> {
|
||||||
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
|
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
|
||||||
grpid
|
grpid
|
||||||
@@ -1633,7 +1634,7 @@ async fn create_or_lookup_group(
|
|||||||
member_ids.push(ContactId::SELF);
|
member_ids.push(ContactId::SELF);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = create_adhoc_group(context, mime_parser, create_blocked, &member_ids, timestamp)
|
let res = create_adhoc_group(context, mime_parser, create_blocked, &member_ids)
|
||||||
.await
|
.await
|
||||||
.context("could not create ad hoc group")?
|
.context("could not create ad hoc group")?
|
||||||
.map(|chat_id| (chat_id, create_blocked));
|
.map(|chat_id| (chat_id, create_blocked));
|
||||||
@@ -1715,7 +1716,7 @@ async fn create_or_lookup_group(
|
|||||||
create_blocked,
|
create_blocked,
|
||||||
create_protected,
|
create_protected,
|
||||||
None,
|
None,
|
||||||
timestamp,
|
mime_parser.timestamp_sent,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed to create group '{grpname}' for grpid={grpid}"))?;
|
.with_context(|| format!("Failed to create group '{grpname}' for grpid={grpid}"))?;
|
||||||
@@ -1762,7 +1763,6 @@ async fn create_or_lookup_group(
|
|||||||
async fn apply_group_changes(
|
async fn apply_group_changes(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
mime_parser: &mut MimeMessage,
|
mime_parser: &mut MimeMessage,
|
||||||
sent_timestamp: i64,
|
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
from_id: ContactId,
|
from_id: ContactId,
|
||||||
to_ids: &[ContactId],
|
to_ids: &[ContactId],
|
||||||
@@ -1800,7 +1800,11 @@ async fn apply_group_changes(
|
|||||||
let allow_member_list_changes = !is_partial_download
|
let allow_member_list_changes = !is_partial_download
|
||||||
&& is_from_in_chat
|
&& is_from_in_chat
|
||||||
&& chat_id
|
&& chat_id
|
||||||
.update_timestamp(context, Param::MemberListTimestamp, sent_timestamp)
|
.update_timestamp(
|
||||||
|
context,
|
||||||
|
Param::MemberListTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Whether to rebuild the member list from scratch.
|
// Whether to rebuild the member list from scratch.
|
||||||
@@ -1839,7 +1843,7 @@ async fn apply_group_changes(
|
|||||||
.set_protection(
|
.set_protection(
|
||||||
context,
|
context,
|
||||||
ProtectionStatus::Protected,
|
ProtectionStatus::Protected,
|
||||||
smeared_time(context),
|
mime_parser.timestamp_sent,
|
||||||
Some(from_id),
|
Some(from_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -1893,7 +1897,11 @@ async fn apply_group_changes(
|
|||||||
.filter(|grpname| grpname.len() < 200)
|
.filter(|grpname| grpname.len() < 200)
|
||||||
{
|
{
|
||||||
if chat_id
|
if chat_id
|
||||||
.update_timestamp(context, Param::GroupNameTimestamp, sent_timestamp)
|
.update_timestamp(
|
||||||
|
context,
|
||||||
|
Param::GroupNameTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
info!(context, "Updating grpname for chat {chat_id}.");
|
info!(context, "Updating grpname for chat {chat_id}.");
|
||||||
@@ -2000,7 +2008,7 @@ async fn apply_group_changes(
|
|||||||
info!(context, "Group-avatar change for {chat_id}.");
|
info!(context, "Group-avatar change for {chat_id}.");
|
||||||
if chat
|
if chat
|
||||||
.param
|
.param
|
||||||
.update_timestamp(Param::AvatarTimestamp, sent_timestamp)?
|
.update_timestamp(Param::AvatarTimestamp, mime_parser.timestamp_sent)?
|
||||||
{
|
{
|
||||||
match avatar_action {
|
match avatar_action {
|
||||||
AvatarAction::Change(profile_image) => {
|
AvatarAction::Change(profile_image) => {
|
||||||
@@ -2049,7 +2057,6 @@ async fn create_or_lookup_mailinglist(
|
|||||||
allow_creation: bool,
|
allow_creation: bool,
|
||||||
list_id_header: &str,
|
list_id_header: &str,
|
||||||
mime_parser: &MimeMessage,
|
mime_parser: &MimeMessage,
|
||||||
timestamp: i64,
|
|
||||||
) -> Result<Option<(ChatId, Blocked)>> {
|
) -> Result<Option<(ChatId, Blocked)>> {
|
||||||
let listid = mailinglist_header_listid(list_id_header)?;
|
let listid = mailinglist_header_listid(list_id_header)?;
|
||||||
|
|
||||||
@@ -2081,7 +2088,7 @@ async fn create_or_lookup_mailinglist(
|
|||||||
blocked,
|
blocked,
|
||||||
ProtectionStatus::Unprotected,
|
ProtectionStatus::Unprotected,
|
||||||
param,
|
param,
|
||||||
timestamp,
|
mime_parser.timestamp_sent,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
@@ -2169,7 +2176,6 @@ fn compute_mailinglist_name(
|
|||||||
async fn apply_mailinglist_changes(
|
async fn apply_mailinglist_changes(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
mime_parser: &MimeMessage,
|
mime_parser: &MimeMessage,
|
||||||
sent_timestamp: i64,
|
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let Some(mailinglist_header) = mime_parser.get_mailinglist_header() else {
|
let Some(mailinglist_header) = mime_parser.get_mailinglist_header() else {
|
||||||
@@ -2185,7 +2191,11 @@ async fn apply_mailinglist_changes(
|
|||||||
let new_name = compute_mailinglist_name(mailinglist_header, listid, mime_parser);
|
let new_name = compute_mailinglist_name(mailinglist_header, listid, mime_parser);
|
||||||
if chat.name != new_name
|
if chat.name != new_name
|
||||||
&& chat_id
|
&& chat_id
|
||||||
.update_timestamp(context, Param::GroupNameTimestamp, sent_timestamp)
|
.update_timestamp(
|
||||||
|
context,
|
||||||
|
Param::GroupNameTimestamp,
|
||||||
|
mime_parser.timestamp_sent,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
info!(context, "Updating listname for chat {chat_id}.");
|
info!(context, "Updating listname for chat {chat_id}.");
|
||||||
@@ -2266,7 +2276,6 @@ async fn create_adhoc_group(
|
|||||||
mime_parser: &MimeMessage,
|
mime_parser: &MimeMessage,
|
||||||
create_blocked: Blocked,
|
create_blocked: Blocked,
|
||||||
member_ids: &[ContactId],
|
member_ids: &[ContactId],
|
||||||
timestamp: i64,
|
|
||||||
) -> Result<Option<ChatId>> {
|
) -> Result<Option<ChatId>> {
|
||||||
if mime_parser.is_mailinglist_message() {
|
if mime_parser.is_mailinglist_message() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
@@ -2305,7 +2314,7 @@ async fn create_adhoc_group(
|
|||||||
create_blocked,
|
create_blocked,
|
||||||
ProtectionStatus::Unprotected,
|
ProtectionStatus::Unprotected,
|
||||||
None,
|
None,
|
||||||
timestamp,
|
mime_parser.timestamp_sent,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -2502,7 +2511,12 @@ async fn mark_recipients_as_verified(
|
|||||||
Origin::Hidden,
|
Origin::Hidden,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
ChatId::set_protection_for_contact(context, to_contact_id).await?;
|
ChatId::set_protection_for_contact(
|
||||||
|
context,
|
||||||
|
to_contact_id,
|
||||||
|
mimeparser.timestamp_sent,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -441,7 +441,13 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
};
|
};
|
||||||
match chat::get_chat_id_by_grpid(context, field_grpid).await? {
|
match chat::get_chat_id_by_grpid(context, field_grpid).await? {
|
||||||
Some((group_chat_id, _, _)) => {
|
Some((group_chat_id, _, _)) => {
|
||||||
secure_connection_established(context, contact_id, group_chat_id).await?;
|
secure_connection_established(
|
||||||
|
context,
|
||||||
|
contact_id,
|
||||||
|
group_chat_id,
|
||||||
|
mime_message.timestamp_sent,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
chat::add_contact_to_chat_ex(
|
chat::add_contact_to_chat_ex(
|
||||||
context,
|
context,
|
||||||
Nosync,
|
Nosync,
|
||||||
@@ -461,6 +467,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
|||||||
context,
|
context,
|
||||||
contact_id,
|
contact_id,
|
||||||
info_chat_id(context, contact_id).await?,
|
info_chat_id(context, contact_id).await?,
|
||||||
|
mime_message.timestamp_sent,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
send_alice_handshake_msg(
|
send_alice_handshake_msg(
|
||||||
@@ -609,7 +616,12 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
|||||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||||
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
peerstate.save_to_db(&context.sql).await.unwrap_or_default();
|
||||||
|
|
||||||
ChatId::set_protection_for_contact(context, contact_id).await?;
|
ChatId::set_protection_for_contact(
|
||||||
|
context,
|
||||||
|
contact_id,
|
||||||
|
mime_message.timestamp_sent,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
} else if let Some(fingerprint) =
|
} else if let Some(fingerprint) =
|
||||||
mime_message.get_header(HeaderDef::SecureJoinFingerprint)
|
mime_message.get_header(HeaderDef::SecureJoinFingerprint)
|
||||||
{
|
{
|
||||||
@@ -675,6 +687,7 @@ async fn secure_connection_established(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
contact_id: ContactId,
|
contact_id: ContactId,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
|
timestamp: i64,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if context
|
if context
|
||||||
.get_config_bool(Config::VerifiedOneOnOneChats)
|
.get_config_bool(Config::VerifiedOneOnOneChats)
|
||||||
@@ -687,7 +700,7 @@ async fn secure_connection_established(
|
|||||||
.set_protection(
|
.set_protection(
|
||||||
context,
|
context,
|
||||||
ProtectionStatus::Protected,
|
ProtectionStatus::Protected,
|
||||||
time(),
|
timestamp,
|
||||||
Some(contact_id),
|
Some(contact_id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
@@ -130,7 +130,9 @@ pub(super) async fn handle_contact_confirm(
|
|||||||
// Note this goes to the 1:1 chat, as when joining a group we implicitly also
|
// Note this goes to the 1:1 chat, as when joining a group we implicitly also
|
||||||
// verify both contacts (this could be a bug/security issue, see
|
// verify both contacts (this could be a bug/security issue, see
|
||||||
// e.g. https://github.com/deltachat/deltachat-core-rust/issues/1177).
|
// e.g. https://github.com/deltachat/deltachat-core-rust/issues/1177).
|
||||||
bobstate.notify_peer_verified(context).await?;
|
bobstate
|
||||||
|
.notify_peer_verified(context, message.timestamp_sent)
|
||||||
|
.await?;
|
||||||
bobstate.emit_progress(context, JoinerProgress::Succeeded);
|
bobstate.emit_progress(context, JoinerProgress::Succeeded);
|
||||||
Ok(retval)
|
Ok(retval)
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ impl BobState {
|
|||||||
/// Notifies the user that the SecureJoin peer is verified.
|
/// Notifies the user that the SecureJoin peer is verified.
|
||||||
///
|
///
|
||||||
/// This creates an info message in the chat being joined.
|
/// This creates an info message in the chat being joined.
|
||||||
async fn notify_peer_verified(&self, context: &Context) -> Result<()> {
|
async fn notify_peer_verified(&self, context: &Context, timestamp: i64) -> Result<()> {
|
||||||
let contact = Contact::get_by_id(context, self.invite().contact_id()).await?;
|
let contact = Contact::get_by_id(context, self.invite().contact_id()).await?;
|
||||||
let chat_id = self.joining_chat_id(context).await?;
|
let chat_id = self.joining_chat_id(context).await?;
|
||||||
|
|
||||||
@@ -232,7 +234,7 @@ impl BobState {
|
|||||||
.set_protection(
|
.set_protection(
|
||||||
context,
|
context,
|
||||||
ProtectionStatus::Protected,
|
ProtectionStatus::Protected,
|
||||||
time(),
|
timestamp,
|
||||||
Some(contact.id),
|
Some(contact.id),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user