mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-10-01 11:49:51 -04:00
Do not propagate typing notifications from shadow-banned users. (#8176)
This commit is contained in:
parent
e0d6244beb
commit
6fe12c9512
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.
|
# limitations under the License.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import random
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from typing import TYPE_CHECKING, List, Set, Tuple
|
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.metrics.background_process_metrics import run_as_background_process
|
||||||
from synapse.replication.tcp.streams import TypingStream
|
from synapse.replication.tcp.streams import TypingStream
|
||||||
from synapse.types import UserID, get_domain_from_id
|
from synapse.types import UserID, get_domain_from_id
|
||||||
@ -227,9 +228,9 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||||||
self._stopped_typing(member)
|
self._stopped_typing(member)
|
||||||
return
|
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()
|
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):
|
if not self.is_mine_id(target_user_id):
|
||||||
raise SynapseError(400, "User is not hosted on this homeserver")
|
raise SynapseError(400, "User is not hosted on this homeserver")
|
||||||
@ -237,6 +238,11 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||||||
if target_user_id != auth_user_id:
|
if target_user_id != auth_user_id:
|
||||||
raise AuthError(400, "Cannot set another user's typing state")
|
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)
|
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)
|
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)
|
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()
|
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):
|
if not self.is_mine_id(target_user_id):
|
||||||
raise SynapseError(400, "User is not hosted on this homeserver")
|
raise SynapseError(400, "User is not hosted on this homeserver")
|
||||||
@ -266,6 +272,11 @@ class TypingWriterHandler(FollowerTypingHandler):
|
|||||||
if target_user_id != auth_user_id:
|
if target_user_id != auth_user_id:
|
||||||
raise AuthError(400, "Cannot set another user's typing state")
|
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)
|
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)
|
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.
|
# Limit timeout to stop people from setting silly typing timeouts.
|
||||||
timeout = min(content.get("timeout", 30000), 120000)
|
timeout = min(content.get("timeout", 30000), 120000)
|
||||||
|
|
||||||
if content["typing"]:
|
try:
|
||||||
await self.typing_handler.started_typing(
|
if content["typing"]:
|
||||||
target_user=target_user,
|
await self.typing_handler.started_typing(
|
||||||
auth_user=requester.user,
|
target_user=target_user,
|
||||||
room_id=room_id,
|
requester=requester,
|
||||||
timeout=timeout,
|
room_id=room_id,
|
||||||
)
|
timeout=timeout,
|
||||||
else:
|
)
|
||||||
await self.typing_handler.stopped_typing(
|
else:
|
||||||
target_user=target_user, auth_user=requester.user, room_id=room_id
|
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, {}
|
return 200, {}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from mock import ANY, Mock, call
|
|||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import AuthError
|
from synapse.api.errors import AuthError
|
||||||
from synapse.types import UserID
|
from synapse.types import UserID, create_requester
|
||||||
|
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
from tests.test_utils import make_awaitable
|
from tests.test_utils import make_awaitable
|
||||||
@ -167,7 +167,10 @@ class TypingNotificationsTestCase(unittest.HomeserverTestCase):
|
|||||||
|
|
||||||
self.get_success(
|
self.get_success(
|
||||||
self.handler.started_typing(
|
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.get_success(
|
||||||
self.handler.started_typing(
|
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.get_success(
|
||||||
self.handler.stopped_typing(
|
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.get_success(
|
||||||
self.handler.started_typing(
|
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.get_success(
|
||||||
self.handler.started_typing(
|
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.events.builder import EventBuilderFactory
|
||||||
from synapse.rest.admin import register_servlets_for_client_rest_resource
|
from synapse.rest.admin import register_servlets_for_client_rest_resource
|
||||||
from synapse.rest.client.v1 import login, room
|
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.replication._base import BaseMultiWorkerStreamTestCase
|
||||||
from tests.test_utils import make_awaitable
|
from tests.test_utils import make_awaitable
|
||||||
@ -175,7 +175,7 @@ class FederationSenderTestCase(BaseMultiWorkerStreamTestCase):
|
|||||||
self.get_success(
|
self.get_success(
|
||||||
typing_handler.started_typing(
|
typing_handler.started_typing(
|
||||||
target_user=UserID.from_string(user),
|
target_user=UserID.from_string(user),
|
||||||
auth_user=UserID.from_string(user),
|
requester=create_requester(user),
|
||||||
room_id=room,
|
room_id=room,
|
||||||
timeout=20000,
|
timeout=20000,
|
||||||
)
|
)
|
||||||
|
@ -179,6 +179,54 @@ class RoomTestCase(_ShadowBannedBase):
|
|||||||
# The summary should be empty since the room doesn't exist.
|
# The summary should be empty since the room doesn't exist.
|
||||||
self.assertEqual(summary, {})
|
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".
|
# To avoid the tests timing out don't add a delay to "annoy the requester".
|
||||||
@patch("random.randint", new=lambda a, b: 0)
|
@patch("random.randint", new=lambda a, b: 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user