Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Sliding Sync /sync endpoint (initial implementation) #17187

Merged
merged 123 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 117 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
f9e6e53
Configurable /sync/e2ee endpoint
MadLittleMods May 6, 2024
1e05a05
Add Sliding Sync `/sync/e2ee` endpoint for To-Device messages
MadLittleMods May 7, 2024
5e925f6
Share tests with test_sendtodevice
MadLittleMods May 8, 2024
69f9143
Comment on tests
MadLittleMods May 8, 2024
d4ff933
Prefer Sync v2 vs Sliding Sync distinction
MadLittleMods May 8, 2024
371ec57
Fix wait_for_sync_for_user in tests
MadLittleMods May 8, 2024
06d12e5
Ugly overloads
MadLittleMods May 8, 2024
b8b70ba
Fix lint
MadLittleMods May 8, 2024
c60a4f8
Add changelog
MadLittleMods May 8, 2024
10ffae6
Shared logic for `get_sync_result_builder()`
MadLittleMods May 8, 2024
6bf4896
Try calculate more
MadLittleMods May 9, 2024
8871dac
Share tests using inheritance
MadLittleMods May 9, 2024
0892283
Add comments docs
MadLittleMods May 9, 2024
adb7e20
Consolidate device_lists /sync tests
MadLittleMods May 9, 2024
f098355
Add `device_one_time_keys_count` tests
MadLittleMods May 9, 2024
6b7cfd7
Add tests for `device_unused_fallback_key_types` in `/sync`
MadLittleMods May 9, 2024
b9e5379
Describe test
MadLittleMods May 9, 2024
f9c9d44
Add stub Sliding Sync endpoint
MadLittleMods May 13, 2024
654e8f6
Add Pydantic model for the Sliding Sync API
MadLittleMods May 13, 2024
aee594a
Can't use StringConstraints
MadLittleMods May 14, 2024
2863fba
More optional
MadLittleMods May 15, 2024
2dd0cde
Fill out more options
MadLittleMods May 15, 2024
c8256b6
Start to map out response
MadLittleMods May 15, 2024
ee6baba
Iterating
MadLittleMods May 15, 2024
f3db068
Copy body to config
MadLittleMods May 15, 2024
9bdfa16
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-e2ee
MadLittleMods May 16, 2024
7331401
Lint
MadLittleMods May 16, 2024
b23abca
Fix test inheritance
MadLittleMods May 16, 2024
821a1b3
Add missing field to docstring
MadLittleMods May 16, 2024
35ca937
Format docstring
MadLittleMods May 16, 2024
4ad7a8b
No need to change this formatting from develop
MadLittleMods May 16, 2024
3092ab5
Calculate room derived membership info for device_lists
MadLittleMods May 20, 2024
3539abe
Membership in timeline for better derived info
MadLittleMods May 20, 2024
5f194f9
Exclude application services
MadLittleMods May 20, 2024
02cecfa
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-e2ee
MadLittleMods May 20, 2024
bfa8c63
Merge branch 'madlittlemods/msc3575-sliding-sync-e2ee' into madlittle…
MadLittleMods May 20, 2024
07d84ab
Start of gathering room list to display in sync
MadLittleMods May 20, 2024
6dadfe9
Try handle no from_token or to_token already newer
MadLittleMods May 20, 2024
9ffafe7
Try to think about this logic
MadLittleMods May 21, 2024
f6122ff
Use `client_patterns()` for endpoint URL
MadLittleMods May 21, 2024
2f112e7
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-e2ee
MadLittleMods May 21, 2024
c2221bb
Lint
MadLittleMods May 21, 2024
717b160
Adjust wording, add todo
MadLittleMods May 21, 2024
c826550
Add some tests
MadLittleMods May 21, 2024
fe48188
Handle more edge cases
MadLittleMods May 21, 2024
fd355f6
WIP
MadLittleMods May 21, 2024
dd9356a
Using unsigned prev_content
MadLittleMods May 21, 2024
17783c3
Log why no unsigned
MadLittleMods May 22, 2024
343de8f
Remove debug logs
MadLittleMods May 22, 2024
1b3a5bf
Fix referencing variable from other lexical scope
MadLittleMods May 22, 2024
c82a084
Update comments and test docstrings
MadLittleMods May 22, 2024
514aba5
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-e2ee
MadLittleMods May 22, 2024
9749795
Update filter to be more precise and avoid more work
MadLittleMods May 22, 2024
06ac1da
Restore copyright header
MadLittleMods May 22, 2024
3da6bc1
Use `@parameterized_class`
MadLittleMods May 22, 2024
d4b41aa
Fix lints
MadLittleMods May 22, 2024
89db566
Merge branch 'madlittlemods/msc3575-sliding-sync-e2ee' into madlittle…
MadLittleMods May 22, 2024
c7b8743
Add changelog
MadLittleMods May 22, 2024
a7c6476
Use `client_patterns()`
MadLittleMods May 22, 2024
13d6146
Fill out sliding window response types
MadLittleMods May 22, 2024
c7f7ae4
Start assembling lists
MadLittleMods May 22, 2024
4c7d7e6
Encode response
MadLittleMods May 22, 2024
6606ac1
Add docstring for parametized attributes
MadLittleMods May 23, 2024
ab0b844
Add actual typing for params (not just docstrings)
MadLittleMods May 23, 2024
a482545
Fix test after removing type ignore
MadLittleMods May 23, 2024
04eeee6
Merge branch 'madlittlemods/msc3575-sliding-sync-e2ee' into madlittle…
MadLittleMods May 23, 2024
8c3de84
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods May 23, 2024
37af87a
Add test to make sure we don't confuse multiple rooms
MadLittleMods May 23, 2024
a822a05
Revert as TODO says
MadLittleMods May 23, 2024
f9fa683
Fix another leaking loop variable
MadLittleMods May 23, 2024
d1bd02d
Add TODO to handle partial stated rooms
MadLittleMods May 23, 2024
b5b3e77
Fix Pydantic `conint`/`constr` usage with mypy
MadLittleMods May 23, 2024
65d9b79
Fix lints
MadLittleMods May 23, 2024
adc0e2f
Fix unserialize type
MadLittleMods May 23, 2024
b12fee5
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods May 28, 2024
44e9a92
Fill in rest docstring
MadLittleMods May 28, 2024
b632cbb
Add better comments
MadLittleMods May 28, 2024
abf139a
Fill out docstring todo
MadLittleMods May 28, 2024
a28569f
Add understanding of this skip
MadLittleMods May 28, 2024
950fd70
Tweak comments
MadLittleMods May 28, 2024
8bf5a62
Add rest test
MadLittleMods May 29, 2024
34d67fd
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods May 29, 2024
49998e0
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods May 30, 2024
09609cb
WIP: TODO comments after pairing with Erik
MadLittleMods Jun 3, 2024
8f09313
Add instance name alongside stream_ordering (`RoomsForUser.event_pos`)
MadLittleMods Jun 3, 2024
803fbbe
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods Jun 3, 2024
a0c042e
Re-arrange how this list will be returned
MadLittleMods Jun 3, 2024
271a196
Use fully-qualified `PersistedEventPosition` when returning membershi…
MadLittleMods Jun 3, 2024
4155e18
Fix circular imports when running specific tests
MadLittleMods Jun 3, 2024
939695d
Update usage
MadLittleMods Jun 3, 2024
73c20d9
Use method to get instance name in tests
MadLittleMods Jun 3, 2024
7b41f41
Fix random lints
MadLittleMods Jun 3, 2024
09638ac
Add changelog
MadLittleMods Jun 3, 2024
8dca8f5
Merge branch 'madlittlemods/rooms-for-user-event-pos' into madlittlem…
MadLittleMods Jun 3, 2024
9c6ec25
Create `membership_snapshot_token` with `instance_map`
MadLittleMods Jun 4, 2024
1268a54
Properly compare tokens and event positions
MadLittleMods Jun 4, 2024
e4c66b8
Avoid serializing response that will never be heard
MadLittleMods Jun 4, 2024
35db057
Add support for kicks
MadLittleMods Jun 4, 2024
3514aa0
Add licensing headers
MadLittleMods Jun 4, 2024
970a0c6
Adjust wording
MadLittleMods Jun 4, 2024
64df6fb
Revert change that should be separated and is failing
MadLittleMods Jun 4, 2024
8bb357a
Note the extras
MadLittleMods Jun 4, 2024
03dd87a
Add test for `notifier.wait_for_stream_token(from_token)`
MadLittleMods Jun 4, 2024
9e46b2a
Fix typo
MadLittleMods Jun 4, 2024
54dbc27
Add None defaults
MadLittleMods Jun 4, 2024
f6a5905
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods Jun 4, 2024
07f57a4
Give a summary of what rooms we're looking for
MadLittleMods Jun 4, 2024
d3ce27b
Balance parenthesis
MadLittleMods Jun 4, 2024
dfee21a
Switch fixup order to fix edge case with newly_left rooms
MadLittleMods Jun 4, 2024
3ce0892
Add test with multiple event persisters that fails the previous `get_…
MadLittleMods Jun 5, 2024
2864837
Allow new `get_sync_room_ids_for_user` implementation to work with mu…
MadLittleMods Jun 5, 2024
2af467d
Remove extra for-loop
MadLittleMods Jun 5, 2024
7bbe2ed
More clear way to express what membership we want to display
MadLittleMods Jun 5, 2024
1fc1b58
Remove assert since we no longer need that information
MadLittleMods Jun 5, 2024
6a6cdc6
Use Set because Tuple doesn't allow - operations
MadLittleMods Jun 5, 2024
278ba63
No need to check from/to token relationship
MadLittleMods Jun 5, 2024
5678307
Add validation for membership
MadLittleMods Jun 5, 2024
703cdc9
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods Jun 5, 2024
c7d1fc3
Fix separator label
MadLittleMods Jun 5, 2024
0f6646d
Add test for no `from_token`
MadLittleMods Jun 6, 2024
0153a6e
Add test for `from_token` after `to_token`
MadLittleMods Jun 6, 2024
6f10b97
Simplify boolean logic and avoid set construction
MadLittleMods Jun 6, 2024
c89f012
Merge branch 'develop' into madlittlemods/msc3575-sliding-sync-0.0.1
MadLittleMods Jun 6, 2024
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/17187.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add initial implementation of an experimental [MSC3575](https://github.com/matrix-org/matrix-spec-proposals/pull/3575) Sliding Sync `/sync` endpoint.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When running synapse in docker along with a syncv3 service, does this feature possibly clash with the syncv3 service using ghcr.io/matrix-org/sliding-sync ?

-- @jsalort, #17187 (comment)

Since this endpoint is currently using /_matrix/client/unstable/org.matrix.simplified_msc3575/sync, I don't think it would clash with the Sliding Sync proxy.

2 changes: 1 addition & 1 deletion synapse/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Membership:
KNOCK: Final = "knock"
LEAVE: Final = "leave"
BAN: Final = "ban"
LIST: Final = (INVITE, JOIN, KNOCK, LEAVE, BAN)
LIST: Final = {INVITE, JOIN, KNOCK, LEAVE, BAN}


class PresenceState:
Expand Down
611 changes: 611 additions & 0 deletions synapse/handlers/sliding_sync.py

Large diffs are not rendered by default.

19 changes: 11 additions & 8 deletions synapse/handlers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -1977,7 +1977,7 @@ async def get_sync_result_builder(
"""
user_id = sync_config.user.to_string()

# Note: we get the users room list *before* we get the current token, this
# Note: we get the users room list *before* we get the `now_token`, this
# avoids checking back in history if rooms are joined after the token is fetched.
token_before_rooms = self.event_sources.get_current_token()
mutable_joined_room_ids = set(await self.store.get_rooms_for_user(user_id))
Expand All @@ -1989,10 +1989,10 @@ async def get_sync_result_builder(
now_token = self.event_sources.get_current_token()
log_kv({"now_token": now_token})

# Since we fetched the users room list before the token, there's a small window
# during which membership events may have been persisted, so we fetch these now
# and modify the joined room list for any changes between the get_rooms_for_user
# call and the get_current_token call.
# Since we fetched the users room list before calculating the `now_token` (see
# above), there's a small window during which membership events may have been
# persisted, so we fetch these now and modify the joined room list for any
# changes between the get_rooms_for_user call and the get_current_token call.
membership_change_events = []
if since_token:
membership_change_events = await self.store.get_membership_changes_for_user(
Expand All @@ -2002,16 +2002,19 @@ async def get_sync_result_builder(
self.rooms_to_exclude_globally,
)

mem_last_change_by_room_id: Dict[str, EventBase] = {}
last_membership_change_by_room_id: Dict[str, EventBase] = {}
for event in membership_change_events:
mem_last_change_by_room_id[event.room_id] = event
last_membership_change_by_room_id[event.room_id] = event

# For the latest membership event in each room found, add/remove the room ID
# from the joined room list accordingly. In this case we only care if the
# latest change is JOIN.

for room_id, event in mem_last_change_by_room_id.items():
for room_id, event in last_membership_change_by_room_id.items():
assert event.internal_metadata.stream_ordering
# As a shortcut, skip any events that happened before we got our
# `get_rooms_for_user()` snapshot (any changes are already represented
# in that list).
if (
event.internal_metadata.stream_ordering
< token_before_rooms.room_key.stream
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
191 changes: 188 additions & 3 deletions synapse/rest/client/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,30 @@
# [This file includes modifications made by New Vector Limited]
#
#
from typing import TYPE_CHECKING, Dict, Optional
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union

from synapse._pydantic_compat import HAS_PYDANTIC_V2

if TYPE_CHECKING or HAS_PYDANTIC_V2:
from pydantic.v1 import Extra, StrictInt, StrictStr, constr, validator
from pydantic.v1 import (
Extra,
StrictBool,
StrictInt,
StrictStr,
conint,
constr,
validator,
)
else:
from pydantic import Extra, StrictInt, StrictStr, constr, validator
from pydantic import (
Extra,
StrictBool,
StrictInt,
StrictStr,
conint,
constr,
validator,
)

from synapse.rest.models import RequestBodyModel
from synapse.util.threepids import validate_email
Expand Down Expand Up @@ -97,3 +113,172 @@ class EmailRequestTokenBody(ThreepidRequestTokenBody):
class MsisdnRequestTokenBody(ThreepidRequestTokenBody):
country: ISO3116_1_Alpha_2
phone_number: StrictStr


class SlidingSyncBody(RequestBodyModel):
"""
Sliding Sync API request body.

Attributes:
lists: Sliding window API. A map of list key to list information
(:class:`SlidingSyncList`). Max lists: 100. The list keys should be
arbitrary strings which the client is using to refer to the list. Keep this
small as it needs to be sent a lot. Max length: 64 bytes.
room_subscriptions: Room subscription API. A map of room ID to room subscription
information. Used to subscribe to a specific room. Sometimes clients know
exactly which room they want to get information about e.g by following a
permalink or by refreshing a webapp currently viewing a specific room. The
sliding window API alone is insufficient for this use case because there's
no way to say "please track this room explicitly".
extensions: Extensions API. A map of extension key to extension config.
"""

class CommonRoomParameters(RequestBodyModel):
"""
Common parameters shared between the sliding window and room subscription APIs.

Attributes:
required_state: Required state for each room returned. An array of event
type and state key tuples. Elements in this array are ORd together to
produce the final set of state events to return. One unique exception is
when you request all state events via `["*", "*"]`. When used, all state
events are returned by default, and additional entries FILTER OUT the
returned set of state events. These additional entries cannot use `*`
themselves. For example, `["*", "*"], ["m.room.member",
"@alice:example.com"]` will *exclude* every `m.room.member` event
*except* for `@alice:example.com`, and include every other state event.
In addition, `["*", "*"], ["m.space.child", "*"]` is an error, the
`m.space.child` filter is not required as it would have been returned
anyway.
timeline_limit: The maximum number of timeline events to return per response.
(Max 1000 messages)
include_old_rooms: Determines if `predecessor` rooms are included in the
`rooms` response. The user MUST be joined to old rooms for them to show up
in the response.
"""

class IncludeOldRooms(RequestBodyModel):
timeline_limit: StrictInt
required_state: List[Tuple[StrictStr, StrictStr]]

required_state: List[Tuple[StrictStr, StrictStr]]
# mypy workaround via https://github.com/pydantic/pydantic/issues/156#issuecomment-1130883884
if TYPE_CHECKING:
timeline_limit: int
else:
timeline_limit: conint(le=1000, strict=True) # type: ignore[valid-type]
include_old_rooms: Optional[IncludeOldRooms] = None

class SlidingSyncList(CommonRoomParameters):
"""
Attributes:
ranges: Sliding window ranges. If this field is missing, no sliding window
is used and all rooms are returned in this list. Integers are
*inclusive*.
sort: How the list should be sorted on the server. The first value is
applied first, then tiebreaks are performed with each subsequent sort
listed.

FIXME: Furthermore, it's not currently defined how servers should behave
if they encounter a filter or sort operation they do not recognise. If
the server rejects the request with an HTTP 400 then that will break
backwards compatibility with new clients vs old servers. However, the
client would be otherwise unaware that only some of the sort/filter
operations have taken effect. We may need to include a "warnings"
section to indicate which sort/filter operations are unrecognised,
allowing for some form of graceful degradation of service.
-- https://github.com/matrix-org/matrix-spec-proposals/blob/kegan/sync-v3/proposals/3575-sync.md#filter-and-sort-extensions

slow_get_all_rooms: Just get all rooms (for clients that don't want to deal with
sliding windows). When true, the `ranges` and `sort` fields are ignored.
required_state: Required state for each room returned. An array of event
type and state key tuples. Elements in this array are ORd together to
produce the final set of state events to return.

One unique exception is when you request all state events via `["*",
"*"]`. When used, all state events are returned by default, and
additional entries FILTER OUT the returned set of state events. These
additional entries cannot use `*` themselves. For example, `["*", "*"],
["m.room.member", "@alice:example.com"]` will *exclude* every
`m.room.member` event *except* for `@alice:example.com`, and include
every other state event. In addition, `["*", "*"], ["m.space.child",
"*"]` is an error, the `m.space.child` filter is not required as it
would have been returned anyway.

Room members can be lazily-loaded by using the special `$LAZY` state key
(`["m.room.member", "$LAZY"]`). Typically, when you view a room, you
want to retrieve all state events except for m.room.member events which
you want to lazily load. To get this behaviour, clients can send the
following::

{
"required_state": [
// activate lazy loading
["m.room.member", "$LAZY"],
// request all state events _except_ for m.room.member
events which are lazily loaded
["*", "*"]
]
}

timeline_limit: The maximum number of timeline events to return per response.
include_old_rooms: Determines if `predecessor` rooms are included in the
`rooms` response. The user MUST be joined to old rooms for them to show up
in the response.
include_heroes: Return a stripped variant of membership events (containing
`user_id` and optionally `avatar_url` and `displayname`) for the users used
to calculate the room name.
filters: Filters to apply to the list before sorting.
bump_event_types: Allowlist of event types which should be considered recent activity
when sorting `by_recency`. By omitting event types from this field,
clients can ensure that uninteresting events (e.g. a profile rename) do
not cause a room to jump to the top of its list(s). Empty or omitted
`bump_event_types` have no effect—all events in a room will be
considered recent activity.
"""

class Filters(RequestBodyModel):
is_dm: Optional[StrictBool] = None
spaces: Optional[List[StrictStr]] = None
is_encrypted: Optional[StrictBool] = None
is_invite: Optional[StrictBool] = None
room_types: Optional[List[Union[StrictStr, None]]] = None
not_room_types: Optional[List[StrictStr]] = None
room_name_like: Optional[StrictStr] = None
tags: Optional[List[StrictStr]] = None
not_tags: Optional[List[StrictStr]] = None

# mypy workaround via https://github.com/pydantic/pydantic/issues/156#issuecomment-1130883884
if TYPE_CHECKING:
ranges: Optional[List[Tuple[int, int]]] = None
else:
ranges: Optional[List[Tuple[conint(ge=0, strict=True), conint(ge=0, strict=True)]]] = None # type: ignore[valid-type]
sort: Optional[List[StrictStr]] = None
slow_get_all_rooms: Optional[StrictBool] = False
include_heroes: Optional[StrictBool] = False
filters: Optional[Filters] = None
bump_event_types: Optional[List[StrictStr]] = None

class RoomSubscription(CommonRoomParameters):
pass

class Extension(RequestBodyModel):
enabled: Optional[StrictBool] = False
lists: Optional[List[StrictStr]] = None
rooms: Optional[List[StrictStr]] = None

# mypy workaround via https://github.com/pydantic/pydantic/issues/156#issuecomment-1130883884
if TYPE_CHECKING:
lists: Optional[Dict[str, SlidingSyncList]] = None
else:
lists: Optional[Dict[constr(max_length=64, strict=True), SlidingSyncList]] = None # type: ignore[valid-type]
room_subscriptions: Optional[Dict[StrictStr, RoomSubscription]] = None
extensions: Optional[Dict[StrictStr, Extension]] = None

@validator("lists")
def lists_length_check(
cls, value: Optional[Dict[str, SlidingSyncList]]
) -> Optional[Dict[str, SlidingSyncList]]:
if value is not None:
assert len(value) <= 100, f"Max lists: 100 but saw {len(value)}"
return value
3 changes: 3 additions & 0 deletions synapse/rest/client/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ async def on_PUT(
try:
if event_type == EventTypes.Member:
membership = content.get("membership", None)
if not isinstance(membership, str):
raise SynapseError(400, "Invalid membership (must be a string)")
Comment on lines +295 to +296
Copy link
Contributor Author

@MadLittleMods MadLittleMods Jun 5, 2024

Choose a reason for hiding this comment

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

To address failing CI:

poetry run trial tests.rest.client.test_rooms.RoomMemberStateTestCase.test_invalid_puts tests.rest.client.test_rooms
poetry run trial tests.rest.client.test_rooms.RoomMemberStateTestCase.test_invalid_puts
tests.rest.client.test_rooms
  RoomMemberStateTestCase
    test_invalid_puts ...                                                [FAIL]

===============================================================================
[FAIL]
Traceback (most recent call last):
  File "/home/eric/Documents/github/element/synapse/tests/rest/client/test_rooms.py", line 1069, in test_invalid_puts
    self.assertEqual(
  File "/home/eric/.cache/pypoetry/virtualenvs/matrix-synapse-xCtC9ulO-py3.12/lib/python3.12/site-packages/twisted/trial/_synctest.py", line 444, in assertEqual
    super().assertEqual(first, second, msg)
  File "/usr/lib/python3.12/unittest/case.py", line 885, in assertEqual
    assertion_func(first, second, msg=msg)
  File "/usr/lib/python3.12/unittest/case.py", line 878, in _baseAssertEqual
    raise self.failureException(msg)
twisted.trial.unittest.FailTest: <HTTPStatus.BAD_REQUEST: 400> != 500 : b'{"errcode":"M_UNKNOWN","error":"Internal server error"}'

tests.rest.client.test_rooms.RoomMemberStateTestCase.test_invalid_puts
-------------------------------------------------------------------------------
Ran 1 tests in 1.203s
_trial_temp/test.log
2024-06-05 11:49:09-0500 [-] synapse.http.server - 146 - ERROR - PUT-7 - Failed handle request via 'RoomStateEventRestServlet': <SynapseRequest at 0x7f408b359a00 method='PUT' uri='/_matrix/client/r0/rooms/!iqYybTUtBNrlPoqnZY:red/state/m.room.member/@sid1:red' clientproto='1.1' site='red'>
	Traceback (most recent call last):
	  File "/home/eric/Documents/github/element/synapse/synapse/http/server.py", line 332, in _async_render_wrapper
	    callback_return = await self._async_render(request)
	                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "/home/eric/Documents/github/element/synapse/synapse/http/server.py", line 544, in _async_render
	    callback_return = await raw_callback_return
	                      ^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "/home/eric/Documents/github/element/synapse/synapse/rest/client/room.py", line 295, in on_PUT
	    event_id, _ = await self.room_member_handler.update_membership(
	                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "/home/eric/Documents/github/element/synapse/synapse/handlers/room_member.py", line 666, in update_membership
	    result = await self.update_membership_locked(
	             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  File "/home/eric/Documents/github/element/synapse/synapse/handlers/room_member.py", line 832, in update_membership_locked
	    if effective_membership_state not in Membership.LIST:
	       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	TypeError: unhashable type: 'list'

Previously, we would just pass whatever we received from the event content into the handler layer that expected a plain string.

Since I changed Membership.LIST to a set, when people sent things like arrays/lists, we got unhashable errors. Whereas previously, the comparison worked fine with a Tuple.

This just adds some validation to the rest layer so the handler can always expect a plain str as the type signature says.


event_id, _ = await self.room_member_handler.update_membership(
requester,
target=UserID.from_string(state_key),
Expand Down
Loading
Loading