diff --git a/src/chat.rs b/src/chat.rs index 94131f866..2de5de15e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3777,7 +3777,8 @@ pub async fn create_group_ex( /// Returns the created chat's id. pub async fn create_broadcast(context: &Context, chat_name: String) -> Result { let grpid = create_id(); - create_broadcast_ex(context, Sync, grpid, chat_name).await + let secret = create_broadcast_shared_secret(); + create_broadcast_ex(context, Sync, grpid, chat_name, secret).await } pub(crate) async fn create_broadcast_ex( @@ -3785,6 +3786,7 @@ pub(crate) async fn create_broadcast_ex( sync: sync::Sync, grpid: String, chat_name: String, + secret: String, ) -> Result { let row_id = { let chat_name = &chat_name; @@ -3813,6 +3815,13 @@ pub(crate) async fn create_broadcast_ex( create_smeared_timestamp(context), ), )?; + let chat_id = t.last_insert_rowid(); + // TODO code duplication of `INSERT INTO broadcasts_shared_secrets` + t.execute( + "INSERT INTO broadcasts_shared_secrets (chat_id, secret) VALUES (?, ?) + ON CONFLICT(chat_id) DO UPDATE SET secret=excluded.chat_id", + (chat_id, &secret), + )?; Ok(t.last_insert_rowid().try_into()?) }; context.sql.transaction(trans_fn).await? @@ -3824,7 +3833,7 @@ pub(crate) async fn create_broadcast_ex( if sync.into() { let id = SyncId::Grpid(grpid); - let action = SyncAction::CreateBroadcast(chat_name); + let action = SyncAction::CreateBroadcast { chat_name, secret }; self::sync(context, id, action).await.log_err(context).ok(); } @@ -5036,7 +5045,10 @@ pub(crate) enum SyncAction { SetVisibility(ChatVisibility), SetMuted(MuteDuration), /// Create broadcast channel with the given name. - CreateBroadcast(String), + CreateBroadcast { + chat_name: String, + secret: String, + }, Rename(String), /// Set chat contacts by their addresses. SetContacts(Vec), @@ -5099,8 +5111,15 @@ impl Context { .id } SyncId::Grpid(grpid) => { - if let SyncAction::CreateBroadcast(name) = action { - create_broadcast_ex(self, Nosync, grpid.clone(), name.clone()).await?; + if let SyncAction::CreateBroadcast { chat_name, secret } = action { + create_broadcast_ex( + self, + Nosync, + grpid.clone(), + chat_name.clone(), + secret.to_string(), + ) + .await?; return Ok(()); } get_chat_id_by_grpid(self, grpid) @@ -5123,7 +5142,7 @@ impl Context { SyncAction::Accept => chat_id.accept_ex(self, Nosync).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::CreateBroadcast(_) => { + SyncAction::CreateBroadcast { .. } => { Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request.")) } SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await, diff --git a/src/chat/chat_tests.rs b/src/chat/chat_tests.rs index 1f1431edf..4c60ab996 100644 --- a/src/chat/chat_tests.rs +++ b/src/chat/chat_tests.rs @@ -3860,12 +3860,25 @@ async fn test_sync_name() -> Result<()> { let a0_broadcast_id = create_broadcast(alice0, "Channel".to_string()).await?; sync(alice0, alice1).await; let a0_broadcast_chat = Chat::load_from_db(alice0, a0_broadcast_id).await?; + set_chat_name(alice0, a0_broadcast_id, "Broadcast channel 42").await?; - sync(alice0, alice1).await; + //sync(alice0, alice1).await; // crash + + let sent = alice0.pop_sent_msg().await; + let rcvd = alice1.recv_msg(&sent).await; + assert_eq!(rcvd.from_id, ContactId::SELF); + assert_eq!(rcvd.to_id, ContactId::SELF); + assert_eq!( + rcvd.text, + "You changed group name from \"Channel\" to \"Broadcast channel 42\"." + ); + assert_eq!(rcvd.param.get_cmd(), SystemMessage::GroupNameChanged); let a1_broadcast_id = get_chat_id_by_grpid(alice1, &a0_broadcast_chat.grpid) .await? .unwrap() .0; + assert_eq!(rcvd.chat_id, a1_broadcast_id); + let a1_broadcast_chat = Chat::load_from_db(alice1, a1_broadcast_id).await?; assert_eq!(a1_broadcast_chat.get_type(), Chattype::OutBroadcast); assert_eq!(a1_broadcast_chat.get_name(), "Broadcast channel 42"); diff --git a/src/param.rs b/src/param.rs index a8576e855..3319fcda1 100644 --- a/src/param.rs +++ b/src/param.rs @@ -175,7 +175,7 @@ pub enum Param { /// For Chats of type [`Chattype::OutBroadcast`] and [`Chattype::InBroadcast`]: // TODO (or just OutBroadcast) /// The symmetric key shared among all chat participants, /// used to encrypt and decrypt messages. - SymmetricKey = b'z', + SymmetricKey = b'z', // TODO remove this again /// For Contacts: If this is the List-Post address of a mailing list, contains /// the List-Id of the mailing list (which is also used as the group id of the chat). diff --git a/src/qr.rs b/src/qr.rs index 645318803..2076837dd 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -381,6 +381,7 @@ pub fn format_backup(qr: &Qr) -> Result { /// scheme: `OPENPGP4FPR:FINGERPRINT#a=ADDR&n=NAME&i=INVITENUMBER&s=AUTH` /// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH` +/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&c=CHANNELNAME&x=CHANNELID&s=SHAREDSECRET` /// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR` async fn decode_openpgp(context: &Context, qr: &str) -> Result { let payload = qr diff --git a/src/receive_imf.rs b/src/receive_imf.rs index c228a1b18..f27fbf7fc 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -3477,8 +3477,22 @@ async fn apply_out_broadcast_changes( chat: &mut Chat, from_id: ContactId, ) -> Result { + // TODO code duplication with apply_in_broadcast_changes() ensure!(chat.typ == Chattype::OutBroadcast); + let mut send_event_chat_modified = false; + let mut better_msg = None; + + apply_chat_name_and_avatar_changes( + context, + mime_parser, + from_id, + chat, + &mut send_event_chat_modified, + &mut better_msg, + ) + .await?; + if let Some(_removed_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberRemoved) { // The sender of the message left the broadcast channel remove_from_chat_contacts_table(context, chat.id, from_id).await?; @@ -3491,7 +3505,16 @@ async fn apply_out_broadcast_changes( }); } - Ok(GroupChangesInfo::default()) + if send_event_chat_modified { + context.emit_event(EventType::ChatModified(chat.id)); + chatlist_events::emit_chatlist_item_changed(context, chat.id); + } + Ok(GroupChangesInfo { + better_msg, + added_removed_id: None, + silent: false, + extra_msgs: vec![], + }) } async fn apply_in_broadcast_changes(