summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Cloke <clokep@users.noreply.github.com>2023-08-02 08:41:32 -0400
committerGitHub <noreply@github.com>2023-08-02 08:41:32 -0400
commit01a45869f034265b9757992aa1a5eb7a0923351c (patch)
treeb0e7e9a927141365fe73d26774b3193f44a1ace6
parentBump cryptography from 41.0.2 to 41.0.3 (#16048) (diff)
downloadsynapse-01a45869f034265b9757992aa1a5eb7a0923351c.tar.xz
Update MSC3958 support to interact with intentional mentions. (#15992)
* Updates the rule ID.
* Use `event_property_is` instead of `event_match`.

This updates the implementation of MSC3958 to match the latest
text from the MSC.
-rw-r--r--changelog.d/15992.misc1
-rw-r--r--rust/benches/evaluator.rs27
-rw-r--r--rust/src/push/base_rules.rs37
-rw-r--r--rust/src/push/evaluator.rs14
-rw-r--r--rust/src/push/mod.rs6
-rw-r--r--tests/push/test_bulk_push_rule_evaluator.py21
6 files changed, 64 insertions, 42 deletions
diff --git a/changelog.d/15992.misc b/changelog.d/15992.misc
new file mode 100644
index 0000000000..539f55b475
--- /dev/null
+++ b/changelog.d/15992.misc
@@ -0,0 +1 @@
+Update support for [MSC3958](https://github.com/matrix-org/matrix-spec-proposals/pull/3958) to match the latest revision of the MSC.
diff --git a/rust/benches/evaluator.rs b/rust/benches/evaluator.rs
index c2f33258a4..6e1eab2a3b 100644
--- a/rust/benches/evaluator.rs
+++ b/rust/benches/evaluator.rs
@@ -13,6 +13,9 @@
 // limitations under the License.
 
 #![feature(test)]
+
+use std::borrow::Cow;
+
 use synapse::push::{
     evaluator::PushRuleEvaluator, Condition, EventMatchCondition, FilteredPushRules, JsonValue,
     PushRules, SimpleJsonValue,
@@ -26,15 +29,15 @@ fn bench_match_exact(b: &mut Bencher) {
     let flattened_keys = [
         (
             "type".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("m.text".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("m.text"))),
         ),
         (
             "room_id".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("!room:server".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("!room:server"))),
         ),
         (
             "content.body".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("test message".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("test message"))),
         ),
     ]
     .into_iter()
@@ -71,15 +74,15 @@ fn bench_match_word(b: &mut Bencher) {
     let flattened_keys = [
         (
             "type".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("m.text".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("m.text"))),
         ),
         (
             "room_id".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("!room:server".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("!room:server"))),
         ),
         (
             "content.body".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("test message".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("test message"))),
         ),
     ]
     .into_iter()
@@ -116,15 +119,15 @@ fn bench_match_word_miss(b: &mut Bencher) {
     let flattened_keys = [
         (
             "type".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("m.text".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("m.text"))),
         ),
         (
             "room_id".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("!room:server".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("!room:server"))),
         ),
         (
             "content.body".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("test message".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("test message"))),
         ),
     ]
     .into_iter()
@@ -161,15 +164,15 @@ fn bench_eval_message(b: &mut Bencher) {
     let flattened_keys = [
         (
             "type".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("m.text".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("m.text"))),
         ),
         (
             "room_id".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("!room:server".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("!room:server"))),
         ),
         (
             "content.body".to_string(),
-            JsonValue::Value(SimpleJsonValue::Str("test message".to_string())),
+            JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("test message"))),
         ),
     ]
     .into_iter()
diff --git a/rust/src/push/base_rules.rs b/rust/src/push/base_rules.rs
index 7eea9313f0..00baceda91 100644
--- a/rust/src/push/base_rules.rs
+++ b/rust/src/push/base_rules.rs
@@ -63,22 +63,6 @@ pub const BASE_PREPEND_OVERRIDE_RULES: &[PushRule] = &[PushRule {
 }];
 
 pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
