Add admin handler to list of handlers used for background tasks (#17847)
Fixes #17823 While we're at it, makes a change where the redactions are sent as the admin if the user is not a member of the server (otherwise these fail with a "User must be our own" message).
This commit is contained in:
parent
d427403c67
commit
58deef5eba
|
@ -0,0 +1,2 @@
|
||||||
|
Fix a bug in the admin redact endpoint where the background task would not run if a worker was specified in
|
||||||
|
the config option `run_background_tasks_on`.
|
|
@ -1365,6 +1365,9 @@ _Added in Synapse 1.72.0._
|
||||||
|
|
||||||
## Redact all the events of a user
|
## Redact all the events of a user
|
||||||
|
|
||||||
|
This endpoint allows an admin to redact the events of a given user. There are no restrictions on redactions for a
|
||||||
|
local user. By default, we puppet the user who sent the message to redact it themselves. Redactions for non-local users are issued using the admin user, and will fail in rooms where the admin user is not admin/does not have the specified power level to issue redactions.
|
||||||
|
|
||||||
The API is
|
The API is
|
||||||
```
|
```
|
||||||
POST /_synapse/admin/v1/user/$user_id/redact
|
POST /_synapse/admin/v1/user/$user_id/redact
|
||||||
|
|
|
@ -73,6 +73,8 @@ class AdminHandler:
|
||||||
self._redact_all_events, REDACT_ALL_EVENTS_ACTION_NAME
|
self._redact_all_events, REDACT_ALL_EVENTS_ACTION_NAME
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.hs = hs
|
||||||
|
|
||||||
async def get_redact_task(self, redact_id: str) -> Optional[ScheduledTask]:
|
async def get_redact_task(self, redact_id: str) -> Optional[ScheduledTask]:
|
||||||
"""Get the current status of an active redaction process
|
"""Get the current status of an active redaction process
|
||||||
|
|
||||||
|
@ -423,8 +425,10 @@ class AdminHandler:
|
||||||
user_id = task.params.get("user_id")
|
user_id = task.params.get("user_id")
|
||||||
assert user_id is not None
|
assert user_id is not None
|
||||||
|
|
||||||
|
# puppet the user if they're ours, otherwise use admin to redact
|
||||||
requester = create_requester(
|
requester = create_requester(
|
||||||
user_id, authenticated_entity=admin.user.to_string()
|
user_id if self.hs.is_mine_id(user_id) else admin.user.to_string(),
|
||||||
|
authenticated_entity=admin.user.to_string(),
|
||||||
)
|
)
|
||||||
|
|
||||||
reason = task.params.get("reason")
|
reason = task.params.get("reason")
|
||||||
|
|
|
@ -249,6 +249,7 @@ class HomeServer(metaclass=abc.ABCMeta):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
REQUIRED_ON_BACKGROUND_TASK_STARTUP = [
|
REQUIRED_ON_BACKGROUND_TASK_STARTUP = [
|
||||||
|
"admin",
|
||||||
"account_validity",
|
"account_validity",
|
||||||
"auth",
|
"auth",
|
||||||
"deactivate_account",
|
"deactivate_account",
|
||||||
|
|
|
@ -23,6 +23,7 @@ import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
@ -56,6 +57,7 @@ from synapse.types import JsonDict, UserID, create_requester
|
||||||
from synapse.util import Clock
|
from synapse.util import Clock
|
||||||
|
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
|
from tests.replication._base import BaseMultiWorkerStreamTestCase
|
||||||
from tests.test_utils import SMALL_PNG
|
from tests.test_utils import SMALL_PNG
|
||||||
from tests.unittest import override_config
|
from tests.unittest import override_config
|
||||||
|
|
||||||
|
@ -5127,7 +5129,6 @@ class UserRedactionTestCase(unittest.HomeserverTestCase):
|
||||||
"""
|
"""
|
||||||
Test that request to redact events in all rooms user is member of is successful
|
Test that request to redact events in all rooms user is member of is successful
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# join rooms, send some messages
|
# join rooms, send some messages
|
||||||
originals = []
|
originals = []
|
||||||
for rm in [self.rm1, self.rm2, self.rm3]:
|
for rm in [self.rm1, self.rm2, self.rm3]:
|
||||||
|
@ -5404,3 +5405,98 @@ class UserRedactionTestCase(unittest.HomeserverTestCase):
|
||||||
matches.append((event_id, event))
|
matches.append((event_id, event))
|
||||||
# we redacted 6 messages
|
# we redacted 6 messages
|
||||||
self.assertEqual(len(matches), 6)
|
self.assertEqual(len(matches), 6)
|
||||||
|
|
||||||
|
|
||||||
|
class UserRedactionBackgroundTaskTestCase(BaseMultiWorkerStreamTestCase):
|
||||||
|
servlets = [
|
||||||
|
synapse.rest.admin.register_servlets,
|
||||||
|
login.register_servlets,
|
||||||
|
admin.register_servlets,
|
||||||
|
room.register_servlets,
|
||||||
|
sync.register_servlets,
|
||||||
|
]
|
||||||
|
|
||||||
|
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
|
||||||
|
self.admin = self.register_user("thomas", "pass", True)
|
||||||
|
self.admin_tok = self.login("thomas", "pass")
|
||||||
|
|
||||||
|
self.bad_user = self.register_user("teresa", "pass")
|
||||||
|
self.bad_user_tok = self.login("teresa", "pass")
|
||||||
|
|
||||||
|
# create rooms - room versions 11+ store the `redacts` key in content while
|
||||||
|
# earlier ones don't so we use a mix of room versions
|
||||||
|
self.rm1 = self.helper.create_room_as(
|
||||||
|
self.admin, tok=self.admin_tok, room_version="7"
|
||||||
|
)
|
||||||
|
self.rm2 = self.helper.create_room_as(self.admin, tok=self.admin_tok)
|
||||||
|
self.rm3 = self.helper.create_room_as(
|
||||||
|
self.admin, tok=self.admin_tok, room_version="11"
|
||||||
|
)
|
||||||
|
|
||||||
|
@override_config({"run_background_tasks_on": "worker1"})
|
||||||
|
def test_redact_messages_all_rooms(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that redact task successfully runs when `run_background_tasks_on` is specified
|
||||||
|
"""
|
||||||
|
self.make_worker_hs(
|
||||||
|
"synapse.app.generic_worker",
|
||||||
|
extra_config={
|
||||||
|
"worker_name": "worker1",
|
||||||
|
"run_background_tasks_on": "worker1",
|
||||||
|
"redis": {"enabled": True},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# join rooms, send some messages
|
||||||
|
original_event_ids = set()
|
||||||
|
for rm in [self.rm1, self.rm2, self.rm3]:
|
||||||
|
join = self.helper.join(rm, self.bad_user, tok=self.bad_user_tok)
|
||||||
|
original_event_ids.add(join["event_id"])
|
||||||
|
for i in range(15):
|
||||||
|
event = {"body": f"hello{i}", "msgtype": "m.text"}
|
||||||
|
res = self.helper.send_event(
|
||||||
|
rm, "m.room.message", event, tok=self.bad_user_tok, expect_code=200
|
||||||
|
)
|
||||||
|
original_event_ids.add(res["event_id"])
|
||||||
|
|
||||||
|
# redact all events in all rooms
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
f"/_synapse/admin/v1/user/{self.bad_user}/redact",
|
||||||
|
content={"rooms": []},
|
||||||
|
access_token=self.admin_tok,
|
||||||
|
)
|
||||||
|
self.assertEqual(channel.code, 200)
|
||||||
|
id = channel.json_body.get("redact_id")
|
||||||
|
|
||||||
|
timeout_s = 10
|
||||||
|
start_time = time.time()
|
||||||
|
redact_result = ""
|
||||||
|
while redact_result != "complete":
|
||||||
|
if start_time + timeout_s < time.time():
|
||||||
|
self.fail("Timed out waiting for redactions.")
|
||||||
|
|
||||||
|
channel2 = self.make_request(
|
||||||
|
"GET",
|
||||||
|
f"/_synapse/admin/v1/user/redact_status/{id}",
|
||||||
|
access_token=self.admin_tok,
|
||||||
|
)
|
||||||
|
redact_result = channel2.json_body["status"]
|
||||||
|
if redact_result == "failed":
|
||||||
|
self.fail("Redaction task failed.")
|
||||||
|
|
||||||
|
redaction_ids = set()
|
||||||
|
for rm in [self.rm1, self.rm2, self.rm3]:
|
||||||
|
filter = json.dumps({"types": [EventTypes.Redaction]})
|
||||||
|
channel = self.make_request(
|
||||||
|
"GET",
|
||||||
|
f"rooms/{rm}/messages?filter={filter}&limit=50",
|
||||||
|
access_token=self.admin_tok,
|
||||||
|
)
|
||||||
|
self.assertEqual(channel.code, 200)
|
||||||
|
|
||||||
|
for event in channel.json_body["chunk"]:
|
||||||
|
if event["type"] == "m.room.redaction":
|
||||||
|
redaction_ids.add(event["redacts"])
|
||||||
|
|
||||||
|
self.assertIncludes(redaction_ids, original_event_ids, exact=True)
|
||||||
|
|
Loading…
Reference in New Issue