diff --git a/src/chat.rs b/src/chat.rs index 2e4aeab45..682c0e6a8 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -4067,7 +4067,7 @@ pub(crate) async fn add_contact_to_chat_ex( let contact_addr = contact.get_addr().to_lowercase(); let added_by = if from_handshake && chat.is_out_broadcast() { // The contact was added via a QR code rather than explicit user action, - // and there is added information in saying 'You added member Alice' + // and there is no useful information in saying 'You added member Alice' // if self is the only one who can add members. ContactId::UNDEFINED } else { @@ -4079,6 +4079,12 @@ pub(crate) async fn add_contact_to_chat_ex( msg.param.set_int(Param::Arg2, from_handshake.into()); msg.param .set_int(Param::ContactAddedRemoved, contact.id.to_u32() as i32); + if chat.is_out_broadcast() { + let secret = load_broadcast_shared_secret(context, chat_id) + .await? + .context("Failed to find broadcast shared secret")?; + msg.param.set(Param::Arg3, secret); + } send_msg(context, chat_id, &mut msg).await?; sync = Nosync; diff --git a/src/headerdef.rs b/src/headerdef.rs index 1669c91c1..4b32a904b 100644 --- a/src/headerdef.rs +++ b/src/headerdef.rs @@ -94,6 +94,11 @@ pub enum HeaderDef { /// This message obsoletes the text of the message defined here by rfc724_mid. ChatEdit, + /// The secret shared amongst all recipients of this broadcast channel, + /// used to encrypt and decrypt messages. + /// This secret is sent to a new member in the member-addition message. + ChatBroadcastSecret, + /// [Autocrypt](https://autocrypt.org/) header. Autocrypt, AutocryptGossip, diff --git a/src/mimefactory.rs b/src/mimefactory.rs index ca8bf447c..2384e5910 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -834,7 +834,7 @@ impl MimeFactory { } } - if let Loaded::Message { chat, .. } = &self.loaded { + if let Loaded::Message { msg, chat } = &self.loaded { if chat.typ == Chattype::OutBroadcast || chat.typ == Chattype::InBroadcast { headers.push(( "List-ID", @@ -844,6 +844,15 @@ impl MimeFactory { )) .into(), )); + + if msg.param.get_cmd() == SystemMessage::MemberAddedToGroup { + if let Some(secret) = msg.param.get(Param::Arg3) { + headers.push(( + "Chat-Broadcast-Secret", + mail_builder::headers::text::Text::new(secret.to_string()).into(), + )); + } + } } } @@ -1024,6 +1033,15 @@ impl MimeFactory { } else { unprotected_headers.push(header.clone()); } + } else if header_name == "chat-broadcast-secret" { + if is_encrypted { + protected_headers.push(header.clone()); + } else { + warn!( + context, + "Message is unnecrypted, not including broadcast secret" + ); + } } else if is_encrypted { protected_headers.push(header.clone()); diff --git a/src/param.rs b/src/param.rs index 4cfecdf70..d6b866663 100644 --- a/src/param.rs +++ b/src/param.rs @@ -106,12 +106,29 @@ pub enum Param { Arg = b'E', /// For Messages + /// + /// For `BobHandshakeMsg::Request`, this is the `Secure-Join-Invitenumber` header. + /// + /// For `BobHandshakeMsg::RequestWithAuth`, this is the `Secure-Join-Auth` header. + /// + /// For [`SystemMessage::MultiDeviceSync`], this contains the ids that are synced. + /// + /// For [`SystemMessage::MemberAddedToGroup`], + /// this is '1' if it was added because of a securejoin-handshake, and '0' otherwise. Arg2 = b'F', - /// `Secure-Join-Fingerprint` header for `{vc,vg}-request-with-auth` messages. + /// For Messages + /// + /// For `BobHandshakeMsg::RequestWithAuth`, + /// this contains the `Secure-Join-Fingerprint` header. + /// + /// For [`SystemMessage::MemberAddedToGroup`] that add to a broadcast channel, + /// this contains the broadcast channel's shared secret. Arg3 = b'G', - /// Deprecated `Secure-Join-Group` header for messages. + /// For Messages + /// + /// Deprecated `Secure-Join-Group` header for `BobHandshakeMsg::RequestWithAuth` messages. Arg4 = b'H', /// For Messages