forked from MirrorHub/synapse
Merge release-v1.7.1 into develop
This commit is contained in:
commit
6e8f8e14f2
7 changed files with 145 additions and 10 deletions
1
changelog.d/6553.bugfix
Normal file
1
changelog.d/6553.bugfix
Normal 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
1
changelog.d/6560.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix a cause of state resets in room versions 2 onwards.
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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])
|
||||||
|
|
Loading…
Reference in a new issue