forked from MirrorHub/synapse
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:
parent
5565f454e1
commit
6c0b44a3d7
5 changed files with 27 additions and 6 deletions
1
changelog.d/12100.bugfix
Normal file
1
changelog.d/12100.bugfix
Normal 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.
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue