parent
77b824008c
commit
8fb5b0f335
|
@ -0,0 +1 @@
|
||||||
|
Improve event validation (#16908).
|
|
@ -129,6 +129,8 @@ class EventTypes:
|
||||||
|
|
||||||
Reaction: Final = "m.reaction"
|
Reaction: Final = "m.reaction"
|
||||||
|
|
||||||
|
CallInvite: Final = "m.call.invite"
|
||||||
|
|
||||||
|
|
||||||
class ToDeviceEventTypes:
|
class ToDeviceEventTypes:
|
||||||
RoomKeyRequest: Final = "m.room_key_request"
|
RoomKeyRequest: Final = "m.room_key_request"
|
||||||
|
|
|
@ -34,6 +34,7 @@ from synapse.api.constants import (
|
||||||
EventTypes,
|
EventTypes,
|
||||||
GuestAccess,
|
GuestAccess,
|
||||||
HistoryVisibility,
|
HistoryVisibility,
|
||||||
|
JoinRules,
|
||||||
Membership,
|
Membership,
|
||||||
RelationTypes,
|
RelationTypes,
|
||||||
UserTypes,
|
UserTypes,
|
||||||
|
@ -1325,6 +1326,18 @@ class EventCreationHandler:
|
||||||
|
|
||||||
self.validator.validate_new(event, self.config)
|
self.validator.validate_new(event, self.config)
|
||||||
await self._validate_event_relation(event)
|
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)
|
logger.debug("Created event %s", event.event_id)
|
||||||
|
|
||||||
return event, context
|
return event, context
|
||||||
|
|
|
@ -41,6 +41,7 @@ from synapse.api.constants import (
|
||||||
AccountDataTypes,
|
AccountDataTypes,
|
||||||
EventContentFields,
|
EventContentFields,
|
||||||
EventTypes,
|
EventTypes,
|
||||||
|
JoinRules,
|
||||||
Membership,
|
Membership,
|
||||||
)
|
)
|
||||||
from synapse.api.filtering import FilterCollection
|
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,
|
self._storage_controllers,
|
||||||
sync_config.user.to_string(),
|
sync_config.user.to_string(),
|
||||||
loaded_recents,
|
loaded_recents,
|
||||||
always_include_ids=current_state_ids,
|
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)})
|
log_kv({"loaded_recents_after_client_filtering": len(loaded_recents)})
|
||||||
|
|
||||||
loaded_recents.extend(recents)
|
loaded_recents.extend(recents)
|
||||||
|
|
|
@ -24,6 +24,7 @@ from typing import Tuple
|
||||||
from twisted.test.proto_helpers import MemoryReactor
|
from twisted.test.proto_helpers import MemoryReactor
|
||||||
|
|
||||||
from synapse.api.constants import EventTypes
|
from synapse.api.constants import EventTypes
|
||||||
|
from synapse.api.errors import SynapseError
|
||||||
from synapse.events import EventBase
|
from synapse.events import EventBase
|
||||||
from synapse.events.snapshot import EventContext, UnpersistedEventContextBase
|
from synapse.events.snapshot import EventContext, UnpersistedEventContextBase
|
||||||
from synapse.rest import admin
|
from synapse.rest import admin
|
||||||
|
@ -51,11 +52,15 @@ class EventCreationTestCase(unittest.HomeserverTestCase):
|
||||||
persistence = self.hs.get_storage_controllers().persistence
|
persistence = self.hs.get_storage_controllers().persistence
|
||||||
assert persistence is not None
|
assert persistence is not None
|
||||||
self._persist_event_storage_controller = persistence
|
self._persist_event_storage_controller = persistence
|
||||||
|
self.store = self.hs.get_datastores().main
|
||||||
|
|
||||||
self.user_id = self.register_user("tester", "foobar")
|
self.user_id = self.register_user("tester", "foobar")
|
||||||
device_id = "dev-1"
|
device_id = "dev-1"
|
||||||
access_token = self.login("tester", "foobar", device_id=device_id)
|
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.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)
|
self.requester = create_requester(self.user_id, device_id=device_id)
|
||||||
|
|
||||||
|
@ -285,6 +290,41 @@ class EventCreationTestCase(unittest.HomeserverTestCase):
|
||||||
AssertionError,
|
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):
|
class ServerAclValidationTestCase(unittest.HomeserverTestCase):
|
||||||
servlets = [
|
servlets = [
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
# [This file includes modifications made by New Vector Limited]
|
# [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 unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from twisted.test.proto_helpers import MemoryReactor
|
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.constants import EventTypes, JoinRules
|
||||||
from synapse.api.errors import Codes, ResourceLimitError
|
from synapse.api.errors import Codes, ResourceLimitError
|
||||||
from synapse.api.filtering import Filtering
|
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.handlers.sync import SyncConfig, SyncResult
|
||||||
from synapse.rest import admin
|
from synapse.rest import admin
|
||||||
from synapse.rest.client import knock, login, room
|
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, [])
|
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
|
_request_key = 0
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue