mirror of
https://github.com/element-hq/synapse.git
synced 2024-12-27 09:58:41 +00:00
parent
77b824008c
commit
8fb5b0f335
1
changelog.d/16908.misc
Normal file
1
changelog.d/16908.misc
Normal file
|
@ -0,0 +1 @@
|
|||
Improve event validation (#16908).
|
|
@ -129,6 +129,8 @@ class EventTypes:
|
|||
|
||||
Reaction: Final = "m.reaction"
|
||||
|
||||
CallInvite: Final = "m.call.invite"
|
||||
|
||||
|
||||
class ToDeviceEventTypes:
|
||||
RoomKeyRequest: Final = "m.room_key_request"
|
||||
|
|
|
@ -34,6 +34,7 @@ from synapse.api.constants import (
|
|||
EventTypes,
|
||||
GuestAccess,
|
||||
HistoryVisibility,
|
||||
JoinRules,
|
||||
Membership,
|
||||
RelationTypes,
|
||||
UserTypes,
|
||||
|
@ -1325,6 +1326,18 @@ class EventCreationHandler:
|
|||
|
||||
self.validator.validate_new(event, self.config)
|
||||
await self._validate_event_relation(event)
|
||||
|
||||
if event.type == EventTypes.CallInvite:
|
||||
room_id = event.room_id
|
||||
room_info = await self.store.get_room_with_stats(room_id)
|
||||
assert room_info is not None
|
||||
|
||||
if room_info.join_rules == JoinRules.PUBLIC:
|
||||
raise SynapseError(
|
||||
403,
|
||||
"Call invites are not allowed in public rooms.",
|
||||
Codes.FORBIDDEN,
|
||||
)
|
||||
logger.debug("Created event %s", event.event_id)
|
||||
|
||||
return event, context
|
||||
|
|
|
@ -41,6 +41,7 @@ from synapse.api.constants import (
|
|||
AccountDataTypes,
|
||||
EventContentFields,
|
||||
EventTypes,
|
||||
JoinRules,
|
||||
Membership,
|
||||
)
|
||||
from synapse.api.filtering import FilterCollection
|
||||
|
@ -675,13 +676,22 @@ class SyncHandler:
|
|||
)
|
||||
)
|
||||
|
||||
loaded_recents = await filter_events_for_client(
|
||||
filtered_recents = await filter_events_for_client(
|
||||
self._storage_controllers,
|
||||
sync_config.user.to_string(),
|
||||
loaded_recents,
|
||||
always_include_ids=current_state_ids,
|
||||
)
|
||||
|
||||
loaded_recents = []
|
||||
for event in filtered_recents:
|
||||
if event.type == EventTypes.CallInvite:
|
||||
room_info = await self.store.get_room_with_stats(event.room_id)
|
||||
assert room_info is not None
|
||||
if room_info.join_rules == JoinRules.PUBLIC:
|
||||
continue
|
||||
loaded_recents.append(event)
|
||||
|
||||
log_kv({"loaded_recents_after_client_filtering": len(loaded_recents)})
|
||||
|
||||
loaded_recents.extend(recents)
|
||||
|
|
|
@ -24,6 +24,7 @@ from typing import Tuple
|
|||
from twisted.test.proto_helpers import MemoryReactor
|
||||
|
||||
from synapse.api.constants import EventTypes
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.events import EventBase
|
||||
from synapse.events.snapshot import EventContext, UnpersistedEventContextBase
|
||||
from synapse.rest import admin
|
||||
|
@ -51,11 +52,15 @@ class EventCreationTestCase(unittest.HomeserverTestCase):
|
|||
persistence = self.hs.get_storage_controllers().persistence
|
||||
assert persistence is not None
|
||||
self._persist_event_storage_controller = persistence
|
||||
self.store = self.hs.get_datastores().main
|
||||
|
||||
self.user_id = self.register_user("tester", "foobar")
|
||||
device_id = "dev-1"
|
||||
access_token = self.login("tester", "foobar", device_id=device_id)
|
||||
self.room_id = self.helper.create_room_as(self.user_id, tok=access_token)
|
||||
self.private_room_id = self.helper.create_room_as(
|
||||
self.user_id, tok=access_token, extra_content={"preset": "private_chat"}
|
||||
)
|
||||
|
||||
self.requester = create_requester(self.user_id, device_id=device_id)
|
||||
|
||||
|
@ -285,6 +290,41 @@ class EventCreationTestCase(unittest.HomeserverTestCase):
|
|||
AssertionError,
|
||||
)
|
||||
|
||||
def test_call_invite_event_creation_fails_in_public_room(self) -> None:
|
||||
# get prev_events for room
|
||||
prev_events = self.get_success(
|
||||
self.store.get_prev_events_for_room(self.room_id)
|
||||
)
|
||||
|
||||
# the invite in a public room should fail
|
||||
self.get_failure(
|
||||
self.handler.create_event(
|
||||
self.requester,
|
||||
{
|
||||
"type": EventTypes.CallInvite,
|
||||
"room_id": self.room_id,
|
||||
"sender": self.requester.user.to_string(),
|
||||
},
|
||||
prev_event_ids=prev_events,
|
||||
auth_event_ids=prev_events,
|
||||
),
|
||||
SynapseError,
|
||||
)
|
||||
|
||||
# but a call invite in a private room should succeed
|
||||
self.get_success(
|
||||
self.handler.create_event(
|
||||
self.requester,
|
||||
{
|
||||
"type": EventTypes.CallInvite,
|
||||
"room_id": self.private_room_id,
|
||||
"sender": self.requester.user.to_string(),
|
||||
},
|
||||
prev_event_ids=prev_events,
|
||||
auth_event_ids=prev_events,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class ServerAclValidationTestCase(unittest.HomeserverTestCase):
|
||||
servlets = [
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# [This file includes modifications made by New Vector Limited]
|
||||
#
|
||||
#
|
||||
from typing import Optional
|
||||
from typing import Collection, List, Optional
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
|
||||
from twisted.test.proto_helpers import MemoryReactor
|
||||
|
@ -25,7 +25,10 @@ from twisted.test.proto_helpers import MemoryReactor
|
|||
from synapse.api.constants import EventTypes, JoinRules
|
||||
from synapse.api.errors import Codes, ResourceLimitError
|
||||
from synapse.api.filtering import Filtering
|
||||
from synapse.api.room_versions import RoomVersions
|
||||
from synapse.api.room_versions import RoomVersion, RoomVersions
|
||||
from synapse.events import EventBase
|
||||
from synapse.events.snapshot import EventContext
|
||||
from synapse.federation.federation_base import event_from_pdu_json
|
||||
from synapse.handlers.sync import SyncConfig, SyncResult
|
||||
from synapse.rest import admin
|
||||
from synapse.rest.client import knock, login, room
|
||||
|
@ -285,6 +288,114 @@ class SyncTestCase(tests.unittest.HomeserverTestCase):
|
|||
)
|
||||
self.assertEqual(eve_initial_sync_after_join.joined, [])
|
||||
|
||||
def test_call_invite_in_public_room_not_returned(self) -> None:
|
||||
user = self.register_user("alice", "password")
|
||||
tok = self.login(user, "password")
|
||||
room_id = self.helper.create_room_as(user, is_public=True, tok=tok)
|
||||
self.handler = self.hs.get_federation_handler()
|
||||
federation_event_handler = self.hs.get_federation_event_handler()
|
||||
|
||||
async def _check_event_auth(
|
||||
origin: Optional[str], event: EventBase, context: EventContext
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
federation_event_handler._check_event_auth = _check_event_auth # type: ignore[method-assign]
|
||||
self.client = self.hs.get_federation_client()
|
||||
|
||||
async def _check_sigs_and_hash_for_pulled_events_and_fetch(
|
||||
dest: str, pdus: Collection[EventBase], room_version: RoomVersion
|
||||
) -> List[EventBase]:
|
||||
return list(pdus)
|
||||
|
||||
self.client._check_sigs_and_hash_for_pulled_events_and_fetch = _check_sigs_and_hash_for_pulled_events_and_fetch # type: ignore[assignment]
|
||||
|
||||
prev_events = self.get_success(self.store.get_prev_events_for_room(room_id))
|
||||
|
||||
# create a call invite event
|
||||
call_event = event_from_pdu_json(
|
||||
{
|
||||
"type": EventTypes.CallInvite,
|
||||
"content": {},
|
||||
"room_id": room_id,
|
||||
"sender": user,
|
||||
"depth": 32,
|
||||
"prev_events": prev_events,
|
||||
"auth_events": prev_events,
|
||||
"origin_server_ts": self.clock.time_msec(),
|
||||
},
|
||||
RoomVersions.V10,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get_success(
|
||||
federation_event_handler.on_receive_pdu("test.serv", call_event)
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
# check that it is in DB
|
||||
recent_event = self.get_success(self.store.get_prev_events_for_room(room_id))
|
||||
self.assertIn(call_event.event_id, recent_event)
|
||||
|
||||
# but that it does not come down /sync in public room
|
||||
sync_result: SyncResult = self.get_success(
|
||||
self.sync_handler.wait_for_sync_for_user(
|
||||
create_requester(user), generate_sync_config(user)
|
||||
)
|
||||
)
|
||||
event_ids = []
|
||||
for event in sync_result.joined[0].timeline.events:
|
||||
event_ids.append(event.event_id)
|
||||
self.assertNotIn(call_event.event_id, event_ids)
|
||||
|
||||
# it will come down in a private room, though
|
||||
user2 = self.register_user("bob", "password")
|
||||
tok2 = self.login(user2, "password")
|
||||
private_room_id = self.helper.create_room_as(
|
||||
user2, is_public=False, tok=tok2, extra_content={"preset": "private_chat"}
|
||||
)
|
||||
|
||||
priv_prev_events = self.get_success(
|
||||
self.store.get_prev_events_for_room(private_room_id)
|
||||
)
|
||||
private_call_event = event_from_pdu_json(
|
||||
{
|
||||
"type": EventTypes.CallInvite,
|
||||
"content": {},
|
||||
"room_id": private_room_id,
|
||||
"sender": user,
|
||||
"depth": 32,
|
||||
"prev_events": priv_prev_events,
|
||||
"auth_events": priv_prev_events,
|
||||
"origin_server_ts": self.clock.time_msec(),
|
||||
},
|
||||
RoomVersions.V10,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
self.get_success(
|
||||
federation_event_handler.on_receive_pdu("test.serv", private_call_event)
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
recent_events = self.get_success(
|
||||
self.store.get_prev_events_for_room(private_room_id)
|
||||
)
|
||||
self.assertIn(private_call_event.event_id, recent_events)
|
||||
|
||||
private_sync_result: SyncResult = self.get_success(
|
||||
self.sync_handler.wait_for_sync_for_user(
|
||||
create_requester(user2), generate_sync_config(user2)
|
||||
)
|
||||
)
|
||||
priv_event_ids = []
|
||||
for event in private_sync_result.joined[0].timeline.events:
|
||||
priv_event_ids.append(event.event_id)
|
||||
|
||||
self.assertIn(private_call_event.event_id, priv_event_ids)
|
||||
|
||||
|
||||
_request_key = 0
|
||||
|
||||
|
|
Loading…
Reference in a new issue