mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-04 06:57:20 +00:00
Add the default .m.rule.knock push rule (MSC4506)
`.m.rule.member_event` suppresses every `m.room.member` event, so a knock (MSC2403) pushes nobody today. The new override rule `.org.matrix.msc4506.rule.knock` matches a knock membership event and the `recipient_permission` condition on `invite`, and notifies with a sound. It sits after `.m.rule.invite_for_me` and before `.m.rule.member_event`. A knock has sender == state_key, so the bulk evaluator's member-event fast path finds nobody to evaluate rules for. With the flag on, a knock now evaluates rules for every local member, at the cost of a message in the same room. Blast radius: the rule pushes every member at or above the room's `invite` level. Synapse creates rooms with `invite: 50`, but a room that omits the key defaults to 0, as do the `private_chat` and `trusted_private_chat` presets, and there every member gets pushed for every knock. `filter_push_rules` drops the rule while `msc4506_enabled` is off, so `/pushrules` serves it only with the flag on. The code departs from the MSC text in three places, to raise as MSC follow-ups. It uses `event_match` where the MSC uses `event_property_is`, matching `.m.rule.invite_for_me`. The MSC escapes the value as `m\.room\.member`, which `event_property_is` compares literally, so that condition never fires. The actions add `highlight: false`, as every other default notify rule does. Co-authored-by: Quentin Gliech <quenting@element.io> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
7a974c88df
commit
43bdb619b7
8 files changed
+47
No files matched your search
@@ -0,0 +1 @@
|
||||
Implement experimental support for [MSC4506](https://github.com/matrix-org/matrix-spec-proposals/pull/4506): notify relevant users if there's a knock on a room.
|
||||
@@ -235,6 +235,7 @@ fn bench_eval_message(b: &mut Bencher) {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
b.iter(|| eval.run(&rules, Some("bob"), Some("person"), None, None));
|
||||
|
||||
@@ -117,6 +117,30 @@ pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
|
||||
default: true,
|
||||
default_enabled: true,
|
||||
},
|
||||
// MSC4506: notify the members of a room who are able to act on a knock
|
||||
// (i.e. those with a power level sufficient to invite the knocker). Must
|
||||
// come before `.m.rule.member_event`, which suppresses all other member
|
||||
// events.
|
||||
PushRule {
|
||||
rule_id: Cow::Borrowed("global/override/.org.matrix.msc4506.rule.knock"),
|
||||
priority_class: 5,
|
||||
conditions: Cow::Borrowed(&[
|
||||
Condition::Known(KnownCondition::EventMatch(EventMatchCondition {
|
||||
key: Cow::Borrowed("type"),
|
||||
pattern: Cow::Borrowed("m.room.member"),
|
||||
})),
|
||||
Condition::Known(KnownCondition::EventMatch(EventMatchCondition {
|
||||
key: Cow::Borrowed("content.membership"),
|
||||
pattern: Cow::Borrowed("knock"),
|
||||
})),
|
||||
Condition::Known(KnownCondition::RecipientPermission {
|
||||
key: Cow::Borrowed("invite"),
|
||||
}),
|
||||
]),
|
||||
actions: Cow::Borrowed(&[Action::Notify, HIGHLIGHT_FALSE_ACTION, SOUND_ACTION]),
|
||||
default: true,
|
||||
default_enabled: true,
|
||||
},
|
||||
PushRule {
|
||||
rule_id: Cow::Borrowed("global/override/.m.rule.member_event"),
|
||||
priority_class: 5,
|
||||
@@ -811,6 +835,7 @@ mod tests {
|
||||
msc4075_enabled,
|
||||
false, // msc4210_enabled
|
||||
false, // msc4306_enabled
|
||||
false, // msc4506_enabled
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -730,6 +730,7 @@ fn test_requires_room_version_supports_condition() {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
None,
|
||||
None,
|
||||
|
||||
@@ -561,6 +561,7 @@ pub struct FilteredPushRules {
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
msc4506_enabled: bool,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
@@ -577,6 +578,7 @@ impl FilteredPushRules {
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
msc4506_enabled: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
push_rules,
|
||||
@@ -588,6 +590,7 @@ impl FilteredPushRules {
|
||||
msc4075_enabled,
|
||||
msc4210_enabled,
|
||||
msc4306_enabled,
|
||||
msc4506_enabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,6 +627,11 @@ impl FilteredPushRules {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.msc4506_enabled && rule.rule_id.contains("/.org.matrix.msc4506.rule.knock")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.msc4028_push_encrypted_events
|
||||
&& rule.rule_id == "global/override/.org.matrix.msc4028.encrypted_event"
|
||||
{
|
||||
|
||||
@@ -192,6 +192,15 @@ class BulkPushRuleEvaluator:
|
||||
)
|
||||
if target_already_in_room:
|
||||
local_users = [event.state_key]
|
||||
elif (
|
||||
self.hs.config.experimental.msc4506_enabled
|
||||
and event.membership == Membership.KNOCK
|
||||
):
|
||||
# MSC4506: a knock (sender == state_key, so not caught above)
|
||||
# should notify the members of the room who can act on it, so
|
||||
# we can't take the membership-events-only-notify-their-target
|
||||
# fast path.
|
||||
local_users = await self.store.get_local_users_in_room(event.room_id)
|
||||
else:
|
||||
# We get the users who may need to be notified by first fetching the
|
||||
# local users currently in the room, finding those that have push rules,
|
||||
|
||||
@@ -128,6 +128,7 @@ def filter_push_rules(
|
||||
msc4075_enabled=experimental_config.msc4075_enabled,
|
||||
msc4210_enabled=experimental_config.msc4210_enabled,
|
||||
msc4306_enabled=experimental_config.msc4306_enabled,
|
||||
msc4506_enabled=experimental_config.msc4506_enabled,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ class FilteredPushRules:
|
||||
msc4075_enabled: bool,
|
||||
msc4210_enabled: bool,
|
||||
msc4306_enabled: bool,
|
||||
msc4506_enabled: bool,
|
||||
): ...
|
||||
def rules(self) -> Collection[tuple[PushRule, bool]]: ...
|
||||
|
||||
|
||||
Reference in new issue
Block a user