Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 9601d41

Browse files
author
David Robertson
authored
Merge branch 'develop' into dmr/typing/tests.appservice
2 parents 154b1c9 + 6e6edea commit 9601d41

File tree

16 files changed

+216
-111
lines changed

16 files changed

+216
-111
lines changed

changelog.d/14960.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Experimental support to suppress notifications from message edits ([MSC3958](https://github.com/matrix-org/matrix-spec-proposals/pull/3958)).

changelog.d/14983.misc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve type hints.

mypy.ini

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ disallow_untyped_defs = False
7272
[mypy-tests.*]
7373
disallow_untyped_defs = False
7474

75+
[mypy-tests.api.*]
76+
disallow_untyped_defs = True
77+
7578
[mypy-tests.app.*]
7679
disallow_untyped_defs = True
7780

rust/benches/evaluator.rs

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ fn bench_eval_message(b: &mut Bencher) {
170170
false,
171171
false,
172172
false,
173+
false,
173174
);
174175

175176
b.iter(|| eval.run(&rules, Some("bob"), Some("person")));

rust/src/push/base_rules.rs

+17
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ pub const BASE_PREPEND_OVERRIDE_RULES: &[PushRule] = &[PushRule {
6363
}];
6464

6565
pub const BASE_APPEND_OVERRIDE_RULES: &[PushRule] = &[
66+
// We don't want to notify on edits. Not only can this be confusing in real
67+
// time (2 notifications, one message) but it's especially confusing
68+
// if a bridge needs to edit a previously backfilled message.
69+
PushRule {
70+
rule_id: Cow::Borrowed("global/override/.com.beeper.suppress_edits"),
71+
priority_class: 5,
72+
conditions: Cow::Borrowed(&[Condition::Known(KnownCondition::EventMatch(
73+
EventMatchCondition {
74+
key: Cow::Borrowed("content.m.relates_to.rel_type"),
75+
pattern: Some(Cow::Borrowed("m.replace")),
76+
pattern_type: None,
77+
},
78+
))]),
79+
actions: Cow::Borrowed(&[Action::DontNotify]),
80+
default: true,
81+
default_enabled: true,
82+
},
6683
PushRule {
6784
rule_id: Cow::Borrowed("global/override/.m.rule.suppress_notices"),
6885
priority_class: 5,

rust/src/push/evaluator.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ fn test_requires_room_version_supports_condition() {
523523
};
524524
let rules = PushRules::new(vec![custom_rule]);
525525
result = evaluator.run(
526-
&FilteredPushRules::py_new(rules, BTreeMap::new(), true, false, true, false),
526+
&FilteredPushRules::py_new(rules, BTreeMap::new(), true, false, true, false, false),
527527
None,
528528
None,
529529
);

rust/src/push/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ pub struct FilteredPushRules {
419419
msc3381_polls_enabled: bool,
420420
msc3664_enabled: bool,
421421
msc3952_intentional_mentions: bool,
422+
msc3958_suppress_edits_enabled: bool,
422423
}
423424

424425
#[pymethods]
@@ -431,6 +432,7 @@ impl FilteredPushRules {
431432
msc3381_polls_enabled: bool,
432433
msc3664_enabled: bool,
433434
msc3952_intentional_mentions: bool,
435+
msc3958_suppress_edits_enabled: bool,
434436
) -> Self {
435437
Self {
436438
push_rules,
@@ -439,6 +441,7 @@ impl FilteredPushRules {
439441
msc3381_polls_enabled,
440442
msc3664_enabled,
441443
msc3952_intentional_mentions,
444+
msc3958_suppress_edits_enabled,
442445
}
443446
}
444447

@@ -476,6 +479,11 @@ impl FilteredPushRules {
476479
{
477480
return false;
478481
}
482+
if !self.msc3958_suppress_edits_enabled
483+
&& rule.rule_id == "global/override/.com.beeper.suppress_edits"
484+
{
485+
return false;
486+
}
479487

480488
true
481489
})

stubs/synapse/synapse_rust/push.pyi

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class FilteredPushRules:
4747
msc3381_polls_enabled: bool,
4848
msc3664_enabled: bool,
4949
msc3952_intentional_mentions: bool,
50+
msc3958_suppress_edits_enabled: bool,
5051
): ...
5152
def rules(self) -> Collection[Tuple[PushRule, bool]]: ...
5253

synapse/api/filtering.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ def unread_thread_notifications(self) -> bool:
252252
return self._room_timeline_filter.unread_thread_notifications
253253

254254
async def filter_presence(
255-
self, events: Iterable[UserPresenceState]
255+
self, presence_states: Iterable[UserPresenceState]
256256
) -> List[UserPresenceState]:
257-
return await self._presence_filter.filter(events)
257+
return await self._presence_filter.filter(presence_states)
258258

259259
async def filter_account_data(self, events: Iterable[JsonDict]) -> List[JsonDict]:
260260
return await self._account_data.filter(events)

synapse/config/experimental.py

+5
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
173173
self.msc3952_intentional_mentions = experimental.get(
174174
"msc3952_intentional_mentions", False
175175
)
176+
177+
# MSC3959: Do not generate notifications for edits.
178+
self.msc3958_supress_edit_notifs = experimental.get(
179+
"msc3958_supress_edit_notifs", False
180+
)

synapse/storage/databases/main/push_rule.py

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def _load_rules(
9090
msc3664_enabled=experimental_config.msc3664_enabled,
9191
msc3381_polls_enabled=experimental_config.msc3381_polls_enabled,
9292
msc3952_intentional_mentions=experimental_config.msc3952_intentional_mentions,
93+
msc3958_suppress_edits_enabled=experimental_config.msc3958_supress_edit_notifs,
9394
)
9495

9596
return filtered_rules

tests/api/test_auth.py

+35-29
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from synapse.appservice import ApplicationService
3232
from synapse.server import HomeServer
3333
from synapse.storage.databases.main.registration import TokenLookupResult
34-
from synapse.types import Requester
34+
from synapse.types import Requester, UserID
3535
from synapse.util import Clock
3636

3737
from tests import unittest
@@ -41,10 +41,12 @@
4141

4242

4343
class AuthTestCase(unittest.HomeserverTestCase):
44-
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer):
44+
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
4545
self.store = Mock()
4646

47-
hs.datastores.main = self.store
47+
# type-ignore: datastores is None until hs.setup() is called---but it'll
48+
# have been called by the HomeserverTestCase machinery.
49+
hs.datastores.main = self.store # type: ignore[union-attr]
4850
hs.get_auth_handler().store = self.store
4951
self.auth = Auth(hs)
5052

@@ -61,7 +63,7 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer):
6163
self.store.insert_client_ip = simple_async_mock(None)
6264
self.store.is_support_user = simple_async_mock(False)
6365

64-
def test_get_user_by_req_user_valid_token(self):
66+
def test_get_user_by_req_user_valid_token(self) -> None:
6567
user_info = TokenLookupResult(
6668
user_id=self.test_user, token_id=5, device_id="device"
6769
)
@@ -74,7 +76,7 @@ def test_get_user_by_req_user_valid_token(self):
7476
requester = self.get_success(self.auth.get_user_by_req(request))
7577
self.assertEqual(requester.user.to_string(), self.test_user)
7678

77-
def test_get_user_by_req_user_bad_token(self):
79+
def test_get_user_by_req_user_bad_token(self) -> None:
7880
self.store.get_user_by_access_token = simple_async_mock(None)
7981

8082
request = Mock(args={})
@@ -86,7 +88,7 @@ def test_get_user_by_req_user_bad_token(self):
8688
self.assertEqual(f.code, 401)
8789
self.assertEqual(f.errcode, "M_UNKNOWN_TOKEN")
8890

89-
def test_get_user_by_req_user_missing_token(self):
91+
def test_get_user_by_req_user_missing_token(self) -> None:
9092
user_info = TokenLookupResult(user_id=self.test_user, token_id=5)
9193
self.store.get_user_by_access_token = simple_async_mock(user_info)
9294

@@ -98,7 +100,7 @@ def test_get_user_by_req_user_missing_token(self):
98100
self.assertEqual(f.code, 401)
99101
self.assertEqual(f.errcode, "M_MISSING_TOKEN")
100102

101-
def test_get_user_by_req_appservice_valid_token(self):
103+
def test_get_user_by_req_appservice_valid_token(self) -> None:
102104
app_service = Mock(
103105
token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None
104106
)
@@ -112,7 +114,7 @@ def test_get_user_by_req_appservice_valid_token(self):
112114
requester = self.get_success(self.auth.get_user_by_req(request))
113115
self.assertEqual(requester.user.to_string(), self.test_user)
114116

115-
def test_get_user_by_req_appservice_valid_token_good_ip(self):
117+
def test_get_user_by_req_appservice_valid_token_good_ip(self) -> None:
116118
from netaddr import IPSet
117119

118120
app_service = Mock(
@@ -131,7 +133,7 @@ def test_get_user_by_req_appservice_valid_token_good_ip(self):
131133
requester = self.get_success(self.auth.get_user_by_req(request))
132134
self.assertEqual(requester.user.to_string(), self.test_user)
133135

134-
def test_get_user_by_req_appservice_valid_token_bad_ip(self):
136+
def test_get_user_by_req_appservice_valid_token_bad_ip(self) -> None:
135137
from netaddr import IPSet
136138

137139
app_service = Mock(
@@ -153,7 +155,7 @@ def test_get_user_by_req_appservice_valid_token_bad_ip(self):
153155
self.assertEqual(f.code, 401)
154156
self.assertEqual(f.errcode, "M_UNKNOWN_TOKEN")
155157

156-
def test_get_user_by_req_appservice_bad_token(self):
158+
def test_get_user_by_req_appservice_bad_token(self) -> None:
157159
self.store.get_app_service_by_token = Mock(return_value=None)
158160
self.store.get_user_by_access_token = simple_async_mock(None)
159161

@@ -166,7 +168,7 @@ def test_get_user_by_req_appservice_bad_token(self):
166168
self.assertEqual(f.code, 401)
167169
self.assertEqual(f.errcode, "M_UNKNOWN_TOKEN")
168170

169-
def test_get_user_by_req_appservice_missing_token(self):
171+
def test_get_user_by_req_appservice_missing_token(self) -> None:
170172
app_service = Mock(token="foobar", url="a_url", sender=self.test_user)
171173
self.store.get_app_service_by_token = Mock(return_value=app_service)
172174
self.store.get_user_by_access_token = simple_async_mock(None)
@@ -179,7 +181,7 @@ def test_get_user_by_req_appservice_missing_token(self):
179181
self.assertEqual(f.code, 401)
180182
self.assertEqual(f.errcode, "M_MISSING_TOKEN")
181183

182-
def test_get_user_by_req_appservice_valid_token_valid_user_id(self):
184+
def test_get_user_by_req_appservice_valid_token_valid_user_id(self) -> None:
183185
masquerading_user_id = b"@doppelganger:matrix.org"
184186
app_service = Mock(
185187
token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None
@@ -200,7 +202,7 @@ def test_get_user_by_req_appservice_valid_token_valid_user_id(self):
200202
requester.user.to_string(), masquerading_user_id.decode("utf8")
201203
)
202204

203-
def test_get_user_by_req_appservice_valid_token_bad_user_id(self):
205+
def test_get_user_by_req_appservice_valid_token_bad_user_id(self) -> None:
204206
masquerading_user_id = b"@doppelganger:matrix.org"
205207
app_service = Mock(
206208
token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None
@@ -217,7 +219,7 @@ def test_get_user_by_req_appservice_valid_token_bad_user_id(self):
217219
self.get_failure(self.auth.get_user_by_req(request), AuthError)
218220

219221
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
220-
def test_get_user_by_req_appservice_valid_token_valid_device_id(self):
222+
def test_get_user_by_req_appservice_valid_token_valid_device_id(self) -> None:
221223
"""
222224
Tests that when an application service passes the device_id URL parameter
223225
with the ID of a valid device for the user in question,
@@ -249,7 +251,7 @@ def test_get_user_by_req_appservice_valid_token_valid_device_id(self):
249251
self.assertEqual(requester.device_id, masquerading_device_id.decode("utf8"))
250252

251253
@override_config({"experimental_features": {"msc3202_device_masquerading": True}})
252-
def test_get_user_by_req_appservice_valid_token_invalid_device_id(self):
254+
def test_get_user_by_req_appservice_valid_token_invalid_device_id(self) -> None:
253255
"""
254256
Tests that when an application service passes the device_id URL parameter
255257
with an ID that is not a valid device ID for the user in question,
@@ -279,7 +281,7 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self):
279281
self.assertEqual(failure.value.code, 400)
280282
self.assertEqual(failure.value.errcode, Codes.EXCLUSIVE)
281283

282-
def test_get_user_by_req__puppeted_token__not_tracking_puppeted_mau(self):
284+
def test_get_user_by_req__puppeted_token__not_tracking_puppeted_mau(self) -> None:
283285
self.store.get_user_by_access_token = simple_async_mock(
284286
TokenLookupResult(
285287
user_id="@baldrick:matrix.org",
@@ -298,7 +300,7 @@ def test_get_user_by_req__puppeted_token__not_tracking_puppeted_mau(self):
298300
self.get_success(self.auth.get_user_by_req(request))
299301
self.store.insert_client_ip.assert_called_once()
300302

301-
def test_get_user_by_req__puppeted_token__tracking_puppeted_mau(self):
303+
def test_get_user_by_req__puppeted_token__tracking_puppeted_mau(self) -> None:
302304
self.auth._track_puppeted_user_ips = True
303305
self.store.get_user_by_access_token = simple_async_mock(
304306
TokenLookupResult(
@@ -318,7 +320,7 @@ def test_get_user_by_req__puppeted_token__tracking_puppeted_mau(self):
318320
self.get_success(self.auth.get_user_by_req(request))
319321
self.assertEqual(self.store.insert_client_ip.call_count, 2)
320322

321-
def test_get_user_from_macaroon(self):
323+
def test_get_user_from_macaroon(self) -> None:
322324
self.store.get_user_by_access_token = simple_async_mock(None)
323325

324326
user_id = "@baldrick:matrix.org"
@@ -336,7 +338,7 @@ def test_get_user_from_macaroon(self):
336338
self.auth.get_user_by_access_token(serialized), InvalidClientTokenError
337339
)
338340

339-
def test_get_guest_user_from_macaroon(self):
341+
def test_get_guest_user_from_macaroon(self) -> None:
340342
self.store.get_user_by_id = simple_async_mock({"is_guest": True})
341343
self.store.get_user_by_access_token = simple_async_mock(None)
342344

@@ -357,7 +359,7 @@ def test_get_guest_user_from_macaroon(self):
357359
self.assertTrue(user_info.is_guest)
358360
self.store.get_user_by_id.assert_called_with(user_id)
359361

360-
def test_blocking_mau(self):
362+
def test_blocking_mau(self) -> None:
361363
self.auth_blocking._limit_usage_by_mau = False
362364
self.auth_blocking._max_mau_value = 50
363365
lots_of_users = 100
@@ -381,7 +383,7 @@ def test_blocking_mau(self):
381383
self.store.get_monthly_active_count = simple_async_mock(small_number_of_users)
382384
self.get_success(self.auth_blocking.check_auth_blocking())
383385

384-
def test_blocking_mau__depending_on_user_type(self):
386+
def test_blocking_mau__depending_on_user_type(self) -> None:
385387
self.auth_blocking._max_mau_value = 50
386388
self.auth_blocking._limit_usage_by_mau = True
387389

@@ -400,7 +402,9 @@ def test_blocking_mau__depending_on_user_type(self):
400402
# Real users not allowed
401403
self.get_failure(self.auth_blocking.check_auth_blocking(), ResourceLimitError)
402404

403-
def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(self):
405+
def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(
406+
self,
407+
) -> None:
404408
self.auth_blocking._max_mau_value = 50
405409
self.auth_blocking._limit_usage_by_mau = True
406410
self.auth_blocking._track_appservice_user_ips = False
@@ -418,7 +422,7 @@ def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(self):
418422
sender="@appservice:sender",
419423
)
420424
requester = Requester(
421-
user="@appservice:server",
425+
user=UserID.from_string("@appservice:server"),
422426
access_token_id=None,
423427
device_id="FOOBAR",
424428
is_guest=False,
@@ -428,7 +432,9 @@ def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(self):
428432
)
429433
self.get_success(self.auth_blocking.check_auth_blocking(requester=requester))
430434

431-
def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self):
435+
def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(
436+
self,
437+
) -> None:
432438
self.auth_blocking._max_mau_value = 50
433439
self.auth_blocking._limit_usage_by_mau = True
434440
self.auth_blocking._track_appservice_user_ips = True
@@ -446,7 +452,7 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self):
446452
sender="@appservice:sender",
447453
)
448454
requester = Requester(
449-
user="@appservice:server",
455+
user=UserID.from_string("@appservice:server"),
450456
access_token_id=None,
451457
device_id="FOOBAR",
452458
is_guest=False,
@@ -459,7 +465,7 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self):
459465
ResourceLimitError,
460466
)
461467

462-
def test_reserved_threepid(self):
468+
def test_reserved_threepid(self) -> None:
463469
self.auth_blocking._limit_usage_by_mau = True
464470
self.auth_blocking._max_mau_value = 1
465471
self.store.get_monthly_active_count = simple_async_mock(2)
@@ -476,7 +482,7 @@ def test_reserved_threepid(self):
476482

477483
self.get_success(self.auth_blocking.check_auth_blocking(threepid=threepid))
478484

479-
def test_hs_disabled(self):
485+
def test_hs_disabled(self) -> None:
480486
self.auth_blocking._hs_disabled = True
481487
self.auth_blocking._hs_disabled_message = "Reason for being disabled"
482488
e = self.get_failure(
@@ -486,7 +492,7 @@ def test_hs_disabled(self):
486492
self.assertEqual(e.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
487493
self.assertEqual(e.value.code, 403)
488494

489-
def test_hs_disabled_no_server_notices_user(self):
495+
def test_hs_disabled_no_server_notices_user(self) -> None:
490496
"""Check that 'hs_disabled_message' works correctly when there is no
491497
server_notices user.
492498
"""
@@ -503,7 +509,7 @@ def test_hs_disabled_no_server_notices_user(self):
503509
self.assertEqual(e.value.errcode, Codes.RESOURCE_LIMIT_EXCEEDED)
504510
self.assertEqual(e.value.code, 403)
505511

506-
def test_server_notices_mxid_special_cased(self):
512+
def test_server_notices_mxid_special_cased(self) -> None:
507513
self.auth_blocking._hs_disabled = True
508514
user = "@user:server"
509515
self.auth_blocking._server_notices_mxid = user

0 commit comments

Comments
 (0)