| | use std::time::Duration; |
| |
|
| | use deltachat_contact_tools::EmailAddress; |
| |
|
| | use super::*; |
| | use crate::chat::{CantSendReason, add_contact_to_chat, remove_contact_from_chat}; |
| | use crate::chatlist::Chatlist; |
| | use crate::constants::Chattype; |
| | use crate::constants::DC_CHAT_ID_TRASH; |
| | use crate::key::self_fingerprint; |
| | use crate::mimeparser::{GossipedKey, SystemMessage}; |
| | use crate::qr::Qr; |
| | use crate::receive_imf::receive_imf; |
| | use crate::stock_str::{self, messages_e2e_encrypted}; |
| | use crate::test_utils::{ |
| | AVATAR_64x64_BYTES, AVATAR_64x64_DEDUPLICATED, TestContext, TestContextManager, |
| | TimeShiftFalsePositiveNote, get_chat_msg, |
| | }; |
| | use crate::tools::SystemTime; |
| |
|
| | #[derive(PartialEq)] |
| | enum SetupContactCase { |
| | Normal, |
| | WrongAliceGossip, |
| | AliceIsBot, |
| | AliceHasName, |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact() { |
| | test_setup_contact_ex(SetupContactCase::Normal).await |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_wrong_alice_gossip() { |
| | test_setup_contact_ex(SetupContactCase::WrongAliceGossip).await |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_alice_is_bot() { |
| | test_setup_contact_ex(SetupContactCase::AliceIsBot).await |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_alice_has_name() { |
| | test_setup_contact_ex(SetupContactCase::AliceHasName).await |
| | } |
| |
|
| | async fn test_setup_contact_ex(case: SetupContactCase) { |
| | let _n = TimeShiftFalsePositiveNote; |
| |
|
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let alice_addr = &alice.get_config(Config::Addr).await.unwrap().unwrap(); |
| | if case == SetupContactCase::AliceHasName { |
| | alice |
| | .set_config(Config::Displayname, Some("Alice")) |
| | .await |
| | .unwrap(); |
| | } |
| | let bob = tcm.bob().await; |
| | bob.set_config(Config::Displayname, Some("Bob Examplenet")) |
| | .await |
| | .unwrap(); |
| | let alice_auto_submitted_hdr; |
| | match case { |
| | SetupContactCase::AliceIsBot => { |
| | alice.set_config_bool(Config::Bot, true).await.unwrap(); |
| | alice_auto_submitted_hdr = "Auto-Submitted: auto-generated"; |
| | } |
| | _ => alice_auto_submitted_hdr = "Auto-Submitted: auto-replied", |
| | }; |
| |
|
| | assert_eq!( |
| | Chatlist::try_load(&alice, 0, None, None) |
| | .await |
| | .unwrap() |
| | .len(), |
| | 0 |
| | ); |
| | assert_eq!( |
| | Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(), |
| | 0 |
| | ); |
| |
|
| | tcm.section("Step 1: Generate QR-code, ChatId(0) indicates setup-contact"); |
| | let qr = get_securejoin_qr(&alice, None).await.unwrap(); |
| | |
| | alice |
| | .set_config(Config::Displayname, Some("Alice Exampleorg")) |
| | .await |
| | .unwrap(); |
| |
|
| | tcm.section("Step 2: Bob scans QR-code, sends vc-request"); |
| | let bob_chat_id = join_securejoin(&bob.ctx, &qr).await.unwrap(); |
| | assert_eq!( |
| | Chatlist::try_load(&bob, 0, None, None).await.unwrap().len(), |
| | 1 |
| | ); |
| | let bob_chat = Chat::load_from_db(&bob, bob_chat_id).await.unwrap(); |
| | assert_eq!( |
| | bob_chat.why_cant_send(&bob).await.unwrap(), |
| | Some(CantSendReason::MissingKey) |
| | ); |
| |
|
| | |
| | let msg_cnt = 2; |
| | let mut i = 0..msg_cnt; |
| | let msg = get_chat_msg(&bob, bob_chat.get_id(), i.next().unwrap(), msg_cnt).await; |
| | assert!(msg.is_info()); |
| | assert_eq!(msg.get_text(), messages_e2e_encrypted(&bob).await); |
| | let msg = get_chat_msg(&bob, bob_chat.get_id(), i.next().unwrap(), msg_cnt).await; |
| | assert!(msg.is_info()); |
| | assert_eq!(msg.get_text(), stock_str::securejoin_wait(&bob).await); |
| |
|
| | let contact_alice_id = bob.add_or_lookup_contact_no_key(&alice).await.id; |
| | let sent = bob.pop_sent_msg().await; |
| | assert!(!sent.payload.contains("Bob Examplenet")); |
| | assert_eq!(sent.recipient(), EmailAddress::new(alice_addr).unwrap()); |
| | let msg = alice.parse_msg(&sent).await; |
| | assert!(!msg.was_encrypted()); |
| | assert_eq!(msg.get_header(HeaderDef::SecureJoin).unwrap(), "vc-request"); |
| | assert!(msg.get_header(HeaderDef::SecureJoinInvitenumber).is_some()); |
| | assert!(!msg.header_exists(HeaderDef::AutoSubmitted)); |
| |
|
| | tcm.section("Step 3: Alice receives vc-request, sends vc-auth-required"); |
| | alice.recv_msg_trash(&sent).await; |
| | assert_eq!( |
| | Chatlist::try_load(&alice, 0, None, None) |
| | .await |
| | .unwrap() |
| | .len(), |
| | 0 |
| | ); |
| |
|
| | let sent = alice.pop_sent_msg().await; |
| | assert!(sent.payload.contains(alice_auto_submitted_hdr)); |
| | assert!(!sent.payload.contains("Alice Exampleorg")); |
| | let msg = bob.parse_msg(&sent).await; |
| | assert!(msg.was_encrypted()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-auth-required" |
| | ); |
| |
|
| | let bob_chat = bob.get_chat(&alice).await; |
| | assert_eq!(bob_chat.can_send(&bob).await.unwrap(), true); |
| |
|
| | tcm.section("Step 4: Bob receives vc-auth-required, sends vc-request-with-auth"); |
| | bob.recv_msg_trash(&sent).await; |
| | let bob_chat = bob.get_chat(&alice).await; |
| | assert_eq!(bob_chat.why_cant_send(&bob).await.unwrap(), None); |
| | assert_eq!(bob_chat.can_send(&bob).await.unwrap(), true); |
| |
|
| | |
| | let event = bob |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. })) |
| | .await; |
| | match event { |
| | EventType::SecurejoinJoinerProgress { |
| | contact_id, |
| | progress, |
| | } => { |
| | assert_eq!(contact_id, contact_alice_id); |
| | assert_eq!(progress, 400); |
| | } |
| | _ => unreachable!(), |
| | } |
| |
|
| | |
| | let sent = bob.pop_sent_msg().await; |
| | assert!(sent.payload.contains("Auto-Submitted: auto-replied")); |
| | assert!(!sent.payload.contains("Bob Examplenet")); |
| | let mut msg = alice.parse_msg(&sent).await; |
| | assert!(msg.was_encrypted()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-request-with-auth" |
| | ); |
| | assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); |
| | let bob_fp = self_fingerprint(&bob).await.unwrap(); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), |
| | bob_fp |
| | ); |
| |
|
| | if case == SetupContactCase::WrongAliceGossip { |
| | let wrong_pubkey = GossipedKey { |
| | public_key: load_self_public_key(&bob).await.unwrap(), |
| | verified: false, |
| | }; |
| | let alice_pubkey = msg |
| | .gossiped_keys |
| | .insert(alice_addr.to_string(), wrong_pubkey) |
| | .unwrap(); |
| | let contact_bob = alice.add_or_lookup_contact_no_key(&bob).await; |
| | let handshake_msg = handle_securejoin_handshake(&alice, &mut msg, contact_bob.id) |
| | .await |
| | .unwrap(); |
| | assert_eq!(handshake_msg, HandshakeMessage::Ignore); |
| | assert_eq!(contact_bob.is_verified(&alice).await.unwrap(), false); |
| |
|
| | msg.gossiped_keys |
| | .insert(alice_addr.to_string(), alice_pubkey) |
| | .unwrap(); |
| | let handshake_msg = handle_securejoin_handshake(&alice, &mut msg, contact_bob.id) |
| | .await |
| | .unwrap(); |
| | assert_eq!(handshake_msg, HandshakeMessage::Ignore); |
| | assert!(contact_bob.is_verified(&alice).await.unwrap()); |
| | return; |
| | } |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(&bob).await; |
| | let contact_bob_id = contact_bob.id; |
| | assert_eq!(contact_bob.is_key_contact(), true); |
| | assert_eq!(contact_bob.is_verified(&alice).await.unwrap(), false); |
| | assert_eq!(contact_bob.get_authname(), ""); |
| |
|
| | tcm.section("Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm"); |
| | alice.recv_msg_trash(&sent).await; |
| | assert_eq!(contact_bob.is_verified(&alice).await.unwrap(), true); |
| | let contact_bob = Contact::get_by_id(&alice, contact_bob_id).await.unwrap(); |
| | assert_eq!(contact_bob.get_authname(), "Bob Examplenet"); |
| | assert!(contact_bob.get_name().is_empty()); |
| | assert_eq!(contact_bob.is_bot(), false); |
| |
|
| | |
| | |
| | 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 |
| | ); |
| |
|
| | |
| | { |
| | let chat = alice.get_chat(&bob).await; |
| | let msg = get_chat_msg(&alice, chat.get_id(), 0, 1).await; |
| | assert!(msg.is_info()); |
| | let expected_text = messages_e2e_encrypted(&alice).await; |
| | assert_eq!(msg.get_text(), expected_text); |
| | } |
| |
|
| | |
| | let contact_alice = Contact::get_by_id(&bob.ctx, contact_alice_id) |
| | .await |
| | .unwrap(); |
| | match case { |
| | SetupContactCase::AliceHasName => assert_eq!(contact_alice.get_authname(), "Alice"), |
| | _ => assert_eq!(contact_alice.get_authname(), ""), |
| | }; |
| |
|
| | |
| | let sent = alice.pop_sent_msg().await; |
| | assert!(sent.payload.contains(alice_auto_submitted_hdr)); |
| | assert!(!sent.payload.contains("Alice Exampleorg")); |
| | let msg = bob.parse_msg(&sent).await; |
| | assert!(msg.was_encrypted()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-contact-confirm" |
| | ); |
| |
|
| | |
| | |
| | |
| | assert_eq!(contact_alice.is_verified(&bob.ctx).await.unwrap(), true); |
| |
|
| | |
| | bob.recv_msg_trash(&sent).await; |
| | assert_eq!(contact_alice.is_verified(&bob.ctx).await.unwrap(), true); |
| | let contact_alice = Contact::get_by_id(&bob.ctx, contact_alice_id) |
| | .await |
| | .unwrap(); |
| | assert_eq!(contact_alice.get_authname(), "Alice Exampleorg"); |
| | assert!(contact_alice.get_name().is_empty()); |
| | assert_eq!(contact_alice.is_bot(), case == SetupContactCase::AliceIsBot); |
| |
|
| | |
| | let msg = get_chat_msg(&bob, bob_chat.get_id(), 0, 1).await; |
| | assert!(msg.is_info()); |
| | assert_eq!(msg.get_text(), messages_e2e_encrypted(&bob).await); |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_bad_qr() { |
| | let bob = TestContext::new_bob().await; |
| | let ret = join_securejoin(&bob.ctx, "not a qr code").await; |
| | assert!(ret.is_err()); |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_bob_knows_alice() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | |
| | let alice_contact_id = bob.add_or_lookup_contact_id(alice).await; |
| |
|
| | tcm.section("Step 1: Generate QR-code"); |
| | |
| | let qr = get_securejoin_qr(alice, None).await?; |
| |
|
| | tcm.section("Step 2+4: Bob scans QR-code, sends vc-request-with-auth, skipping vc-request"); |
| | join_securejoin(bob, &qr).await.unwrap(); |
| |
|
| | |
| | let event = bob |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. })) |
| | .await; |
| | match event { |
| | EventType::SecurejoinJoinerProgress { |
| | contact_id, |
| | progress, |
| | } => { |
| | assert_eq!(contact_id, alice_contact_id); |
| | assert_eq!(progress, 400); |
| | } |
| | _ => unreachable!(), |
| | } |
| |
|
| | |
| | let sent = bob.pop_sent_msg().await; |
| | let msg = alice.parse_msg(&sent).await; |
| | assert!(msg.was_encrypted()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-request-with-auth" |
| | ); |
| | assert!(msg.get_header(HeaderDef::SecureJoinAuth).is_some()); |
| | let bob_fp = load_self_public_key(bob).await?.dc_fingerprint(); |
| | assert_eq!( |
| | *msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), |
| | bob_fp.hex() |
| | ); |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(bob).await; |
| | assert_eq!(contact_bob.is_verified(alice).await?, false); |
| |
|
| | tcm.section("Step 5+6: Alice receives vc-request-with-auth, sends vc-contact-confirm"); |
| | alice.recv_msg_trash(&sent).await; |
| | assert_eq!(contact_bob.is_verified(alice).await?, true); |
| |
|
| | |
| | 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()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-contact-confirm" |
| | ); |
| |
|
| | |
| | let contact_alice = bob.add_or_lookup_contact_no_key(alice).await; |
| | assert_eq!(contact_alice.is_verified(bob).await?, true); |
| |
|
| | |
| | |
| | |
| | tcm.section("Step 7: Bob receives vc-contact-confirm"); |
| | bob.recv_msg_trash(&sent).await; |
| | assert_eq!(contact_alice.is_verified(bob).await?, true); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_setup_contact_concurrent_calls() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | |
| | let qr_stale = "OPENPGP4FPR:1234567890123456789012345678901234567890#a=claire%40foo.de&n=&i=12345678901&s=23456789012"; |
| | let claire_id = join_securejoin(&bob, qr_stale).await?; |
| | let chat = Chat::load_from_db(&bob, claire_id).await?; |
| | assert!(!claire_id.is_special()); |
| | assert_eq!(chat.typ, Chattype::Single); |
| | assert!(bob.pop_sent_msg().await.payload().contains("claire@foo.de")); |
| |
|
| | |
| | |
| | let qr = get_securejoin_qr(&alice, None).await?; |
| | let alice_id = join_securejoin(&bob, &qr).await?; |
| | let chat = Chat::load_from_db(&bob, alice_id).await?; |
| | assert!(!alice_id.is_special()); |
| | assert_eq!(chat.typ, Chattype::Single); |
| | assert_ne!(claire_id, alice_id); |
| | assert!( |
| | bob.pop_sent_msg() |
| | .await |
| | .payload() |
| | .contains("alice@example.org") |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_secure_join() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | |
| | assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 0); |
| | assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 0); |
| |
|
| | let alice_chatid = chat::create_group(&alice, "the chat").await?; |
| |
|
| | tcm.section("Step 1: Generate QR-code, secure-join implied by chatid"); |
| | let qr = get_securejoin_qr(&alice, Some(alice_chatid)).await.unwrap(); |
| |
|
| | tcm.section("Step 2: Bob scans QR-code, sends vg-request"); |
| | let bob_chatid = join_securejoin(&bob, &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()); |
| | assert!(!msg.header_exists(HeaderDef::AutoSubmitted)); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | assert!(!msg.header_exists(HeaderDef::SecureJoinGroup)); |
| |
|
| | tcm.section("Step 3: Alice receives vg-request, sends vg-auth-required"); |
| | alice.recv_msg_trash(&sent).await; |
| |
|
| | let sent = alice.pop_sent_msg().await; |
| | assert!(sent.payload.contains("Auto-Submitted: auto-replied")); |
| | let msg = bob.parse_msg(&sent).await; |
| | assert!(msg.was_encrypted()); |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vg-auth-required" |
| | ); |
| |
|
| | tcm.section("Step 4: Bob receives vg-auth-required, sends vg-request-with-auth"); |
| | bob.recv_msg_trash(&sent).await; |
| | let sent = bob.pop_sent_msg().await; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | assert_eq!(chat::get_chat_contacts(&bob, bob_chatid).await?.len(), 0); |
| |
|
| | let contact_alice_id = bob.add_or_lookup_contact_no_key(&alice).await.id; |
| |
|
| | |
| | let event = bob |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. })) |
| | .await; |
| | match event { |
| | EventType::SecurejoinJoinerProgress { |
| | contact_id, |
| | progress, |
| | } => { |
| | assert_eq!(contact_id, contact_alice_id); |
| | assert_eq!(progress, 400); |
| | } |
| | _ => unreachable!(), |
| | } |
| |
|
| | |
| | assert!(sent.payload.contains("Auto-Submitted: auto-replied")); |
| | 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 = self_fingerprint(&bob).await?; |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoinFingerprint).unwrap(), |
| | bob_fp |
| | ); |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(&bob).await; |
| | assert_eq!(contact_bob.is_verified(&alice).await?, false); |
| |
|
| | tcm.section("Step 5+6: Alice receives vg-request-with-auth, sends vg-member-added"); |
| | alice.recv_msg_trash(&sent).await; |
| | assert_eq!(contact_bob.is_verified(&alice).await?, true); |
| |
|
| | |
| | let event = alice |
| | .evtracker |
| | .get_matching(|evt| { |
| | matches!( |
| | evt, |
| | EventType::SecurejoinInviterProgress { progress: 1000, .. } |
| | ) |
| | }) |
| | .await; |
| | match event { |
| | EventType::SecurejoinInviterProgress { |
| | contact_id, |
| | chat_type, |
| | chat_id, |
| | progress, |
| | } => { |
| | assert_eq!(contact_id, contact_bob.id); |
| | assert_eq!(chat_type, Chattype::Group); |
| | assert_eq!(chat_id, alice_chatid); |
| | assert_eq!(progress, 1000); |
| | } |
| | _ => unreachable!(), |
| | } |
| |
|
| | 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" |
| | ); |
| | |
| | |
| | |
| | assert!(!msg.header_exists(HeaderDef::AutoSubmitted)); |
| | |
| | assert!(msg.get_header(HeaderDef::AutocryptGossip).is_some()); |
| |
|
| | { |
| | |
| | |
| |
|
| | let chat = alice.get_chat(&bob).await; |
| | assert_eq!( |
| | chat.blocked, |
| | Blocked::Yes, |
| | "Alice's 1:1 chat with Bob is not hidden" |
| | ); |
| | |
| | |
| | |
| | let msg = get_chat_msg(&alice, alice_chatid, 0, 2).await; |
| | assert!(msg.is_info()); |
| | let expected_text = messages_e2e_encrypted(&alice).await; |
| | assert_eq!(msg.get_text(), expected_text); |
| | } |
| |
|
| | |
| | |
| | |
| | let contact_alice = bob.add_or_lookup_contact_no_key(&alice).await; |
| | assert_eq!(contact_alice.is_verified(&bob).await?, true); |
| |
|
| | tcm.section("Step 7: Bob receives vg-member-added"); |
| | bob.recv_msg(&sent).await; |
| | { |
| | |
| | assert_eq!(contact_alice.is_verified(&bob).await?, true); |
| | let chat = bob.get_chat(&alice).await; |
| | 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).await.unwrap() { |
| | if let chat::ChatItem::Message { msg_id } = item { |
| | let msg = Message::load_from_db(&bob.ctx, msg_id).await.unwrap(); |
| | let text = msg.get_text(); |
| | println!("msg {msg_id} text: {text}"); |
| | } |
| | } |
| | } |
| |
|
| | let bob_chat = Chat::load_from_db(&bob.ctx, bob_chatid).await?; |
| | assert!(bob_chat.typ == Chattype::Group); |
| |
|
| | |
| | |
| | assert_eq!(chat::get_chat_contacts(&bob, bob_chatid).await?.len(), 2); |
| |
|
| | |
| | |
| | |
| | assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 1); |
| | assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 1); |
| |
|
| | |
| | let bobs_chat_with_alice = bob.create_chat(&alice).await; |
| | let sent = bob.send_text(bobs_chat_with_alice.id, "Hello").await; |
| | alice.recv_msg(&sent).await; |
| | assert_eq!(Chatlist::try_load(&alice, 0, None, None).await?.len(), 2); |
| | assert_eq!(Chatlist::try_load(&bob, 0, None, None).await?.len(), 2); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_adhoc_group_no_qr() -> Result<()> { |
| | let alice = TestContext::new_alice().await; |
| |
|
| | let mime = br#"Subject: First thread |
| | Message-ID: first@example.org |
| | To: Alice <alice@example.org>, Bob <bob@example.net> |
| | From: Claire <claire@example.org> |
| | Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no |
| | |
| | First thread."#; |
| |
|
| | receive_imf(&alice, mime, false).await?; |
| | let msg = alice.get_last_msg().await; |
| | let chat_id = msg.chat_id; |
| |
|
| | assert!(get_securejoin_qr(&alice, Some(chat_id)).await.is_err()); |
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_unknown_sender() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | tcm.execute_securejoin(&alice, &bob).await; |
| |
|
| | let alice_chat_id = alice |
| | .create_group_with_members("Group with Bob", &[&bob]) |
| | .await; |
| |
|
| | let sent = alice.send_text(alice_chat_id, "Hi!").await; |
| | let bob_chat_id = bob.recv_msg(&sent).await.chat_id; |
| |
|
| | let sent = bob.send_text(bob_chat_id, "Hi hi!").await; |
| |
|
| | let alice_bob_contact_id = alice.add_or_lookup_contact_id(&bob).await; |
| | remove_contact_from_chat(&alice, alice_chat_id, alice_bob_contact_id).await?; |
| | alice.pop_sent_msg().await; |
| |
|
| | |
| | let msg = alice.recv_msg(&sent).await; |
| | assert_eq!(msg.text, "Hi hi!"); |
| | assert_eq!(msg.get_override_sender_name().unwrap(), "bob@example.net"); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_lost_contact_confirm() { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = tcm.alice().await; |
| | let bob = tcm.bob().await; |
| |
|
| | let qr = get_securejoin_qr(&alice, None).await.unwrap(); |
| | join_securejoin(&bob.ctx, &qr).await.unwrap(); |
| |
|
| | |
| | let sent = bob.pop_sent_msg().await; |
| | alice.recv_msg_trash(&sent).await; |
| |
|
| | |
| | let sent = alice.pop_sent_msg().await; |
| | bob.recv_msg_trash(&sent).await; |
| |
|
| | |
| | let sent = bob.pop_sent_msg().await; |
| | alice.recv_msg_trash(&sent).await; |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(&bob).await; |
| | assert_eq!(contact_bob.is_verified(&alice).await.unwrap(), true); |
| |
|
| | |
| | let _sent_vc_contact_confirm = alice.pop_sent_msg().await; |
| |
|
| | |
| | let contact_alice = bob.add_or_lookup_contact_no_key(&alice).await; |
| | assert_eq!(contact_alice.is_verified(&bob).await.unwrap(), true); |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_parallel_securejoin() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let alice_chat1_id = chat::create_group(alice, "First chat").await?; |
| | let alice_chat2_id = chat::create_group(alice, "Second chat").await?; |
| |
|
| | let qr1 = get_securejoin_qr(alice, Some(alice_chat1_id)).await?; |
| | let qr2 = get_securejoin_qr(alice, Some(alice_chat2_id)).await?; |
| |
|
| | |
| | let bob_chat1_id = join_securejoin(bob, &qr1).await?; |
| | let sent_vg_request1 = bob.pop_sent_msg().await; |
| |
|
| | let bob_chat2_id = join_securejoin(bob, &qr2).await?; |
| | let sent_vg_request2 = bob.pop_sent_msg().await; |
| |
|
| | |
| | |
| | alice.recv_msg_trash(&sent_vg_request1).await; |
| | let sent_vg_auth_required1 = alice.pop_sent_msg().await; |
| |
|
| | alice.recv_msg_trash(&sent_vg_request2).await; |
| | let _sent_vg_auth_required2 = alice.pop_sent_msg().await; |
| |
|
| | |
| | |
| | |
| | bob.recv_msg_trash(&sent_vg_auth_required1).await; |
| |
|
| | |
| | let sent_vg_request_with_auth2 = bob.pop_sent_msg().await; |
| | let sent_vg_request_with_auth1 = bob.pop_sent_msg().await; |
| |
|
| | |
| | alice.recv_msg_trash(&sent_vg_request_with_auth1).await; |
| | let sent_vg_member_added1 = alice.pop_sent_msg().await; |
| | let joined_chat_id1 = bob.recv_msg(&sent_vg_member_added1).await.chat_id; |
| | assert_eq!(joined_chat_id1, bob_chat1_id); |
| |
|
| | alice.recv_msg_trash(&sent_vg_request_with_auth2).await; |
| | let sent_vg_member_added2 = alice.pop_sent_msg().await; |
| | let joined_chat_id2 = bob.recv_msg(&sent_vg_member_added2).await.chat_id; |
| | assert_eq!(joined_chat_id2, bob_chat2_id); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_parallel_setup_contact() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | let fiona = &tcm.fiona().await; |
| |
|
| | |
| | |
| | let alice_qr = get_securejoin_qr(alice, None).await?; |
| | join_securejoin(bob, &alice_qr).await?; |
| | let sent_alice_vc_request = bob.pop_sent_msg().await; |
| |
|
| | |
| | |
| | let fiona_qr = get_securejoin_qr(fiona, None).await?; |
| | join_securejoin(bob, &fiona_qr).await?; |
| | let sent_fiona_vc_request = bob.pop_sent_msg().await; |
| |
|
| | fiona.recv_msg_trash(&sent_fiona_vc_request).await; |
| | let sent_fiona_vc_auth_required = fiona.pop_sent_msg().await; |
| |
|
| | bob.recv_msg_trash(&sent_fiona_vc_auth_required).await; |
| | let sent_fiona_vc_request_with_auth = bob.pop_sent_msg().await; |
| |
|
| | fiona.recv_msg_trash(&sent_fiona_vc_request_with_auth).await; |
| | let sent_fiona_vc_contact_confirm = fiona.pop_sent_msg().await; |
| |
|
| | bob.recv_msg_trash(&sent_fiona_vc_contact_confirm).await; |
| | let bob_fiona_contact_id = bob.add_or_lookup_contact_id(fiona).await; |
| | let bob_fiona_contact = Contact::get_by_id(bob, bob_fiona_contact_id).await.unwrap(); |
| | assert_eq!(bob_fiona_contact.is_verified(bob).await.unwrap(), true); |
| |
|
| | |
| | alice.recv_msg_trash(&sent_alice_vc_request).await; |
| | let sent_alice_vc_auth_required = alice.pop_sent_msg().await; |
| |
|
| | bob.recv_msg_trash(&sent_alice_vc_auth_required).await; |
| | let sent_alice_vc_request_with_auth = bob.pop_sent_msg().await; |
| |
|
| | alice.recv_msg_trash(&sent_alice_vc_request_with_auth).await; |
| | let sent_alice_vc_contact_confirm = alice.pop_sent_msg().await; |
| |
|
| | bob.recv_msg_trash(&sent_alice_vc_contact_confirm).await; |
| | let bob_alice_contact_id = bob.add_or_lookup_contact_id(alice).await; |
| | let bob_alice_contact = Contact::get_by_id(bob, bob_alice_contact_id).await.unwrap(); |
| | assert_eq!(bob_alice_contact.is_verified(bob).await.unwrap(), true); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_wrong_auth_token() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | |
| | |
| | tcm.send_recv(alice, bob, "hi").await; |
| |
|
| | let alice_qr = get_securejoin_qr(alice, None).await?; |
| | println!("{}", &alice_qr); |
| | let invalid_alice_qr = alice_qr.replace("&s=", "&s=INVALIDAUTHTOKEN&someotherkey="); |
| |
|
| | join_securejoin(bob, &invalid_alice_qr).await?; |
| | let sent = bob.pop_sent_msg().await; |
| |
|
| | let msg = alice.parse_msg(&sent).await; |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-request-with-auth" |
| | ); |
| |
|
| | alice.recv_msg_trash(&sent).await; |
| |
|
| | let alice_bob_contact = alice.add_or_lookup_contact(bob).await; |
| | assert!(!alice_bob_contact.is_verified(alice).await?); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_send_avatar_in_securejoin() -> Result<()> { |
| | async fn exec_securejoin_group( |
| | tcm: &TestContextManager, |
| | scanner: &TestContext, |
| | scanned: &TestContext, |
| | ) { |
| | let chat_id = chat::create_group(scanned, "group").await.unwrap(); |
| | let qr = get_securejoin_qr(scanned, Some(chat_id)).await.unwrap(); |
| | tcm.exec_securejoin_qr(scanner, scanned, &qr).await; |
| | } |
| | async fn exec_securejoin_broadcast( |
| | tcm: &TestContextManager, |
| | scanner: &TestContext, |
| | scanned: &TestContext, |
| | ) { |
| | let chat_id = chat::create_broadcast(scanned, "group".to_string()) |
| | .await |
| | .unwrap(); |
| | let qr = get_securejoin_qr(scanned, Some(chat_id)).await.unwrap(); |
| | tcm.exec_securejoin_qr(scanner, scanned, &qr).await; |
| | } |
| |
|
| | for round in 0..6 { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let file = alice.dir.path().join("avatar.png"); |
| | tokio::fs::write(&file, AVATAR_64x64_BYTES).await?; |
| | alice |
| | .set_config(Config::Selfavatar, Some(file.to_str().unwrap())) |
| | .await?; |
| |
|
| | match round { |
| | 0 => { |
| | tcm.execute_securejoin(alice, bob).await; |
| | } |
| | 1 => { |
| | tcm.execute_securejoin(bob, alice).await; |
| | } |
| | 2 => { |
| | exec_securejoin_group(&tcm, alice, bob).await; |
| | } |
| | 3 => { |
| | exec_securejoin_group(&tcm, bob, alice).await; |
| | } |
| | 4 => { |
| | exec_securejoin_broadcast(&tcm, alice, bob).await; |
| | } |
| | 5 => { |
| | exec_securejoin_broadcast(&tcm, bob, alice).await; |
| | } |
| | _ => panic!(), |
| | } |
| |
|
| | let alice_on_bob = bob.add_or_lookup_contact_no_key(alice).await; |
| | let avatar = alice_on_bob.get_profile_image(bob).await?.unwrap(); |
| | assert_eq!( |
| | avatar.file_name().unwrap().to_str().unwrap(), |
| | AVATAR_64x64_DEDUPLICATED |
| | ); |
| | } |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_expired_contact_auth_token() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | |
| | let qr = get_securejoin_qr(alice, None).await?; |
| |
|
| | |
| | SystemTime::shift(Duration::from_secs(7 * 24 * 3600)); |
| |
|
| | |
| | join_securejoin(bob, &qr).await?; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | bob.recv_msg_trash(&alice.pop_sent_msg().await).await; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(bob).await; |
| | assert_eq!(contact_bob.is_verified(alice).await.unwrap(), false); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_expired_group_auth_token() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let alice_chat_id = chat::create_group(alice, "Group").await?; |
| |
|
| | |
| | let qr = get_securejoin_qr(alice, Some(alice_chat_id)).await.unwrap(); |
| |
|
| | |
| | SystemTime::shift(Duration::from_secs(7 * 24 * 3600)); |
| |
|
| | |
| | join_securejoin(bob, &qr).await?; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | bob.recv_msg_trash(&alice.pop_sent_msg().await).await; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | let bob_member_added_msg = bob.recv_msg(&alice.pop_sent_msg().await).await; |
| | assert!(bob_member_added_msg.is_info()); |
| | assert_eq!( |
| | bob_member_added_msg.get_info_type(), |
| | SystemMessage::MemberAddedToGroup |
| | ); |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(bob).await; |
| | assert_eq!(contact_bob.is_verified(alice).await.unwrap(), false); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_expired_synced_auth_token() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let alice2 = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | alice.set_config_bool(Config::SyncMsgs, true).await?; |
| | alice2.set_config_bool(Config::SyncMsgs, true).await?; |
| |
|
| | |
| | let qr = get_securejoin_qr(alice2, None).await?; |
| |
|
| | alice2.send_sync_msg().await.unwrap(); |
| | let sync_msg = alice2.pop_sent_msg().await; |
| |
|
| | |
| | SystemTime::shift(Duration::from_secs(7 * 24 * 3600)); |
| |
|
| | alice.recv_msg_trash(&sync_msg).await; |
| |
|
| | |
| | join_securejoin(bob, &qr).await?; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | bob.recv_msg_trash(&alice.pop_sent_msg().await).await; |
| |
|
| | |
| | alice.recv_msg_trash(&bob.pop_sent_msg().await).await; |
| |
|
| | |
| | let contact_bob = alice.add_or_lookup_contact_no_key(bob).await; |
| | assert_eq!(contact_bob.is_verified(alice).await.unwrap(), false); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_rejoin_group() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let alice_chat_id = chat::create_group(alice, "the chat").await?; |
| |
|
| | let qr = get_securejoin_qr(alice, Some(alice_chat_id)).await?; |
| | tcm.exec_securejoin_qr(bob, alice, &qr).await; |
| |
|
| | |
| | for expected_progress in [400, 1000] { |
| | let EventType::SecurejoinJoinerProgress { progress, .. } = bob |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. })) |
| | .await |
| | else { |
| | unreachable!(); |
| | }; |
| | assert_eq!(progress, expected_progress); |
| | } |
| |
|
| | |
| | join_securejoin(bob, &qr).await?; |
| |
|
| | |
| | let EventType::SecurejoinJoinerProgress { progress, .. } = bob |
| | .evtracker |
| | .get_matching(|evt| matches!(evt, EventType::SecurejoinJoinerProgress { .. })) |
| | .await |
| | else { |
| | unreachable!(); |
| | }; |
| | assert_eq!(progress, 1000); |
| |
|
| | |
| | assert!(bob.pop_sent_msg_opt(Duration::ZERO).await.is_none()); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_securejoin_qr_name_is_last() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | alice |
| | .set_config(Config::Displayname, Some("Alice Axe")) |
| | .await?; |
| | let qr = get_securejoin_qr(alice, None).await?; |
| | assert!(qr.ends_with("Alice+Axe")); |
| |
|
| | let alice_chat_id = chat::create_group(alice, "The Chat").await?; |
| | let qr = get_securejoin_qr(alice, Some(alice_chat_id)).await?; |
| | assert!(qr.ends_with("The+Chat")); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_get_securejoin_qr_name_is_truncated() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | alice |
| | .set_config( |
| | Config::Displayname, |
| | Some("Alice Axe Has A Very Long Family Name Really Indeed"), |
| | ) |
| | .await?; |
| | let qr = get_securejoin_qr(alice, None).await?; |
| | assert!(qr.ends_with("Alice+Axe+Has+A+Very+Lon_")); |
| | assert!(!qr.ends_with(".")); |
| |
|
| | let alice_chat_id = |
| | chat::create_group(alice, "The Chat With One Of The Longest Titles Around").await?; |
| | let qr = get_securejoin_qr(alice, Some(alice_chat_id)).await?; |
| | assert!(qr.ends_with("The+Chat+With+One+Of+The_")); |
| | assert!(!qr.ends_with(".")); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_two_group_securejoins() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | let fiona = &tcm.fiona().await; |
| |
|
| | let group_id = chat::create_group(alice, "Group").await?; |
| |
|
| | let qr = get_securejoin_qr(alice, Some(group_id)).await?; |
| |
|
| | |
| | tcm.exec_securejoin_qr(bob, alice, &qr).await; |
| |
|
| | |
| | tcm.exec_securejoin_qr(fiona, alice, &qr).await; |
| |
|
| | let fiona_chat_id = fiona.get_last_msg().await.chat_id; |
| | fiona |
| | .golden_test_chat(fiona_chat_id, "two_group_securejoins") |
| | .await; |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_qr_no_implicit_inviter_addition() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| | let charlie = &tcm.charlie().await; |
| |
|
| | |
| | let alice_chat_id = alice |
| | .create_group_with_members("Group with Bob", &[bob]) |
| | .await; |
| | let alice_qr = get_securejoin_qr(alice, Some(alice_chat_id)).await?; |
| |
|
| | |
| | let bob_chat_id = tcm.exec_securejoin_qr(bob, alice, &alice_qr).await; |
| |
|
| | |
| | let bob_qr = get_securejoin_qr(bob, Some(bob_chat_id)).await?; |
| |
|
| | |
| | let alice_bob_contact_id = alice.add_or_lookup_contact_id(bob).await; |
| | remove_contact_from_chat(alice, alice_chat_id, alice_bob_contact_id).await?; |
| |
|
| | |
| | let removal_msg = alice.pop_sent_msg().await; |
| | bob.recv_msg(&removal_msg).await; |
| |
|
| | |
| | let charlie_chat_id = join_securejoin(charlie, &bob_qr).await?; |
| |
|
| | |
| | let sent = charlie.pop_sent_msg().await; |
| | bob.recv_msg_trash(&sent).await; |
| |
|
| | |
| | let sent = bob.pop_sent_msg().await; |
| | charlie.recv_msg_trash(&sent).await; |
| |
|
| | |
| | |
| | let sent = charlie.pop_sent_msg().await; |
| | bob.recv_msg_trash(&sent).await; |
| |
|
| | |
| | let charlie_chat_contacts = chat::get_chat_contacts(charlie, charlie_chat_id).await?; |
| | assert_eq!(charlie_chat_contacts.len(), 0); |
| |
|
| | |
| | let alice_charlie_contact_id = alice.add_or_lookup_contact_id(charlie).await; |
| | add_contact_to_chat(alice, alice_chat_id, alice_charlie_contact_id).await?; |
| |
|
| | let sent = alice.pop_sent_msg().await; |
| | assert_eq!(charlie.recv_msg(&sent).await.chat_id, charlie_chat_id); |
| |
|
| | |
| | let charlie_chat_contacts = chat::get_chat_contacts(charlie, charlie_chat_id).await?; |
| | assert_eq!(charlie_chat_contacts.len(), 2); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_user_deletes_chat_before_securejoin_completes() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let qr = get_securejoin_qr(alice, None).await?; |
| | let bob_chat_id = join_securejoin(bob, &qr).await?; |
| |
|
| | let bob_alice_chat = bob.get_chat(alice).await; |
| | |
| | assert_eq!(bob_alice_chat.can_send(bob).await?, false); |
| | assert_eq!(bob_alice_chat.id, bob_chat_id); |
| |
|
| | let request = bob.pop_sent_msg().await; |
| |
|
| | bob_chat_id.delete(bob).await?; |
| |
|
| | alice.recv_msg_trash(&request).await; |
| | let auth_required = alice.pop_sent_msg().await; |
| |
|
| | bob.recv_msg_trash(&auth_required).await; |
| |
|
| | |
| | |
| | assert!(bob.get_chat(alice).await.can_send(bob).await?); |
| |
|
| | Ok(()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #[tokio::test(flavor = "multi_thread", worker_threads = 2)] |
| | async fn test_vc_request_encrypted_at_rest() -> Result<()> { |
| | let mut tcm = TestContextManager::new(); |
| | let alice = &tcm.alice().await; |
| | let bob = &tcm.bob().await; |
| |
|
| | let qr = get_securejoin_qr(alice, None).await?; |
| |
|
| | let Qr::AskVerifyContact { invitenumber, .. } = check_qr(bob, &qr).await? else { |
| | panic!("Failed to parse QR code"); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | let payload = format!("To: <alice@example.org> |
| | Subject: [...] |
| | Date: Tue, 6 Jan 2026 08:20:47 +0000 |
| | References: <4f108a03-6c03-4f41-a6fb-fcd05b94c21f@localhost> |
| | Chat-Version: 1.0 |
| | Autocrypt: addr=bob@example.net; prefer-encrypt=mutual; keydata=xsBNBF4wx1cBCADOwLS/xCd8iKDWUsyTfVzWby+ZGKPpamPTvdj0GFgnf0B1EBaA5//PjA |
| | zbK5iKio6QNEmZagzJPkXPByJcAIRUm0T16tqDtCvxm+H93YEXpHi/XWOeJw9kohATSqUtsRO0pFJe |
| | DvPiMTmQrEmHYoWDSQBfCrowZdvnMAlbJ9JjYOngcMeTxc0jxmPs5s17yFC+1OWu4fwWCyUM3wy1Jz |
| | dKTcDWryrSkvmgFdUqJ7pJDk1HFTt+x9tvQlK3un9BXiRwv0u0zDSuI8eDH/dRLA4UL9Pq6vmJmBam |
| | e1BPsE1PA7VzeTSJR2ooJXMT6o2AmH8PPUfRkv3OiWuh7LM5FSpHABEBAAHNETxib2JAZXhhbXBsZS |
| | 5uZXQ+wsCOBBMBCAA4BQJpXW0wFiEEzMtaqfbhFByUMWXx2xixjLz3BIcCGwMCHgAECwkIBwYVCAkK |
| | CwIDFgIBAScCGQEACgkQ2xixjLz3BIcexwgAsOauz2xZ6QhVBQNX3Hg8OoYTn60w6b4XUOpI4UtqAT |
| | bAmPr5VPhCUa5vzI19QCSekLZIVxUSl6C+7YF/mU8yJldKPgq1Kpr8tbnISNbUDpvuGz7NQdK0TEwx |
| | RkPDw+ilqY7v2Rhhg0Sogi23Yrbyqvs72oorDjia6dBA7VLixpW1O9h/MfQ6WiXJcHSavoLqk2hFW1 |
| | y/AsVmArGiuT+kzRJWhTzojZLjQLHTKQii/AOQ3MhkJycyayI/igSEDWWwCcuqL8SF+PUJWGyU5PxU |
| | 2hTHDBsVItLLsqseM3WrwJRkBBdsdsR8+moHVyXJV9Gfl/4UFQCgltdEwWISgNTbAc7ATQReMMdXAQ |
| | gAogeBLbIjaeJII3W2pxsu+SEusQkJVykbGYDtqyXV+XBZisY4GE0kTawK5mqSh+rDqquCxDgYWBRT |
| | nGZwEKohnj2NG75pjfyVPhYMUdJt7+Ya1oiFvZlgrrOj1btjevq53yFtQolMN+X2oS8mlf9jSzIyPC |
| | eDxJk1N1gxaAATg3ByAyB1Td0wDdFPp48ni8qzfyGZeYicvJlx74YnOaja2lnI/y+I9LsmmqiOgI8H |
| | cbmH1od5qSnVjhcpBoTEA15YLIEkSE3C00Q5USlDS3EVg/IOu3FXnLl7v0hQ/jXyv88eycfpSfFcbM |
| | Hot9VtJ4TIPIoSX7DQ+uU2SXJKiZNkVQARAQABwsB2BBgBCAAgBQJpXW0wAhsMFiEEzMtaqfbhFByU |
| | MWXx2xixjLz3BIcACgkQ2xixjLz3BIcxvwf9G33yLtvekpNGeRbWkjRXSa083k/4CZpkF0Fb5led1O |
| | hjRjw9KQdZj68qn1vVrDxygnYdHwZWy8WbwEkK+l3gyJ2v2D/Wsj+sHjQ1YMtPnx+EsRFWjKsolYfN |
| | gJZ+IfMTasip8uJNxN5LIvI/svn43mzgeLUudddekmr/2eekhXfYz5covje3yf+u4rYDWQ78TLpJL5 |
| | bxTwiiUyV1ZIO1G2F4RNjv8wZHsGD3DasQck+OCV7jQNuyojcmq6J22lXN0clisI51mHzwkLAnI+Yh |
| | jRj3nqwVSCxsmgfejap53JGHEL0CEy6KvepLqjFf8BiK4kwRBmI7/YWOyY2xBWdTew== |
| | Secure-Join: vc-request |
| | Secure-Join-Invitenumber: {invitenumber} |
| | MIME-Version: 1.0 |
| | From: <bob@example.net> |
| | Message-ID: <4f108a03-6c03-4f41-a6fb-fcd05b94c21f@localhost> |
| | Content-Type: multipart/encrypted; |
| | protocol=\"application/pgp-encrypted\"; |
| | boundary=\"1767687657/562150/131174/example.org\" |
| | |
| | This is a MIME-encapsulated message. |
| | |
| | --1767687657/562150/131174/example.org |
| | Content-Type: application/pgp-encrypted |
| | Content-Disposition: attachment |
| | |
| | Version: 1 |
| | |
| | --1767687657/562150/131174/example.org |
| | Content-Type: application/octet-stream |
| | Content-Disposition: inline; filename=\"msg.asc\" |
| | |
| | -----BEGIN PGP MESSAGE----- |
| | |
| | wV4D5tq63hTeebASAQdAGKP3GqsznPOYBXOo8FYf5x8r0ZaJZUGkXIR+Oi32H1Mw |
| | LdVEu0jcXmZ1fGZ7LLPtvfwllB2W9Bhiy/lCZZs+c98VYzSWaT0DHmp23WvTsBZn |
| | 0sDeAS0n2I6xPwYhUjqL8G1a9xdyvZRgHYUXhiARrXzx7G+aX8/KFjk6e2OZxiVy |
| | PSHKh61T9wPYzPMlToPsI0GjXAzOgI9I3XQ8xPqihiUpnU6BSg+Tj26m9ZqdJe8v |
| | aVAHxAu7aqz7eljp2H336Idgfvf1lXdA6gMA8HhHI729Ws/Mc8lcgefM9kzZWEIN |
| | FOBYmf4JCdTghESpEJ5i+pF28ChqZ3+8lGzNmT66c2SQRTclwxFa4SS19D4mxkHq |
| | iOMqj7LZ8R6IhnNVRD1V4mVapc7vFVZy8ViyZlmhJF0TBR/TEXlit6vtSkDKFiR9 |
| | Tb5zuFQVAwhun3i1tG3/Ii1ReflZNnteVlL1J1XnptOJ70vVUeO3qRqkbkiH8Mdm |
| | Asvy24WKkz9jmEgdt0Hj8VUHtcOL5xmtsr0ZUCLUriylpzDh8E+0LTl2/DOgH+mI |
| | D/gFLCzFHjI0jfXyLTGCYOPYAnvqJukLBT/X7JbCAI/62aq0K28Lp6beJhFs+bIz |
| | gU6dGXsFMe/RpRHrIAkMAaM5xkxMDRuRJDxiUdS/X+Y8 |
| | =QrdS |
| | -----END PGP MESSAGE----- |
| | |
| | --1767687657/562150/131174/example.org-- |
| | "); |
| |
|
| | |
| | |
| | let received = receive_imf(alice, payload.as_bytes(), false) |
| | .await? |
| | .unwrap(); |
| | assert_eq!(received.chat_id, DC_CHAT_ID_TRASH); |
| |
|
| | |
| | let sent = alice.pop_sent_msg().await; |
| | let msg = bob.parse_msg(&sent).await; |
| | assert_eq!( |
| | msg.get_header(HeaderDef::SecureJoin).unwrap(), |
| | "vc-auth-required" |
| | ); |
| |
|
| | Ok(()) |
| | } |
| |
|