Skip to content

Commit bbb2673

Browse files
committed
feat: allow scanning multiple securejoin QR codes in parallel
1 parent 449ba4e commit bbb2673

File tree

7 files changed

+415
-678
lines changed

7 files changed

+415
-678
lines changed

src/chat.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ use crate::mimeparser::SystemMessage;
4242
use crate::param::{Param, Params};
4343
use crate::peerstate::Peerstate;
4444
use crate::receive_imf::ReceivedMsg;
45-
use crate::securejoin::BobState;
4645
use crate::smtp::send_msg_to_smtp;
4746
use crate::stock_str;
4847
use crate::sync::{self, Sync::*, SyncData};
@@ -2569,19 +2568,27 @@ pub(crate) async fn update_special_chat_names(context: &Context) -> Result<()> {
25692568
/// Checks if there is a 1:1 chat in-progress SecureJoin for Bob and, if necessary, schedules a task
25702569
/// unblocking the chat and notifying the user accordingly.
25712570
pub(crate) async fn resume_securejoin_wait(context: &Context) -> Result<()> {
2572-
let Some(bobstate) = BobState::from_db(&context.sql).await? else {
2573-
return Ok(());
2574-
};
2575-
if !bobstate.in_progress() {
2576-
return Ok(());
2577-
}
2578-
let chat_id = bobstate.alice_chat();
2579-
let chat = Chat::load_from_db(context, chat_id).await?;
2580-
let timeout = chat
2581-
.check_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT)
2571+
let chat_ids: Vec<ChatId> = context
2572+
.sql
2573+
.query_map(
2574+
"SELECT chat_id FROM bobstate",
2575+
(),
2576+
|row| {
2577+
let chat_id: ChatId = row.get(0)?;
2578+
Ok(chat_id)
2579+
},
2580+
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
2581+
)
25822582
.await?;
2583-
if timeout > 0 {
2584-
chat_id.spawn_securejoin_wait(context, timeout);
2583+
2584+
for chat_id in chat_ids {
2585+
let chat = Chat::load_from_db(context, chat_id).await?;
2586+
let timeout = chat
2587+
.check_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT)
2588+
.await?;
2589+
if timeout > 0 {
2590+
chat_id.spawn_securejoin_wait(context, timeout);
2591+
}
25852592
}
25862593
Ok(())
25872594
}

src/contact.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,11 @@ pub enum Origin {
505505
/// set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling contact_is_verified() !
506506
SecurejoinInvited = 0x0100_0000,
507507

508-
/// set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling contact_is_verified() !
508+
/// Set on Bob's side for contacts scanned from a QR code.
509+
/// Only means the contact has been scanned from the QR code,
510+
/// but does not mean that securejoin succeeded
511+
/// or the key has not changed since the last scan.
512+
/// Getting the current key verification status requires calling contact_is_verified() !
509513
SecurejoinJoined = 0x0200_0000,
510514

511515
/// contact added manually by create_contact(), this should be the largest origin as otherwise the user cannot modify the names

src/receive_imf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ pub(crate) async fn receive_imf_inner(
364364
if mime_parser.get_header(HeaderDef::SecureJoin).is_some() {
365365
let res;
366366
if mime_parser.incoming {
367-
res = handle_securejoin_handshake(context, &mime_parser, from_id)
367+
res = handle_securejoin_handshake(context, &mut mime_parser, from_id)
368368
.await
369369
.context("error in Secure-Join message handling")?;
370370

src/securejoin.rs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ use crate::token;
2626
use crate::tools::time;
2727

2828
mod bob;
29-
mod bobstate;
3029
mod qrinvite;
3130

32-
pub(crate) use bobstate::BobState;
3331
use qrinvite::QrInvite;
3432

3533
use crate::token::Namespace;
@@ -168,8 +166,7 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId> {
168166
bob::start_protocol(context, invite).await
169167
}
170168

171-
/// Send handshake message from Alice's device;
172-
/// Bob's handshake messages are sent in `BobState::send_handshake_message()`.
169+
/// Send handshake message from Alice's device.
173170
async fn send_alice_handshake_msg(
174171
context: &Context,
175172
contact_id: ContactId,
@@ -259,7 +256,7 @@ pub(crate) enum HandshakeMessage {
259256
/// This leaves it on the IMAP server. It means other devices on this account can
260257
/// receive and potentially process this message as well. This is useful for example
261258
/// when the other device is running the protocol and has the relevant QR-code
262-
/// information while this device does not have the joiner state ([`BobState`]).
259+
/// information while this device does not have the joiner state.
263260
Ignore,
264261
/// The message should be further processed by incoming message handling.
265262
///
@@ -281,7 +278,7 @@ pub(crate) enum HandshakeMessage {
281278
/// database; this is done by `receive_imf()` later on as needed.
282279
pub(crate) async fn handle_securejoin_handshake(
283280
context: &Context,
284-
mime_message: &MimeMessage,
281+
mime_message: &mut MimeMessage,
285282
contact_id: ContactId,
286283
) -> Result<HandshakeMessage> {
287284
if contact_id.is_special() {
@@ -479,15 +476,10 @@ pub(crate) async fn handle_securejoin_handshake(
479476
==== Step 7 in "Setup verified contact" protocol ====
480477
=======================================================*/
481478
"vc-contact-confirm" => {
482-
if let Some(mut bobstate) = BobState::from_db(&context.sql).await? {
483-
if !bobstate.is_msg_expected(context, step) {
484-
warn!(context, "Unexpected vc-contact-confirm.");
485-
return Ok(HandshakeMessage::Ignore);
486-
}
487-
488-
bobstate.step_contact_confirm(context).await?;
489-
bobstate.emit_progress(context, JoinerProgress::Succeeded);
490-
}
479+
context.emit_event(EventType::SecurejoinJoinerProgress {
480+
contact_id,
481+
progress: JoinerProgress::Succeeded.to_usize(),
482+
});
491483
Ok(HandshakeMessage::Ignore)
492484
}
493485
"vg-member-added" => {
@@ -506,15 +498,22 @@ pub(crate) async fn handle_securejoin_handshake(
506498
);
507499
return Ok(HandshakeMessage::Propagate);
508500
}
509-
if let Some(mut bobstate) = BobState::from_db(&context.sql).await? {
510-
if !bobstate.is_msg_expected(context, step) {
511-
warn!(context, "Unexpected vg-member-added.");
512-
return Ok(HandshakeMessage::Propagate);
513-
}
514501

515-
bobstate.step_contact_confirm(context).await?;
516-
bobstate.emit_progress(context, JoinerProgress::Succeeded);
502+
// Mark peer as backward verified.
503+
//
504+
// This is needed for the case when we join a non-protected group
505+
// because in this case `Chat-Verified` header that otherwise
506+
// sets backward verification is not sent.
507+
if let Some(peerstate) = &mut mime_message.peerstate {
508+
peerstate.backward_verified_key_id =
509+
Some(context.get_config_i64(Config::KeyId).await?).filter(|&id| id > 0);
510+
peerstate.save_to_db(&context.sql).await?;
517511
}
512+
513+
context.emit_event(EventType::SecurejoinJoinerProgress {
514+
contact_id,
515+
progress: JoinerProgress::Succeeded.to_usize(),
516+
});
518517
Ok(HandshakeMessage::Propagate)
519518
}
520519

0 commit comments

Comments
 (0)