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

Add MSC3604 opt3 + prior #12625

Closed
wants to merge 16 commits into from
Closed
1 change: 1 addition & 0 deletions changelog.d/11885.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support [MSC3667](https://github.com/matrix-org/matrix-doc/pull/3667) in a new room version.
1 change: 1 addition & 0 deletions changelog.d/12623.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for [MSC3787: Allowing knocks to restricted rooms](https://github.com/matrix-org/matrix-spec-proposals/pull/3787).
2 changes: 1 addition & 1 deletion scripts-dev/complement.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ docker build -t $COMPLEMENT_BASE_IMAGE -f "docker/complement/$COMPLEMENT_DOCKERF
# Run the tests!
echo "Images built; running complement"
cd "$COMPLEMENT_DIR"
go test -v -tags synapse_blacklist,msc2716,msc3030,faster_joins -count=1 "$@" ./tests/...
go test -v -tags synapse_blacklist,msc2716,msc3030,faster_joins,msc3787 -count=1 "$@" ./tests/...
2 changes: 2 additions & 0 deletions synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class JoinRules:
PRIVATE: Final = "private"
# As defined for MSC3083.
RESTRICTED: Final = "restricted"
# As defined for MSC3787.
KNOCK_RESTRICTED: Final = "knock_restricted"


class RestrictedJoinRuleTypes:
Expand Down
125 changes: 125 additions & 0 deletions synapse/api/room_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ class RoomVersion:
msc2716_historical: bool
# MSC2716: Adds support for redacting "insertion", "chunk", and "marker" events
msc2716_redactions: bool
# MSC3667: Treat string format power levels as invalid, thus denied.
msc3667_int_only_power_levels: bool
# 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


class RoomVersions:
Expand All @@ -99,6 +104,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V2 = RoomVersion(
"2",
Expand All @@ -115,6 +122,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V3 = RoomVersion(
"3",
Expand All @@ -131,6 +140,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V4 = RoomVersion(
"4",
Expand All @@ -147,6 +158,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V5 = RoomVersion(
"5",
Expand All @@ -163,6 +176,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V6 = RoomVersion(
"6",
Expand All @@ -179,6 +194,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
MSC2176 = RoomVersion(
"org.matrix.msc2176",
Expand All @@ -195,6 +212,8 @@ class RoomVersions:
msc2403_knocking=False,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V7 = RoomVersion(
"7",
Expand All @@ -211,6 +230,8 @@ class RoomVersions:
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V8 = RoomVersion(
"8",
Expand All @@ -227,6 +248,8 @@ class RoomVersions:
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
V9 = RoomVersion(
"9",
Expand All @@ -243,7 +266,10 @@ class RoomVersions:
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
# Not to be confused with MSC2176
MSC2716v3 = RoomVersion(
"org.matrix.msc2716v3",
RoomDisposition.UNSTABLE,
Expand All @@ -259,6 +285,100 @@ class RoomVersions:
msc2403_knocking=True,
msc2716_historical=True,
msc2716_redactions=True,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
MSC3667 = RoomVersion(
# v7 + MSC3667
"org.matrix.msc3667",
RoomDisposition.UNSTABLE,
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=False,
msc3375_redaction_rules=False,
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=True,
)
MSC3787 = RoomVersion(
"org.matrix.msc3787",
RoomDisposition.UNSTABLE,
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,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=True,
)
MSC3604Opt1 = RoomVersion(
"org.matrix.msc3604.opt1",
RoomDisposition.UNSTABLE,
EventFormatVersions.V3,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=True,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=False,
msc3787_knock_restricted_join_rule=False,
)
MSC3604Opt2 = RoomVersion(
# v9 + MSC2176 + MSC3667
"org.matrix.msc3604.opt2",
RoomDisposition.UNSTABLE,
EventFormatVersions.V3,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=True,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=True,
msc3787_knock_restricted_join_rule=False,
)
MSC3604Opt3 = RoomVersion(
# v9 + MSC2176 + MSC3667 + MSC3787
"org.matrix.msc3604.opt3",
RoomDisposition.UNSTABLE,
EventFormatVersions.V3,
StateResolutionVersions.V2,
enforce_key_validity=True,
special_case_aliases_auth=False,
strict_canonicaljson=True,
limit_notifications_power_levels=True,
msc2176_redaction_rules=True,
msc3083_join_rules=True,
msc3375_redaction_rules=True,
msc2403_knocking=True,
msc2716_historical=False,
msc2716_redactions=False,
msc3667_int_only_power_levels=True,
msc3787_knock_restricted_join_rule=True,
)


Expand All @@ -276,6 +396,11 @@ class RoomVersions:
RoomVersions.V8,
RoomVersions.V9,
RoomVersions.MSC2716v3,
RoomVersions.MSC3667,
RoomVersions.MSC3787,
RoomVersions.MSC3604Opt1,
RoomVersions.MSC3604Opt2,
RoomVersions.MSC3604Opt3,
)
}

Expand Down
37 changes: 33 additions & 4 deletions synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@ def check_auth_rules_for_event(
Raises:
AuthError if the checks fail
"""
# Before we get too far into event auth, validate that the event is even
# valid enough to be used
if event.type == EventTypes.PowerLevels:
# If applicable, validate that the known power levels are integers
if room_version_obj.msc3667_int_only_power_levels:
for k, v in event.content.items():
if k in ["events", "notifications", "users"]:
if type(v) is not dict:
raise AuthError(403, "Not a valid object: %s" % (k,))
for _k2, v2 in v.items():
if type(v2) is not int:
raise AuthError(403, "Not a valid power level: %s" % (v2,))
else:
if type(v) is not int:
raise AuthError(403, "Not a valid power level: %s" % (v,))

# We need to ensure that the auth events are actually for the same room, to
# stop people from using powers they've been granted in other rooms for
# example.
Expand Down Expand Up @@ -414,7 +430,12 @@ def _is_membership_change_allowed(
raise AuthError(403, "You are banned from this room")
elif join_rule == JoinRules.PUBLIC:
pass
elif room_version.msc3083_join_rules and join_rule == JoinRules.RESTRICTED:
elif (
room_version.msc3083_join_rules and join_rule == JoinRules.RESTRICTED
) or (
room_version.msc3787_knock_restricted_join_rule
and join_rule == JoinRules.KNOCK_RESTRICTED
):
# This is the same as public, but the event must contain a reference
# to the server who authorised the join. If the event does not contain
# the proper content it is rejected.
Expand All @@ -440,8 +461,13 @@ def _is_membership_change_allowed(
if authorising_user_level < invite_level:
raise AuthError(403, "Join event authorised by invalid server.")

elif join_rule == JoinRules.INVITE or (
room_version.msc2403_knocking and join_rule == JoinRules.KNOCK
elif (
join_rule == JoinRules.INVITE
or (room_version.msc2403_knocking and join_rule == JoinRules.KNOCK)
or (
room_version.msc3787_knock_restricted_join_rule
and join_rule == JoinRules.KNOCK_RESTRICTED
)
):
if not caller_in_room and not caller_invited:
raise AuthError(403, "You are not invited to this room.")
Expand All @@ -462,7 +488,10 @@ def _is_membership_change_allowed(
if user_level < ban_level or user_level <= target_level:
raise AuthError(403, "You don't have permission to ban")
elif room_version.msc2403_knocking and Membership.KNOCK == membership:
if join_rule != JoinRules.KNOCK:
if join_rule != JoinRules.KNOCK and (
not room_version.msc3787_knock_restricted_join_rule
or join_rule != JoinRules.KNOCK_RESTRICTED
):
raise AuthError(403, "You don't have permission to knock")
elif target_user_id != event.user_id:
raise AuthError(403, "You cannot knock for other users")
Expand Down
10 changes: 9 additions & 1 deletion synapse/handlers/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,15 @@ async def has_restricted_join_rules(

# If the join rule is not restricted, this doesn't apply.
join_rules_event = await self._store.get_event(join_rules_event_id)
return join_rules_event.content.get("join_rule") == JoinRules.RESTRICTED
content_join_rule = join_rules_event.content.get("join_rule")
if content_join_rule == JoinRules.RESTRICTED:
return True

# also check for MSC3787 behaviour
if room_version.msc3787_knock_restricted_join_rule:
return content_join_rule == JoinRules.KNOCK_RESTRICTED

return False

async def get_rooms_that_allow_join(
self, state_ids: StateMap[str]
Expand Down
9 changes: 7 additions & 2 deletions synapse/handlers/room_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,13 @@ async def _is_local_room_accessible(
if join_rules_event_id:
join_rules_event = await self._store.get_event(join_rules_event_id)
join_rule = join_rules_event.content.get("join_rule")
if join_rule == JoinRules.PUBLIC or (
room_version.msc2403_knocking and join_rule == JoinRules.KNOCK
if (
join_rule == JoinRules.PUBLIC
or (room_version.msc2403_knocking and join_rule == JoinRules.KNOCK)
or (
room_version.msc3787_knock_restricted_join_rule
and join_rule == JoinRules.KNOCK_RESTRICTED
)
):
return True

Expand Down