mirror of
https://github.com/element-hq/synapse.git
synced 2026-09-25 15:33:55 +00:00
Add push rules for MSC4075: MatrixRTC invites and notifications (#20227)
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
This commit is contained in:
co-authored by
Andrew Morgan
parent
1c122cd825
commit
b8bd6f93a1
@@ -0,0 +1 @@
|
||||
Add push rules for MSC4075: MatrixRTC invites and notifications.
|
||||
@@ -215,6 +215,7 @@ fn bench_eval_message(b: &mut Bencher) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
b.iter(|| eval.run(&rules, Some("bob"), Some("person"), None));
|
||||
|
||||
@@ -145,6 +145,45 @@ pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
|
||||
default: true,
|
||||
default_enabled: true,
|
||||
},
|
||||
PushRule {
|
||||
rule_id: Cow::Borrowed("global/override/.org.matrix.msc4075.rule.rtc.invite_for_me"),
|
||||
priority_class: 5,
|
||||
conditions: Cow::Borrowed(&[
|
||||
Condition::Known(KnownCondition::EventMatch(EventMatchCondition {
|
||||
key: Cow::Borrowed("type"),
|
||||
pattern: Cow::Borrowed("org.matrix.msc4075.rtc.notification"),
|
||||
})),
|
||||
Condition::Known(KnownCondition::ExactEventPropertyContainsType(
|
||||
EventPropertyIsTypeCondition {
|
||||
key: Cow::Borrowed(r"content.m\.mentions.user_ids"),
|
||||
value_type: Cow::Borrowed(&EventMatchPatternType::UserId),
|
||||
},
|
||||
)),
|
||||
]),
|
||||
actions: Cow::Borrowed(&[Action::Notify, RING_ACTION]),
|
||||
default: true,
|
||||
default_enabled: true,
|
||||
},
|
||||
PushRule {
|
||||
rule_id: Cow::Borrowed("global/override/.org.matrix.msc4075.rule.rtc.invite_for_room"),
|
||||
priority_class: 5,
|
||||
conditions: Cow::Borrowed(&[
|
||||
Condition::Known(KnownCondition::EventMatch(EventMatchCondition {
|
||||
key: Cow::Borrowed("type"),
|
||||
pattern: Cow::Borrowed("org.matrix.msc4075.rtc.notification"),
|
||||
})),
|
||||
Condition::Known(KnownCondition::EventPropertyIs(EventPropertyIsCondition {
|
||||
key: Cow::Borrowed(r"content.m\.mentions.room"),
|
||||
value: Cow::Owned(SimpleJsonValue::Bool(true)),
|
||||
})),
|
||||
Condition::Known(KnownCondition::SenderNotificationPermission {
|
||||
key: Cow::Borrowed("room"),
|
||||
}),
|
||||
]),
|
||||
actions: Cow::Borrowed(&[Action::Notify, RING_ACTION]),
|
||||
default: true,
|
||||
default_enabled: true,
|
||||
},
|
||||
PushRule {
|
||||
rule_id: Cow::Borrowed("global/override/.m.rule.is_user_mention"),
|
||||
priority_class: 5,
|
||||
@@ -734,3 +773,135 @@ lazy_static! {
|
||||
.map(|rule| { (&*rule.rule_id, rule) })
|
||||
.collect();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use super::RING_ACTION;
|
||||
use crate::push::evaluator::PushRuleEvaluator;
|
||||
use crate::push::{Action, FilteredPushRules, JsonValue, PushRules, SimpleJsonValue};
|
||||
|
||||
const RTC_NOTIFICATION_TYPE: &str = "org.matrix.msc4075.rtc.notification";
|
||||
const ALICE: &str = "@alice:example.org";
|
||||
const BOB: &str = "@bob:example.org";
|
||||
|
||||
/// The default push rules with no user-defined rules.
|
||||
///
|
||||
/// The generic mention rules are disabled so that they cannot mask the
|
||||
/// MSC4075 rules, which have identical actions and come immediately
|
||||
/// before them in the override list.
|
||||
fn push_rules(msc4075_enabled: bool) -> FilteredPushRules {
|
||||
let mut enabled_map = BTreeMap::new();
|
||||
enabled_map.insert("global/override/.m.rule.is_user_mention".to_string(), false);
|
||||
enabled_map.insert("global/override/.m.rule.is_room_mention".to_string(), false);
|
||||
|
||||
FilteredPushRules::py_new(
|
||||
PushRules::new(vec![]),
|
||||
enabled_map,
|
||||
false, // msc1767_enabled
|
||||
false, // msc3381_polls_enabled
|
||||
false, // msc3664_enabled
|
||||
false, // msc4028_push_encrypted_events
|
||||
msc4075_enabled,
|
||||
false, // msc4210_enabled
|
||||
false, // msc4306_enabled
|
||||
)
|
||||
}
|
||||
|
||||
/// Builds an evaluator for an event of the given type whose `m.mentions`
|
||||
/// lists the given user IDs and optionally mentions the room, sent by a
|
||||
/// user with the given power level.
|
||||
fn build_evaluator(
|
||||
event_type: &'static str,
|
||||
mentioned_user_ids: &[&'static str],
|
||||
mentions_room: bool,
|
||||
sender_power_level: i64,
|
||||
) -> PushRuleEvaluator {
|
||||
let mut flattened_keys = BTreeMap::new();
|
||||
flattened_keys.insert(
|
||||
"type".to_string(),
|
||||
JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed(event_type))),
|
||||
);
|
||||
flattened_keys.insert(
|
||||
r"content.m\.mentions.user_ids".to_string(),
|
||||
JsonValue::Array(
|
||||
mentioned_user_ids
|
||||
.iter()
|
||||
.map(|&user_id| SimpleJsonValue::Str(Cow::Borrowed(user_id)))
|
||||
.collect(),
|
||||
),
|
||||
);
|
||||
if mentions_room {
|
||||
flattened_keys.insert(
|
||||
r"content.m\.mentions.room".to_string(),
|
||||
JsonValue::Value(SimpleJsonValue::Bool(true)),
|
||||
);
|
||||
}
|
||||
|
||||
PushRuleEvaluator::py_new(
|
||||
flattened_keys,
|
||||
true,
|
||||
10,
|
||||
Some(sender_power_level),
|
||||
BTreeMap::new(),
|
||||
BTreeMap::new(),
|
||||
false,
|
||||
vec![],
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_invite_for_me_notifies_mentioned_user() {
|
||||
let evaluator = build_evaluator(RTC_NOTIFICATION_TYPE, &[ALICE], false, 0);
|
||||
|
||||
let actions = evaluator.run(&push_rules(true), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![Action::Notify, RING_ACTION]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_invite_for_me_ignores_other_users() {
|
||||
let evaluator = build_evaluator(RTC_NOTIFICATION_TYPE, &[BOB], false, 0);
|
||||
|
||||
let actions = evaluator.run(&push_rules(true), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_invite_for_room_notifies_with_permission() {
|
||||
// The default `notifications.room` power level is 50.
|
||||
let evaluator = build_evaluator(RTC_NOTIFICATION_TYPE, &[], true, 50);
|
||||
|
||||
let actions = evaluator.run(&push_rules(true), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![Action::Notify, RING_ACTION]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_invite_for_room_requires_permission() {
|
||||
let evaluator = build_evaluator(RTC_NOTIFICATION_TYPE, &[], true, 0);
|
||||
|
||||
let actions = evaluator.run(&push_rules(true), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_rules_ignore_other_event_types() {
|
||||
let evaluator = build_evaluator("org.example.other", &[ALICE], true, 50);
|
||||
|
||||
let actions = evaluator.run(&push_rules(true), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rtc_rules_are_omitted_when_msc4075_is_disabled() {
|
||||
let evaluator = build_evaluator(RTC_NOTIFICATION_TYPE, &[ALICE], true, 50);
|
||||
|
||||
let actions = evaluator.run(&push_rules(false), Some(ALICE), None, None);
|
||||
assert_eq!(actions, vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,6 +637,7 @@ fn test_requires_room_version_supports_condition() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
|
||||
@@ -557,6 +557,7 @@ pub struct FilteredPushRules {
|
||||
msc3381_polls_enabled: bool,
|
||||
msc3664_enabled: bool,
|
||||
msc4028_push_encrypted_events: bool,
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
}
|
||||
@@ -572,6 +573,7 @@ impl FilteredPushRules {
|
||||
msc3381_polls_enabled: bool,
|
||||
msc3664_enabled: bool,
|
||||
msc4028_push_encrypted_events: bool,
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
) -> Self {
|
||||
@@ -582,6 +584,7 @@ impl FilteredPushRules {
|
||||
msc3381_polls_enabled,
|
||||
msc3664_enabled,
|
||||
msc4028_push_encrypted_events,
|
||||
msc4075_enabled,
|
||||
msc4210_enabled,
|
||||
msc4306_enabled,
|
||||
}
|
||||
@@ -626,6 +629,15 @@ impl FilteredPushRules {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.msc4075_enabled
|
||||
&& (rule.rule_id
|
||||
== "global/override/.org.matrix.msc4075.rule.rtc.invite_for_me"
|
||||
|| rule.rule_id
|
||||
== "global/override/.org.matrix.msc4075.rule.rtc.invite_for_room")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.msc4210_enabled
|
||||
&& (rule.rule_id == "global/override/.m.rule.contains_display_name"
|
||||
|| rule.rule_id == "global/content/.m.rule.contains_user_name"
|
||||
|
||||
@@ -191,6 +191,9 @@ class ExperimentalConfig(Config):
|
||||
"msc4069_profile_inhibit_propagation", False
|
||||
)
|
||||
|
||||
# MSC4075: MatrixRTC invites and notifications
|
||||
self.msc4075_enabled: bool = experimental.get("msc4075_enabled", False)
|
||||
|
||||
# MSC4108: Mechanism to allow OIDC sign in and E2EE set up via QR code - 2024 version:
|
||||
# See: https://github.com/element-hq/synapse/issues/19434
|
||||
self.msc4108_enabled = experimental.get("msc4108_enabled", False)
|
||||
|
||||
@@ -106,6 +106,7 @@ def _load_rules(
|
||||
msc3664_enabled=experimental_config.msc3664_enabled,
|
||||
msc3381_polls_enabled=experimental_config.msc3381_polls_enabled,
|
||||
msc4028_push_encrypted_events=experimental_config.msc4028_push_encrypted_events,
|
||||
msc4075_enabled=experimental_config.msc4075_enabled,
|
||||
msc4210_enabled=experimental_config.msc4210_enabled,
|
||||
msc4306_enabled=experimental_config.msc4306_enabled,
|
||||
)
|
||||
|
||||
@@ -48,6 +48,7 @@ class FilteredPushRules:
|
||||
msc3381_polls_enabled: bool,
|
||||
msc3664_enabled: bool,
|
||||
msc4028_push_encrypted_events: bool,
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
): ...
|
||||
|
||||
@@ -650,3 +650,31 @@ class TestBulkPushRuleEvaluator(HomeserverTestCase):
|
||||
type="m.room.message",
|
||||
)
|
||||
)
|
||||
|
||||
def _get_rule_ids(self) -> set[str]:
|
||||
"""Returns the IDs of all push rules that apply to Alice."""
|
||||
filtered_push_rules = self.get_success(
|
||||
self.hs.get_datastores().main.get_push_rules_for_user(self.alice)
|
||||
)
|
||||
return {rule.rule_id for rule, _ in filtered_push_rules.rules()}
|
||||
|
||||
def test_msc4075_rules_omitted_when_disabled(self) -> None:
|
||||
"""The MSC4075 base rules should be filtered out unless the feature is enabled."""
|
||||
rule_ids = self._get_rule_ids()
|
||||
self.assertNotIn(
|
||||
"global/override/.org.matrix.msc4075.rule.rtc.invite_for_me", rule_ids
|
||||
)
|
||||
self.assertNotIn(
|
||||
"global/override/.org.matrix.msc4075.rule.rtc.invite_for_room", rule_ids
|
||||
)
|
||||
|
||||
@override_config({"experimental_features": {"msc4075_enabled": True}})
|
||||
def test_msc4075_rules_present_when_enabled(self) -> None:
|
||||
"""The MSC4075 base rules should be included when the feature is enabled."""
|
||||
rule_ids = self._get_rule_ids()
|
||||
self.assertIn(
|
||||
"global/override/.org.matrix.msc4075.rule.rtc.invite_for_me", rule_ids
|
||||
)
|
||||
self.assertIn(
|
||||
"global/override/.org.matrix.msc4075.rule.rtc.invite_for_room", rule_ids
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user