* commit '81731c6e7': Fix: Pillow error when uploading RGBA image (#3325) (#6241) Add User-Interactive Auth to /account/3pid/add (#6119) Lint Changelog Discard retention policies when retrieving state blacklist more tests Newsfile Add tests Propagate reason in remotely rejected invites MSC2367 Allow reason field on all member events
This commit is contained in:
@@ -57,3 +57,10 @@ Don't get pushed for rooms you've muted
|
||||
Rejected events are not pushed
|
||||
Test that rejected pushers are removed.
|
||||
Events come down the correct room
|
||||
|
||||
# https://buildkite.com/matrix-dot-org/sytest/builds/326#cca62404-a88a-4fcb-ad41-175fd3377603
|
||||
Presence changes to UNAVAILABLE are reported to remote room members
|
||||
If remote user leaves room, changes device and rejoins we see update in sync
|
||||
uploading self-signing key notifies over federation
|
||||
Inbound federation can receive redacted events
|
||||
Outbound federation can request missing events
|
||||
|
||||
1
changelog.d/6119.feature
Normal file
1
changelog.d/6119.feature
Normal file
@@ -0,0 +1 @@
|
||||
Require User-Interactive Authentication for `/account/3pid/add`, meaning the user's password will be required to add a third-party ID to their account.
|
||||
1
changelog.d/6241.bugfix
Normal file
1
changelog.d/6241.bugfix
Normal file
@@ -0,0 +1 @@
|
||||
Fix error from the Pillow library when uploading RGBA images.
|
||||
1
changelog.d/6434.feature
Normal file
1
changelog.d/6434.feature
Normal file
@@ -0,0 +1 @@
|
||||
Add support for MSC 2367, which allows specifying a reason on all membership events.
|
||||
@@ -1435,9 +1435,9 @@ class FederationHandler(BaseHandler):
|
||||
return event
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def do_remotely_reject_invite(self, target_hosts, room_id, user_id):
|
||||
def do_remotely_reject_invite(self, target_hosts, room_id, user_id, content):
|
||||
origin, event, event_format_version = yield self._make_and_verify_event(
|
||||
target_hosts, room_id, user_id, "leave"
|
||||
target_hosts, room_id, user_id, "leave", content=content,
|
||||
)
|
||||
# Mark as outlier as we don't have any state for this event; we're not
|
||||
# even in the room.
|
||||
|
||||
@@ -99,7 +99,9 @@ class RoomMemberHandler(object):
|
||||
raise NotImplementedError()
|
||||
|
||||
@abc.abstractmethod
|
||||
def _remote_reject_invite(self, requester, remote_room_hosts, room_id, target):
|
||||
def _remote_reject_invite(
|
||||
self, requester, remote_room_hosts, room_id, target, content
|
||||
):
|
||||
"""Attempt to reject an invite for a room this server is not in. If we
|
||||
fail to do so we locally mark the invite as rejected.
|
||||
|
||||
@@ -109,6 +111,7 @@ class RoomMemberHandler(object):
|
||||
reject invite
|
||||
room_id (str)
|
||||
target (UserID): The user rejecting the invite
|
||||
content (dict): The content for the rejection event
|
||||
|
||||
Returns:
|
||||
Deferred[dict]: A dictionary to be returned to the client, may
|
||||
@@ -526,7 +529,7 @@ class RoomMemberHandler(object):
|
||||
# send the rejection to the inviter's HS.
|
||||
remote_room_hosts = remote_room_hosts + [inviter.domain]
|
||||
res = yield self._remote_reject_invite(
|
||||
requester, remote_room_hosts, room_id, target
|
||||
requester, remote_room_hosts, room_id, target, content,
|
||||
)
|
||||
return res
|
||||
|
||||
@@ -1056,13 +1059,15 @@ class RoomMemberMasterHandler(RoomMemberHandler):
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _remote_reject_invite(self, requester, remote_room_hosts, room_id, target):
|
||||
def _remote_reject_invite(
|
||||
self, requester, remote_room_hosts, room_id, target, content
|
||||
):
|
||||
"""Implements RoomMemberHandler._remote_reject_invite
|
||||
"""
|
||||
fed_handler = self.federation_handler
|
||||
try:
|
||||
ret = yield fed_handler.do_remotely_reject_invite(
|
||||
remote_room_hosts, room_id, target.to_string()
|
||||
remote_room_hosts, room_id, target.to_string(), content=content,
|
||||
)
|
||||
return ret
|
||||
except Exception as e:
|
||||
|
||||
@@ -55,7 +55,9 @@ class RoomMemberWorkerHandler(RoomMemberHandler):
|
||||
|
||||
return ret
|
||||
|
||||
def _remote_reject_invite(self, requester, remote_room_hosts, room_id, target):
|
||||
def _remote_reject_invite(
|
||||
self, requester, remote_room_hosts, room_id, target, content
|
||||
):
|
||||
"""Implements RoomMemberHandler._remote_reject_invite
|
||||
"""
|
||||
return self._remote_reject_client(
|
||||
@@ -63,6 +65,7 @@ class RoomMemberWorkerHandler(RoomMemberHandler):
|
||||
remote_room_hosts=remote_room_hosts,
|
||||
room_id=room_id,
|
||||
user_id=target.to_string(),
|
||||
content=content,
|
||||
)
|
||||
|
||||
def _user_joined_room(self, target, room_id):
|
||||
|
||||
@@ -93,6 +93,7 @@ class ReplicationRemoteRejectInviteRestServlet(ReplicationEndpoint):
|
||||
{
|
||||
"requester": ...,
|
||||
"remote_room_hosts": [...],
|
||||
"content": { ... }
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -107,7 +108,7 @@ class ReplicationRemoteRejectInviteRestServlet(ReplicationEndpoint):
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
@staticmethod
|
||||
def _serialize_payload(requester, room_id, user_id, remote_room_hosts):
|
||||
def _serialize_payload(requester, room_id, user_id, remote_room_hosts, content):
|
||||
"""
|
||||
Args:
|
||||
requester(Requester)
|
||||
@@ -118,12 +119,14 @@ class ReplicationRemoteRejectInviteRestServlet(ReplicationEndpoint):
|
||||
return {
|
||||
"requester": requester.serialize(),
|
||||
"remote_room_hosts": remote_room_hosts,
|
||||
"content": content,
|
||||
}
|
||||
|
||||
async def _handle_request(self, request, room_id, user_id):
|
||||
content = parse_json_object_from_request(request)
|
||||
|
||||
remote_room_hosts = content["remote_room_hosts"]
|
||||
event_content = content["content"]
|
||||
|
||||
requester = Requester.deserialize(self.store, content["requester"])
|
||||
|
||||
@@ -134,7 +137,7 @@ class ReplicationRemoteRejectInviteRestServlet(ReplicationEndpoint):
|
||||
|
||||
try:
|
||||
event = await self.federation_handler.do_remotely_reject_invite(
|
||||
remote_room_hosts, room_id, user_id
|
||||
remote_room_hosts, room_id, user_id, event_content,
|
||||
)
|
||||
ret = event.get_pdu_json()
|
||||
except Exception as e:
|
||||
|
||||
@@ -715,7 +715,7 @@ class RoomMembershipRestServlet(TransactionRestServlet):
|
||||
target = UserID.from_string(content["user_id"])
|
||||
|
||||
event_content = None
|
||||
if "reason" in content and membership_action in ["kick", "ban"]:
|
||||
if "reason" in content:
|
||||
event_content = {"reason": content["reason"]}
|
||||
|
||||
await self.room_member_handler.update_membership(
|
||||
|
||||
@@ -725,6 +725,7 @@ class ThreepidAddRestServlet(RestServlet):
|
||||
self.auth = hs.get_auth()
|
||||
self.auth_handler = hs.get_auth_handler()
|
||||
|
||||
@interactive_auth_handler
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
@@ -735,6 +736,10 @@ class ThreepidAddRestServlet(RestServlet):
|
||||
client_secret = body["client_secret"]
|
||||
sid = body["sid"]
|
||||
|
||||
yield self.auth_handler.validate_user_via_ui_auth(
|
||||
requester, body, self.hs.get_ip_from_request(request)
|
||||
)
|
||||
|
||||
validation_session = yield self.identity_handler.validate_threepid_session(
|
||||
client_secret, sid
|
||||
)
|
||||
|
||||
@@ -129,5 +129,8 @@ class Thumbnailer(object):
|
||||
|
||||
def _encode_image(self, output_image, output_type):
|
||||
output_bytes_io = BytesIO()
|
||||
output_image.save(output_bytes_io, self.FORMATS[output_type], quality=80)
|
||||
fmt = self.FORMATS[output_type]
|
||||
if fmt == "JPEG":
|
||||
output_image = output_image.convert("RGB")
|
||||
output_image.save(output_bytes_io, fmt, quality=80)
|
||||
return output_bytes_io
|
||||
|
||||
@@ -100,9 +100,9 @@ def filter_events_for_client(
|
||||
retention_policies = {}
|
||||
|
||||
for room_id in room_ids:
|
||||
retention_policies[room_id] = (
|
||||
yield storage.main.get_retention_policy_for_room(room_id)
|
||||
)
|
||||
retention_policies[
|
||||
room_id
|
||||
] = yield storage.main.get_retention_policy_for_room(room_id)
|
||||
|
||||
def allowed(event):
|
||||
"""
|
||||
|
||||
@@ -1180,3 +1180,143 @@ class PerRoomProfilesForbiddenTestCase(unittest.HomeserverTestCase):
|
||||
|
||||
res_displayname = channel.json_body["content"]["displayname"]
|
||||
self.assertEqual(res_displayname, self.displayname, channel.result)
|
||||
|
||||
|
||||
class RoomMembershipReasonTestCase(unittest.HomeserverTestCase):
|
||||
"""Tests that clients can add a "reason" field to membership events and
|
||||
that they get correctly added to the generated events and propagated.
|
||||
"""
|
||||
|
||||
servlets = [
|
||||
synapse.rest.admin.register_servlets_for_client_rest_resource,
|
||||
room.register_servlets,
|
||||
login.register_servlets,
|
||||
]
|
||||
|
||||
def prepare(self, reactor, clock, homeserver):
|
||||
self.creator = self.register_user("creator", "test")
|
||||
self.creator_tok = self.login("creator", "test")
|
||||
|
||||
self.second_user_id = self.register_user("second", "test")
|
||||
self.second_tok = self.login("second", "test")
|
||||
|
||||
self.room_id = self.helper.create_room_as(self.creator, tok=self.creator_tok)
|
||||
|
||||
def test_join_reason(self):
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/join".format(self.room_id),
|
||||
content={"reason": reason},
|
||||
access_token=self.second_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_leave_reason(self):
|
||||
self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
|
||||
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/leave".format(self.room_id),
|
||||
content={"reason": reason},
|
||||
access_token=self.second_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_kick_reason(self):
|
||||
self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
|
||||
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/kick".format(self.room_id),
|
||||
content={"reason": reason, "user_id": self.second_user_id},
|
||||
access_token=self.second_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_ban_reason(self):
|
||||
self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
|
||||
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/ban".format(self.room_id),
|
||||
content={"reason": reason, "user_id": self.second_user_id},
|
||||
access_token=self.creator_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_unban_reason(self):
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/unban".format(self.room_id),
|
||||
content={"reason": reason, "user_id": self.second_user_id},
|
||||
access_token=self.creator_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_invite_reason(self):
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/invite".format(self.room_id),
|
||||
content={"reason": reason, "user_id": self.second_user_id},
|
||||
access_token=self.creator_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def test_reject_invite_reason(self):
|
||||
self.helper.invite(
|
||||
self.room_id,
|
||||
src=self.creator,
|
||||
targ=self.second_user_id,
|
||||
tok=self.creator_tok,
|
||||
)
|
||||
|
||||
reason = "hello"
|
||||
request, channel = self.make_request(
|
||||
"POST",
|
||||
"/_matrix/client/r0/rooms/{}/leave".format(self.room_id),
|
||||
content={"reason": reason},
|
||||
access_token=self.second_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
self._check_for_reason(reason)
|
||||
|
||||
def _check_for_reason(self, reason):
|
||||
request, channel = self.make_request(
|
||||
"GET",
|
||||
"/_matrix/client/r0/rooms/{}/state/m.room.member/{}".format(
|
||||
self.room_id, self.second_user_id
|
||||
),
|
||||
access_token=self.creator_tok,
|
||||
)
|
||||
self.render(request)
|
||||
self.assertEqual(channel.code, 200, channel.result)
|
||||
|
||||
event_content = channel.json_body
|
||||
|
||||
self.assertEqual(event_content.get("reason"), reason, channel.result)
|
||||
|
||||
Reference in New Issue
Block a user