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

Add support for room version 10 #13220

Merged
merged 9 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from 7 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/13220.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for room version 10.
33 changes: 33 additions & 0 deletions synapse/api/room_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class RoomVersion:
# MSC3787: Adds support for a `knock_restricted` join rule, mixing concepts of
# knocks and restricted join rules into the same join condition.
msc3787_knock_restricted_join_rule: bool
# MSC3667: Enforce integer power levels
msc3667_int_only_power_levels: bool


class RoomVersions:
Expand All @@ -103,6 +105,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V2 = RoomVersion(
"2",
Expand All @@ -120,6 +123,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V3 = RoomVersion(
"3",
Expand All @@ -137,6 +141,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V4 = RoomVersion(
"4",
Expand All @@ -154,6 +159,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V5 = RoomVersion(
"5",
Expand All @@ -171,6 +177,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V6 = RoomVersion(
"6",
Expand All @@ -188,6 +195,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
MSC2176 = RoomVersion(
"org.matrix.msc2176",
Expand All @@ -205,6 +213,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V7 = RoomVersion(
"7",
Expand All @@ -222,6 +231,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V8 = RoomVersion(
"8",
Expand All @@ -239,6 +249,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
V9 = RoomVersion(
"9",
Expand All @@ -256,6 +267,7 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
MSC2716v3 = RoomVersion(
"org.matrix.msc2716v3",
Expand All @@ -273,6 +285,7 @@ class RoomVersions:
msc2716_historical=True,
msc2716_redactions=True,
msc3787_knock_restricted_join_rule=False,
msc3667_int_only_power_levels=False,
)
MSC3787 = RoomVersion(
"org.matrix.msc3787",
Expand All @@ -290,6 +303,25 @@ class RoomVersions:
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=False,
)
V10 = RoomVersion(
"10",
RoomDisposition.STABLE,
EventFormatVersions.V3,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=False,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3787_knock_restricted_join_rule=True,
msc3667_int_only_power_levels=True,
)


Expand All @@ -308,6 +340,7 @@ class RoomVersions:
RoomVersions.V9,
RoomVersions.MSC2716v3,
RoomVersions.MSC3787,
RoomVersions.V10,
)
}

Expand Down
27 changes: 26 additions & 1 deletion synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def validate_event_for_room_version(event: "EventBase") -> None:
Raises:
SynapseError if there is a problem with the event
"""

squahtx marked this conversation as resolved.
Show resolved Hide resolved
_check_size_limits(event)

if not hasattr(event, "room_id"):
Expand Down Expand Up @@ -734,12 +735,36 @@ def _check_power_levels(
UserID.from_string(k)
except Exception:
raise SynapseError(400, "Not a valid user_id: %s" % (k,))

try:
int(v)
except Exception:
raise SynapseError(400, "Not a valid power level: %s" % (v,))

# Reject events with stringy power levels if required by room version
if (
event.type == EventTypes.PowerLevels
and room_version_obj.msc3667_int_only_power_levels
):
for k, v in event.content.items():
if k in {
"users_default",
"events_default",
"state_default",
"ban",
"redact",
"kick",
"invite",
}:
if not isinstance(v, int):
raise SynapseError(400, f"{v} must be an integer.")
if k in {"events", "notifications", "users"}:
if not isinstance(v, dict) or not all(
isinstance(v, int) for v in v.values()
):
raise SynapseError(
400, f"{v} must be a dict wherein all the values are integers."
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be confusing to get errors like "100 must be an integer." when power levels are strings. We could use repr (!r) to format the error, so that strings will be single quoted, which is a tiny bit clearer.

Suggested change
if not isinstance(v, int):
raise SynapseError(400, f"{v} must be an integer.")
if k in {"events", "notifications", "users"}:
if not isinstance(v, dict) or not all(
isinstance(v, int) for v in v.values()
):
raise SynapseError(
400, f"{v} must be a dict wherein all the values are integers."
)
if not isinstance(v, int):
raise SynapseError(400, f"{v!r} must be an integer.")
if k in {"events", "notifications", "users"}:
if not isinstance(v, dict) or not all(
isinstance(v, int) for v in v.values()
):
raise SynapseError(
400, f"{v!r} must be a dict wherein all the values are integers."
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen !r before, thanks for sharing!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The notation was introduced in Python 3's str.format() and has made its way into f-strings.

https://pyformat.info/#conversion_flags describes the relevant part of str.format. I think most people would prefer to use f-strings these days though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also was unaware of pyformat.info. That website looks very useful, thank you for mentioning it.


key = (event.type, event.state_key)
current_state = auth_events.get(key)

Expand Down
41 changes: 40 additions & 1 deletion tests/test_event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from synapse import event_auth
from synapse.api.constants import EventContentFields
from synapse.api.errors import AuthError
from synapse.api.errors import AuthError, SynapseError
from synapse.api.room_versions import EventFormatVersions, RoomVersion, RoomVersions
from synapse.events import EventBase, make_event_from_dict
from synapse.storage.databases.main.events_worker import EventRedactBehaviour
Expand Down Expand Up @@ -689,6 +689,45 @@ def test_join_rules_msc3083_restricted(self) -> None:
auth_events.values(),
)

def test_room_v10_rejects_string_power_levels(self) -> None:
pl_event_content = {"users_default": "42"}
pl_event = make_event_from_dict(
H-Shay marked this conversation as resolved.
Show resolved Hide resolved
{
"room_id": TEST_ROOM_ID,
**_maybe_get_event_id_dict_for_room_version(RoomVersions.V10),
"type": "m.room.power_levels",
"sender": "@test:test.com",
"state_key": "",
"content": pl_event_content,
"signatures": {"test.com": {"ed25519:0": "some9signature"}},
},
room_version=RoomVersions.V10,
)

pl_event2_content = {"events": {"m.room.name": "42", "m.room.power_levels": 42}}
pl_event2 = make_event_from_dict(
{
"room_id": TEST_ROOM_ID,
**_maybe_get_event_id_dict_for_room_version(RoomVersions.V10),
"type": "m.room.power_levels",
"sender": "@test:test.com",
"state_key": "",
"content": pl_event2_content,
"signatures": {"test.com": {"ed25519:0": "some9signature"}},
},
room_version=RoomVersions.V10,
)

with self.assertRaises(SynapseError):
event_auth._check_power_levels(
pl_event.room_version, pl_event, {("fake_type", "fake_key"): pl_event2}
)

with self.assertRaises(SynapseError):
event_auth._check_power_levels(
pl_event.room_version, pl_event2, {("fake_type", "fake_key"): pl_event}
)


# helpers for making events
TEST_DOMAIN = "example.com"
Expand Down