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

Do not propagate typing notifications from shadow-banned users. #8176

Merged
merged 4 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/8176.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for shadow-banning users (ignoring any message send requests).
21 changes: 16 additions & 5 deletions synapse/handlers/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
# limitations under the License.

import logging
import random
from collections import namedtuple
from typing import TYPE_CHECKING, List, Set, Tuple

from synapse.api.errors import AuthError, SynapseError
from synapse.api.errors import AuthError, ShadowBanError, SynapseError
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.replication.tcp.streams import TypingStream
from synapse.types import UserID, get_domain_from_id
Expand Down Expand Up @@ -227,16 +228,21 @@ def _handle_timeout_for_member(self, now: int, member: RoomMember):
self._stopped_typing(member)
return

async def started_typing(self, target_user, auth_user, room_id, timeout):
async def started_typing(self, target_user, requester, room_id, timeout):
target_user_id = target_user.to_string()
auth_user_id = auth_user.to_string()
auth_user_id = requester.user.to_string()

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

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

if requester.shadow_banned:
# We randomly sleep a bit just to annoy the requester.
await self.clock.sleep(random.randint(1, 10))
raise ShadowBanError()

await self.auth.check_user_in_room(room_id, target_user_id)

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

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

async def stopped_typing(self, target_user, auth_user, room_id):
async def stopped_typing(self, target_user, requester, room_id):
target_user_id = target_user.to_string()
auth_user_id = auth_user.to_string()
auth_user_id = requester.user.to_string()

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

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

if requester.shadow_banned:
# We randomly sleep a bit just to annoy the requester.
await self.clock.sleep(random.randint(1, 10))
raise ShadowBanError()

await self.auth.check_user_in_room(room_id, target_user_id)

logger.debug("%s has stopped typing in %s", target_user_id, room_id)
Expand Down
26 changes: 15 additions & 11 deletions synapse/rest/client/v1/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,17 +869,21 @@ async def on_PUT(self, request, room_id, user_id):
# Limit timeout to stop people from setting silly typing timeouts.
timeout = min(content.get("timeout", 30000), 120000)

if content["typing"]:
await self.typing_handler.started_typing(
target_user=target_user,
auth_user=requester.user,
room_id=room_id,
timeout=timeout,
)
else:
await self.typing_handler.stopped_typing(
target_user=target_user, auth_user=requester.user, room_id=room_id
)
try:
if content["typing"]:
await self.typing_handler.started_typing(
target_user=target_user,
requester=requester,
room_id=room_id,
timeout=timeout,
)
else:
await self.typing_handler.stopped_typing(
target_user=target_user, requester=requester, room_id=room_id
)
except ShadowBanError:
# Pretend this worked without error.
pass

return 200, {}

Expand Down
26 changes: 20 additions & 6 deletions tests/handlers/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from twisted.internet import defer

from synapse.api.errors import AuthError
from synapse.types import UserID
from synapse.types import UserID, create_requester

from tests import unittest
from tests.test_utils import make_awaitable
Expand Down Expand Up @@ -167,7 +167,10 @@ def test_started_typing_local(self):

self.get_success(
self.handler.started_typing(
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=20000
target_user=U_APPLE,
requester=create_requester(U_APPLE),
room_id=ROOM_ID,
timeout=20000,
)
)

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

self.get_success(
self.handler.started_typing(
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=20000
target_user=U_APPLE,
requester=create_requester(U_APPLE),
room_id=ROOM_ID,
timeout=20000,
)
)

Expand Down Expand Up @@ -269,7 +275,9 @@ def test_stopped_typing(self):

self.get_success(
self.handler.stopped_typing(
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID
target_user=U_APPLE,
requester=create_requester(U_APPLE),
room_id=ROOM_ID,
)
)

Expand Down Expand Up @@ -309,7 +317,10 @@ def test_typing_timeout(self):

self.get_success(
self.handler.started_typing(
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=10000
target_user=U_APPLE,
requester=create_requester(U_APPLE),
room_id=ROOM_ID,
timeout=10000,
)
)

Expand Down Expand Up @@ -348,7 +359,10 @@ def test_typing_timeout(self):

self.get_success(
self.handler.started_typing(
target_user=U_APPLE, auth_user=U_APPLE, room_id=ROOM_ID, timeout=10000
target_user=U_APPLE,
requester=create_requester(U_APPLE),
room_id=ROOM_ID,
timeout=10000,
)
)

Expand Down
48 changes: 48 additions & 0 deletions tests/rest/client/test_shadow_banned.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,54 @@ def test_upgrade(self):
# The summary should be empty since the room doesn't exist.
self.assertEqual(summary, {})

def test_typing(self):
"""Typing notifications should not be propagated into the room."""
# The create works fine.
room_id = self.helper.create_room_as(
self.banned_user_id, tok=self.banned_access_token
)

request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (room_id, self.banned_user_id),
{"typing": True, "timeout": 30000},
access_token=self.banned_access_token,
)
self.render(request)
self.assertEquals(200, channel.code)

# There should be no typing events.
event_source = self.hs.get_event_sources().sources["typing"]
self.assertEquals(event_source.get_current_key(), 0)

# The other user can join and sending typing events.
clokep marked this conversation as resolved.
Show resolved Hide resolved
self.helper.join(room_id, self.other_user_id, tok=self.other_access_token)

request, channel = self.make_request(
"PUT",
"/rooms/%s/typing/%s" % (room_id, self.other_user_id),
{"typing": True, "timeout": 30000},
access_token=self.other_access_token,
)
self.render(request)
self.assertEquals(200, channel.code)

# These appear in the room.
self.assertEquals(event_source.get_current_key(), 1)
events = self.get_success(
event_source.get_new_events(from_key=0, room_ids=[room_id])
)
self.assertEquals(
events[0],
[
{
"type": "m.typing",
"room_id": room_id,
"content": {"user_ids": [self.other_user_id]},
}
],
)


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