Merge release-v1.7.1 into develop

pull/6563/head
Richard van der Hoff 2019-12-18 09:51:51 +00:00
commit 6e8f8e14f2
7 changed files with 145 additions and 10 deletions

1
changelog.d/6553.bugfix Normal file
View File

@ -0,0 +1 @@
Fix a bug causing responses to the `/context` client endpoint to not use the pruned version of the event.

1
changelog.d/6560.bugfix Normal file
View File

@ -0,0 +1 @@
Fix a cause of state resets in room versions 2 onwards.

View File

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
import logging import logging
from typing import Set, Tuple
from canonicaljson import encode_canonical_json from canonicaljson import encode_canonical_json
from signedjson.key import decode_verify_key_bytes from signedjson.key import decode_verify_key_bytes
@ -633,7 +634,7 @@ def get_public_keys(invite_event):
return public_keys return public_keys
def auth_types_for_event(event): def auth_types_for_event(event) -> Set[Tuple[str]]:
"""Given an event, return a list of (EventType, StateKey) that may be """Given an event, return a list of (EventType, StateKey) that may be
needed to auth the event. The returned list may be a superset of what needed to auth the event. The returned list may be a superset of what
would actually be required depending on the full state of the room. would actually be required depending on the full state of the room.
@ -642,20 +643,20 @@ def auth_types_for_event(event):
actually auth the event. actually auth the event.
""" """
if event.type == EventTypes.Create: if event.type == EventTypes.Create:
return [] return set()
auth_types = [ auth_types = {
(EventTypes.PowerLevels, ""), (EventTypes.PowerLevels, ""),
(EventTypes.Member, event.sender), (EventTypes.Member, event.sender),
(EventTypes.Create, ""), (EventTypes.Create, ""),
] }
if event.type == EventTypes.Member: if event.type == EventTypes.Member:
membership = event.content["membership"] membership = event.content["membership"]
if membership in [Membership.JOIN, Membership.INVITE]: if membership in [Membership.JOIN, Membership.INVITE]:
auth_types.append((EventTypes.JoinRules, "")) auth_types.add((EventTypes.JoinRules, ""))
auth_types.append((EventTypes.Member, event.state_key)) auth_types.add((EventTypes.Member, event.state_key))
if membership == Membership.INVITE: if membership == Membership.INVITE:
if "third_party_invite" in event.content: if "third_party_invite" in event.content:
@ -663,6 +664,6 @@ def auth_types_for_event(event):
EventTypes.ThirdPartyInvite, EventTypes.ThirdPartyInvite,
event.content["third_party_invite"]["signed"]["token"], event.content["third_party_invite"]["signed"]["token"],
) )
auth_types.append(key) auth_types.add(key)
return auth_types return auth_types

View File

@ -671,6 +671,7 @@ class FederationHandler(BaseHandler):
bad_room_id, bad_room_id,
room_id, room_id,
) )
del fetched_events[bad_event_id] del fetched_events[bad_event_id]
return fetched_events return fetched_events

View File

@ -907,7 +907,10 @@ class RoomContextHandler(object):
results["events_before"] = yield filter_evts(results["events_before"]) results["events_before"] = yield filter_evts(results["events_before"])
results["events_after"] = yield filter_evts(results["events_after"]) results["events_after"] = yield filter_evts(results["events_after"])
results["event"] = event # filter_evts can return a pruned event in case the user is allowed to see that
# there's something there but not see the content, so use the event that's in
# `filtered` rather than the event we retrieved from the datastore.
results["event"] = filtered[0]
if results["events_after"]: if results["events_after"]:
last_event_id = results["events_after"][-1].event_id last_event_id = results["events_after"][-1].event_id
@ -938,7 +941,7 @@ class RoomContextHandler(object):
if event_filter: if event_filter:
state_events = event_filter.filter(state_events) state_events = event_filter.filter(state_events)
results["state"] = state_events results["state"] = yield filter_evts(state_events)
# We use a dummy token here as we only care about the room portion of # We use a dummy token here as we only care about the room portion of
# the token, which we replace. # the token, which we replace.

View File

@ -52,7 +52,8 @@ def filter_events_for_client(
apply_retention_policies=True, apply_retention_policies=True,
): ):
""" """
Check which events a user is allowed to see Check which events a user is allowed to see. If the user can see the event but its
sender asked for their data to be erased, prune the content of the event.
Args: Args:
storage storage

View File

