diff --git a/synapse/event_auth.py b/synapse/event_auth.py
index f5abcde2db..5999c264dc 100644
--- a/synapse/event_auth.py
+++ b/synapse/event_auth.py
@@ -32,6 +32,7 @@ from typing import (
Mapping,
MutableMapping,
Optional,
+ Protocol,
Set,
Tuple,
Union,
@@ -41,7 +42,6 @@ from typing import (
from canonicaljson import encode_canonical_json
from signedjson.key import decode_verify_key_bytes
from signedjson.sign import SignatureVerifyException, verify_signed_json
-from typing_extensions import Protocol
from unpaddedbase64 import decode_base64
from synapse.api.constants import (
@@ -388,6 +388,7 @@ LENIENT_EVENT_BYTE_LIMITS_ROOM_VERSIONS = {
RoomVersions.V9,
RoomVersions.V10,
RoomVersions.MSC1767v10,
+ RoomVersions.MSC3757v10,
}
@@ -565,6 +566,7 @@ def _is_membership_change_allowed(
logger.debug(
"_is_membership_change_allowed: %s",
{
+ "caller_membership": caller.membership if caller else None,
"caller_in_room": caller_in_room,
"caller_invited": caller_invited,
"caller_knocked": caller_knocked,
@@ -676,7 +678,8 @@ def _is_membership_change_allowed(
and join_rule == JoinRules.KNOCK_RESTRICTED
)
):
- if not caller_in_room and not caller_invited:
+ # You can only join the room if you are invited or are already in the room.
+ if not (caller_in_room or caller_invited):
raise AuthError(403, "You are not invited to this room.")
else:
# TODO (erikj): may_join list
@@ -790,9 +793,10 @@ def get_send_level(
def _can_send_event(event: "EventBase", auth_events: StateMap["EventBase"]) -> bool:
+ state_key = event.get_state_key()
power_levels_event = get_power_level_event(auth_events)
- send_level = get_send_level(event.type, event.get("state_key"), power_levels_event)
+ send_level = get_send_level(event.type, state_key, power_levels_event)
user_level = get_user_power_level(event.user_id, auth_events)
if user_level < send_level:
@@ -803,11 +807,34 @@ def _can_send_event(event: "EventBase", auth_events: StateMap["EventBase"]) -> b
errcode=Codes.INSUFFICIENT_POWER,
)
- # Check state_key
- if hasattr(event, "state_key"):
- if event.state_key.startswith("@"):
- if event.state_key != event.user_id:
- raise AuthError(403, "You are not allowed to set others state")
+ if (
+ state_key is not None
+ and state_key.startswith("@")
+ and state_key != event.user_id
+ ):
+ if event.room_version.msc3757_enabled:
+ try:
+ colon_idx = state_key.index(":", 1)
+ suffix_idx = state_key.find("_", colon_idx + 1)
+ state_key_user_id = (
+ state_key[:suffix_idx] if suffix_idx != -1 else state_key
+ )
+ if not UserID.is_valid(state_key_user_id):
+ raise ValueError
+ except ValueError:
+ raise SynapseError(
+ 400,
+ "State key neither equals a valid user ID, nor starts with one plus an underscore",
+ errcode=Codes.BAD_JSON,
+ )
+ if (
+ # sender is owner of the state key
+ state_key_user_id == event.user_id
+ # sender has higher PL than the owner of the state key
+ or user_level > get_user_power_level(state_key_user_id, auth_events)
+ ):
+ return True
+ raise AuthError(403, "You are not allowed to set others state")
return True
@@ -887,7 +914,8 @@ def _check_power_levels(
raise SynapseError(400, f"{v!r} must be an integer.")
if k in {"events", "notifications", "users"}:
if not isinstance(v, collections.abc.Mapping) or not all(
- type(v) is int for v in v.values() # noqa: E721
+ type(v) is int
+ for v in v.values() # noqa: E721
):
raise SynapseError(
400,
@@ -958,8 +986,7 @@ def _check_power_levels(
if old_level == user_level:
raise AuthError(
403,
- "You don't have permission to remove ops level equal "
- "to your own",
+ "You don't have permission to remove ops level equal to your own",
)
# Check if the old and new levels are greater than the user level
|