Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Batch up power level event when creating rooms #14070

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/14070.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Batch up initial power level event when creating rooms.
19 changes: 18 additions & 1 deletion synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@

import logging
import typing
from typing import Any, Collection, Dict, Iterable, List, Optional, Set, Tuple, Union
from typing import (
Any,
Collection,
Dict,
Iterable,
List,
Mapping,
Optional,
Set,
Tuple,
Union,
)

from canonicaljson import encode_canonical_json
from signedjson.key import decode_verify_key_bytes
Expand Down Expand Up @@ -134,6 +145,7 @@ def validate_event_for_room_version(event: "EventBase") -> None:
async def check_state_independent_auth_rules(
store: _EventSourceStore,
event: "EventBase",
batched_auth_events: Optional[Mapping[str, "EventBase"]] = None,
) -> None:
"""Check that an event complies with auth rules that are independent of room state

Expand All @@ -143,6 +155,8 @@ async def check_state_independent_auth_rules(
Args:
store: the datastore; used to fetch the auth events for validation
event: the event being checked.
batched_auth_events: if the event being authed is part of a batch, any events
from the same batch that may be necessary to auth the current event

Raises:
AuthError if the checks fail
Expand All @@ -162,6 +176,9 @@ async def check_state_independent_auth_rules(
redact_behaviour=EventRedactBehaviour.as_is,
allow_rejected=True,
)
if batched_auth_events:
auth_events.update(batched_auth_events)

room_id = event.room_id
auth_dict: MutableStateMap[str] = {}
expected_auth_types = auth_types_for_event(event.room_version, event)
Expand Down
18 changes: 13 additions & 5 deletions synapse/handlers/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
from typing import TYPE_CHECKING, Collection, List, Optional, Union
from typing import TYPE_CHECKING, Collection, List, Mapping, Optional, Union

from synapse import event_auth
from synapse.api.constants import (
Expand All @@ -29,7 +29,6 @@
)
from synapse.events import EventBase
from synapse.events.builder import EventBuilder
from synapse.events.snapshot import EventContext
from synapse.types import StateMap, get_domain_from_id

if TYPE_CHECKING:
Expand All @@ -51,12 +50,21 @@ def __init__(self, hs: "HomeServer"):
async def check_auth_rules_from_context(
self,
event: EventBase,
context: EventContext,
batched_auth_events: Optional[Mapping[str, EventBase]] = None,
) -> None:
"""Check an event passes the auth rules at its own auth events"""
await check_state_independent_auth_rules(self._store, event)
"""Check an event passes the auth rules at its own auth events
Args:
event: event to be authed
batched_auth_events: if the event being authed is part of a batch, any events
from the same batch that may be necessary to auth the current event
"""
await check_state_independent_auth_rules(
self._store, event, batched_auth_events
)
auth_event_ids = event.auth_event_ids()
auth_events_by_id = await self._store.get_events(auth_event_ids)
if batched_auth_events:
auth_events_by_id.update(batched_auth_events)
check_state_dependent_auth_rules(event, auth_events_by_id.values())

def compute_auth_events(
Expand Down
16 changes: 8 additions & 8 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,7 @@ async def on_make_join_request(

# The remote hasn't signed it yet, obviously. We'll do the full checks
# when we get the event back in `on_send_join_request`
await self._event_auth_handler.check_auth_rules_from_context(event, context)
await self._event_auth_handler.check_auth_rules_from_context(event)
return event

async def on_invite_request(
Expand Down Expand Up @@ -1003,7 +1003,9 @@ async def on_invite_request(

context = EventContext.for_outlier(self._storage_controllers)

await self._bulk_push_rule_evaluator.action_for_event_by_user(event, context)
await self._bulk_push_rule_evaluator.action_for_event_by_user(
[(event, context)]
)
try:
await self._federation_event_handler.persist_events_and_notify(
event.room_id, [(event, context)]
Expand Down Expand Up @@ -1109,7 +1111,7 @@ async def on_make_leave_request(
try:
# The remote hasn't signed it yet, obviously. We'll do the full checks
# when we get the event back in `on_send_leave_request`
await self._event_auth_handler.check_auth_rules_from_context(event, context)
await self._event_auth_handler.check_auth_rules_from_context(event)
except AuthError as e:
logger.warning("Failed to create new leave %r because %s", event, e)
raise e
Expand Down Expand Up @@ -1168,7 +1170,7 @@ async def on_make_knock_request(
try:
# The remote hasn't signed it yet, obviously. We'll do the full checks
# when we get the event back in `on_send_knock_request`
await self._event_auth_handler.check_auth_rules_from_context(event, context)
await self._event_auth_handler.check_auth_rules_from_context(event)
except AuthError as e:
logger.warning("Failed to create new knock %r because %s", event, e)
raise e
Expand Down Expand Up @@ -1334,9 +1336,7 @@ async def exchange_third_party_invite(

try:
validate_event_for_room_version(event)
await self._event_auth_handler.check_auth_rules_from_context(
event, context
)
await self._event_auth_handler.check_auth_rules_from_context(event)
except AuthError as e:
logger.warning("Denying new third party invite %r because %s", event, e)
raise e
Expand Down Expand Up @@ -1386,7 +1386,7 @@ async def on_exchange_third_party_invite_request(

try:
validate_event_for_room_version(event)
await self._event_auth_handler.check_auth_rules_from_context(event, context)
await self._event_auth_handler.check_auth_rules_from_context(event)
except AuthError as e:
logger.warning("Denying third party invite %r because %s", event, e)
raise e
Expand Down
2 changes: 1 addition & 1 deletion synapse/handlers/federation_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2118,7 +2118,7 @@ async def _run_push_actions_and_persist_event(
)
else:
await self._bulk_push_rule_evaluator.action_for_event_by_user(
event, context
[(event, context)]
)

try:
Expand Down
26 changes: 13 additions & 13 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -1360,8 +1360,16 @@ async def handle_new_client_event(
else:
try:
validate_event_for_room_version(event)
# If we are persisting a batch of events the event(s) needed to auth the
# current event may be part of the batch and will not be in the DB yet
event_id_to_event = {e.event_id: e for e, _ in events_and_context}
batched_auth_events = {}
for event_id in event.auth_event_ids():
auth_event = event_id_to_event.get(event_id)
if auth_event:
batched_auth_events[event_id] = auth_event
await self._event_auth_handler.check_auth_rules_from_context(
event, context
event, batched_auth_events
)
except AuthError as err:
logger.warning("Denying new event %r because %s", event, err)
Expand Down Expand Up @@ -1424,18 +1432,10 @@ async def _persist_events(
PartialStateConflictError: if attempting to persist a partial state event in
a room that has been un-partial stated.
"""