-    // We don't want to notify on edits. Not only can this be confusing in real
-    // time (2 notifications, one message) but it's especially confusing
-    // if a bridge needs to edit a previously backfilled message.
-    PushRule {
-        rule_id: Cow::Borrowed("global/override/.com.beeper.suppress_edits"),
-        priority_class: 5,
-        conditions: Cow::Borrowed(&[Condition::Known(KnownCondition::EventMatch(
-            EventMatchCondition {
-                key: Cow::Borrowed("content.m\\.relates_to.rel_type"),
-                pattern: Cow::Borrowed("m.replace"),
-            },
-        ))]),
-        actions: Cow::Borrowed(&[]),
-        default: true,
-        default_enabled: true,
-    },
     PushRule {
         rule_id: Cow::Borrowed("global/override/.m.rule.suppress_notices"),
         priority_class: 5,
@@ -146,7 +130,7 @@ pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
         priority_class: 5,
         conditions: Cow::Borrowed(&[Condition::Known(
             KnownCondition::ExactEventPropertyContainsType(EventPropertyIsTypeCondition {
-                key: Cow::Borrowed("content.m\\.mentions.user_ids"),
+                key: Cow::Borrowed(r"content.m\.mentions.user_ids"),
                 value_type: Cow::Borrowed(&EventMatchPatternType::UserId),
             }),
         )]),
@@ -167,8 +151,8 @@ pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
         priority_class: 5,
         conditions: Cow::Borrowed(&[
             Condition::Known(KnownCondition::EventPropertyIs(EventPropertyIsCondition {
-                key: Cow::Borrowed("content.m\\.mentions.room"),
-                value: Cow::Borrowed(&SimpleJsonValue::Bool(true)),
+                key: Cow::Borrowed(r"content.m\.mentions.room"),
+                value: Cow::Owned(SimpleJsonValue::Bool(true)),
             })),
             Condition::Known(KnownCondition::SenderNotificationPermission {
                 key: Cow::Borrowed("room"),
@@ -241,6 +225,21 @@ pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
         default: true,
         default_enabled: true,
     },
+    // We don't want to notify on edits *unless* the edit directly mentions a
+    // user, which is handled above.
+    PushRule {
+        rule_id: Cow::Borrowed("global/override/.org.matrix.msc3958.suppress_edits"),
+        priority_class: 5,
+        conditions: Cow::Borrowed(&[Condition::Known(KnownCondition::EventPropertyIs(
+            EventPropertyIsCondition {
+                key: Cow::Borrowed(r"content.m\.relates_to.rel_type"),
+                value: Cow::Owned(SimpleJsonValue::Str(Cow::Borrowed("m.replace"))),
+            },
+        ))]),
+        actions: Cow::Borrowed(&[]),
+        default: true,
+        default_enabled: true,
+    },
     PushRule {
         rule_id: Cow::Borrowed("global/override/.org.matrix.msc3930.rule.poll_response"),
         priority_class: 5,
diff --git a/rust/src/push/evaluator.rs b/rust/src/push/evaluator.rs
index 59c53b1776..48e670478b 100644
--- a/rust/src/push/evaluator.rs
+++ b/rust/src/push/evaluator.rs
@@ -117,7 +117,7 @@ impl PushRuleEvaluator {
         msc3931_enabled: bool,
     ) -> Result<Self, Error> {
         let body = match flattened_keys.get("content.body") {
-            Some(JsonValue::Value(SimpleJsonValue::Str(s))) => s.clone(),
+            Some(JsonValue::Value(SimpleJsonValue::Str(s))) => s.clone().into_owned(),
             _ => String::new(),
         };
 
@@ -313,13 +313,15 @@ impl PushRuleEvaluator {
                 };
 
                 let pattern = match &*exact_event_match.value_type {
-                    EventMatchPatternType::UserId => user_id,
-                    EventMatchPatternType::UserLocalpart => get_localpart_from_id(user_id)?,
+                    EventMatchPatternType::UserId => user_id.to_owned(),
+                    EventMatchPatternType::UserLocalpart => {
+                        get_localpart_from_id(user_id)?.to_owned()
+                    }
                 };
 
                 self.match_event_property_contains(
                     exact_event_match.key.clone(),
-                    Cow::Borrowed(&SimpleJsonValue::Str(pattern.to_string())),
+                    Cow::Borrowed(&SimpleJsonValue::Str(Cow::Owned(pattern))),
                 )?
             }
             KnownCondition::ContainsDisplayName => {
@@ -494,7 +496,7 @@ fn push_rule_evaluator() {
     let mut flattened_keys = BTreeMap::new();
     flattened_keys.insert(
         "content.body".to_string(),
-        JsonValue::Value(SimpleJsonValue::Str("foo bar bob hello".to_string())),
+        JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("foo bar bob hello"))),
     );
     let evaluator = PushRuleEvaluator::py_new(
         flattened_keys,
@@ -522,7 +524,7 @@ fn test_requires_room_version_supports_condition() {
     let mut flattened_keys = BTreeMap::new();
     flattened_keys.insert(
         "content.body".to_string(),
-        JsonValue::Value(SimpleJsonValue::Str("foo bar bob hello".to_string())),
+        JsonValue::Value(SimpleJsonValue::Str(Cow::Borrowed("foo bar bob hello"))),
     );
     let flags = vec![RoomVersionFeatures::ExtensibleEvents.as_str().to_string()];
     let evaluator = PushRuleEvaluator::py_new(
diff --git a/rust/src/push/mod.rs b/rust/src/push/mod.rs
index 514980579b..829fb79d0e 100644
--- a/rust/src/push/mod.rs
+++ b/rust/src/push/mod.rs
@@ -256,7 +256,7 @@ impl<'de> Deserialize<'de> for Action {
 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
 #[serde(untagged)]
 pub enum SimpleJsonValue {
-    Str(String),
+    Str(Cow<'static, str>),
     Int(i64),
     Bool(bool),
     Null,
@@ -265,7 +265,7 @@ pub enum SimpleJsonValue {
 impl<'source> FromPyObject<'source> for SimpleJsonValue {
     fn extract(ob: &'source PyAny) -> PyResult<Self> {
         if let Ok(s) = <PyString as pyo3::PyTryFrom>::try_from(ob) {
-            Ok(SimpleJsonValue::Str(s.to_string()))
+            Ok(SimpleJsonValue::Str(Cow::Owned(s.to_string())))
         // A bool *is* an int, ensure we try bool first.
         } else if let Ok(b) = <PyBool as pyo3::PyTryFrom>::try_from(ob) {
             Ok(SimpleJsonValue::Bool(b.extract()?))
@@ -585,7 +585,7 @@ impl FilteredPushRules {
                 }
 
                 if !self.msc3958_suppress_edits_enabled
-                    && rule.rule_id == "global/override/.com.beeper.suppress_edits"
+                    && rule.rule_id == "global/override/.org.matrix.msc3958.suppress_edits"
                 {
                     return false;
                 }
diff --git a/tests/push/test_bulk_push_rule_evaluator.py b/tests/push/test_bulk_push_rule_evaluator.py
index 1e06f86071..829b9df83d 100644
--- a/tests/push/test_bulk_push_rule_evaluator.py
+++ b/tests/push/test_bulk_push_rule_evaluator.py
@@ -409,12 +409,12 @@ class TestBulkPushRuleEvaluator(HomeserverTestCase):
             )
         )
 
-        # Room mentions from those without power should not notify.
+        # The edit should not cause a notification.
         self.assertFalse(
             self._create_and_process(
                 bulk_evaluator,
                 {
-                    "body": self.alice,
+                    "body": "Test message",
                     "m.relates_to": {
                         "rel_type": RelationTypes.REPLACE,
                         "event_id": event.event_id,
@@ -422,3 +422,20 @@ class TestBulkPushRuleEvaluator(HomeserverTestCase):
                 },
             )
         )
+
+        # An edit which is a mention will cause a notification.
+        self.assertTrue(
+            self._create_and_process(
+                bulk_evaluator,
+                {
+                    "body": "Test message",
+                    "m.relates_to": {
+                        "rel_type": RelationTypes.REPLACE,
+                        "event_id": event.event_id,
+                    },
+                    "m.mentions": {
+                        "user_ids": [self.alice],
+                    },
+                },
+            )
+        )