|
|
|
@ -151,6 +151,401 @@ class ShutdownRoomTestCase(unittest.HomeserverTestCase): |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DeleteRoomTestCase(unittest.HomeserverTestCase): |
|
|
|
|
servlets = [ |
|
|
|
|
synapse.rest.admin.register_servlets, |
|
|
|
|
login.register_servlets, |
|
|
|
|
events.register_servlets, |
|
|
|
|
room.register_servlets, |
|
|
|
|
room.register_deprecated_servlets, |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
def prepare(self, reactor, clock, hs): |
|
|
|
|
self.event_creation_handler = hs.get_event_creation_handler() |
|
|
|
|
hs.config.user_consent_version = "1" |
|
|
|
|
|
|
|
|
|
consent_uri_builder = Mock() |
|
|
|
|
consent_uri_builder.build_user_consent_uri.return_value = "http://example.com" |
|
|
|
|
self.event_creation_handler._consent_uri_builder = consent_uri_builder |
|
|
|
|
|
|
|
|
|
self.store = hs.get_datastore() |
|
|
|
|
|
|
|
|
|
self.admin_user = self.register_user("admin", "pass", admin=True) |
|
|
|
|
self.admin_user_tok = self.login("admin", "pass") |
|
|
|
|
|
|
|
|
|
self.other_user = self.register_user("user", "pass") |
|
|
|
|
self.other_user_tok = self.login("user", "pass") |
|
|
|
|
|
|
|
|
|
# Mark the admin user as having consented |
|
|
|
|
self.get_success(self.store.user_set_consent_version(self.admin_user, "1")) |
|
|
|
|
|
|
|
|
|
self.room_id = self.helper.create_room_as( |
|
|
|
|
self.other_user, tok=self.other_user_tok |
|
|
|
|
) |
|
|
|
|
self.url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id |
|
|
|
|
|
|
|
|
|
def test_requester_is_no_admin(self): |
|
|
|
|
""" |
|
|
|
|
If the user is not a server admin, an error 403 is returned. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", self.url, json.dumps({}), access_token=self.other_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"]) |
|
|
|
|
|
|
|
|
|
def test_room_does_not_exist(self): |
|
|
|
|
""" |
|
|
|
|
Check that unknown rooms/server return error 404. |
|
|
|
|
""" |
|
|
|
|
url = "/_synapse/admin/v1/rooms/!unknown:test/delete" |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", url, json.dumps({}), access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(404, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"]) |
|
|
|
|
|
|
|
|
|
def test_room_is_not_valid(self): |
|
|
|
|
""" |
|
|
|
|
Check that invalid room names, return an error 400. |
|
|
|
|
""" |
|
|
|
|
url = "/_synapse/admin/v1/rooms/invalidroom/delete" |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", url, json.dumps({}), access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual( |
|
|
|
|
"invalidroom is not a legal room ID", channel.json_body["error"], |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
def test_new_room_user_does_not_exist(self): |
|
|
|
|
""" |
|
|
|
|
Tests that the user ID must be from local server but it does not have to exist. |
|
|
|
|
""" |
|
|
|
|
body = json.dumps({"new_room_user_id": "@unknown:test"}) |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
self.url, |
|
|
|
|
content=body.encode(encoding="utf_8"), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertIn("new_room_id", channel.json_body) |
|
|
|
|
self.assertIn("kicked_users", channel.json_body) |
|
|
|
|
self.assertIn("failed_to_kick_users", channel.json_body) |
|
|
|
|
self.assertIn("local_aliases", channel.json_body) |
|
|
|
|
|
|
|
|
|
def test_new_room_user_is_not_local(self): |
|
|
|
|
""" |
|
|
|
|
Check that only local users can create new room to move members. |
|
|
|
|
""" |
|
|
|
|
body = json.dumps({"new_room_user_id": "@not:exist.bla"}) |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
self.url, |
|
|
|
|
content=body.encode(encoding="utf_8"), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual( |
|
|
|
|
"User must be our own: @not:exist.bla", channel.json_body["error"], |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
def test_block_is_not_bool(self): |
|
|
|
|
""" |
|
|
|
|
If parameter `block` is not boolean, return an error |
|
|
|
|
""" |
|
|
|
|
body = json.dumps({"block": "NotBool"}) |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
self.url, |
|
|
|
|
content=body.encode(encoding="utf_8"), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(400, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(Codes.BAD_JSON, channel.json_body["errcode"]) |
|
|
|
|
|
|
|
|
|
def test_purge_room_and_block(self): |
|
|
|
|
"""Test to purge a room and block it. |
|
|
|
|
Members will not be moved to a new room and will not receive a message. |
|
|
|
|
""" |
|
|
|
|
# Test that room is not purged |
|
|
|
|
with self.assertRaises(AssertionError): |
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
|
|
|
|
|
# Test that room is not blocked |
|
|
|
|
self._is_blocked(self.room_id, expect=False) |
|
|
|
|
|
|
|
|
|
# Assert one user in room |
|
|
|
|
self._is_member(room_id=self.room_id, user_id=self.other_user) |
|
|
|
|
|
|
|
|
|
body = json.dumps({"block": True}) |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
self.url.encode("ascii"), |
|
|
|
|
content=body.encode(encoding="utf_8"), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(None, channel.json_body["new_room_id"]) |
|
|
|
|
self.assertEqual(self.other_user, channel.json_body["kicked_users"][0]) |
|
|
|
|
self.assertIn("failed_to_kick_users", channel.json_body) |
|
|
|
|
self.assertIn("local_aliases", channel.json_body) |
|
|
|
|
|
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
self._is_blocked(self.room_id, expect=True) |
|
|
|
|
self._has_no_members(self.room_id) |
|
|
|
|
|
|
|
|
|
def test_purge_room_and_not_block(self): |
|
|
|
|
"""Test to purge a room and do not block it. |
|
|
|
|
Members will not be moved to a new room and will not receive a message. |
|
|
|
|
""" |
|
|
|
|
# Test that room is not purged |
|
|
|
|
with self.assertRaises(AssertionError): |
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
|
|
|
|
|
# Test that room is not blocked |
|
|
|
|
self._is_blocked(self.room_id, expect=False) |
|
|
|
|
|
|
|
|
|
# Assert one user in room |
|
|
|
|
self._is_member(room_id=self.room_id, user_id=self.other_user) |
|
|
|
|
|
|
|
|
|
body = json.dumps({"block": False}) |
|
|
|
|
|
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
self.url.encode("ascii"), |
|
|
|
|
content=body.encode(encoding="utf_8"), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(None, channel.json_body["new_room_id"]) |
|
|
|
|
self.assertEqual(self.other_user, channel.json_body["kicked_users"][0]) |
|
|
|
|
self.assertIn("failed_to_kick_users", channel.json_body) |
|
|
|
|
self.assertIn("local_aliases", channel.json_body) |
|
|
|
|
|
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
self._is_blocked(self.room_id, expect=False) |
|
|
|
|
self._has_no_members(self.room_id) |
|
|
|
|
|
|
|
|
|
def test_shutdown_room_consent(self): |
|
|
|
|
"""Test that we can shutdown rooms with local users who have not |
|
|
|
|
yet accepted the privacy policy. This used to fail when we tried to |
|
|
|
|
force part the user from the old room. |
|
|
|
|
Members will be moved to a new room and will receive a message. |
|
|
|
|
""" |
|
|
|
|
self.event_creation_handler._block_events_without_consent_error = None |
|
|
|
|
|
|
|
|
|
# Assert one user in room |
|
|
|
|
users_in_room = self.get_success(self.store.get_users_in_room(self.room_id)) |
|
|
|
|
self.assertEqual([self.other_user], users_in_room) |
|
|
|
|
|
|
|
|
|
# Enable require consent to send events |
|
|
|
|
self.event_creation_handler._block_events_without_consent_error = "Error" |
|
|
|
|
|
|
|
|
|
# Assert that the user is getting consent error |
|
|
|
|
self.helper.send( |
|
|
|
|
self.room_id, body="foo", tok=self.other_user_tok, expect_code=403 |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
# Test that room is not purged |
|
|
|
|
with self.assertRaises(AssertionError): |
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
|
|
|
|
|
# Assert one user in room |
|
|
|
|
self._is_member(room_id=self.room_id, user_id=self.other_user) |
|
|
|
|
|
|
|
|
|
# Test that the admin can still send shutdown |
|
|
|
|
url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id |
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
url.encode("ascii"), |
|
|
|
|
json.dumps({"new_room_user_id": self.admin_user}), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(self.other_user, channel.json_body["kicked_users"][0]) |
|
|
|
|
self.assertIn("new_room_id", channel.json_body) |
|
|
|
|
self.assertIn("failed_to_kick_users", channel.json_body) |
|
|
|
|
self.assertIn("local_aliases", channel.json_body) |
|
|
|
|
|
|
|
|
|
# Test that member has moved to new room |
|
|
|
|
self._is_member( |
|
|
|
|
room_id=channel.json_body["new_room_id"], user_id=self.other_user |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
self._has_no_members(self.room_id) |
|
|
|
|
|
|
|
|
|
def test_shutdown_room_block_peek(self): |
|
|
|
|
"""Test that a world_readable room can no longer be peeked into after |
|
|
|
|
it has been shut down. |
|
|
|
|
Members will be moved to a new room and will receive a message. |
|
|
|
|
""" |
|
|
|
|
self.event_creation_handler._block_events_without_consent_error = None |
|
|
|
|
|
|
|
|
|
# Enable world readable |
|
|
|
|
url = "rooms/%s/state/m.room.history_visibility" % (self.room_id,) |
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"PUT", |
|
|
|
|
url.encode("ascii"), |
|
|
|
|
json.dumps({"history_visibility": "world_readable"}), |
|
|
|
|
access_token=self.other_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
|
|
|
|
|
# Test that room is not purged |
|
|
|
|
with self.assertRaises(AssertionError): |
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
|
|
|
|
|
# Assert one user in room |
|
|
|
|
self._is_member(room_id=self.room_id, user_id=self.other_user) |
|
|
|
|
|
|
|
|
|
# Test that the admin can still send shutdown |
|
|
|
|
url = "/_synapse/admin/v1/rooms/%s/delete" % self.room_id |
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"POST", |
|
|
|
|
url.encode("ascii"), |
|
|
|
|
json.dumps({"new_room_user_id": self.admin_user}), |
|
|
|
|
access_token=self.admin_user_tok, |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
|
|
|
|
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"]) |
|
|
|
|
self.assertEqual(self.other_user, channel.json_body["kicked_users"][0]) |
|
|
|
|
self.assertIn("new_room_id", channel.json_body) |
|
|
|
|
self.assertIn("failed_to_kick_users", channel.json_body) |
|
|
|
|
self.assertIn("local_aliases", channel.json_body) |
|
|
|
|
|
|
|
|
|
# Test that member has moved to new room |
|
|
|
|
self._is_member( |
|
|
|
|
room_id=channel.json_body["new_room_id"], user_id=self.other_user |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
self._is_purged(self.room_id) |
|
|
|
|
self._has_no_members(self.room_id) |
|
|
|
|
|
|
|
|
|
# Assert we can no longer peek into the room |
|
|
|
|
self._assert_peek(self.room_id, expect_code=403) |
|
|
|
|
|
|
|
|
|
def _is_blocked(self, room_id, expect=True): |
|
|
|
|
"""Assert that the room is blocked or not |
|
|
|
|
""" |
|
|
|
|
d = self.store.is_room_blocked(room_id) |
|
|
|
|
if expect: |
|
|
|
|
self.assertTrue(self.get_success(d)) |
|
|
|
|
else: |
|
|
|
|
self.assertIsNone(self.get_success(d)) |
|
|
|
|
|
|
|
|
|
def _has_no_members(self, room_id): |
|
|
|
|
"""Assert there is now no longer anyone in the room |
|
|
|
|
""" |
|
|
|
|
users_in_room = self.get_success(self.store.get_users_in_room(room_id)) |
|
|
|
|
self.assertEqual([], users_in_room) |
|
|
|
|
|
|
|
|
|
def _is_member(self, room_id, user_id): |
|
|
|
|
"""Test that user is member of the room |
|
|
|
|
""" |
|
|
|
|
users_in_room = self.get_success(self.store.get_users_in_room(room_id)) |
|
|
|
|
self.assertIn(user_id, users_in_room) |
|
|
|
|
|
|
|
|
|
def _is_purged(self, room_id): |
|
|
|
|
"""Test that the following tables have been purged of all rows related to the room. |
|
|
|
|
""" |
|
|
|
|
for table in ( |
|
|
|
|
"current_state_events", |
|
|
|
|
"event_backward_extremities", |
|
|
|
|
"event_forward_extremities", |
|
|
|
|
"event_json", |
|
|
|
|
"event_push_actions", |
|
|
|
|
"event_search", |
|
|
|
|
"events", |
|
|
|
|
"group_rooms", |
|
|
|
|
"public_room_list_stream", |
|
|
|
|
"receipts_graph", |
|
|
|
|
"receipts_linearized", |
|
|
|
|
"room_aliases", |
|
|
|
|
"room_depth", |
|
|
|
|
"room_memberships", |
|
|
|
|
"room_stats_state", |
|
|
|
|
"room_stats_current", |
|
|
|
|
"room_stats_historical", |
|
|
|
|
"room_stats_earliest_token", |
|
|
|
|
"rooms", |
|
|
|
|
"stream_ordering_to_exterm", |
|
|
|
|
"users_in_public_rooms", |
|
|
|
|
"users_who_share_private_rooms", |
|
|
|
|
"appservice_room_list", |
|
|
|
|
"e2e_room_keys", |
|
|
|
|
"event_push_summary", |
|
|
|
|
"pusher_throttle", |
|
|
|
|
"group_summary_rooms", |
|
|
|
|
"local_invites", |
|
|
|
|
"room_account_data", |
|
|
|
|
"room_tags", |
|
|
|
|
# "state_groups", # Current impl leaves orphaned state groups around. |
|
|
|
|
"state_groups_state", |
|
|
|
|
): |
|
|
|
|
count = self.get_success( |
|
|
|
|
self.store.db.simple_select_one_onecol( |
|
|
|
|
table=table, |
|
|
|
|
keyvalues={"room_id": room_id}, |
|
|
|
|
retcol="COUNT(*)", |
|
|
|
|
desc="test_purge_room", |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
self.assertEqual(count, 0, msg="Rows not purged in {}".format(table)) |
|
|
|
|
|
|
|
|
|
def _assert_peek(self, room_id, expect_code): |
|
|
|
|
"""Assert that the admin user can (or cannot) peek into the room. |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
url = "rooms/%s/initialSync" % (room_id,) |
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"GET", url.encode("ascii"), access_token=self.admin_user_tok |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
self.assertEqual( |
|
|
|
|
expect_code, int(channel.result["code"]), msg=channel.result["body"] |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
url = "events?timeout=0&room_id=" + room_id |
|
|
|
|
request, channel = self.make_request( |
|
|
|
|
"GET", url.encode("ascii"), access_token=self.admin_user_tok |
|
|
|
|
) |
|
|
|
|
self.render(request) |
|
|
|
|
self.assertEqual( |
|
|
|
|
expect_code, int(channel.result["code"]), msg=channel.result["body"] |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PurgeRoomTestCase(unittest.HomeserverTestCase): |
|
|
|
|
"""Test /purge_room admin API. |
|
|
|
|
""" |
|
|
|
|