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.
This commit is contained in:
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, Dict,
Iterable, Iterable,
List, List,
Mapping,
Optional, Optional,
Set, Set,
TypeVar, TypeVar,
@ -361,10 +362,10 @@ class Filter:
return self._check_fields(field_matchers) return self._check_fields(field_matchers)
else: else:
content = event.get("content") 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 # always be true for events, but account_data has been allowed to
# have non-dict content. # have non-dict content.
if not isinstance(content, dict): if not isinstance(content, Mapping):
content = {} content = {}
sender = event.get("sender", None) sender = event.get("sender", None)

View file

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

View file

@ -18,6 +18,7 @@
from unittest.mock import patch from unittest.mock import patch
import jsonschema import jsonschema
from frozendict import frozendict
from synapse.api.constants import EventContentFields from synapse.api.constants import EventContentFields
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
@ -327,6 +328,15 @@ class FilteringTestCase(unittest.HomeserverTestCase):
self.assertFalse(Filter(self.hs, definition)._check(event)) 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): def test_filter_not_labels(self):
definition = {"org.matrix.not_labels": ["#fun"]} definition = {"org.matrix.not_labels": ["#fun"]}
event = MockEvent( event = MockEvent(

View file

@ -14,6 +14,8 @@
from typing import Any, Dict from typing import Any, Dict
import frozendict
from synapse.api.room_versions import RoomVersions from synapse.api.room_versions import RoomVersions
from synapse.events import FrozenEvent from synapse.events import FrozenEvent
from synapse.push import push_rule_evaluator 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", "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 # wildcards should match
condition = { condition = {
"kind": "event_match", "kind": "event_match",