for event, context in events_and_context:
# Skip push notification actions for historical messages
# because we don't want to notify people about old history back in time.
# The historical messages also do not have the proper `context.current_state_ids`
# and `state_groups` because they have `prev_events` that aren't persisted yet
# (historical messages persisted in reverse-chronological order).
if not event.internal_metadata.is_historical():
with opentracing.start_active_span("calculate_push_actions"):
await self._bulk_push_rule_evaluator.action_for_event_by_user(
event, context
)
with opentracing.start_active_span("calculate_push_actions"):
await self._bulk_push_rule_evaluator.action_for_event_by_user(
events_and_context
)

try:
# If we're a worker we need to hit out to the master.
Expand Down
10 changes: 4 additions & 6 deletions synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,7 @@ async def upgrade_room(
},
)
validate_event_for_room_version(tombstone_event)
await self._event_auth_handler.check_auth_rules_from_context(
tombstone_event, tombstone_context
)
await self._event_auth_handler.check_auth_rules_from_context(tombstone_event)

# Upgrade the room
#
Expand Down Expand Up @@ -1159,6 +1157,7 @@ async def send(
depth += 1
state_map[(EventTypes.Member, creator.user.to_string())] = member_event_id

events_to_send = []
# We treat the power levels override specially as this needs to be one
# of the first events that get sent into a room.
pl_content = initial_state.pop((EventTypes.PowerLevels, ""), None)
Expand All @@ -1167,7 +1166,7 @@ async def send(
EventTypes.PowerLevels, pl_content, False
)
current_state_group = power_context._state_group
await send(power_event, power_context, creator)
events_to_send.append((power_event, power_context))
else:
power_level_content: JsonDict = {
"users": {creator_id: 100},
Expand Down Expand Up @@ -1216,9 +1215,8 @@ async def send(
False,
)
current_state_group = pl_context._state_group
await send(pl_event, pl_context, creator)
events_to_send.append((pl_event, pl_context))

events_to_send = []
if room_alias and (EventTypes.CanonicalAlias, "") not in initial_state:
room_alias_event, room_alias_context = await create_event(
EventTypes.CanonicalAlias, {"alias": room_alias.to_string()}, True
Expand Down
Loading