From 849032d6d540c316e8112e5d4fae228404a4bd87 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 13 Jul 2026 12:00:12 +0100 Subject: [PATCH] Add default push rules for live location share start (MSCxxxx draft) Underride rules .io.element.rule.beacon_info(_one_to_one) matching org.matrix.msc3672.beacon_info with content.live == true, so recipients are pushed when someone starts a live location share (incl. E2EE rooms, since beacon_info is an unencrypted state event). Gated behind experimental_features.mscxxxx_beacon_push_rules_enabled; rule ids and flag to be renamed once the MSC is numbered. Co-Authored-By: Claude Fable 5 --- rust/src/push/base_rules.rs | 37 +++++++++++++++++++++ rust/src/push/evaluator.rs | 1 + rust/src/push/mod.rs | 9 +++++ synapse/config/experimental.py | 7 ++++ synapse/storage/databases/main/push_rule.py | 1 + synapse/synapse_rust/push.pyi | 1 + 6 files changed, 56 insertions(+) diff --git a/rust/src/push/base_rules.rs b/rust/src/push/base_rules.rs index 47d5289006..7472d65bda 100644 --- a/rust/src/push/base_rules.rs +++ b/rust/src/push/base_rules.rs @@ -721,6 +721,43 @@ pub const BASE_APPEND_UNDERRIDE_RULES: &[PushRule] = &[ default: true, default_enabled: true, }, + PushRule { + rule_id: Cow::Borrowed("global/underride/.io.element.rule.beacon_info_one_to_one"), + priority_class: 1, + conditions: Cow::Borrowed(&[ + Condition::Known(KnownCondition::RoomMemberCount { + is: Some(Cow::Borrowed("2")), + }), + Condition::Known(KnownCondition::EventMatch(EventMatchCondition { + key: Cow::Borrowed("type"), + pattern: Cow::Borrowed("org.matrix.msc3672.beacon_info"), + })), + Condition::Known(KnownCondition::EventPropertyIs(EventPropertyIsCondition { + key: Cow::Borrowed("content.live"), + value: Cow::Owned(SimpleJsonValue::Bool(true)), + })), + ]), + actions: Cow::Borrowed(&[Action::Notify, SOUND_ACTION]), + default: true, + default_enabled: true, + }, + PushRule { + rule_id: Cow::Borrowed("global/underride/.io.element.rule.beacon_info"), + priority_class: 1, + conditions: Cow::Borrowed(&[ + Condition::Known(KnownCondition::EventMatch(EventMatchCondition { + key: Cow::Borrowed("type"), + pattern: Cow::Borrowed("org.matrix.msc3672.beacon_info"), + })), + Condition::Known(KnownCondition::EventPropertyIs(EventPropertyIsCondition { + key: Cow::Borrowed("content.live"), + value: Cow::Owned(SimpleJsonValue::Bool(true)), + })), + ]), + actions: Cow::Borrowed(&[Action::Notify]), + default: true, + default_enabled: true, + }, ]; lazy_static! { diff --git a/rust/src/push/evaluator.rs b/rust/src/push/evaluator.rs index 1cbca4c635..250d2890c0 100644 --- a/rust/src/push/evaluator.rs +++ b/rust/src/push/evaluator.rs @@ -637,6 +637,7 @@ fn test_requires_room_version_supports_condition() { false, false, false, + false, ), None, None, diff --git a/rust/src/push/mod.rs b/rust/src/push/mod.rs index 780d7a8cbd..31f35907dd 100644 --- a/rust/src/push/mod.rs +++ b/rust/src/push/mod.rs @@ -559,6 +559,7 @@ pub struct FilteredPushRules { msc4028_push_encrypted_events: bool, msc4210_enabled: bool, msc4306_enabled: bool, + mscxxxx_beacon_push_rules_enabled: bool, } #[pymethods] @@ -574,6 +575,7 @@ impl FilteredPushRules { msc4028_push_encrypted_events: bool, msc4210_enabled: bool, msc4306_enabled: bool, + mscxxxx_beacon_push_rules_enabled: bool, ) -> Self { Self { push_rules, @@ -584,6 +586,7 @@ impl FilteredPushRules { msc4028_push_encrypted_events, msc4210_enabled, msc4306_enabled, + mscxxxx_beacon_push_rules_enabled, } } @@ -620,6 +623,12 @@ impl FilteredPushRules { return false; } + if !self.mscxxxx_beacon_push_rules_enabled + && rule.rule_id.contains("/.io.element.rule.beacon_info") + { + return false; + } + if !self.msc4028_push_encrypted_events && rule.rule_id == "global/override/.org.matrix.msc4028.encrypted_event" { diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py index f99f7b139e..c58324589b 100644 --- a/synapse/config/experimental.py +++ b/synapse/config/experimental.py @@ -156,6 +156,13 @@ class ExperimentalConfig(Config): "msc3381_polls_enabled", False ) + # MSCXXXX (unnumbered draft): default push rules for live location share + # beacon_info start events (the MSC3672 state event). Unstable rule ids: + # .io.element.rule.beacon_info(_one_to_one). + self.mscxxxx_beacon_push_rules_enabled: bool = experimental.get( + "mscxxxx_beacon_push_rules_enabled", False + ) + # MSC3912: Relation-based redactions. self.msc3912_enabled: bool = experimental.get("msc3912_enabled", False) diff --git a/synapse/storage/databases/main/push_rule.py b/synapse/storage/databases/main/push_rule.py index d361166cec..5e5eb6ddec 100644 --- a/synapse/storage/databases/main/push_rule.py +++ b/synapse/storage/databases/main/push_rule.py @@ -107,6 +107,7 @@ def _load_rules( msc4028_push_encrypted_events=experimental_config.msc4028_push_encrypted_events, msc4210_enabled=experimental_config.msc4210_enabled, msc4306_enabled=experimental_config.msc4306_enabled, + mscxxxx_beacon_push_rules_enabled=experimental_config.mscxxxx_beacon_push_rules_enabled, ) return filtered_rules diff --git a/synapse/synapse_rust/push.pyi b/synapse/synapse_rust/push.pyi index ef0d5f94f4..bac316c38b 100644 --- a/synapse/synapse_rust/push.pyi +++ b/synapse/synapse_rust/push.pyi @@ -50,6 +50,7 @@ class FilteredPushRules: msc4028_push_encrypted_events: bool, msc4210_enabled: bool, msc4306_enabled: bool, + mscxxxx_beacon_push_rules_enabled: bool, ): ... def rules(self) -> Collection[tuple[PushRule, bool]]: ...