mirror of
https://github.com/chatmail/core.git
synced 2026-05-14 04:16:30 +03:00
feat: Sync Alice's verification on Bob's side
This commit is contained in:
46
src/chat.rs
46
src/chat.rs
@@ -5118,10 +5118,8 @@ pub(crate) enum SyncAction {
|
|||||||
chat_name: String,
|
chat_name: String,
|
||||||
shared_secret: String,
|
shared_secret: String,
|
||||||
},
|
},
|
||||||
CreateInBroadcast {
|
/// Mark the contact with the given fingerprint as verified by self.
|
||||||
chat_name: String,
|
MarkVerified,
|
||||||
shared_secret: String,
|
|
||||||
},
|
|
||||||
Rename(String),
|
Rename(String),
|
||||||
/// Set chat contacts by their addresses.
|
/// Set chat contacts by their addresses.
|
||||||
SetContacts(Vec<String>),
|
SetContacts(Vec<String>),
|
||||||
@@ -5177,6 +5175,14 @@ impl Context {
|
|||||||
SyncAction::Unblock => {
|
SyncAction::Unblock => {
|
||||||
return contact::set_blocked(self, Nosync, contact_id, false).await;
|
return contact::set_blocked(self, Nosync, contact_id, false).await;
|
||||||
}
|
}
|
||||||
|
SyncAction::MarkVerified => {
|
||||||
|
return contact::mark_contact_id_as_verified(
|
||||||
|
self,
|
||||||
|
contact_id,
|
||||||
|
ContactId::SELF,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
ChatIdBlocked::get_for_contact(self, contact_id, Blocked::Request)
|
ChatIdBlocked::get_for_contact(self, contact_id, Blocked::Request)
|
||||||
@@ -5208,8 +5214,9 @@ impl Context {
|
|||||||
SyncAction::Accept => chat_id.accept_ex(self, Nosync).await,
|
SyncAction::Accept => chat_id.accept_ex(self, Nosync).await,
|
||||||
SyncAction::SetVisibility(v) => chat_id.set_visibility_ex(self, Nosync, *v).await,
|
SyncAction::SetVisibility(v) => chat_id.set_visibility_ex(self, Nosync, *v).await,
|
||||||
SyncAction::SetMuted(duration) => set_muted_ex(self, Nosync, chat_id, *duration).await,
|
SyncAction::SetMuted(duration) => set_muted_ex(self, Nosync, chat_id, *duration).await,
|
||||||
SyncAction::CreateOutBroadcast { .. } | SyncAction::CreateInBroadcast { .. } => {
|
SyncAction::CreateOutBroadcast { .. } | SyncAction::MarkVerified => {
|
||||||
// Create action should have been handled by handle_sync_create_chat() already
|
// Create action should have been handled by handle_sync_create_chat() already.
|
||||||
|
// MarkVerified action should have been handled by mark_contact_id_as_verified() already.
|
||||||
Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request."))
|
Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request."))
|
||||||
}
|
}
|
||||||
SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await,
|
SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await,
|
||||||
@@ -5222,7 +5229,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_sync_create_chat(&self, action: &SyncAction, grpid: &str) -> Result<bool> {
|
async fn handle_sync_create_chat(&self, action: &SyncAction, grpid: &str) -> Result<bool> {
|
||||||
Ok(match action {
|
match action {
|
||||||
SyncAction::CreateOutBroadcast {
|
SyncAction::CreateOutBroadcast {
|
||||||
chat_name,
|
chat_name,
|
||||||
shared_secret,
|
shared_secret,
|
||||||
@@ -5235,29 +5242,10 @@ impl Context {
|
|||||||
shared_secret.to_string(),
|
shared_secret.to_string(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
return Ok(true);
|
Ok(true)
|
||||||
}
|
}
|
||||||
SyncAction::CreateInBroadcast {
|
_ => Ok(false),
|
||||||
chat_name,
|
}
|
||||||
shared_secret,
|
|
||||||
} => {
|
|
||||||
let chat_id = ChatId::create_multiuser_record(
|
|
||||||
self,
|
|
||||||
Chattype::InBroadcast,
|
|
||||||
grpid,
|
|
||||||
chat_name,
|
|
||||||
Blocked::Not,
|
|
||||||
ProtectionStatus::Unprotected,
|
|
||||||
None,
|
|
||||||
smeared_time(self),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
save_broadcast_shared_secret(self, chat_id, shared_secret).await?;
|
|
||||||
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emits the appropriate `MsgsChanged` event. Should be called if the number of unnoticed
|
/// Emits the appropriate `MsgsChanged` event. Should be called if the number of unnoticed
|
||||||
|
|||||||
@@ -3133,8 +3133,19 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {
|
|||||||
alice.recv_msg_trash(&request).await;
|
alice.recv_msg_trash(&request).await;
|
||||||
let answer = alice.pop_sent_msg().await;
|
let answer = alice.pop_sent_msg().await;
|
||||||
bob0.recv_msg(&answer).await;
|
bob0.recv_msg(&answer).await;
|
||||||
|
|
||||||
|
// Sync Bob's verification of Alice:
|
||||||
|
sync(bob0, bob1).await;
|
||||||
|
// TODO uncommenting the next line creates a message "Can't decrypt outgoing messages, probably you're using DC on multiple devices without transferring your key"
|
||||||
|
// bob1.recv_msg(&request).await;
|
||||||
bob1.recv_msg(&answer).await;
|
bob1.recv_msg(&answer).await;
|
||||||
|
|
||||||
|
// The 1:1 chat should not be visible to the user on any of the devices.
|
||||||
|
// The contact should be marked as verified.
|
||||||
|
check_direct_chat_is_hidden_and_contact_is_verified(alice, bob0).await;
|
||||||
|
check_direct_chat_is_hidden_and_contact_is_verified(bob0, alice).await;
|
||||||
|
check_direct_chat_is_hidden_and_contact_is_verified(bob1, alice).await;
|
||||||
|
|
||||||
tcm.section("Alice sends first message to broadcast.");
|
tcm.section("Alice sends first message to broadcast.");
|
||||||
let sent_msg = alice.send_text(alice_chat_id, "Hello!").await;
|
let sent_msg = alice.send_text(alice_chat_id, "Hello!").await;
|
||||||
let bob0_hello = bob0.recv_msg(&sent_msg).await;
|
let bob0_hello = bob0.recv_msg(&sent_msg).await;
|
||||||
@@ -3165,6 +3176,20 @@ async fn test_leave_broadcast_multidevice() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn check_direct_chat_is_hidden_and_contact_is_verified(
|
||||||
|
t: &TestContext,
|
||||||
|
contact: &TestContext,
|
||||||
|
) {
|
||||||
|
let contact = t.add_or_lookup_contact_no_key(contact).await;
|
||||||
|
if let Some(direct_chat) = ChatIdBlocked::lookup_by_contact(t, contact.id)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
assert_eq!(direct_chat.blocked, Blocked::Yes);
|
||||||
|
}
|
||||||
|
assert!(contact.is_verified(t).await.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
/// Test that only the owner of the broadcast channel
|
/// Test that only the owner of the broadcast channel
|
||||||
/// can send messages into the chat.
|
/// can send messages into the chat.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -3521,6 +3521,7 @@ async fn apply_out_broadcast_changes(
|
|||||||
} else if let Some(added_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) {
|
} else if let Some(added_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) {
|
||||||
// TODO this block can be removed,
|
// TODO this block can be removed,
|
||||||
// now that all of Alice's devices get to know about Bob joining via Bob's QR message.
|
// now that all of Alice's devices get to know about Bob joining via Bob's QR message.
|
||||||
|
// TODO test if this creates some problems with duplicate member-added messages on Alice's device
|
||||||
let contact = lookup_key_contact_by_address(context, added_addr, None).await?;
|
let contact = lookup_key_contact_by_address(context, added_addr, None).await?;
|
||||||
if let Some(contact) = contact {
|
if let Some(contact) = contact {
|
||||||
better_msg.get_or_insert(
|
better_msg.get_or_insert(
|
||||||
|
|||||||
@@ -595,8 +595,6 @@ pub(crate) async fn observe_securejoin_on_other_device(
|
|||||||
inviter_progress(context, contact_id, 1000);
|
inviter_progress(context, contact_id, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO not sure if I should add vb-request-with-auth here
|
|
||||||
// Actually, I'm not even sure why vg-request-with-auth is here - why do we create a 1:1 chat??
|
|
||||||
if step == "vg-request-with-auth" || step == "vc-request-with-auth" {
|
if step == "vg-request-with-auth" || step == "vc-request-with-auth" {
|
||||||
// This actually reflects what happens on the first device (which does the secure
|
// This actually reflects what happens on the first device (which does the secure
|
||||||
// join) and causes a subsequent "vg-member-added" message to create an unblocked
|
// join) and causes a subsequent "vg-member-added" message to create an unblocked
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::contact::Origin;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::key::self_fingerprint;
|
use crate::key::self_fingerprint;
|
||||||
use crate::log::info;
|
use crate::log::{LogExt as _, info};
|
||||||
use crate::message::{Message, Viewtype};
|
use crate::message::{Message, Viewtype};
|
||||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||||
use crate::param::Param;
|
use crate::param::Param;
|
||||||
@@ -81,6 +81,13 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul
|
|||||||
contact_id: invite.contact_id(),
|
contact_id: invite.contact_id(),
|
||||||
progress: JoinerProgress::RequestWithAuthSent.to_usize(),
|
progress: JoinerProgress::RequestWithAuthSent.to_usize(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Our second device won't be able to decrypt the outgoing message
|
||||||
|
// because it will be symmetrically encrypted with the AUTH token.
|
||||||
|
// So, we need to send a sync message:
|
||||||
|
let id = chat::SyncId::ContactFingerprint(invite.fingerprint().hex());
|
||||||
|
let action = chat::SyncAction::MarkVerified;
|
||||||
|
chat::sync(context, id, action).await.log_err(context).ok();
|
||||||
} else {
|
} else {
|
||||||
// Start the version 1 protocol and initialise the state.
|
// Start the version 1 protocol and initialise the state.
|
||||||
let has_key = context
|
let has_key = context
|
||||||
|
|||||||
Reference in New Issue
Block a user