mirror of
https://github.com/chatmail/core.git
synced 2026-05-19 23:06:32 +03:00
Don't use opt_level=1, instead box futures
This commit is contained in:
@@ -9,7 +9,6 @@ rust-version = "1.56"
|
|||||||
[profile.dev]
|
[profile.dev]
|
||||||
debug = 0
|
debug = 0
|
||||||
panic = 'abort'
|
panic = 'abort'
|
||||||
opt-level = 1
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -695,214 +695,222 @@ mod tests {
|
|||||||
use crate::test_utils::{TestContext, TestContextManager};
|
use crate::test_utils::{TestContext, TestContextManager};
|
||||||
use crate::tools::EmailAddress;
|
use crate::tools::EmailAddress;
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[test]
|
||||||
async fn test_setup_contact() {
|
fn test_setup_contact() {
|
||||||
let mut tcm = TestContextManager::new();
|
let body = Box::pin(async {
|
||||||
let alice = tcm.alice().await;
|
let mut tcm = TestContextManager::new();
|
||||||
let bob = tcm.bob().await;
|
let alice = tcm.alice().await;
|
||||||
assert_eq!(
|
let bob = tcm.bob().await;
|
||||||
Chatlist::try_load(&alice, 0, None, None)
|
assert_eq!(
|
||||||
.await
|
Chatlist::try_load(&alice, 0, None, None)
|
||||||
.unwrap()
|
.await
|
||||||
.len(),
|
.unwrap()
|
||||||
0
|
.len(),
|
||||||
);
|
0
|
||||||
assert_eq!(
|
);
|
||||||
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
assert_eq!(
|
||||||
0
|
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
||||||
);
|
0
|
||||||
|
);
|
||||||
|
|
||||||
// Step 1: Generate QR-code, ChatId(0) indicates setup-contact
|
// Step 1: Generate QR-code, ChatId(0) indicates setup-contact
|
||||||
let qr = get_securejoin_qr(&alice.ctx, None).await.unwrap();
|
let qr = get_securejoin_qr(&alice.ctx, None).await.unwrap();
|
||||||
|
|
||||||
// Step 2: Bob scans QR-code, sends vc-request
|
// Step 2: Bob scans QR-code, sends vc-request
|
||||||
join_securejoin(&bob.ctx, &qr).await.unwrap();
|
join_securejoin(&bob.ctx, &qr).await.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
let sent = bob.pop_sent_msg().await;
|
let sent = bob.pop_sent_msg().await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sent.recipient(),
|
sent.recipient(),
|
||||||
EmailAddress::new("alice@example.org").unwrap()
|
EmailAddress::new("alice@example.org").unwrap()
|
||||||
);
|
);
|
||||||
let msg = alice.parse_msg(&sent).await;
|
let msg = alice.parse_msg(&sent).await;
|
||||||
assert!(!msg.was_encrypted());
|
assert!(!msg.was_encrypted());
|
||||||
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vc-request");
|
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vc-request");
|
||||||
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
|
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
|
||||||
|
|
||||||
// Step 3: Alice receives vc-request, sends vc-auth-required
|
// Step 3: Alice receives vc-request, sends vc-auth-required
|
||||||
alice.recv_msg(&sent).await;
|
alice.recv_msg(&sent).await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Chatlist::try_load(&alice, 0, None, None)
|
Chatlist::try_load(&alice, 0, None, None)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.len(),
|
.len(),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
let sent = alice.pop_sent_msg().await;
|
let sent = alice.pop_sent_msg().await;
|
||||||
let msg = bob.parse_msg(&sent).await;
|
let msg = bob.parse_msg(&sent).await;
|
||||||
assert!(msg.was_encrypted());
|
assert!(msg.was_encrypted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
"vc-auth-required"
|
"vc-auth-required"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Step 4: Bob receives vc-auth-required, sends vc-request-with-auth
|
// Step 4: Bob receives vc-auth-required, sends vc-request-with-auth
|
||||||
bob.recv_msg(&sent).await;
|
bob.recv_msg(&sent).await;
|
||||||
|
|
||||||
// Check Bob emitted the JoinerProgress event.
|
// Check Bob emitted the JoinerProgress event.
|
||||||
let event = bob
|
let event = bob
|
||||||
.evtracker
|
.evtracker
|
||||||
.get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. }))
|
.get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. }))
|
||||||
.await;
|
.await;
|
||||||
match event {
|
match event {
|
||||||
EventType::SecurejoinJoinerProgress {
|
EventType::SecurejoinJoinerProgress {
|
||||||
contact_id,
|
contact_id,
|
||||||
progress,
|
progress,
|
||||||
} => {
|
} => {
|
||||||
let alice_contact_id =
|
let alice_contact_id =
|
||||||
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
||||||
.await
|
.await
|
||||||
.expect("Error looking up contact")
|
.expect("Error looking up contact")
|
||||||
.expect("Contact not found");
|
.expect("Contact not found");
|
||||||
assert_eq!(contact_id, alice_contact_id);
|
assert_eq!(contact_id, alice_contact_id);
|
||||||
assert_eq!(progress, 400);
|
assert_eq!(progress, 400);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Bob sent the right message.
|
// Check Bob sent the right message.
|
||||||
let sent = bob.pop_sent_msg().await;
|
let sent = bob.pop_sent_msg().await;
|
||||||
let msg = alice.parse_msg(&sent).await;
|
let msg = alice.parse_msg(&sent).await;
|
||||||
assert!(msg.was_encrypted());
|
assert!(msg.was_encrypted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
"vc-request-with-auth"
|
"vc-request-with-auth"
|
||||||
);
|
);
|
||||||
assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some());
|
assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some());
|
||||||
let bob_fp = SignedPublicKey::load_self(&bob.ctx)
|
let bob_fp = SignedPublicKey::load_self(&bob.ctx)
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.fingerprint();
|
|
||||||
assert_eq!(
|
|
||||||
*msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(),
|
|
||||||
bob_fp.hex()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Alice should not yet have Bob verified
|
|
||||||
let contact_bob_id =
|
|
||||||
Contact::lookup_id_by_addr(&alice.ctx, "bob@example.net", Origin::Unknown)
|
|
||||||
.await
|
|
||||||
.expect("Error looking up contact")
|
|
||||||
.expect("Contact not found");
|
|
||||||
let contact_bob = Contact::load_from_db(&alice.ctx, contact_bob_id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&alice.ctx).await.unwrap(),
|
|
||||||
VerifiedStatus::Unverified
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm
|
|
||||||
alice.recv_msg(&sent).await;
|
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&alice.ctx).await.unwrap(),
|
|
||||||
VerifiedStatus::BidirectVerified
|
|
||||||
);
|
|
||||||
|
|
||||||
// exactly one one-to-one chat should be visible for both now
|
|
||||||
// (check this before calling alice.create_chat() explicitly below)
|
|
||||||
assert_eq!(
|
|
||||||
Chatlist::try_load(&alice, 0, None, None)
|
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.len(),
|
.fingerprint();
|
||||||
1
|
assert_eq!(
|
||||||
);
|
*msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(),
|
||||||
assert_eq!(
|
bob_fp.hex()
|
||||||
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
);
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check Alice got the verified message in her 1:1 chat.
|
// Alice should not yet have Bob verified
|
||||||
{
|
let contact_bob_id =
|
||||||
let chat = alice.create_chat(&bob).await;
|
Contact::lookup_id_by_addr(&alice.ctx, "bob@example.net", Origin::Unknown)
|
||||||
let msg_id = chat::get_chat_msgs(&alice.ctx, chat.get_id(), DC_GCM_ADDDAYMARKER)
|
.await
|
||||||
|
.expect("Error looking up contact")
|
||||||
|
.expect("Contact not found");
|
||||||
|
let contact_bob = Contact::load_from_db(&alice.ctx, contact_bob_id)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.into_iter()
|
assert_eq!(
|
||||||
.filter_map(|item| match item {
|
contact_bob.is_verified(&alice.ctx).await.unwrap(),
|
||||||
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
VerifiedStatus::Unverified
|
||||||
_ => None,
|
);
|
||||||
})
|
|
||||||
.max()
|
|
||||||
.expect("No messages in Alice's 1:1 chat");
|
|
||||||
let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap();
|
|
||||||
assert!(msg.is_info());
|
|
||||||
let text = msg.get_text().unwrap();
|
|
||||||
assert!(text.contains("bob@example.net verified"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Alice sent the right message to Bob.
|
// Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm
|
||||||
let sent = alice.pop_sent_msg().await;
|
alice.recv_msg(&sent).await;
|
||||||
let msg = bob.parse_msg(&sent).await;
|
assert_eq!(
|
||||||
assert!(msg.was_encrypted());
|
contact_bob.is_verified(&alice.ctx).await.unwrap(),
|
||||||
assert_eq!(
|
VerifiedStatus::BidirectVerified
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
);
|
||||||
"vc-contact-confirm"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Bob should not yet have Alice verified
|
// exactly one one-to-one chat should be visible for both now
|
||||||
let contact_alice_id =
|
// (check this before calling alice.create_chat() explicitly below)
|
||||||
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
assert_eq!(
|
||||||
|
Chatlist::try_load(&alice, 0, None, None)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.len(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check Alice got the verified message in her 1:1 chat.
|
||||||
|
{
|
||||||
|
let chat = alice.create_chat(&bob).await;
|
||||||
|
let msg_id = chat::get_chat_msgs(&alice.ctx, chat.get_id(), DC_GCM_ADDDAYMARKER)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|item| match item {
|
||||||
|
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.max()
|
||||||
|
.expect("No messages in Alice's 1:1 chat");
|
||||||
|
let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap();
|
||||||
|
assert!(msg.is_info());
|
||||||
|
let text = msg.get_text().unwrap();
|
||||||
|
assert!(text.contains("bob@example.net verified"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Alice sent the right message to Bob.
|
||||||
|
let sent = alice.pop_sent_msg().await;
|
||||||
|
let msg = bob.parse_msg(&sent).await;
|
||||||
|
assert!(msg.was_encrypted());
|
||||||
|
assert_eq!(
|
||||||
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
|
"vc-contact-confirm"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Bob should not yet have Alice verified
|
||||||
|
let contact_alice_id =
|
||||||
|
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
||||||
|
.await
|
||||||
|
.expect("Error looking up contact")
|
||||||
|
.expect("Contact not found");
|
||||||
|
let contact_alice = Contact::load_from_db(&bob.ctx, contact_alice_id)
|
||||||
.await
|
.await
|
||||||
.expect("Error looking up contact")
|
.unwrap();
|
||||||
.expect("Contact not found");
|
assert_eq!(
|
||||||
let contact_alice = Contact::load_from_db(&bob.ctx, contact_alice_id)
|
contact_bob.is_verified(&bob.ctx).await.unwrap(),
|
||||||
.await
|
VerifiedStatus::Unverified
|
||||||
.unwrap();
|
);
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&bob.ctx).await.unwrap(),
|
|
||||||
VerifiedStatus::Unverified
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 7: Bob receives vc-contact-confirm, sends vc-contact-confirm-received
|
// Step 7: Bob receives vc-contact-confirm, sends vc-contact-confirm-received
|
||||||
bob.recv_msg(&sent).await;
|
bob.recv_msg(&sent).await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
contact_alice.is_verified(&bob.ctx).await.unwrap(),
|
contact_alice.is_verified(&bob.ctx).await.unwrap(),
|
||||||
VerifiedStatus::BidirectVerified
|
VerifiedStatus::BidirectVerified
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check Bob got the verified message in his 1:1 chat.
|
// Check Bob got the verified message in his 1:1 chat.
|
||||||
{
|
{
|
||||||
let chat = bob.create_chat(&alice).await;
|
let chat = bob.create_chat(&alice).await;
|
||||||
let msg_id = chat::get_chat_msgs(&bob.ctx, chat.get_id(), DC_GCM_ADDDAYMARKER)
|
let msg_id = chat::get_chat_msgs(&bob.ctx, chat.get_id(), DC_GCM_ADDDAYMARKER)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|item| match item {
|
.filter_map(|item| match item {
|
||||||
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.max()
|
.max()
|
||||||
.expect("No messages in Bob's 1:1 chat");
|
.expect("No messages in Bob's 1:1 chat");
|
||||||
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
||||||
assert!(msg.is_info());
|
assert!(msg.is_info());
|
||||||
let text = msg.get_text().unwrap();
|
let text = msg.get_text().unwrap();
|
||||||
assert!(text.contains("alice@example.org verified"));
|
assert!(text.contains("alice@example.org verified"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check Bob sent the final message
|
// Check Bob sent the final message
|
||||||
let sent = bob.pop_sent_msg().await;
|
let sent = bob.pop_sent_msg().await;
|
||||||
let msg = alice.parse_msg(&sent).await;
|
let msg = alice.parse_msg(&sent).await;
|
||||||
assert!(msg.was_encrypted());
|
assert!(msg.was_encrypted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
"vc-contact-confirm-received"
|
"vc-contact-confirm-received"
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
return tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.worker_threads(2usize)
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("Failed building the Runtime")
|
||||||
|
.block_on(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
@@ -1068,231 +1076,240 @@ mod tests {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[test]
|
||||||
async fn test_secure_join() -> Result<()> {
|
fn test_secure_join() -> Result<()> {
|
||||||
let mut tcm = TestContextManager::new();
|
let body = Box::pin(async {
|
||||||
let alice = tcm.alice().await;
|
let mut tcm = TestContextManager::new();
|
||||||
let bob = tcm.bob().await;
|
let alice = tcm.alice().await;
|
||||||
|
let bob = tcm.bob().await;
|
||||||
|
|
||||||
// We start with empty chatlists.
|
// We start with empty chatlists.
|
||||||
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 0);
|
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 0);
|
||||||
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 0);
|
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 0);
|
||||||
|
|
||||||
let alice_chatid =
|
let alice_chatid =
|
||||||
chat::create_group_chat(&alice.ctx, ProtectionStatus::Protected, "the chat").await?;
|
chat::create_group_chat(&alice.ctx, ProtectionStatus::Protected, "the chat")
|
||||||
|
.await?;
|
||||||
|
|
||||||
// Step 1: Generate QR-code, secure-join implied by chatid
|
// Step 1: Generate QR-code, secure-join implied by chatid
|
||||||
let qr = get_securejoin_qr(&alice.ctx, Some(alice_chatid))
|
let qr = get_securejoin_qr(&alice.ctx, Some(alice_chatid))
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Step 2: Bob scans QR-code, sends vg-request
|
|
||||||
let bob_chatid = join_securejoin(&bob.ctx, &qr).await?;
|
|
||||||
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 1);
|
|
||||||
|
|
||||||
let sent = bob.pop_sent_msg().await;
|
|
||||||
assert_eq!(
|
|
||||||
sent.recipient(),
|
|
||||||
EmailAddress::new("alice@example.org").unwrap()
|
|
||||||
);
|
|
||||||
let msg = alice.parse_msg(&sent).await;
|
|
||||||
assert!(!msg.was_encrypted());
|
|
||||||
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vg-request");
|
|
||||||
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
|
|
||||||
|
|
||||||
// Step 3: Alice receives vg-request, sends vg-auth-required
|
|
||||||
alice.recv_msg(&sent).await;
|
|
||||||
|
|
||||||
let sent = alice.pop_sent_msg().await;
|
|
||||||
let msg = bob.parse_msg(&sent).await;
|
|
||||||
assert!(msg.was_encrypted());
|
|
||||||
assert_eq!(
|
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
|
||||||
"vg-auth-required"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 4: Bob receives vg-auth-required, sends vg-request-with-auth
|
|
||||||
bob.recv_msg(&sent).await;
|
|
||||||
let sent = bob.pop_sent_msg().await;
|
|
||||||
|
|
||||||
// Check Bob emitted the JoinerProgress event.
|
|
||||||
let event = bob
|
|
||||||
.evtracker
|
|
||||||
.get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. }))
|
|
||||||
.await;
|
|
||||||
match event {
|
|
||||||
EventType::SecurejoinJoinerProgress {
|
|
||||||
contact_id,
|
|
||||||
progress,
|
|
||||||
} => {
|
|
||||||
let alice_contact_id =
|
|
||||||
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
|
||||||
.await
|
|
||||||
.expect("Error looking up contact")
|
|
||||||
.expect("Contact not found");
|
|
||||||
assert_eq!(contact_id, alice_contact_id);
|
|
||||||
assert_eq!(progress, 400);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Bob sent the right handshake message.
|
|
||||||
let msg = alice.parse_msg(&sent).await;
|
|
||||||
assert!(msg.was_encrypted());
|
|
||||||
assert_eq!(
|
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
|
||||||
"vg-request-with-auth"
|
|
||||||
);
|
|
||||||
assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some());
|
|
||||||
let bob_fp = SignedPublicKey::load_self(&bob.ctx).await?.fingerprint();
|
|
||||||
assert_eq!(
|
|
||||||
*msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(),
|
|
||||||
bob_fp.hex()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Alice should not yet have Bob verified
|
|
||||||
let contact_bob_id =
|
|
||||||
Contact::lookup_id_by_addr(&alice.ctx, "bob@example.net", Origin::Unknown)
|
|
||||||
.await?
|
|
||||||
.expect("Contact not found");
|
|
||||||
let contact_bob = Contact::load_from_db(&alice.ctx, contact_bob_id).await?;
|
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&alice.ctx).await?,
|
|
||||||
VerifiedStatus::Unverified
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 5+6: Alice receives vg-request-with-auth, sends vg-member-added
|
|
||||||
alice.recv_msg(&sent).await;
|
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&alice.ctx).await?,
|
|
||||||
VerifiedStatus::BidirectVerified
|
|
||||||
);
|
|
||||||
|
|
||||||
let sent = alice.pop_sent_msg().await;
|
|
||||||
let msg = bob.parse_msg(&sent).await;
|
|
||||||
assert!(msg.was_encrypted());
|
|
||||||
assert_eq!(
|
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
|
||||||
"vg-member-added"
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Now Alice's chat with Bob should still be hidden, the verified message should
|
|
||||||
// appear in the group chat.
|
|
||||||
|
|
||||||
let chat = alice
|
|
||||||
.get_chat(&bob)
|
|
||||||
.await
|
.await
|
||||||
.expect("Alice has no 1:1 chat with bob");
|
.unwrap();
|
||||||
|
|
||||||
|
// Step 2: Bob scans QR-code, sends vg-request
|
||||||
|
let bob_chatid = join_securejoin(&bob.ctx, &qr).await?;
|
||||||
|
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 1);
|
||||||
|
|
||||||
|
let sent = bob.pop_sent_msg().await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chat.blocked,
|
sent.recipient(),
|
||||||
Blocked::Yes,
|
EmailAddress::new("alice@example.org").unwrap()
|
||||||
"Alice's 1:1 chat with Bob is not hidden"
|
|
||||||
);
|
);
|
||||||
let msg_id = chat::get_chat_msgs(&alice.ctx, alice_chatid, DC_GCM_ADDDAYMARKER)
|
let msg = alice.parse_msg(&sent).await;
|
||||||
.await
|
assert!(!msg.was_encrypted());
|
||||||
.unwrap()
|
assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vg-request");
|
||||||
.into_iter()
|
assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some());
|
||||||
.filter_map(|item| match item {
|
|
||||||
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.min()
|
|
||||||
.expect("No messages in Alice's group chat");
|
|
||||||
let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap();
|
|
||||||
assert!(msg.is_info());
|
|
||||||
let text = msg.get_text().unwrap();
|
|
||||||
assert!(text.contains("bob@example.net verified"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bob should not yet have Alice verified
|
// Step 3: Alice receives vg-request, sends vg-auth-required
|
||||||
let contact_alice_id =
|
alice.recv_msg(&sent).await;
|
||||||
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
|
||||||
.await
|
|
||||||
.expect("Error looking up contact")
|
|
||||||
.expect("Contact not found");
|
|
||||||
let contact_alice = Contact::load_from_db(&bob.ctx, contact_alice_id).await?;
|
|
||||||
assert_eq!(
|
|
||||||
contact_bob.is_verified(&bob.ctx).await?,
|
|
||||||
VerifiedStatus::Unverified
|
|
||||||
);
|
|
||||||
|
|
||||||
// Step 7: Bob receives vg-member-added, sends vg-member-added-received
|
let sent = alice.pop_sent_msg().await;
|
||||||
bob.recv_msg(&sent).await;
|
let msg = bob.parse_msg(&sent).await;
|
||||||
{
|
assert!(msg.was_encrypted());
|
||||||
// Bob has Alice verified, message shows up in the group chat.
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
contact_alice.is_verified(&bob.ctx).await?,
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
|
"vg-auth-required"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 4: Bob receives vg-auth-required, sends vg-request-with-auth
|
||||||
|
bob.recv_msg(&sent).await;
|
||||||
|
let sent = bob.pop_sent_msg().await;
|
||||||
|
|
||||||
|
// Check Bob emitted the JoinerProgress event.
|
||||||
|
let event = bob
|
||||||
|
.evtracker
|
||||||
|
.get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. }))
|
||||||
|
.await;
|
||||||
|
match event {
|
||||||
|
EventType::SecurejoinJoinerProgress {
|
||||||
|
contact_id,
|
||||||
|
progress,
|
||||||
|
} => {
|
||||||
|
let alice_contact_id =
|
||||||
|
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
||||||
|
.await
|
||||||
|
.expect("Error looking up contact")
|
||||||
|
.expect("Contact not found");
|
||||||
|
assert_eq!(contact_id, alice_contact_id);
|
||||||
|
assert_eq!(progress, 400);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Bob sent the right handshake message.
|
||||||
|
let msg = alice.parse_msg(&sent).await;
|
||||||
|
assert!(msg.was_encrypted());
|
||||||
|
assert_eq!(
|
||||||
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
|
"vg-request-with-auth"
|
||||||
|
);
|
||||||
|
assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some());
|
||||||
|
let bob_fp = SignedPublicKey::load_self(&bob.ctx).await?.fingerprint();
|
||||||
|
assert_eq!(
|
||||||
|
*msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(),
|
||||||
|
bob_fp.hex()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Alice should not yet have Bob verified
|
||||||
|
let contact_bob_id =
|
||||||
|
Contact::lookup_id_by_addr(&alice.ctx, "bob@example.net", Origin::Unknown)
|
||||||
|
.await?
|
||||||
|
.expect("Contact not found");
|
||||||
|
let contact_bob = Contact::load_from_db(&alice.ctx, contact_bob_id).await?;
|
||||||
|
assert_eq!(
|
||||||
|
contact_bob.is_verified(&alice.ctx).await?,
|
||||||
|
VerifiedStatus::Unverified
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 5+6: Alice receives vg-request-with-auth, sends vg-member-added
|
||||||
|
alice.recv_msg(&sent).await;
|
||||||
|
assert_eq!(
|
||||||
|
contact_bob.is_verified(&alice.ctx).await?,
|
||||||
VerifiedStatus::BidirectVerified
|
VerifiedStatus::BidirectVerified
|
||||||
);
|
);
|
||||||
let chat = bob
|
|
||||||
.get_chat(&alice)
|
let sent = alice.pop_sent_msg().await;
|
||||||
.await
|
let msg = bob.parse_msg(&sent).await;
|
||||||
.expect("Bob has no 1:1 chat with Alice");
|
assert!(msg.was_encrypted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
chat.blocked,
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
Blocked::Yes,
|
"vg-member-added"
|
||||||
"Bob's 1:1 chat with Alice is not hidden"
|
|
||||||
);
|
);
|
||||||
for item in chat::get_chat_msgs(&bob.ctx, bob_chatid, DC_GCM_ADDDAYMARKER)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
{
|
{
|
||||||
if let chat::ChatItem::Message { msg_id } = item {
|
// Now Alice's chat with Bob should still be hidden, the verified message should
|
||||||
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
// appear in the group chat.
|
||||||
let text = msg.get_text().unwrap();
|
|
||||||
println!("msg {} text: {}", msg_id, text);
|
let chat = alice
|
||||||
}
|
.get_chat(&bob)
|
||||||
|
.await
|
||||||
|
.expect("Alice has no 1:1 chat with bob");
|
||||||
|
assert_eq!(
|
||||||
|
chat.blocked,
|
||||||
|
Blocked::Yes,
|
||||||
|
"Alice's 1:1 chat with Bob is not hidden"
|
||||||
|
);
|
||||||
|
let msg_id = chat::get_chat_msgs(&alice.ctx, alice_chatid, DC_GCM_ADDDAYMARKER)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|item| match item {
|
||||||
|
chat::ChatItem::Message { msg_id } => Some(msg_id),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.min()
|
||||||
|
.expect("No messages in Alice's group chat");
|
||||||
|
let msg = Message::load_from_db(&alice.ctx, msg_id).await.unwrap();
|
||||||
|
assert!(msg.is_info());
|
||||||
|
let text = msg.get_text().unwrap();
|
||||||
|
assert!(text.contains("bob@example.net verified"));
|
||||||
}
|
}
|
||||||
let mut msg_iter = chat::get_chat_msgs(&bob.ctx, bob_chatid, DC_GCM_ADDDAYMARKER)
|
|
||||||
.await
|
// Bob should not yet have Alice verified
|
||||||
.unwrap()
|
let contact_alice_id =
|
||||||
.into_iter();
|
Contact::lookup_id_by_addr(&bob.ctx, "alice@example.org", Origin::Unknown)
|
||||||
loop {
|
.await
|
||||||
match msg_iter.next() {
|
.expect("Error looking up contact")
|
||||||
Some(chat::ChatItem::Message { msg_id }) => {
|
.expect("Contact not found");
|
||||||
|
let contact_alice = Contact::load_from_db(&bob.ctx, contact_alice_id).await?;
|
||||||
|
assert_eq!(
|
||||||
|
contact_bob.is_verified(&bob.ctx).await?,
|
||||||
|
VerifiedStatus::Unverified
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 7: Bob receives vg-member-added, sends vg-member-added-received
|
||||||
|
bob.recv_msg(&sent).await;
|
||||||
|
{
|
||||||
|
// Bob has Alice verified, message shows up in the group chat.
|
||||||
|
assert_eq!(
|
||||||
|
contact_alice.is_verified(&bob.ctx).await?,
|
||||||
|
VerifiedStatus::BidirectVerified
|
||||||
|
);
|
||||||
|
let chat = bob
|
||||||
|
.get_chat(&alice)
|
||||||
|
.await
|
||||||
|
.expect("Bob has no 1:1 chat with Alice");
|
||||||
|
assert_eq!(
|
||||||
|
chat.blocked,
|
||||||
|
Blocked::Yes,
|
||||||
|
"Bob's 1:1 chat with Alice is not hidden"
|
||||||
|
);
|
||||||
|
for item in chat::get_chat_msgs(&bob.ctx, bob_chatid, DC_GCM_ADDDAYMARKER)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
if let chat::ChatItem::Message { msg_id } = item {
|
||||||
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
||||||
let text = msg.get_text().unwrap();
|
let text = msg.get_text().unwrap();
|
||||||
match text.contains("alice@example.org verified") {
|
println!("msg {} text: {}", msg_id, text);
|
||||||
true => {
|
}
|
||||||
assert!(msg.is_info());
|
}
|
||||||
break;
|
let mut msg_iter = chat::get_chat_msgs(&bob.ctx, bob_chatid, DC_GCM_ADDDAYMARKER)
|
||||||
}
|
.await
|
||||||
false => continue,
|
.unwrap()
|
||||||
}
|
.into_iter();
|
||||||
|
loop {
|
||||||
|
match msg_iter.next() {
|
||||||
|
Some(chat::ChatItem::Message { msg_id }) => {
|
||||||
|
let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap();
|
||||||
|
let text = msg.get_text().unwrap();
|
||||||
|
match text.contains("alice@example.org verified") {
|
||||||
|
true => {
|
||||||
|
assert!(msg.is_info());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
false => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(_) => continue,
|
||||||
|
None => panic!("Verified message not found in Bob's group chat"),
|
||||||
}
|
}
|
||||||
Some(_) => continue,
|
|
||||||
None => panic!("Verified message not found in Bob's group chat"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let sent = bob.pop_sent_msg().await;
|
let sent = bob.pop_sent_msg().await;
|
||||||
let msg = alice.parse_msg(&sent).await;
|
let msg = alice.parse_msg(&sent).await;
|
||||||
assert!(msg.was_encrypted());
|
assert!(msg.was_encrypted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
msg.get_header(HeaderDef::SecureJoin).unwrap(),
|
||||||
"vg-member-added-received"
|
"vg-member-added-received"
|
||||||
);
|
);
|
||||||
|
|
||||||
let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await?;
|
let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await?;
|
||||||
assert!(bob_chat.is_protected());
|
assert!(bob_chat.is_protected());
|
||||||
assert!(bob_chat.typ == Chattype::Group);
|
assert!(bob_chat.typ == Chattype::Group);
|
||||||
|
|
||||||
// On this "happy path", Alice and Bob get only a group-chat where all information are added to.
|
// On this "happy path", Alice and Bob get only a group-chat where all information are added to.
|
||||||
// The one-to-one chats are used internally for the hidden handshake messages,
|
// The one-to-one chats are used internally for the hidden handshake messages,
|
||||||
// however, should not be visible in the UIs.
|
// however, should not be visible in the UIs.
|
||||||
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 1);
|
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 1);
|
||||||
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 1);
|
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 1);
|
||||||
|
|
||||||
// If Bob then sends a direct message to alice, however, the one-to-one with Alice should appear.
|
// If Bob then sends a direct message to alice, however, the one-to-one with Alice should appear.
|
||||||
let bobs_chat_with_alice = bob.create_chat(&alice).await;
|
let bobs_chat_with_alice = bob.create_chat(&alice).await;
|
||||||
let sent = bob.send_text(bobs_chat_with_alice.id, "Hello").await;
|
let sent = bob.send_text(bobs_chat_with_alice.id, "Hello").await;
|
||||||
alice.recv_msg(&sent).await;
|
alice.recv_msg(&sent).await;
|
||||||
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 2);
|
assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 2);
|
||||||
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 2);
|
assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 2);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
});
|
||||||
|
return tokio::runtime::Builder::new_multi_thread()
|
||||||
|
.worker_threads(2usize)
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.expect("Failed building the Runtime")
|
||||||
|
.block_on(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
|||||||
Reference in New Issue
Block a user