Fix `PushRuleEvaluator` and `Filter` to work on frozendicts (#12100)

* Fix `PushRuleEvaluator` to work on frozendicts

frozendicts do not (necessarily) inherit from dict, so this needs to handle
them correctly.

* Fix event filtering for frozen events

Looks like this one was introduced by #11194.
pull/12089/head
Richard van der Hoff 2022-02-28 17:40:24 +00:00 committed by GitHub
parent 5565f454e1
commit 6c0b44a3d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 27 additions and 6 deletions

1
changelog.d/12100.bugfix Normal file
View File

@ -0,0 +1 @@
Fix a long-standing bug which could cause push notifications to malfunction if `use_frozen_dicts` was set in the configuration.

View File

@ -22,6 +22,7 @@ from typing import (
Dict,
Iterable,
List,
Mapping,
Optional,
Set,
TypeVar,
@ -361,10 +362,10 @@ class Filter:
return self._check_fields(field_matchers)
else:
content = event.get("content")
# Content is assumed to be a dict below, so ensure it is. This should
# Content is assumed to be a mapping below, so ensure it is. This should
# always be true for events, but account_data has been allowed to
# have non-dict content.
if not isinstance(content, dict):
if not isinstance(content, Mapping):
content = {}
sender = event.get("sender", None)

View File

@ -15,12 +15,12 @@
import logging
import re
from typing import Any, Dict, List, Optional, Pattern, Tuple, Union
from typing import Any, Dict, List, Mapping, Optional, Pattern, Tuple, Union
from matrix_common.regex import glob_to_regex, to_word_pattern
from synapse.events import EventBase
from synapse.types import JsonDict, UserID
from synapse.types import UserID
from synapse.util.caches.lrucache import LruCache
logger = logging.getLogger(__name__)
@ -223,7 +223,7 @@ def _glob_matches(glob: str, value: str, word_boundary: bool = False) -> bool:
def _flatten_dict(
d: Union[EventBase, JsonDict],
d: Union[EventBase, Mapping[str, Any]],
prefix: Optional[List[str]] = None,
result: Optional[Dict[str, str]] = None,
) -> Dict[str, str]:
@ -234,7 +234,7 @@ def _flatten_dict(
for key, value in d.items():
if isinstance(value, str):
result[".".join(prefix + [key])] = value.lower()
elif isinstance(value, dict):
elif isinstance(value, Mapping):
_flatten_dict(value, prefix=(prefix + [key]), result=result)
return result

View File

@ -18,6 +18,7 @@
from unittest.mock import patch
import jsonschema
from frozendict import frozendict
from synapse.api.constants import EventContentFields
from synapse.api.errors import SynapseError
@ -327,6 +328,15 @@ class FilteringTestCase(unittest.HomeserverTestCase):
self.assertFalse(Filter(self.hs, definition)._check(event))
# check it works with frozendicts too
event = MockEvent(
sender="@foo:bar",
type="m.room.message",
room_id="!secretbase:unknown",
content=frozendict({EventContentFields.LABELS: ["#fun"]}),
)
self.assertTrue(Filter(self.hs, definition)._check(event))
def test_filter_not_labels(self):
definition = {"org.matrix.not_labels": ["#fun"]}
event = MockEvent(

View File

@ -14,6 +14,8 @@
from typing import Any, Dict
import frozendict
from synapse.api.room_versions import RoomVersions
from synapse.events import FrozenEvent
from synapse.push import push_rule_evaluator
@ -191,6 +193,13 @@ class PushRuleEvaluatorTestCase(unittest.TestCase):
"pattern should only match at the start/end of the value",
)
# it should work on frozendicts too
self._assert_matches(
condition,
frozendict.frozendict({"value": "FoobaZ"}),
"patterns should match on frozendicts",
)
# wildcards should match
condition = {
"kind": "event_match",