mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 01:46:34 +03:00
Merge remote-tracking branch 'origin/main' into hoc/channels-encryption-only-qrcodes
This commit is contained in:
13
src/chat.rs
13
src/chat.rs
@@ -1983,7 +1983,7 @@ impl Chat {
|
||||
}
|
||||
|
||||
/// Adds missing values to the msg object,
|
||||
/// writes the record to the database and returns its msg_id.
|
||||
/// writes the record to the database.
|
||||
///
|
||||
/// If `update_msg_id` is set, that record is reused;
|
||||
/// if `update_msg_id` is None, a new record is created.
|
||||
@@ -1992,7 +1992,7 @@ impl Chat {
|
||||
context: &Context,
|
||||
msg: &mut Message,
|
||||
update_msg_id: Option<MsgId>,
|
||||
) -> Result<MsgId> {
|
||||
) -> Result<()> {
|
||||
let mut to_id = 0;
|
||||
let mut location_id = 0;
|
||||
|
||||
@@ -2270,7 +2270,7 @@ impl Chat {
|
||||
.await?;
|
||||
}
|
||||
context.scheduler.interrupt_ephemeral_task().await;
|
||||
Ok(msg.id)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sends a `SyncAction` synchronising chat contacts to other devices.
|
||||
@@ -3006,8 +3006,7 @@ async fn prepare_send_msg(
|
||||
if !msg.hidden {
|
||||
chat_id.unarchive_if_not_muted(context, msg.state).await?;
|
||||
}
|
||||
msg.id = chat.prepare_msg_raw(context, msg, update_msg_id).await?;
|
||||
msg.chat_id = chat_id;
|
||||
chat.prepare_msg_raw(context, msg, update_msg_id).await?;
|
||||
|
||||
let row_ids = create_send_msg_jobs(context, msg)
|
||||
.await
|
||||
@@ -4561,13 +4560,13 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
||||
msg.state = MessageState::OutPending;
|
||||
msg.rfc724_mid = create_outgoing_rfc724_mid();
|
||||
msg.timestamp_sort = curr_timestamp;
|
||||
let new_msg_id = chat.prepare_msg_raw(context, &mut msg, None).await?;
|
||||
chat.prepare_msg_raw(context, &mut msg, None).await?;
|
||||
|
||||
curr_timestamp += 1;
|
||||
if !create_send_msg_jobs(context, &mut msg).await?.is_empty() {
|
||||
context.scheduler.interrupt_smtp().await;
|
||||
}
|
||||
created_msgs.push(new_msg_id);
|
||||
created_msgs.push(msg.id);
|
||||
}
|
||||
for msg_id in created_msgs {
|
||||
context.emit_msgs_changed(chat_id, msg_id);
|
||||
|
||||
@@ -3459,6 +3459,30 @@ async fn test_chat_get_encryption_info() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_out_failed_on_all_keys_missing() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
let fiona = &tcm.fiona().await;
|
||||
|
||||
let bob_chat_id = bob
|
||||
.create_group_with_members(ProtectionStatus::Unprotected, "", &[alice, fiona])
|
||||
.await;
|
||||
bob.send_text(bob_chat_id, "Gossiping Fiona's key").await;
|
||||
alice
|
||||
.recv_msg(&bob.send_text(bob_chat_id, "No key gossip").await)
|
||||
.await;
|
||||
SystemTime::shift(Duration::from_secs(60));
|
||||
remove_contact_from_chat(bob, bob_chat_id, ContactId::SELF).await?;
|
||||
let alice_chat_id = alice.recv_msg(&bob.pop_sent_msg().await).await.chat_id;
|
||||
alice_chat_id.accept(alice).await?;
|
||||
let mut msg = Message::new_text("Hi".to_string());
|
||||
send_msg(alice, alice_chat_id, &mut msg).await.ok();
|
||||
assert_eq!(msg.id.get_state(alice).await?, MessageState::OutFailed);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_chat_media() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::path::PathBuf;
|
||||
|
||||
use crate::chat::ChatId;
|
||||
use crate::config::Config;
|
||||
use crate::constants::Chattype;
|
||||
use crate::contact::ContactId;
|
||||
use crate::ephemeral::Timer as EphemeralTimer;
|
||||
use crate::message::MsgId;
|
||||
@@ -272,6 +273,9 @@ pub enum EventType {
|
||||
/// ID of the contact that wants to join.
|
||||
contact_id: ContactId,
|
||||
|
||||
/// The type of the joined chat.
|
||||
chat_type: Chattype,
|
||||
|
||||
/// Progress as:
|
||||
/// 300=vg-/vc-request received, typically shown as "bob@addr joins".
|
||||
/// 600=vg-/vc-request-with-auth received and verified, typically shown as "bob@addr verified".
|
||||
|
||||
@@ -32,16 +32,30 @@ use qrinvite::QrInvite;
|
||||
|
||||
use crate::token::Namespace;
|
||||
|
||||
fn inviter_progress(context: &Context, contact_id: ContactId, progress: usize) {
|
||||
fn inviter_progress(
|
||||
context: &Context,
|
||||
contact_id: ContactId,
|
||||
step: &str,
|
||||
progress: usize,
|
||||
) -> Result<()> {
|
||||
logged_debug_assert!(
|
||||
context,
|
||||
progress <= 1000,
|
||||
"inviter_progress: contact {contact_id}, progress={progress}, but value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success."
|
||||
);
|
||||
let chat_type = match step.get(..3) {
|
||||
Some("vc-") => Chattype::Single,
|
||||
Some("vg-") => Chattype::Group,
|
||||
Some("vb-") => Chattype::OutBroadcast,
|
||||
_ => bail!("Unknown securejoin step {step}"),
|
||||
};
|
||||
context.emit_event(EventType::SecurejoinInviterProgress {
|
||||
contact_id,
|
||||
chat_type,
|
||||
progress,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a Secure Join QR code.
|
||||
@@ -346,7 +360,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
||||
return Ok(HandshakeMessage::Ignore);
|
||||
}
|
||||
|
||||
inviter_progress(context, contact_id, 300);
|
||||
inviter_progress(context, contact_id, step, 300)?;
|
||||
|
||||
let from_addr = ContactAddress::new(&mime_message.from.addr)?;
|
||||
let autocrypt_fingerprint = mime_message.autocrypt_fingerprint.as_deref().unwrap_or("");
|
||||
@@ -442,7 +456,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
||||
ChatId::create_for_contact(context, contact_id).await?;
|
||||
}
|
||||
context.emit_event(EventType::ContactsChanged(Some(contact_id)));
|
||||
inviter_progress(context, contact_id, 600);
|
||||
inviter_progress(context, contact_id, step, 600)?;
|
||||
if let Some(group_chat_id) = group_chat_id {
|
||||
// Join group.
|
||||
secure_connection_established(
|
||||
@@ -455,8 +469,8 @@ pub(crate) async fn handle_securejoin_handshake(
|
||||
|
||||
chat::add_contact_to_chat_ex(context, Nosync, group_chat_id, contact_id, true)
|
||||
.await?;
|
||||
inviter_progress(context, contact_id, 800);
|
||||
inviter_progress(context, contact_id, 1000);
|
||||
inviter_progress(context, contact_id, step, 800)?;
|
||||
inviter_progress(context, contact_id, step, 1000)?;
|
||||
if step == "vb-request-with-auth" {
|
||||
// For broadcasts, we don't want to delete the message,
|
||||
// because the other device should also internally add the member
|
||||
@@ -480,7 +494,7 @@ pub(crate) async fn handle_securejoin_handshake(
|
||||
.await
|
||||
.context("failed sending vc-contact-confirm message")?;
|
||||
|
||||
inviter_progress(context, contact_id, 1000);
|
||||
inviter_progress(context, contact_id, step, 1000)?;
|
||||
Ok(HandshakeMessage::Ignore) // "Done" would delete the message and break multi-device (the key from Autocrypt-header is needed)
|
||||
}
|
||||
}
|
||||
@@ -609,11 +623,11 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
||||
ChatId::set_protection_for_contact(context, contact_id, mime_message.timestamp_sent).await?;
|
||||
|
||||
if step == "vg-member-added" {
|
||||
inviter_progress(context, contact_id, 800);
|
||||
inviter_progress(context, contact_id, step, 800)?;
|
||||
}
|
||||
// TODO superflous vb-member-added (we're early-returning above):
|
||||
if step == "vg-member-added" || step == "vb-member-added" || step == "vc-contact-confirm" {
|
||||
inviter_progress(context, contact_id, 1000);
|
||||
inviter_progress(context, contact_id, step, 1000)?;
|
||||
}
|
||||
|
||||
if step == "vg-request-with-auth" || step == "vc-request-with-auth" {
|
||||
|
||||
@@ -366,6 +366,29 @@ async fn test_setup_contact_bob_knows_alice() -> Result<()> {
|
||||
alice.recv_msg_trash(&sent).await;
|
||||
assert_eq!(contact_bob.is_verified(alice).await?, true);
|
||||
|
||||
// Check Alice signalled success via the SecurejoinInviterProgress event.
|
||||
let event = alice
|
||||
.evtracker
|
||||
.get_matching(|evt| {
|
||||
matches!(
|
||||
evt,
|
||||
EventType::SecurejoinInviterProgress { progress: 1000, .. }
|
||||
)
|
||||
})
|
||||
.await;
|
||||
match event {
|
||||
EventType::SecurejoinInviterProgress {
|
||||
contact_id,
|
||||
chat_type,
|
||||
progress,
|
||||
} => {
|
||||
assert_eq!(contact_id, contact_bob.id);
|
||||
assert_eq!(chat_type, Chattype::Single);
|
||||
assert_eq!(progress, 1000);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let sent = alice.pop_sent_msg().await;
|
||||
let msg = bob.parse_msg(&sent).await;
|
||||
assert!(msg.was_encrypted());
|
||||
@@ -516,6 +539,29 @@ async fn test_secure_join() -> Result<()> {
|
||||
alice.recv_msg_trash(&sent).await;
|
||||
assert_eq!(contact_bob.is_verified(&alice).await?, true);
|
||||
|
||||
// Check Alice signalled success via the SecurejoinInviterProgress event.
|
||||
let event = alice
|
||||
.evtracker
|
||||
.get_matching(|evt| {
|
||||
matches!(
|
||||
evt,
|
||||
EventType::SecurejoinInviterProgress { progress: 1000, .. }
|
||||
)
|
||||
})
|
||||
.await;
|
||||
match event {
|
||||
EventType::SecurejoinInviterProgress {
|
||||
contact_id,
|
||||
chat_type,
|
||||
progress,
|
||||
} => {
|
||||
assert_eq!(contact_id, contact_bob.id);
|
||||
assert_eq!(chat_type, Chattype::Group);
|
||||
assert_eq!(progress, 1000);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let sent = alice.pop_sent_msg().await;
|
||||
let msg = bob.parse_msg(&sent).await;
|
||||
assert!(msg.was_encrypted());
|
||||
|
||||
Reference in New Issue
Block a user