admin.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. # Copyright 2018 New Vector Ltd
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. from twisted.internet import defer
  17. from six.moves import http_client
  18. from synapse.api.constants import Membership
  19. from synapse.api.errors import AuthError, SynapseError, Codes, NotFoundError
  20. from synapse.types import UserID, create_requester
  21. from synapse.http.servlet import parse_json_object_from_request
  22. from .base import ClientV1RestServlet, client_path_patterns
  23. import logging
  24. logger = logging.getLogger(__name__)
  25. class UsersRestServlet(ClientV1RestServlet):
  26. PATTERNS = client_path_patterns("/admin/users/(?P<user_id>[^/]*)")
  27. def __init__(self, hs):
  28. super(UsersRestServlet, self).__init__(hs)
  29. self.handlers = hs.get_handlers()
  30. @defer.inlineCallbacks
  31. def on_GET(self, request, user_id):
  32. target_user = UserID.from_string(user_id)
  33. requester = yield self.auth.get_user_by_req(request)
  34. is_admin = yield self.auth.is_server_admin(requester.user)
  35. if not is_admin:
  36. raise AuthError(403, "You are not a server admin")
  37. # To allow all users to get the users list
  38. # if not is_admin and target_user != auth_user:
  39. # raise AuthError(403, "You are not a server admin")
  40. if not self.hs.is_mine(target_user):
  41. raise SynapseError(400, "Can only users a local user")
  42. ret = yield self.handlers.admin_handler.get_users()
  43. defer.returnValue((200, ret))
  44. class WhoisRestServlet(ClientV1RestServlet):
  45. PATTERNS = client_path_patterns("/admin/whois/(?P<user_id>[^/]*)")
  46. def __init__(self, hs):
  47. super(WhoisRestServlet, self).__init__(hs)
  48. self.handlers = hs.get_handlers()
  49. @defer.inlineCallbacks
  50. def on_GET(self, request, user_id):
  51. target_user = UserID.from_string(user_id)
  52. requester = yield self.auth.get_user_by_req(request)
  53. auth_user = requester.user
  54. is_admin = yield self.auth.is_server_admin(requester.user)
  55. if not is_admin and target_user != auth_user:
  56. raise AuthError(403, "You are not a server admin")
  57. if not self.hs.is_mine(target_user):
  58. raise SynapseError(400, "Can only whois a local user")
  59. ret = yield self.handlers.admin_handler.get_whois(target_user)
  60. defer.returnValue((200, ret))
  61. class PurgeMediaCacheRestServlet(ClientV1RestServlet):
  62. PATTERNS = client_path_patterns("/admin/purge_media_cache")
  63. def __init__(self, hs):
  64. self.media_repository = hs.get_media_repository()
  65. super(PurgeMediaCacheRestServlet, self).__init__(hs)
  66. @defer.inlineCallbacks
  67. def on_POST(self, request):
  68. requester = yield self.auth.get_user_by_req(request)
  69. is_admin = yield self.auth.is_server_admin(requester.user)
  70. if not is_admin:
  71. raise AuthError(403, "You are not a server admin")
  72. before_ts = request.args.get("before_ts", None)
  73. if not before_ts:
  74. raise SynapseError(400, "Missing 'before_ts' arg")
  75. logger.info("before_ts: %r", before_ts[0])
  76. try:
  77. before_ts = int(before_ts[0])
  78. except Exception:
  79. raise SynapseError(400, "Invalid 'before_ts' arg")
  80. ret = yield self.media_repository.delete_old_remote_media(before_ts)
  81. defer.returnValue((200, ret))
  82. class PurgeHistoryRestServlet(ClientV1RestServlet):
  83. PATTERNS = client_path_patterns(
  84. "/admin/purge_history/(?P<room_id>[^/]*)(/(?P<event_id>[^/]+))?"
  85. )
  86. def __init__(self, hs):
  87. """
  88. Args:
  89. hs (synapse.server.HomeServer)
  90. """
  91. super(PurgeHistoryRestServlet, self).__init__(hs)
  92. self.handlers = hs.get_handlers()
  93. self.store = hs.get_datastore()
  94. @defer.inlineCallbacks
  95. def on_POST(self, request, room_id, event_id):
  96. requester = yield self.auth.get_user_by_req(request)
  97. is_admin = yield self.auth.is_server_admin(requester.user)
  98. if not is_admin:
  99. raise AuthError(403, "You are not a server admin")
  100. body = parse_json_object_from_request(request, allow_empty_body=True)
  101. delete_local_events = bool(body.get("delete_local_events", False))
  102. # establish the topological ordering we should keep events from. The
  103. # user can provide an event_id in the URL or the request body, or can
  104. # provide a timestamp in the request body.
  105. if event_id is None:
  106. event_id = body.get('purge_up_to_event_id')
  107. if event_id is not None:
  108. event = yield self.store.get_event(event_id)
  109. if event.room_id != room_id:
  110. raise SynapseError(400, "Event is for wrong room.")
  111. token = yield self.store.get_topological_token_for_event(event_id)
  112. logger.info(
  113. "[purge] purging up to token %s (event_id %s)",
  114. token, event_id,
  115. )
  116. elif 'purge_up_to_ts' in body:
  117. ts = body['purge_up_to_ts']
  118. if not isinstance(ts, int):
  119. raise SynapseError(
  120. 400, "purge_up_to_ts must be an int",
  121. errcode=Codes.BAD_JSON,
  122. )
  123. stream_ordering = (
  124. yield self.store.find_first_stream_ordering_after_ts(ts)
  125. )
  126. r = (
  127. yield self.store.get_room_event_after_stream_ordering(
  128. room_id, stream_ordering,
  129. )
  130. )
  131. if not r:
  132. logger.warn(
  133. "[purge] purging events not possible: No event found "
  134. "(received_ts %i => stream_ordering %i)",
  135. ts, stream_ordering,
  136. )
  137. raise SynapseError(
  138. 404,
  139. "there is no event to be purged",
  140. errcode=Codes.NOT_FOUND,
  141. )
  142. (stream, topo, _event_id) = r
  143. token = "t%d-%d" % (topo, stream)
  144. logger.info(
  145. "[purge] purging up to token %s (received_ts %i => "
  146. "stream_ordering %i)",
  147. token, ts, stream_ordering,
  148. )
  149. else:
  150. raise SynapseError(
  151. 400,
  152. "must specify purge_up_to_event_id or purge_up_to_ts",
  153. errcode=Codes.BAD_JSON,
  154. )
  155. purge_id = yield self.handlers.message_handler.start_purge_history(
  156. room_id, token,
  157. delete_local_events=delete_local_events,
  158. )
  159. defer.returnValue((200, {
  160. "purge_id": purge_id,
  161. }))
  162. class PurgeHistoryStatusRestServlet(ClientV1RestServlet):
  163. PATTERNS = client_path_patterns(
  164. "/admin/purge_history_status/(?P<purge_id>[^/]+)"
  165. )
  166. def __init__(self, hs):
  167. """
  168. Args:
  169. hs (synapse.server.HomeServer)
  170. """
  171. super(PurgeHistoryStatusRestServlet, self).__init__(hs)
  172. self.handlers = hs.get_handlers()
  173. @defer.inlineCallbacks
  174. def on_GET(self, request, purge_id):
  175. requester = yield self.auth.get_user_by_req(request)
  176. is_admin = yield self.auth.is_server_admin(requester.user)
  177. if not is_admin:
  178. raise AuthError(403, "You are not a server admin")
  179. purge_status = self.handlers.message_handler.get_purge_status(purge_id)
  180. if purge_status is None:
  181. raise NotFoundError("purge id '%s' not found" % purge_id)
  182. defer.returnValue((200, purge_status.asdict()))
  183. class DeactivateAccountRestServlet(ClientV1RestServlet):
  184. PATTERNS = client_path_patterns("/admin/deactivate/(?P<target_user_id>[^/]*)")
  185. def __init__(self, hs):
  186. super(DeactivateAccountRestServlet, self).__init__(hs)
  187. self._deactivate_account_handler = hs.get_deactivate_account_handler()
  188. @defer.inlineCallbacks
  189. def on_POST(self, request, target_user_id):
  190. body = parse_json_object_from_request(request, allow_empty_body=True)
  191. erase = body.get("erase", False)
  192. if not isinstance(erase, bool):
  193. raise SynapseError(
  194. http_client.BAD_REQUEST,
  195. "Param 'erase' must be a boolean, if given",
  196. Codes.BAD_JSON,
  197. )
  198. UserID.from_string(target_user_id)
  199. requester = yield self.auth.get_user_by_req(request)
  200. is_admin = yield self.auth.is_server_admin(requester.user)
  201. if not is_admin:
  202. raise AuthError(403, "You are not a server admin")
  203. yield self._deactivate_account_handler.deactivate_account(
  204. target_user_id, erase,
  205. )
  206. defer.returnValue((200, {}))
  207. class ShutdownRoomRestServlet(ClientV1RestServlet):
  208. """Shuts down a room by removing all local users from the room and blocking
  209. all future invites and joins to the room. Any local aliases will be repointed
  210. to a new room created by `new_room_user_id` and kicked users will be auto
  211. joined to the new room.
  212. """
  213. PATTERNS = client_path_patterns("/admin/shutdown_room/(?P<room_id>[^/]+)")
  214. DEFAULT_MESSAGE = (
  215. "Sharing illegal content on this server is not permitted and rooms in"
  216. " violation will be blocked."
  217. )
  218. def __init__(self, hs):
  219. super(ShutdownRoomRestServlet, self).__init__(hs)
  220. self.store = hs.get_datastore()
  221. self.state = hs.get_state_handler()
  222. self._room_creation_handler = hs.get_room_creation_handler()
  223. self.event_creation_handler = hs.get_event_creation_handler()
  224. self.room_member_handler = hs.get_room_member_handler()
  225. @defer.inlineCallbacks
  226. def on_POST(self, request, room_id):
  227. requester = yield self.auth.get_user_by_req(request)
  228. is_admin = yield self.auth.is_server_admin(requester.user)
  229. if not is_admin:
  230. raise AuthError(403, "You are not a server admin")
  231. content = parse_json_object_from_request(request)
  232. new_room_user_id = content.get("new_room_user_id")
  233. if not new_room_user_id:
  234. raise SynapseError(400, "Please provide field `new_room_user_id`")
  235. room_creator_requester = create_requester(new_room_user_id)
  236. message = content.get("message", self.DEFAULT_MESSAGE)
  237. room_name = content.get("room_name", "Content Violation Notification")
  238. info = yield self._room_creation_handler.create_room(
  239. room_creator_requester,
  240. config={
  241. "preset": "public_chat",
  242. "name": room_name,
  243. "power_level_content_override": {
  244. "users_default": -10,
  245. },
  246. },
  247. ratelimit=False,
  248. )
  249. new_room_id = info["room_id"]
  250. yield self.event_creation_handler.create_and_send_nonmember_event(
  251. room_creator_requester,
  252. {
  253. "type": "m.room.message",
  254. "content": {"body": message, "msgtype": "m.text"},
  255. "room_id": new_room_id,
  256. "sender": new_room_user_id,
  257. },
  258. ratelimit=False,
  259. )
  260. requester_user_id = requester.user.to_string()
  261. logger.info("Shutting down room %r", room_id)
  262. yield self.store.block_room(room_id, requester_user_id)
  263. users = yield self.state.get_current_user_in_room(room_id)
  264. kicked_users = []
  265. for user_id in users:
  266. if not self.hs.is_mine_id(user_id):
  267. continue
  268. logger.info("Kicking %r from %r...", user_id, room_id)
  269. target_requester = create_requester(user_id)
  270. yield self.room_member_handler.update_membership(
  271. requester=target_requester,
  272. target=target_requester.user,
  273. room_id=room_id,
  274. action=Membership.LEAVE,
  275. content={},
  276. ratelimit=False
  277. )
  278. yield self.room_member_handler.forget(target_requester.user, room_id)
  279. yield self.room_member_handler.update_membership(
  280. requester=target_requester,
  281. target=target_requester.user,
  282. room_id=new_room_id,
  283. action=Membership.JOIN,
  284. content={},
  285. ratelimit=False
  286. )
  287. kicked_users.append(user_id)
  288. aliases_for_room = yield self.store.get_aliases_for_room(room_id)
  289. yield self.store.update_aliases_for_room(
  290. room_id, new_room_id, requester_user_id
  291. )
  292. defer.returnValue((200, {
  293. "kicked_users": kicked_users,
  294. "local_aliases": aliases_for_room,
  295. "new_room_id": new_room_id,
  296. }))
  297. class QuarantineMediaInRoom(ClientV1RestServlet):
  298. """Quarantines all media in a room so that no one can download it via
  299. this server.
  300. """
  301. PATTERNS = client_path_patterns("/admin/quarantine_media/(?P<room_id>[^/]+)")
  302. def __init__(self, hs):
  303. super(QuarantineMediaInRoom, self).__init__(hs)
  304. self.store = hs.get_datastore()
  305. @defer.inlineCallbacks
  306. def on_POST(self, request, room_id):
  307. requester = yield self.auth.get_user_by_req(request)
  308. is_admin = yield self.auth.is_server_admin(requester.user)
  309. if not is_admin:
  310. raise AuthError(403, "You are not a server admin")
  311. num_quarantined = yield self.store.quarantine_media_ids_in_room(
  312. room_id, requester.user.to_string(),
  313. )
  314. defer.returnValue((200, {"num_quarantined": num_quarantined}))
  315. class ListMediaInRoom(ClientV1RestServlet):
  316. """Lists all of the media in a given room.
  317. """
  318. PATTERNS = client_path_patterns("/admin/room/(?P<room_id>[^/]+)/media")
  319. def __init__(self, hs):
  320. super(ListMediaInRoom, self).__init__(hs)
  321. self.store = hs.get_datastore()
  322. @defer.inlineCallbacks
  323. def on_GET(self, request, room_id):
  324. requester = yield self.auth.get_user_by_req(request)
  325. is_admin = yield self.auth.is_server_admin(requester.user)
  326. if not is_admin:
  327. raise AuthError(403, "You are not a server admin")
  328. local_mxcs, remote_mxcs = yield self.store.get_media_mxcs_in_room(room_id)
  329. defer.returnValue((200, {"local": local_mxcs, "remote": remote_mxcs}))
  330. class ResetPasswordRestServlet(ClientV1RestServlet):
  331. """Post request to allow an administrator reset password for a user.
  332. This needs user to have administrator access in Synapse.
  333. Example:
  334. http://localhost:8008/_matrix/client/api/v1/admin/reset_password/
  335. @user:to_reset_password?access_token=admin_access_token
  336. JsonBodyToSend:
  337. {
  338. "new_password": "secret"
  339. }
  340. Returns:
  341. 200 OK with empty object if success otherwise an error.
  342. """
  343. PATTERNS = client_path_patterns("/admin/reset_password/(?P<target_user_id>[^/]*)")
  344. def __init__(self, hs):
  345. self.store = hs.get_datastore()
  346. super(ResetPasswordRestServlet, self).__init__(hs)
  347. self.hs = hs
  348. self.auth = hs.get_auth()
  349. self._set_password_handler = hs.get_set_password_handler()
  350. @defer.inlineCallbacks
  351. def on_POST(self, request, target_user_id):
  352. """Post request to allow an administrator reset password for a user.
  353. This needs user to have administrator access in Synapse.
  354. """
  355. UserID.from_string(target_user_id)
  356. requester = yield self.auth.get_user_by_req(request)
  357. is_admin = yield self.auth.is_server_admin(requester.user)
  358. if not is_admin:
  359. raise AuthError(403, "You are not a server admin")
  360. params = parse_json_object_from_request(request)
  361. new_password = params['new_password']
  362. if not new_password:
  363. raise SynapseError(400, "Missing 'new_password' arg")
  364. logger.info("new_password: %r", new_password)
  365. yield self._set_password_handler.set_password(
  366. target_user_id, new_password, requester
  367. )
  368. defer.returnValue((200, {}))
  369. class GetUsersPaginatedRestServlet(ClientV1RestServlet):
  370. """Get request to get specific number of users from Synapse.
  371. This needs user to have administrator access in Synapse.
  372. Example:
  373. http://localhost:8008/_matrix/client/api/v1/admin/users_paginate/
  374. @admin:user?access_token=admin_access_token&start=0&limit=10
  375. Returns:
  376. 200 OK with json object {list[dict[str, Any]], count} or empty object.
  377. """
  378. PATTERNS = client_path_patterns("/admin/users_paginate/(?P<target_user_id>[^/]*)")
  379. def __init__(self, hs):
  380. self.store = hs.get_datastore()
  381. super(GetUsersPaginatedRestServlet, self).__init__(hs)
  382. self.hs = hs
  383. self.auth = hs.get_auth()
  384. self.handlers = hs.get_handlers()
  385. @defer.inlineCallbacks
  386. def on_GET(self, request, target_user_id):
  387. """Get request to get specific number of users from Synapse.
  388. This needs user to have administrator access in Synapse.
  389. """
  390. target_user = UserID.from_string(target_user_id)
  391. requester = yield self.auth.get_user_by_req(request)
  392. is_admin = yield self.auth.is_server_admin(requester.user)
  393. if not is_admin:
  394. raise AuthError(403, "You are not a server admin")
  395. # To allow all users to get the users list
  396. # if not is_admin and target_user != auth_user:
  397. # raise AuthError(403, "You are not a server admin")
  398. if not self.hs.is_mine(target_user):
  399. raise SynapseError(400, "Can only users a local user")
  400. order = "name" # order by name in user table
  401. start = request.args.get("start")[0]
  402. limit = request.args.get("limit")[0]
  403. if not limit:
  404. raise SynapseError(400, "Missing 'limit' arg")
  405. if not start:
  406. raise SynapseError(400, "Missing 'start' arg")
  407. logger.info("limit: %s, start: %s", limit, start)
  408. ret = yield self.handlers.admin_handler.get_users_paginate(
  409. order, start, limit
  410. )
  411. defer.returnValue((200, ret))
  412. @defer.inlineCallbacks
  413. def on_POST(self, request, target_user_id):
  414. """Post request to get specific number of users from Synapse..
  415. This needs user to have administrator access in Synapse.
  416. Example:
  417. http://localhost:8008/_matrix/client/api/v1/admin/users_paginate/
  418. @admin:user?access_token=admin_access_token
  419. JsonBodyToSend:
  420. {
  421. "start": "0",
  422. "limit": "10
  423. }
  424. Returns:
  425. 200 OK with json object {list[dict[str, Any]], count} or empty object.
  426. """
  427. UserID.from_string(target_user_id)
  428. requester = yield self.auth.get_user_by_req(request)
  429. is_admin = yield self.auth.is_server_admin(requester.user)
  430. if not is_admin:
  431. raise AuthError(403, "You are not a server admin")
  432. order = "name" # order by name in user table
  433. params = parse_json_object_from_request(request)
  434. limit = params['limit']
  435. start = params['start']
  436. if not limit:
  437. raise SynapseError(400, "Missing 'limit' arg")
  438. if not start:
  439. raise SynapseError(400, "Missing 'start' arg")
  440. logger.info("limit: %s, start: %s", limit, start)
  441. ret = yield self.handlers.admin_handler.get_users_paginate(
  442. order, start, limit
  443. )
  444. defer.returnValue((200, ret))
  445. class SearchUsersRestServlet(ClientV1RestServlet):
  446. """Get request to search user table for specific users according to
  447. search term.
  448. This needs user to have administrator access in Synapse.
  449. Example:
  450. http://localhost:8008/_matrix/client/api/v1/admin/search_users/
  451. @admin:user?access_token=admin_access_token&term=alice
  452. Returns:
  453. 200 OK with json object {list[dict[str, Any]], count} or empty object.
  454. """
  455. PATTERNS = client_path_patterns("/admin/search_users/(?P<target_user_id>[^/]*)")
  456. def __init__(self, hs):
  457. self.store = hs.get_datastore()
  458. super(SearchUsersRestServlet, self).__init__(hs)
  459. self.hs = hs
  460. self.auth = hs.get_auth()
  461. self.handlers = hs.get_handlers()
  462. @defer.inlineCallbacks
  463. def on_GET(self, request, target_user_id):
  464. """Get request to search user table for specific users according to
  465. search term.
  466. This needs user to have a administrator access in Synapse.
  467. """
  468. target_user = UserID.from_string(target_user_id)
  469. requester = yield self.auth.get_user_by_req(request)
  470. is_admin = yield self.auth.is_server_admin(requester.user)
  471. if not is_admin:
  472. raise AuthError(403, "You are not a server admin")
  473. # To allow all users to get the users list
  474. # if not is_admin and target_user != auth_user:
  475. # raise AuthError(403, "You are not a server admin")
  476. if not self.hs.is_mine(target_user):
  477. raise SynapseError(400, "Can only users a local user")
  478. term = request.args.get("term")[0]
  479. if not term:
  480. raise SynapseError(400, "Missing 'term' arg")
  481. logger.info("term: %s ", term)
  482. ret = yield self.handlers.admin_handler.search_users(
  483. term
  484. )
  485. defer.returnValue((200, ret))
  486. def register_servlets(hs, http_server):
  487. WhoisRestServlet(hs).register(http_server)
  488. PurgeMediaCacheRestServlet(hs).register(http_server)
  489. PurgeHistoryStatusRestServlet(hs).register(http_server)
  490. DeactivateAccountRestServlet(hs).register(http_server)
  491. PurgeHistoryRestServlet(hs).register(http_server)
  492. UsersRestServlet(hs).register(http_server)
  493. ResetPasswordRestServlet(hs).register(http_server)
  494. GetUsersPaginatedRestServlet(hs).register(http_server)
  495. SearchUsersRestServlet(hs).register(http_server)
  496. ShutdownRoomRestServlet(hs).register(http_server)
  497. QuarantineMediaInRoom(hs).register(http_server)
  498. ListMediaInRoom(hs).register(http_server)