Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b952dcdb34 | |||
| 2cacaa3408 | |||
| eaaaf169c2 | |||
| eb2733c2d8 | |||
| 16fabc8b32 |
@@ -0,0 +1 @@
|
|||||||
|
Add membership event to batch of events for batch persisting during room creation.
|
||||||
+62
-19
@@ -1256,12 +1256,22 @@ class EventCreationHandler:
|
|||||||
raise SynapseError(
|
raise SynapseError(
|
||||||
403, "This event is not allowed in this context", Codes.FORBIDDEN
|
403, "This event is not allowed in this context", Codes.FORBIDDEN
|
||||||
)
|
)
|
||||||
|
# the third-party rules want to replace the event. We'll need to build a new
|
||||||
|
# event.
|
||||||
elif new_content is not None:
|
elif new_content is not None:
|
||||||
# the third-party rules want to replace the event. We'll need to build a new
|
if for_batch:
|
||||||
# event.
|
event, context = await self._rebuild_event_after_third_party_rules(
|
||||||
event, context = await self._rebuild_event_after_third_party_rules(
|
new_content,
|
||||||
new_content, event
|
event,
|
||||||
)
|
for_batch=True,
|
||||||
|
state_map=state_map,
|
||||||
|
prev_event_ids=prev_event_ids,
|
||||||
|
current_state_group=current_state_group,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
event, context = await self._rebuild_event_after_third_party_rules(
|
||||||
|
new_content, event
|
||||||
|
)
|
||||||
|
|
||||||
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)
|
||||||
@@ -2047,10 +2057,27 @@ class EventCreationHandler:
|
|||||||
del self._rooms_to_exclude_from_dummy_event_insertion[room_id]
|
del self._rooms_to_exclude_from_dummy_event_insertion[room_id]
|
||||||
|
|
||||||
async def _rebuild_event_after_third_party_rules(
|
async def _rebuild_event_after_third_party_rules(
|
||||||
self, third_party_result: dict, original_event: EventBase
|
self,
|
||||||
|
third_party_result: dict,
|
||||||
|
original_event: EventBase,
|
||||||
|
for_batch: bool = False,
|
||||||
|
state_map: Optional[StateMap[str]] = None,
|
||||||
|
prev_event_ids: Optional[List[str]] = None,
|
||||||
|
current_state_group: Optional[int] = None,
|
||||||
) -> Tuple[EventBase, EventContext]:
|
) -> Tuple[EventBase, EventContext]:
|
||||||
# the third_party_event_rules want to replace the event.
|
"""
|
||||||
# we do some basic checks, and then return the replacement event and context.
|
The third_party_event_rules want to replace the event.
|
||||||
|
we do some basic checks, and then return the replacement event and context.
|
||||||
|
If for_batch is true, state_map, prev_event_ids, and current_state_group must be
|
||||||
|
provided.
|
||||||
|
third_party_result: An event dict provided by third-party rules
|
||||||
|
original_event: the original event being replaced
|
||||||
|
for_batch: whether the event being created is part of a batch being created
|
||||||
|
for batch persisting to the DB
|
||||||
|
state_map: the current state prior to the new event
|
||||||
|
prev_event_ids: the prev_events of the new event
|
||||||
|
current_state_group: the state group prior to the event
|
||||||
|
"""
|
||||||
|
|
||||||
# Construct a new EventBuilder and validate it, which helps with the
|
# Construct a new EventBuilder and validate it, which helps with the
|
||||||
# rest of these checks.
|
# rest of these checks.
|
||||||
@@ -2093,16 +2120,32 @@ class EventCreationHandler:
|
|||||||
for k, v in original_event.internal_metadata.get_dict().items():
|
for k, v in original_event.internal_metadata.get_dict().items():
|
||||||
setattr(builder.internal_metadata, k, v)
|
setattr(builder.internal_metadata, k, v)
|
||||||
|
|
||||||
# modules can send new state events, so we re-calculate the auth events just in
|
if for_batch:
|
||||||
# case.
|
assert state_map is not None
|
||||||
prev_event_ids = await self.store.get_prev_events_for_room(builder.room_id)
|
assert current_state_group is not None
|
||||||
|
assert prev_event_ids is not None
|
||||||
|
auth_event_ids = self._event_auth_handler.compute_auth_events(
|
||||||
|
builder, state_map
|
||||||
|
)
|
||||||
|
event = await builder.build(
|
||||||
|
prev_event_ids=prev_event_ids,
|
||||||
|
auth_event_ids=auth_event_ids,
|
||||||
|
)
|
||||||
|
context = await self.state.compute_event_context_for_batched(
|
||||||
|
event,
|
||||||
|
state_ids_before_event=state_map,
|
||||||
|
current_state_group=current_state_group,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# modules can send new state events, so we re-calculate the auth events just in
|
||||||
|
# case.
|
||||||
|
prev_event_ids = await self.store.get_prev_events_for_room(builder.room_id)
|
||||||
|
event = await builder.build(
|
||||||
|
prev_event_ids=prev_event_ids,
|
||||||
|
auth_event_ids=None,
|
||||||
|
)
|
||||||
|
# we rebuild the event context, to be on the safe side. If nothing else,
|
||||||
|
# delta_ids might need an update.
|
||||||
|
context = await self.state.compute_event_context(event)
|
||||||
|
|
||||||
event = await builder.build(
|
|
||||||
prev_event_ids=prev_event_ids,
|
|
||||||
auth_event_ids=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
# we rebuild the event context, to be on the safe side. If nothing else,
|
|
||||||
# delta_ids might need an update.
|
|
||||||
context = await self.state.compute_event_context(event)
|
|
||||||
return event, context
|
return event, context
|
||||||
|
|||||||
+70
-21
@@ -1125,42 +1125,91 @@ class RoomCreationHandler:
|
|||||||
EventTypes.Create, creation_content, False
|
EventTypes.Create, creation_content, False
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug("Sending %s in new room", EventTypes.Member)
|
await self.event_creation_handler.handle_new_client_event(
|
||||||
ev = await self.event_creation_handler.handle_new_client_event(
|
|
||||||
requester=creator,
|
requester=creator,
|
||||||
events_and_context=[(creation_event, creation_context)],
|
events_and_context=[(creation_event, creation_context)],
|
||||||
ratelimit=False,
|
ratelimit=False,
|
||||||
ignore_shadow_ban=True,
|
ignore_shadow_ban=True,
|
||||||
)
|
)
|
||||||
last_sent_event_id = ev.event_id
|
logger.debug("Sending %s in new room", EventTypes.Member)
|
||||||
|
|
||||||
member_event_id, _ = await self.room_member_handler.update_membership(
|
# Do some checks and create a membership event
|
||||||
creator,
|
if creator_join_profile is None:
|
||||||
creator.user,
|
creator_join_profile = {}
|
||||||
room_id,
|
else:
|
||||||
"join",
|
# We do a copy here as we potentially change some keys
|
||||||
ratelimit=False,
|
# later on.
|
||||||
content=creator_join_profile,
|
creator_join_profile = dict(creator_join_profile)
|
||||||
new_room=True,
|
|
||||||
prev_event_ids=[last_sent_event_id],
|
# allow the server notices mxid to set room-level profile
|
||||||
depth=depth,
|
is_requester_server_notices_user = (
|
||||||
|
self._server_notices_mxid is not None
|
||||||
|
and creator.user.to_string() == self._server_notices_mxid
|
||||||
)
|
)
|
||||||
prev_event = [member_event_id]
|
room_handler = self.hs.get_room_member_handler()
|
||||||
|
|
||||||
# update the depth and state map here as the membership event has been created
|
if (
|
||||||
# through a different code path
|
not room_handler.allow_per_room_profiles
|
||||||
depth += 1
|
and not is_requester_server_notices_user
|
||||||
state_map[(EventTypes.Member, creator.user.to_string())] = member_event_id
|
) or creator.shadow_banned:
|
||||||
|
# Strip profile data, knowing that new profile data will be added to the
|
||||||
|
# event's content in event_creation_handler.create_event() using the target's
|
||||||
|
# global profile.
|
||||||
|
creator_join_profile.pop("displayname", None)
|
||||||
|
creator_join_profile.pop("avatar_url", None)
|
||||||
|
|
||||||
# we need the state group of the membership event as it is the current state group
|
if len(creator_join_profile.get("displayname") or "") > 256:
|
||||||
|
raise SynapseError(
|
||||||
|
400,
|
||||||
|
f"Displayname is too long (max {256})",
|
||||||
|
errcode=Codes.BAD_JSON,
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(creator_join_profile.get("avatar_url") or "") > 1000:
|
||||||
|
raise SynapseError(
|
||||||
|
400,
|
||||||
|
f"Avatar URL is too long (max {1000})",
|
||||||
|
errcode=Codes.BAD_JSON,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
"avatar_url" in creator_join_profile
|
||||||
|
and creator_join_profile.get("avatar_url") is not None
|
||||||
|
):
|
||||||
|
profile_handler = self.hs.get_profile_handler()
|
||||||
|
if not await profile_handler.check_avatar_size_and_mime_type(
|
||||||
|
creator_join_profile["avatar_url"],
|
||||||
|
):
|
||||||
|
raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
|
||||||
|
|
||||||
|
# The event content should *not* include the authorising user as
|
||||||
|
# it won't be properly signed. Strip it out since it might come
|
||||||
|
# back from a client updating a display name / avatar.
|
||||||
|
#
|
||||||
|
# This only applies to restricted rooms, but there should be no reason
|
||||||
|
# for a client to include it. Unconditionally remove it.
|
||||||
|
creator_join_profile.pop(EventContentFields.AUTHORISING_USER, None)
|
||||||
|
creator_join_profile["membership"] = "join"
|
||||||
|
|
||||||
|
# we need the state group of the creation event as it is the current state group
|
||||||
event_to_state = (
|
event_to_state = (
|
||||||
await self._storage_controllers.state.get_state_group_for_events(
|
await self._storage_controllers.state.get_state_group_for_events(
|
||||||
[member_event_id]
|
[creation_event.event_id]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
current_state_group = event_to_state[member_event_id]
|
current_state_group = event_to_state[creation_event.event_id]
|
||||||
|
|
||||||
events_to_send = []
|
events_to_send = []
|
||||||
|
member_event, member_context = await create_event(
|
||||||
|
EventTypes.Member,
|
||||||
|
creator_join_profile,
|
||||||
|
True,
|
||||||
|
state_key=creator.user.to_string(),
|
||||||
|
room_id=room_id,
|
||||||
|
)
|
||||||
|
current_state_group = member_context._state_group
|
||||||
|
events_to_send.append((member_event, member_context))
|
||||||
|
|
||||||
# We treat the power levels override specially as this needs to be one
|
# We treat the power levels override specially as this needs to be one
|
||||||
# of the first events that get sent into a room.
|
# of the first events that get sent into a room.
|
||||||
pl_content = initial_state.pop((EventTypes.PowerLevels, ""), None)
|
pl_content = initial_state.pop((EventTypes.PowerLevels, ""), None)
|
||||||
|
|||||||
@@ -715,7 +715,7 @@ class RoomsCreateTestCase(RoomBase):
|
|||||||
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
|
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
|
||||||
self.assertTrue("room_id" in channel.json_body)
|
self.assertTrue("room_id" in channel.json_body)
|
||||||
assert channel.resource_usage is not None
|
assert channel.resource_usage is not None
|
||||||
self.assertEqual(33, channel.resource_usage.db_txn_count)
|
self.assertEqual(25, channel.resource_usage.db_txn_count)
|
||||||
|
|
||||||
def test_post_room_initial_state(self) -> None:
|
def test_post_room_initial_state(self) -> None:
|
||||||
# POST with initial_state config key, expect new room id
|
# POST with initial_state config key, expect new room id
|
||||||
@@ -728,7 +728,7 @@ class RoomsCreateTestCase(RoomBase):
|
|||||||
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
|
self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
|
||||||
self.assertTrue("room_id" in channel.json_body)
|
self.assertTrue("room_id" in channel.json_body)
|
||||||
assert channel.resource_usage is not None
|
assert channel.resource_usage is not None
|
||||||
self.assertEqual(36, channel.resource_usage.db_txn_count)
|
self.assertEqual(28, channel.resource_usage.db_txn_count)
|
||||||
|
|
||||||
def test_post_room_visibility_key(self) -> None:
|
def test_post_room_visibility_key(self) -> None:
|
||||||
# POST with visibility config key, expect new room id
|
# POST with visibility config key, expect new room id
|
||||||
|
|||||||
Reference in New Issue
Block a user