@ -29,6 +29,7 @@ import synapse.rest.admin
from synapse.api.constants import EventContentFields, EventTypes, Membership from synapse.api.constants import EventContentFields, EventTypes, Membership
from synapse.handlers.pagination import PurgeStatus from synapse.handlers.pagination import PurgeStatus
from synapse.rest.client.v1 import login, profile, room from synapse.rest.client.v1 import login, profile, room
from synapse.rest.client.v2_alpha import account
from synapse.util.stringutils import random_string from synapse.util.stringutils import random_string
from tests import unittest from tests import unittest
@ -1597,3 +1598,129 @@ class LabelsTestCase(unittest.HomeserverTestCase):
) )
return event_id return event_id
class ContextTestCase(unittest.HomeserverTestCase):
servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource,
room.register_servlets,
login.register_servlets,
account.register_servlets,
]
def prepare(self, reactor, clock, homeserver):
self.user_id = self.register_user("user", "password")
self.tok = self.login("user", "password")
self.room_id = self.helper.create_room_as(self.user_id, tok=self.tok)
self.other_user_id = self.register_user("user2", "password")
self.other_tok = self.login("user2", "password")
self.helper.invite(self.room_id, self.user_id, self.other_user_id, tok=self.tok)
self.helper.join(self.room_id, self.other_user_id, tok=self.other_tok)
def test_erased_sender(self):
"""Test that an erasure request results in the requester's events being hidden
from any new member of the room.
"""
# Send a bunch of events in the room.
self.helper.send(self.room_id, "message 1", tok=self.tok)
self.helper.send(self.room_id, "message 2", tok=self.tok)
event_id = self.helper.send(self.room_id, "message 3", tok=self.tok)["event_id"]
self.helper.send(self.room_id, "message 4", tok=self.tok)
self.helper.send(self.room_id, "message 5", tok=self.tok)
# Check that we can still see the messages before the erasure request.
request, channel = self.make_request(
"GET",
'/rooms/%s/context/%s?filter={"types":["m.room.message"]}'
% (self.room_id, event_id),
access_token=self.tok,
)
self.render(request)
self.assertEqual(channel.code, 200, channel.result)
events_before = channel.json_body["events_before"]
self.assertEqual(len(events_before), 2, events_before)
self.assertEqual(
events_before[0].get("content", {}).get("body"),
"message 2",
events_before[0],
)
self.assertEqual(
events_before[1].get("content", {}).get("body"),
"message 1",
events_before[1],
)
self.assertEqual(
channel.json_body["event"].get("content", {}).get("body"),
"message 3",
channel.json_body["event"],
)
events_after = channel.json_body["events_after"]
self.assertEqual(len(events_after), 2, events_after)
self.assertEqual(
events_after[0].get("content", {}).get("body"),
"message 4",
events_after[0],
)
self.assertEqual(
events_after[1].get("content", {}).get("body"),
"message 5",
events_after[1],
)
# Deactivate the first account and erase the user's data.
deactivate_account_handler = self.hs.get_deactivate_account_handler()
self.get_success(
deactivate_account_handler.deactivate_account(self.user_id, erase_data=True)
)
# Invite another user in the room. This is needed because messages will be
# pruned only if the user wasn't a member of the room when the messages were
# sent.
invited_user_id = self.register_user("user3", "password")
invited_tok = self.login("user3", "password")
self.helper.invite(
self.room_id, self.other_user_id, invited_user_id, tok=self.other_tok
)
self.helper.join(self.room_id, invited_user_id, tok=invited_tok)
# Check that a user that joined the room after the erasure request can't see
# the messages anymore.
request, channel = self.make_request(
"GET",
'/rooms/%s/context/%s?filter={"types":["m.room.message"]}'
% (self.room_id, event_id),
access_token=invited_tok,
)
self.render(request)
self.assertEqual(channel.code, 200, channel.result)
events_before = channel.json_body["events_before"]
self.assertEqual(len(events_before), 2, events_before)
self.assertDictEqual(events_before[0].get("content"), {}, events_before[0])
self.assertDictEqual(events_before[1].get("content"), {}, events_before[1])
self.assertDictEqual(
channel.json_body["event"].get("content"), {}, channel.json_body["event"]
)
events_after = channel.json_body["events_after"]
self.assertEqual(len(events_after), 2, events_after)
self.assertDictEqual(events_after[0].get("content"), {}, events_after[0])
self.assertEqual(events_after[1].get("content"), {}, events_after[1])