test_device.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2020 Dirk Klimpel
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. import json
  16. import urllib.parse
  17. import synapse.rest.admin
  18. from synapse.api.errors import Codes
  19. from synapse.rest.client.v1 import login
  20. from tests import unittest
  21. class DeviceRestTestCase(unittest.HomeserverTestCase):
  22. servlets = [
  23. synapse.rest.admin.register_servlets,
  24. login.register_servlets,
  25. ]
  26. def prepare(self, reactor, clock, hs):
  27. self.handler = hs.get_device_handler()
  28. self.admin_user = self.register_user("admin", "pass", admin=True)
  29. self.admin_user_tok = self.login("admin", "pass")
  30. self.other_user = self.register_user("user", "pass")
  31. self.other_user_token = self.login("user", "pass")
  32. res = self.get_success(self.handler.get_devices_by_user(self.other_user))
  33. self.other_user_device_id = res[0]["device_id"]
  34. self.url = "/_synapse/admin/v2/users/%s/devices/%s" % (
  35. urllib.parse.quote(self.other_user),
  36. self.other_user_device_id,
  37. )
  38. def test_no_auth(self):
  39. """
  40. Try to get a device of an user without authentication.
  41. """
  42. request, channel = self.make_request("GET", self.url, b"{}")
  43. self.render(request)
  44. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  45. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  46. request, channel = self.make_request("PUT", self.url, b"{}")
  47. self.render(request)
  48. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  49. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  50. request, channel = self.make_request("DELETE", self.url, b"{}")
  51. self.render(request)
  52. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  53. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  54. def test_requester_is_no_admin(self):
  55. """
  56. If the user is not a server admin, an error is returned.
  57. """
  58. request, channel = self.make_request(
  59. "GET", self.url, access_token=self.other_user_token,
  60. )
  61. self.render(request)
  62. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  63. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  64. request, channel = self.make_request(
  65. "PUT", self.url, access_token=self.other_user_token,
  66. )
  67. self.render(request)
  68. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  69. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  70. request, channel = self.make_request(
  71. "DELETE", self.url, access_token=self.other_user_token,
  72. )
  73. self.render(request)
  74. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  75. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  76. def test_user_does_not_exist(self):
  77. """
  78. Tests that a lookup for a user that does not exist returns a 404
  79. """
  80. url = (
  81. "/_synapse/admin/v2/users/@unknown_person:test/devices/%s"
  82. % self.other_user_device_id
  83. )
  84. request, channel = self.make_request(
  85. "GET", url, access_token=self.admin_user_tok,
  86. )
  87. self.render(request)
  88. self.assertEqual(404, channel.code, msg=channel.json_body)
  89. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  90. request, channel = self.make_request(
  91. "PUT", url, access_token=self.admin_user_tok,
  92. )
  93. self.render(request)
  94. self.assertEqual(404, channel.code, msg=channel.json_body)
  95. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  96. request, channel = self.make_request(
  97. "DELETE", url, access_token=self.admin_user_tok,
  98. )
  99. self.render(request)
  100. self.assertEqual(404, channel.code, msg=channel.json_body)
  101. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  102. def test_user_is_not_local(self):
  103. """
  104. Tests that a lookup for a user that is not a local returns a 400
  105. """
  106. url = (
  107. "/_synapse/admin/v2/users/@unknown_person:unknown_domain/devices/%s"
  108. % self.other_user_device_id
  109. )
  110. request, channel = self.make_request(
  111. "GET", url, access_token=self.admin_user_tok,
  112. )
  113. self.render(request)
  114. self.assertEqual(400, channel.code, msg=channel.json_body)
  115. self.assertEqual("Can only lookup local users", channel.json_body["error"])
  116. request, channel = self.make_request(
  117. "PUT", url, access_token=self.admin_user_tok,
  118. )
  119. self.render(request)
  120. self.assertEqual(400, channel.code, msg=channel.json_body)
  121. self.assertEqual("Can only lookup local users", channel.json_body["error"])
  122. request, channel = self.make_request(
  123. "DELETE", url, access_token=self.admin_user_tok,
  124. )
  125. self.render(request)
  126. self.assertEqual(400, channel.code, msg=channel.json_body)
  127. self.assertEqual("Can only lookup local users", channel.json_body["error"])
  128. def test_unknown_device(self):
  129. """
  130. Tests that a lookup for a device that does not exist returns either 404 or 200.
  131. """
  132. url = "/_synapse/admin/v2/users/%s/devices/unknown_device" % urllib.parse.quote(
  133. self.other_user
  134. )
  135. request, channel = self.make_request(
  136. "GET", url, access_token=self.admin_user_tok,
  137. )
  138. self.render(request)
  139. self.assertEqual(404, channel.code, msg=channel.json_body)
  140. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  141. request, channel = self.make_request(
  142. "PUT", url, access_token=self.admin_user_tok,
  143. )
  144. self.render(request)
  145. self.assertEqual(200, channel.code, msg=channel.json_body)
  146. request, channel = self.make_request(
  147. "DELETE", url, access_token=self.admin_user_tok,
  148. )
  149. self.render(request)
  150. # Delete unknown device returns status 200
  151. self.assertEqual(200, channel.code, msg=channel.json_body)
  152. def test_update_device_too_long_display_name(self):
  153. """
  154. Update a device with a display name that is invalid (too long).
  155. """
  156. # Set iniital display name.
  157. update = {"display_name": "new display"}
  158. self.get_success(
  159. self.handler.update_device(
  160. self.other_user, self.other_user_device_id, update
  161. )
  162. )
  163. # Request to update a device display name with a new value that is longer than allowed.
  164. update = {
  165. "display_name": "a"
  166. * (synapse.handlers.device.MAX_DEVICE_DISPLAY_NAME_LEN + 1)
  167. }
  168. body = json.dumps(update)
  169. request, channel = self.make_request(
  170. "PUT",
  171. self.url,
  172. access_token=self.admin_user_tok,
  173. content=body.encode(encoding="utf_8"),
  174. )
  175. self.render(request)
  176. self.assertEqual(400, channel.code, msg=channel.json_body)
  177. self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
  178. # Ensure the display name was not updated.
  179. request, channel = self.make_request(
  180. "GET", self.url, access_token=self.admin_user_tok,
  181. )
  182. self.render(request)
  183. self.assertEqual(200, channel.code, msg=channel.json_body)
  184. self.assertEqual("new display", channel.json_body["display_name"])
  185. def test_update_no_display_name(self):
  186. """
  187. Tests that a update for a device without JSON returns a 200
  188. """
  189. # Set iniital display name.
  190. update = {"display_name": "new display"}
  191. self.get_success(
  192. self.handler.update_device(
  193. self.other_user, self.other_user_device_id, update
  194. )
  195. )
  196. request, channel = self.make_request(
  197. "PUT", self.url, access_token=self.admin_user_tok,
  198. )
  199. self.render(request)
  200. self.assertEqual(200, channel.code, msg=channel.json_body)
  201. # Ensure the display name was not updated.
  202. request, channel = self.make_request(
  203. "GET", self.url, access_token=self.admin_user_tok,
  204. )
  205. self.render(request)
  206. self.assertEqual(200, channel.code, msg=channel.json_body)
  207. self.assertEqual("new display", channel.json_body["display_name"])
  208. def test_update_display_name(self):
  209. """
  210. Tests a normal successful update of display name
  211. """
  212. # Set new display_name
  213. body = json.dumps({"display_name": "new displayname"})
  214. request, channel = self.make_request(
  215. "PUT",
  216. self.url,
  217. access_token=self.admin_user_tok,
  218. content=body.encode(encoding="utf_8"),
  219. )
  220. self.render(request)
  221. self.assertEqual(200, channel.code, msg=channel.json_body)
  222. # Check new display_name
  223. request, channel = self.make_request(
  224. "GET", self.url, access_token=self.admin_user_tok,
  225. )
  226. self.render(request)
  227. self.assertEqual(200, channel.code, msg=channel.json_body)
  228. self.assertEqual("new displayname", channel.json_body["display_name"])
  229. def test_get_device(self):
  230. """
  231. Tests that a normal lookup for a device is successfully
  232. """
  233. request, channel = self.make_request(
  234. "GET", self.url, access_token=self.admin_user_tok,
  235. )
  236. self.render(request)
  237. self.assertEqual(200, channel.code, msg=channel.json_body)
  238. self.assertEqual(self.other_user, channel.json_body["user_id"])
  239. # Check that all fields are available
  240. self.assertIn("user_id", channel.json_body)
  241. self.assertIn("device_id", channel.json_body)
  242. self.assertIn("display_name", channel.json_body)
  243. self.assertIn("last_seen_ip", channel.json_body)
  244. self.assertIn("last_seen_ts", channel.json_body)
  245. def test_delete_device(self):
  246. """
  247. Tests that a remove of a device is successfully
  248. """
  249. # Count number of devies of an user.
  250. res = self.get_success(self.handler.get_devices_by_user(self.other_user))
  251. number_devices = len(res)
  252. self.assertEqual(1, number_devices)
  253. # Delete device
  254. request, channel = self.make_request(
  255. "DELETE", self.url, access_token=self.admin_user_tok,
  256. )
  257. self.render(request)
  258. self.assertEqual(200, channel.code, msg=channel.json_body)
  259. # Ensure that the number of devices is decreased
  260. res = self.get_success(self.handler.get_devices_by_user(self.other_user))
  261. self.assertEqual(number_devices - 1, len(res))
  262. class DevicesRestTestCase(unittest.HomeserverTestCase):
  263. servlets = [
  264. synapse.rest.admin.register_servlets,
  265. login.register_servlets,
  266. ]
  267. def prepare(self, reactor, clock, hs):
  268. self.admin_user = self.register_user("admin", "pass", admin=True)
  269. self.admin_user_tok = self.login("admin", "pass")
  270. self.other_user = self.register_user("user", "pass")
  271. self.url = "/_synapse/admin/v2/users/%s/devices" % urllib.parse.quote(
  272. self.other_user
  273. )
  274. def test_no_auth(self):
  275. """
  276. Try to list devices of an user without authentication.
  277. """
  278. request, channel = self.make_request("GET", self.url, b"{}")
  279. self.render(request)
  280. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  281. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  282. def test_requester_is_no_admin(self):
  283. """
  284. If the user is not a server admin, an error is returned.
  285. """
  286. other_user_token = self.login("user", "pass")
  287. request, channel = self.make_request(
  288. "GET", self.url, access_token=other_user_token,
  289. )
  290. self.render(request)
  291. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  292. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  293. def test_user_does_not_exist(self):
  294. """
  295. Tests that a lookup for a user that does not exist returns a 404
  296. """
  297. url = "/_synapse/admin/v2/users/@unknown_person:test/devices"
  298. request, channel = self.make_request(
  299. "GET", url, access_token=self.admin_user_tok,
  300. )
  301. self.render(request)
  302. self.assertEqual(404, channel.code, msg=channel.json_body)
  303. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  304. def test_user_is_not_local(self):
  305. """
  306. Tests that a lookup for a user that is not a local returns a 400
  307. """
  308. url = "/_synapse/admin/v2/users/@unknown_person:unknown_domain/devices"
  309. request, channel = self.make_request(
  310. "GET", url, access_token=self.admin_user_tok,
  311. )
  312. self.render(request)
  313. self.assertEqual(400, channel.code, msg=channel.json_body)
  314. self.assertEqual("Can only lookup local users", channel.json_body["error"])
  315. def test_get_devices(self):
  316. """
  317. Tests that a normal lookup for devices is successfully
  318. """
  319. # Create devices
  320. number_devices = 5
  321. for n in range(number_devices):
  322. self.login("user", "pass")
  323. # Get devices
  324. request, channel = self.make_request(
  325. "GET", self.url, access_token=self.admin_user_tok,
  326. )
  327. self.render(request)
  328. self.assertEqual(200, channel.code, msg=channel.json_body)
  329. self.assertEqual(number_devices, len(channel.json_body["devices"]))
  330. self.assertEqual(self.other_user, channel.json_body["devices"][0]["user_id"])
  331. # Check that all fields are available
  332. for d in channel.json_body["devices"]:
  333. self.assertIn("user_id", d)
  334. self.assertIn("device_id", d)
  335. self.assertIn("display_name", d)
  336. self.assertIn("last_seen_ip", d)
  337. self.assertIn("last_seen_ts", d)
  338. class DeleteDevicesRestTestCase(unittest.HomeserverTestCase):
  339. servlets = [
  340. synapse.rest.admin.register_servlets,
  341. login.register_servlets,
  342. ]
  343. def prepare(self, reactor, clock, hs):
  344. self.handler = hs.get_device_handler()
  345. self.admin_user = self.register_user("admin", "pass", admin=True)
  346. self.admin_user_tok = self.login("admin", "pass")
  347. self.other_user = self.register_user("user", "pass")
  348. self.url = "/_synapse/admin/v2/users/%s/delete_devices" % urllib.parse.quote(
  349. self.other_user
  350. )
  351. def test_no_auth(self):
  352. """
  353. Try to delete devices of an user without authentication.
  354. """
  355. request, channel = self.make_request("POST", self.url, b"{}")
  356. self.render(request)
  357. self.assertEqual(401, int(channel.result["code"]), msg=channel.result["body"])
  358. self.assertEqual(Codes.MISSING_TOKEN, channel.json_body["errcode"])
  359. def test_requester_is_no_admin(self):
  360. """
  361. If the user is not a server admin, an error is returned.
  362. """
  363. other_user_token = self.login("user", "pass")
  364. request, channel = self.make_request(
  365. "POST", self.url, access_token=other_user_token,
  366. )
  367. self.render(request)
  368. self.assertEqual(403, int(channel.result["code"]), msg=channel.result["body"])
  369. self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
  370. def test_user_does_not_exist(self):
  371. """
  372. Tests that a lookup for a user that does not exist returns a 404
  373. """
  374. url = "/_synapse/admin/v2/users/@unknown_person:test/delete_devices"
  375. request, channel = self.make_request(
  376. "POST", url, access_token=self.admin_user_tok,
  377. )
  378. self.render(request)
  379. self.assertEqual(404, channel.code, msg=channel.json_body)
  380. self.assertEqual(Codes.NOT_FOUND, channel.json_body["errcode"])
  381. def test_user_is_not_local(self):
  382. """
  383. Tests that a lookup for a user that is not a local returns a 400
  384. """
  385. url = "/_synapse/admin/v2/users/@unknown_person:unknown_domain/delete_devices"
  386. request, channel = self.make_request(
  387. "POST", url, access_token=self.admin_user_tok,
  388. )
  389. self.render(request)
  390. self.assertEqual(400, channel.code, msg=channel.json_body)
  391. self.assertEqual("Can only lookup local users", channel.json_body["error"])
  392. def test_unknown_devices(self):
  393. """
  394. Tests that a remove of a device that does not exist returns 200.
  395. """
  396. body = json.dumps({"devices": ["unknown_device1", "unknown_device2"]})
  397. request, channel = self.make_request(
  398. "POST",
  399. self.url,
  400. access_token=self.admin_user_tok,
  401. content=body.encode(encoding="utf_8"),
  402. )
  403. self.render(request)
  404. # Delete unknown devices returns status 200
  405. self.assertEqual(200, channel.code, msg=channel.json_body)
  406. def test_delete_devices(self):
  407. """
  408. Tests that a remove of devices is successfully
  409. """
  410. # Create devices
  411. number_devices = 5
  412. for n in range(number_devices):
  413. self.login("user", "pass")
  414. # Get devices
  415. res = self.get_success(self.handler.get_devices_by_user(self.other_user))
  416. self.assertEqual(number_devices, len(res))
  417. # Create list of device IDs
  418. device_ids = []
  419. for d in res:
  420. device_ids.append(str(d["device_id"]))
  421. # Delete devices
  422. body = json.dumps({"devices": device_ids})
  423. request, channel = self.make_request(
  424. "POST",
  425. self.url,
  426. access_token=self.admin_user_tok,
  427. content=body.encode(encoding="utf_8"),
  428. )
  429. self.render(request)
  430. self.assertEqual(200, channel.code, msg=channel.json_body)
  431. res = self.get_success(self.handler.get_devices_by_user(self.other_user))
  432. self.assertEqual(0, len(res))