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

Add query parameter ts to allow appservices set the origin_server_ts for state events #11866

Merged
merged 30 commits into from
Oct 3, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f076866
Add query parameter ts to allow appservices set the original_server_t…
lukasdenk Jan 31, 2022
1a0fc0c
Apply suggestion to synapse/rest/client/room.py
lukasdenk Feb 1, 2022
f5804c3
Apply missing default value
lukasdenk Feb 1, 2022
ae1fbcb
Fix method parameter ordering.
lukasdenk Feb 1, 2022
248ddde
set default parsed value to None
lukasdenk Feb 1, 2022
c1abcf0
fix linting problem
lukasdenk Feb 1, 2022
69320e1
add documentation for original_server_ts parameter
lukasdenk Feb 1, 2022
cb2d34c
Merge remote-tracking branch 'origin/develop' into ts_for_states
lukasdenk Feb 1, 2022
c0c7a66
test ts query param for send and state events
lukasdenk Feb 7, 2022
72d606f
Merge branch 'develop' into ts_for_states
lukasdenk Feb 7, 2022
40eeae7
rename impersonated_user to appservice_user_id
lukasdenk Feb 7, 2022
dcfb170
import urllib at top of file instead of locally writing the whole path
lukasdenk Feb 7, 2022
8d44470
use consistent explanation of appservice_user_id param
lukasdenk Feb 7, 2022
f00f240
introduce msc3316_ts query param
lukasdenk Feb 7, 2022
f6e28bc
Merge remote-tracking branch 'origin/develop' into ts_for_states
lukasdenk Feb 7, 2022
4329180
Merge remote-tracking branch 'origin/develop' into ts_for_states
lukasdenk Feb 8, 2022
e54b2c2
Fix memory import
lukasdenk Feb 17, 2022
6b87d69
Merge remote-tracking branch 'origin/develop' into ts_for_states
lukasdenk Feb 17, 2022
ee295e0
fix linting probs
lukasdenk Feb 18, 2022
13b81ed
Update changelog.d/11866.feature
lukasdenk Mar 2, 2022
331cb48
add comment to Update tests/rest/client/test_rooms.py
lukasdenk Mar 8, 2022
d3e957a
test
lukasdenk Mar 15, 2022
5fab986
Merge remote-tracking branch 'fork2/ts_for_states' into ts_for_states
lukasdenk Mar 15, 2022
6b56dfc
Merge remote-tracking branch 'origin/develop' into ts_for_states
clokep Sep 30, 2022
fd62763
Use the proper urlencode.
clokep Sep 30, 2022
5a320d1
Handle review comments and fix-up code and use stable identifier.
clokep Sep 30, 2022
0bc7b54
Refactor to avoid dictionary unless needed.
clokep Sep 30, 2022
e3a0166
Clean-up another reference to unstable identifier.
clokep Sep 30, 2022
d6149af
Manually call /createRoom.
clokep Oct 3, 2022
65a79c0
Merge remote-tracking branch 'origin/develop' into ts_for_states
clokep Oct 3, 2022
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/11866.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow application services to set the `origin_server_ts` of a state event by providing the query parameter `ts` in `PUT /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}`, per [MSC3316](https://github.com/matrix-org/matrix-doc/pull/3316). Contributed by @lukasdenk.
13 changes: 13 additions & 0 deletions synapse/handlers/room_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ async def _local_membership_update(
require_consent: bool = True,
outlier: bool = False,
historical: bool = False,
origin_server_ts: Optional[int] = None,
) -> Tuple[str, int]:
"""
Internal membership update function to get an existing event or create
Expand Down Expand Up @@ -310,6 +311,8 @@ async def _local_membership_update(
historical: Indicates whether the message is being inserted
back in time around some existing events. This is used to skip
a few checks and mark the event as backfilled.
origin_server_ts: The origin_server_ts to use if a new event is created. Uses
the current timestamp if set to None.

Returns:
Tuple of event ID and stream ordering position
Expand Down Expand Up @@ -348,6 +351,7 @@ async def _local_membership_update(
"state_key": user_id,
# For backwards compatibility:
"membership": membership,
"origin_server_ts": origin_server_ts,
},
txn_id=txn_id,
allow_no_prev_events=allow_no_prev_events,
Expand Down Expand Up @@ -456,6 +460,7 @@ async def update_membership(
allow_no_prev_events: bool = False,
prev_event_ids: Optional[List[str]] = None,
auth_event_ids: Optional[List[str]] = None,
origin_server_ts: Optional[int] = None,
) -> Tuple[str, int]:
"""Update a user's membership in a room.

Expand Down Expand Up @@ -487,6 +492,8 @@ async def update_membership(
The event ids to use as the auth_events for the new event.
Should normally be left as None, which will cause them to be calculated
based on the room state at the prev_events.
origin_server_ts: The origin_server_ts to use if a new event is created. Uses
the current timestamp if set to None.

Returns:
A tuple of the new event ID and stream ID.
Expand Down Expand Up @@ -526,6 +533,7 @@ async def update_membership(
allow_no_prev_events=allow_no_prev_events,
prev_event_ids=prev_event_ids,
auth_event_ids=auth_event_ids,
origin_server_ts=origin_server_ts,
)

return result
Expand All @@ -548,6 +556,7 @@ async def update_membership_locked(
allow_no_prev_events: bool = False,
prev_event_ids: Optional[List[str]] = None,
auth_event_ids: Optional[List[str]] = None,
origin_server_ts: Optional[int] = None,
) -> Tuple[str, int]:
"""Helper for update_membership.

Expand Down Expand Up @@ -581,6 +590,8 @@ async def update_membership_locked(
The event ids to use as the auth_events for the new event.
Should normally be left as None, which will cause them to be calculated
based on the room state at the prev_events.
origin_server_ts: The origin_server_ts to use if a new event is created. Uses
the current timestamp if set to None.

Returns:
A tuple of the new event ID and stream ID.
Expand Down Expand Up @@ -712,6 +723,7 @@ async def update_membership_locked(
require_consent=require_consent,
outlier=outlier,
historical=historical,
origin_server_ts=origin_server_ts,
)

latest_event_ids = await self.store.get_prev_events_for_room(room_id)
Expand Down Expand Up @@ -935,6 +947,7 @@ async def update_membership_locked(
content=content,
require_consent=require_consent,
outlier=outlier,
origin_server_ts=origin_server_ts,
)

async def _should_perform_remote_join(
Expand Down
19 changes: 16 additions & 3 deletions synapse/rest/client/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ async def on_PUT(

content = parse_json_object_from_request(request)

event_dict = {
event_dict: JsonDict = {
"type": event_type,
"content": content,
"room_id": room_id,
Expand All @@ -204,6 +204,13 @@ async def on_PUT(
if state_key is not None:
event_dict["state_key"] = state_key

# Twisted will have processed the args by now.
assert request.args is not None
anoadragon453 marked this conversation as resolved.
Show resolved Hide resolved
if requester.app_service:
event_dict["origin_server_ts"] = parse_integer(
request, "org.matrix.msc3316.ts"
)
clokep marked this conversation as resolved.
Show resolved Hide resolved

lukasdenk marked this conversation as resolved.
Show resolved Hide resolved
try:
if event_type == EventTypes.Member:
membership = content.get("membership", None)
Expand All @@ -213,6 +220,7 @@ async def on_PUT(
room_id=room_id,
action=membership,
content=content,
origin_server_ts=event_dict.get("origin_server_ts"),
)
else:
(
Expand Down Expand Up @@ -261,8 +269,13 @@ async def on_POST(

# Twisted will have processed the args by now.
assert request.args is not None
if b"ts" in request.args and requester.app_service:
event_dict["origin_server_ts"] = parse_integer(request, "ts", 0)
if requester.app_service:
if b"ts" in request.args:
event_dict["origin_server_ts"] = parse_integer(request, "ts")
elif b"org.matrix.msc3316.ts" in request.args:
event_dict["origin_server_ts"] = parse_integer(
request, "org.matrix.msc3316.ts"
)
clokep marked this conversation as resolved.
Show resolved Hide resolved

try:
(
Expand Down
73 changes: 70 additions & 3 deletions tests/rest/client/test_rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@

import json
from typing import Iterable, List
from unittest.mock import Mock, call

from authlib.common.urls import url_encode
from unittest.mock import Mock, call, patch
from urllib import parse as urlparse

from twisted.internet import defer
from twisted.internet.task import Clock
from twisted.test.proto_helpers import MemoryReactor

import synapse.rest.admin
from synapse.api.constants import (
Expand All @@ -32,13 +36,15 @@
RelationTypes,
)
from synapse.api.errors import Codes, HttpResponseException
from synapse.appservice import ApplicationService
from synapse.handlers.pagination import PurgeStatus
from synapse.rest import admin
from synapse.rest.client import account, directory, login, profile, room, sync
from synapse.rest.client import account, directory, login, profile, register, room, sync
from synapse.server import HomeServer
from synapse.types import JsonDict, RoomAlias, UserID, create_requester
from synapse.util.stringutils import random_string

from tests import unittest
from tests import unittest, server
from tests.test_utils import make_awaitable

PATH_PREFIX = b"/_matrix/client/api/v1"
Expand Down Expand Up @@ -966,6 +972,67 @@ async def user_may_join_room(
self.helper.join(self.room3, self.user2, expect_code=403, tok=self.tok2)


class RoomAppserviceTsParamTestCase(unittest.HomeserverTestCase):
servlets = [
room.register_servlets,
synapse.rest.admin.register_servlets,
register.register_servlets,
]

def prepare(self, reactor, clock, homeserver):
self.appservice_user, _ = self.register_appservice_user(
"as_user_potato", self.appservice.token
)

self.room = self.helper.create_room_as(
room_creator=self.appservice_user,
tok=self.appservice.token,
appservice_user_id=self.appservice_user,
)

def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer:
config = self.default_config()

self.appservice = ApplicationService(
token="i_am_an_app_service",
hostname="test",
id="1234",
namespaces={"users": [{"regex": r"@as_user.*", "exclusive": True}]},
# Note: this user does not have to match the regex above
sender="@as_main:test",
)

mock_load_appservices = Mock(return_value=[self.appservice])
with patch(
"synapse.storage.databases.main.appservice.load_appservices",
mock_load_appservices,
):
hs = self.setup_test_homeserver(config=config)
return hs


def test_send_event_ts(self):
ts = 1
event_id = self._send(ts)
# check that the event was successfully persisted to the database with the correct timestamp.
res = self.get_success(self.hs.get_datastore().get_event(event_id))
self.assertEquals(ts, res.origin_server_ts)

def _send(self, ts:int) ->str:
url_params = {
"user_id": self.appservice_user,
"ts": ts,
}
channel = server.make_request(
"PUT",
path=f"/_matrix/client/r0/rooms/{self.room}/send/m.room.message/{None}?" + url_encode(url_params),
content={"membership": "invite"},
access_token=self.appservice.token,
)
self.assertEqual(channel.code, 200)
return channel.json_body["event_id"]


class RoomJoinRatelimitTestCase(RoomBase):
user_id = "@sid1:red"

Expand Down
Loading