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

Commit 6fe12c9

Browse files
authored
Do not propagate typing notifications from shadow-banned users. (#8176)
1 parent e0d6244 commit 6fe12c9

File tree

6 files changed

+102
-24
lines changed

6 files changed

+102
-24
lines changed

changelog.d/8176.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add support for shadow-banning users (ignoring any message send requests).

synapse/handlers/typing.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
# limitations under the License.
1515

1616
import logging
17+
import random
1718
from collections import namedtuple
1819
from typing import TYPE_CHECKING, List, Set, Tuple
1920

20-
from synapse.api.errors import AuthError, SynapseError
21+
from synapse.api.errors import AuthError, ShadowBanError, SynapseError
2122
from synapse.metrics.background_process_metrics import run_as_background_process
2223
from synapse.replication.tcp.streams import TypingStream
2324
from synapse.types import UserID, get_domain_from_id
@@ -227,16 +228,21 @@ def _handle_timeout_for_member(self, now: int, member: RoomMember):
227228
self._stopped_typing(member)
228229
return
229230

230-
async def started_typing(self, target_user, auth_user, room_id, timeout):
231+
async def started_typing(self, target_user, requester, room_id, timeout):
231232
target_user_id = target_user.to_string()
232-
auth_user_id = auth_user.to_string()
233+
auth_user_id = requester.user.to_string()
233234

234235
if not self.is_mine_id(target_user_id):
235236
raise SynapseError(400, "User is not hosted on this homeserver")
236237

237238
if target_user_id != auth_user_id:
238239
raise AuthError(400, "Cannot set another user's typing state")
239240

241+
if requester.shadow_banned:
242+
# We randomly sleep a bit just to annoy the requester.
243+
await self.clock.sleep(random.randint(1, 10))
244+
raise ShadowBanError()
245+
240246
await self.auth.check_user_in_room(room_id, target_user_id)
241247

242248
logger.debug("%s has started typing in %s", target_user_id, room_id)
@@ -256,16 +262,21 @@ async def started_typing(self, target_user, auth_user, room_id, timeout):
256262

257263
self._push_update(member=member, typing=True)
258264

259-
async def stopped_typing(self, target_user, auth_user, room_id):
265+
async def stopped_typing(self, target_user, requester, room_id):
260266
target_user_id = target_user.to_string()
261-
auth_user_id = auth_user.to_string()
267+
auth_user_id = requester.user.to_string()
262268

263269
if not self.is_mine_id(target_user_id):
264270
raise SynapseError(400, "User is not hosted on this homeserver")
265271

266272
if target_user_id != auth_user_id:
267273
raise AuthError(400, "Cannot set another user's typing state")
268274

275+
if requester.shadow_banned:
276+
# We randomly sleep a bit just to annoy the requester.
277+
await self.clock.sleep(random.randint(1, 10))
278+
raise ShadowBanError()
279+
269280
await self.auth.check_user_in_room(room_id, target_user_id)
270281

271282
logger.debug("%s has stopped typing in %s", target_user_id, room_id)

synapse/rest/client/v1/room.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -868,17 +868,21 @@ async def on_PUT(self, request, room_id, user_id):
868868
# Limit timeout to stop people from setting silly typing timeouts.
869869
timeout = min(content.get("timeout", 30000), 120000)
870870

871-
if content["typing"]:
872-
await self.typing_handler.started_typing(
873-
target_user=target_user,
874-
auth_user=requester.user,
875-
room_id=room_id,
876-
timeout=timeout,
877-
)
878-
else:
879-
await self.typing_handler.stopped_typing(
880-
target_user=target_user, auth_user=requester.user, room_id=room_id
881-
)
871+
try:
872+
if content["typing"]:
873+
await self.typing_handler.started_typing(
874+
target_user=target_user,
875+
requester=requester,
876+
room_id=room_id,
877+
timeout=timeout,
878+
)
879+
else:
880+
await self.typing_handler.stopped_typing(
881+
target_user=target_user, requester=requester, room_id=room_id
882+
)
883+
except ShadowBanError:
884+
# Pretend this worked without error.
885+
pass
882886

883887
return 200, {}
884888

tests/handlers/test_typing.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from twisted.internet import defer
2222

2323
from synapse.api.errors import AuthError
24-
from synapse.types import UserID
24+
from synapse.types import UserID, create_requester
2525

2626
from tests import unittest
2727
from tests.test_utils import make_awaitable
@@ -167,7 +167,10 @@ def test_started_typing_local(self):
167167

168168
self.get_success(
169169
self.handler.started_typing(
170-
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=20000
170+
target_user=U_APPLE,
171+
requester=create_requester(U_APPLE),
172+
room_id=ROOM_ID,
173+
timeout=20000,
171174
)
172175
)
173176

@@ -194,7 +197,10 @@ def test_started_typing_remote_send(self):
194197

195198
self.get_success(
196199
self.handler.started_typing(
197-
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=20000
200+
target_user=U_APPLE,
201+
requester=create_requester(U_APPLE),
202+
room_id=ROOM_ID,
203+
timeout=20000,
198204
)
199205
)
200206

@@ -269,7 +275,9 @@ def test_stopped_typing(self):
269275

270276
self.get_success(
271277
self.handler.stopped_typing(
272-
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID
278+
target_user=U_APPLE,
279+
requester=create_requester(U_APPLE),
280+
room_id=ROOM_ID,
273281
)
274282
)
275283

@@ -309,7 +317,10 @@ def test_typing_timeout(self):
309317

310318
self.get_success(
311319
self.handler.started_typing(
312-
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=10000
320+
target_user=U_APPLE,
321+
requester=create_requester(U_APPLE),
322+
room_id=ROOM_ID,
323+
timeout=10000,
313324
)
314325
)
315326

@@ -348,7 +359,10 @@ def test_typing_timeout(self):
348359

349360
self.get_success(
350361
self.handler.started_typing(
351-
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=10000
362+
target_user=U_APPLE,
363+
requester=create_requester(U_APPLE),
364+
room_id=ROOM_ID,
365+
timeout=10000,
352366
)
353367
)
354368

tests/replication/test_federation_sender_shard.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from synapse.events.builder import EventBuilderFactory
2121
from synapse.rest.admin import register_servlets_for_client_rest_resource
2222
from synapse.rest.client.v1 import login, room
23-
from synapse.types import UserID
23+
from synapse.types import UserID, create_requester
2424

2525
from tests.replication._base import BaseMultiWorkerStreamTestCase
2626
from tests.test_utils import make_awaitable
@@ -175,7 +175,7 @@ def test_send_typing_sharded(self):
175175
self.get_success(
176176
typing_handler.started_typing(
177177
target_user=UserID.from_string(user),
178-
auth_user=UserID.from_string(user),
178+
requester=create_requester(user),
179179
room_id=room,
180180
timeout=20000,
181181
)

tests/rest/client/test_shadow_banned.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,54 @@ def test_upgrade(self):
179179
# The summary should be empty since the room doesn't exist.
180180
self.assertEqual(summary, {})
181181

182+
def test_typing(self):
183+
"""Typing notifications should not be propagated into the room."""
184+
# The create works fine.
185+
room_id = self.helper.create_room_as(
186+
self.banned_user_id, tok=self.banned_access_token
187+
)
188+
189+
request, channel = self.make_request(
190+
"PUT",
191+
"/rooms/%s/typing/%s" % (room_id, self.banned_user_id),
192+
{"typing": True, "timeout": 30000},
193+
access_token=self.banned_access_token,
194+
)
195+
self.render(request)
196+
self.assertEquals(200, channel.code)
197+
198+
# There should be no typing events.
199+
event_source = self.hs.get_event_sources().sources["typing"]
200+
self.assertEquals(event_source.get_current_key(), 0)
201+
202+
# The other user can join and send typing events.
203+
self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)
204+
205+
request, channel = self.make_request(
206+
"PUT",
207+
"/rooms/%s/typing/%s" % (room_id, self.other_user_id),
208+
{"typing": True, "timeout": 30000},
209+
access_token=self.other_access_token,
210+
)
211+
self.render(request)
212+
self.assertEquals(200, channel.code)
213+
214+
# These appear in the room.
215+
self.assertEquals(event_source.get_current_key(), 1)
216+
events = self.get_success(
217+
event_source.get_new_events(from_key=0, room_ids=[room_id])
218+
)
219+
self.assertEquals(
220+
events[0],
221+
[
222+
{
223+
"type": "m.typing",
224+
"room_id": room_id,
225+
"content": {"user_ids": [self.other_user_id]},
226+
}
227+
],
228+
)
229+
182230

183231
# To avoid the tests timing out don't add a delay to "annoy the requester".
184232
@patch("random.randint", new=lambda a, b: 0)

0 commit comments

Comments
 (0)