diff --git a/changelog.d/12601.feature b/changelog.d/12601.feature new file mode 100644 index 000000000..c13360ff3 --- /dev/null +++ b/changelog.d/12601.feature @@ -0,0 +1 @@ +Implement MSC3786: Add a default push rule to ignore m.room.server_acl events. diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py index abed5e7ed..b20d94968 100644 --- a/synapse/config/experimental.py +++ b/synapse/config/experimental.py @@ -81,3 +81,6 @@ class ExperimentalConfig(Config): # MSC2815 (allow room moderators to view redacted event content) self.msc2815_enabled: bool = experimental.get("msc2815_enabled", False) + + # MSC3786 (Add a default push rule to ignore m.room.server_acl events) + self.msc3786_enabled: bool = experimental.get("msc3786_enabled", False) diff --git a/synapse/push/baserules.py b/synapse/push/baserules.py index f42f605f2..a17b35a60 100644 --- a/synapse/push/baserules.py +++ b/synapse/push/baserules.py @@ -277,6 +277,21 @@ BASE_APPEND_OVERRIDE_RULES: List[Dict[str, Any]] = [ ], "actions": ["dont_notify"], }, + # XXX: This is an experimental rule that is only enabled if msc3786_enabled + # is enabled, if it is not the rule gets filtered out in _load_rules() in + # PushRulesWorkerStore + { + "rule_id": "global/override/.org.matrix.msc3786.rule.room.server_acl", + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.room.server_acl", + "_cache_key": "_room_server_acl", + } + ], + "actions": ["dont_notify"], + }, ] diff --git a/synapse/storage/databases/main/push_rule.py b/synapse/storage/databases/main/push_rule.py index eb85bbd39..4ed913e24 100644 --- a/synapse/storage/databases/main/push_rule.py +++ b/synapse/storage/databases/main/push_rule.py @@ -17,6 +17,7 @@ import logging from typing import TYPE_CHECKING, Dict, List, Tuple, Union from synapse.api.errors import StoreError +from synapse.config.homeserver import ExperimentalConfig from synapse.push.baserules import list_with_base_rules from synapse.replication.slave.storage._slaved_id_tracker import SlavedIdTracker from synapse.storage._base import SQLBaseStore, db_to_json @@ -42,7 +43,21 @@ if TYPE_CHECKING: logger = logging.getLogger(__name__) -def _load_rules(rawrules, enabled_map): +def _is_experimental_rule_enabled( + rule_id: str, experimental_config: ExperimentalConfig +) -> bool: + """Used by `_load_rules` to filter out experimental rules when they + have not been enabled. + """ + if ( + rule_id == "global/override/.org.matrix.msc3786.rule.room.server_acl" + and not experimental_config.msc3786_enabled + ): + return False + return True + + +def _load_rules(rawrules, enabled_map, experimental_config: ExperimentalConfig): ruleslist = [] for rawrule in rawrules: rule = dict(rawrule) @@ -51,17 +66,26 @@ def _load_rules(rawrules, enabled_map): rule["default"] = False ruleslist.append(rule) - # We're going to be mutating this a lot, so do a deep copy - rules = list(list_with_base_rules(ruleslist)) + # We're going to be mutating this a lot, so copy it. We also filter out + # any experimental default push rules that aren't enabled. + rules = [ + rule + for rule in list_with_base_rules(ruleslist) + if _is_experimental_rule_enabled(rule["rule_id"], experimental_config) + ] for i, rule in enumerate(rules): rule_id = rule["rule_id"] - if rule_id in enabled_map: - if rule.get("enabled", True) != bool(enabled_map[rule_id]): - # Rules are cached across users. - rule = dict(rule) - rule["enabled"] = bool(enabled_map[rule_id]) - rules[i] = rule + + if rule_id not in enabled_map: + continue + if rule.get("enabled", True) == bool(enabled_map[rule_id]): + continue + + # Rules are cached across users. + rule = dict(rule) + rule["enabled"] = bool(enabled_map[rule_id]) + rules[i] = rule return rules @@ -141,7 +165,7 @@ class PushRulesWorkerStore( enabled_map = await self.get_push_rules_enabled_for_user(user_id) - return _load_rules(rows, enabled_map) + return _load_rules(rows, enabled_map, self.hs.config.experimental) @cached(max_entries=5000) async def get_push_rules_enabled_for_user(self, user_id) -> Dict[str, bool]: @@ -200,7 +224,9 @@ class PushRulesWorkerStore( enabled_map_by_user = await self.bulk_get_push_rules_enabled(user_ids) for user_id, rules in results.items(): - results[user_id] = _load_rules(rules, enabled_map_by_user.get(user_id, {})) + results[user_id] = _load_rules( + rules, enabled_map_by_user.get(user_id, {}), self.hs.config.experimental + ) return results