Skip to content

Commit d250e70

Browse files
committed
fix: Don't resend webxdc status updates in OutBroadcast-s (#7679)
We don't remember which status updates are "initial" (sent initially by the broadcast owner) and which were sent by subscribers, so don't resend any of them to avoid accidental sharing of confidential data.
1 parent aed8d8c commit d250e70

5 files changed

Lines changed: 37 additions & 10 deletions

File tree

src/chat.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4560,7 +4560,7 @@ pub async fn resend_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
45604560
// note(treefit): only matters if it is the last message in chat (but probably to expensive to check, debounce also solves it)
45614561
chatlist_events::emit_chatlist_item_changed(context, msg.chat_id);
45624562

4563-
if msg.viewtype == Viewtype::Webxdc {
4563+
if msg.viewtype == Viewtype::Webxdc && msg.chat_typ != Chattype::OutBroadcast {
45644564
let conn_fn = |conn: &mut rusqlite::Connection| {
45654565
let range = conn.query_row(
45664566
"SELECT IFNULL(min(id), 1), IFNULL(max(id), 0) \

src/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,14 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9);
107107
IntoStaticStr,
108108
Serialize,
109109
Deserialize,
110+
Default,
110111
)]
111112
#[repr(u32)]
112113
pub enum Chattype {
113114
/// A 1:1 chat, i.e. a normal chat with a single contact.
114115
///
115116
/// Created by [`ChatId::create_for_contact`].
117+
#[default]
116118
Single = 100,
117119

118120
/// Group chat.

src/message.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ pub struct Message {
452452
pub(crate) is_dc_message: MessengerMessage,
453453
pub(crate) original_msg_id: MsgId,
454454
pub(crate) mime_modified: bool,
455+
pub(crate) chat_typ: Chattype,
455456
pub(crate) chat_visibility: ChatVisibility,
456457
pub(crate) chat_blocked: Blocked,
457458
pub(crate) location_id: u32,
@@ -526,6 +527,7 @@ impl Message {
526527
m.param AS param,
527528
m.hidden AS hidden,
528529
m.location_id AS location,
530+
c.type AS chat_typ,
529531
c.archived AS visibility,
530532
c.blocked AS blocked
531533
FROM msgs m
@@ -585,6 +587,10 @@ impl Message {
585587
param: row.get::<_, String>("param")?.parse().unwrap_or_default(),
586588
hidden: row.get("hidden")?,
587589
location_id: row.get("location")?,
590+
// This is safe: see `ChatId::delete_ex()`, `None` chat type can't happen.
591+
chat_typ: row
592+
.get::<_, Option<_>>("chat_typ")?
593+
.unwrap_or(Chattype::Single),
588594
chat_visibility: row.get::<_, Option<_>>("visibility")?.unwrap_or_default(),
589595
chat_blocked: row
590596
.get::<_, Option<Blocked>>("blocked")?

src/mimefactory.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,14 +2009,15 @@ impl MimeFactory {
20092009
HeaderDef::IrohGossipTopic.get_headername(),
20102010
mail_builder::headers::raw::Raw::new(topic).into(),
20112011
));
2012-
if let (Some(json), _) = context
2013-
.render_webxdc_status_update_object(
2014-
msg.id,
2015-
StatusUpdateSerial::MIN,
2016-
StatusUpdateSerial::MAX,
2017-
None,
2018-
)
2019-
.await?
2012+
if msg.chat_typ != Chattype::OutBroadcast
2013+
&& let (Some(json), _) = context
2014+
.render_webxdc_status_update_object(
2015+
msg.id,
2016+
StatusUpdateSerial::MIN,
2017+
StatusUpdateSerial::MAX,
2018+
None,
2019+
)
2020+
.await?
20202021
{
20212022
parts.push(context.build_status_update_part(&json));
20222023
}

src/webxdc/webxdc_tests.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ async fn test_in_broadcast_send_status_update() -> Result<()> {
16121612
bob.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#)
16131613
.await?;
16141614
bob.flush_status_updates().await?;
1615-
let sent_msg = bob.pop_sent_msg().await;
1615+
let sent_msg = bob.pop_sent_msg_opt(Duration::ZERO).await.unwrap();
16161616

16171617
alice.recv_msg_trash(&sent_msg).await;
16181618
assert_eq!(
@@ -1636,6 +1636,24 @@ async fn test_in_broadcast_send_status_update() -> Result<()> {
16361636
let status =
16371637
helper_send_receive_status_update(bob, alice, &bob_instance, &alice_instance).await?;
16381638
assert_eq!(status, r#"[{"payload":42,"serial":1,"max_serial":1}]"#);
1639+
1640+
// Subscribers' status updates are confidential.
1641+
let fiona = &tcm.fiona().await;
1642+
let fiona_chat_id = tcm.exec_securejoin_qr(fiona, alice, &qr).await;
1643+
resend_msgs(alice, &[alice_instance.id]).await?;
1644+
let sent1 = alice.pop_sent_msg().await;
1645+
alice.flush_status_updates().await?;
1646+
// See above for bob -- status updates are flushed immediately, no need to wait.
1647+
assert!(alice.pop_sent_msg_opt(Duration::ZERO).await.is_none());
1648+
let fiona_instance = fiona.recv_msg(&sent1).await;
1649+
assert_eq!(fiona_instance.chat_id, fiona_chat_id);
1650+
assert_eq!(fiona_instance.chat_typ, Chattype::InBroadcast);
1651+
assert_eq!(
1652+
fiona
1653+
.get_webxdc_status_updates(fiona_instance.id, StatusUpdateSerial(0))
1654+
.await?,
1655+
r#"[]"#
1656+
);
16391657
Ok(())
16401658
}
16411659

0 commit comments

Comments
 (0)