forked from MirrorHub/synapse
Do not propagate typing notifications from shadow-banned users. (#8176)
This commit is contained in:
parent
e0d6244beb
commit
6fe12c9512
6 changed files with 102 additions and 24 deletions
1
changelog.d/8176.feature
Normal file
1
changelog.d/8176.feature
Normal file
|
@ -0,0 +1 @@
|
|||
Add support for shadow-banning users (ignoring any message send requests).
|
|
@ -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
|
||||
|
@ -227,9 +228,9 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||
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")
|
||||
|
@ -237,6 +238,11 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||
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)
|
||||
|
@ -256,9 +262,9 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||
|
||||
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")
|
||||
|
@ -266,6 +272,11 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||
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)
|
||||
|
|
|
@ -868,17 +868,21 @@ class RoomTypingRestServlet(RestServlet):
|
|||
# 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, {}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ from mock import ANY, Mock, call
|
|||
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
|
||||
|
@ -167,7 +167,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -194,7 +197,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -269,7 +275,9 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -309,7 +317,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -348,7 +359,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||
|
||||
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,
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ from synapse.api.constants import EventTypes, Membership
|
|||
from synapse.events.builder import EventBuilderFactory
|
||||
from synapse.rest.admin import register_servlets_for_client_rest_resource
|
||||
from synapse.rest.client.v1 import login, room
|
||||
from synapse.types import UserID
|
||||
from synapse.types import UserID, create_requester
|
||||
|
||||
from tests.replication._base import BaseMultiWorkerStreamTestCase
|
||||
from tests.test_utils import make_awaitable
|
||||
|
@ -175,7 +175,7 @@ class FederationSenderTestCase(BaseMultiWorkerStreamTestCase):
|
|||
self.get_success(
|
||||
typing_handler.started_typing(
|
||||
target_user=UserID.from_string(user),
|
||||
auth_user=UserID.from_string(user),
|
||||
requester=create_requester(user),
|
||||
room_id=room,
|
||||
timeout=20000,
|
||||
)
|
||||
|
|
|
@ -179,6 +179,54 @@ class RoomTestCase(_ShadowBannedBase):
|
|||
# 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 send typing events.
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue