123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061 |
- # -*- coding: utf-8 -*-
- # Copyright 2014-2016 OpenMarket Ltd
- # Copyright 2017 Vector Creations Ltd
- # Copyright 2018-2019 New Vector Ltd
- # Copyright 2019 The Matrix.org Foundation C.I.C.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Tests REST events for /rooms paths."""
- import json
- from urllib import parse as urlparse
- from mock import Mock
- import synapse.rest.admin
- from synapse.api.constants import EventContentFields, EventTypes, Membership
- from synapse.handlers.pagination import PurgeStatus
- from synapse.rest.client.v1 import directory, login, profile, room
- from synapse.rest.client.v2_alpha import account
- from synapse.types import JsonDict, RoomAlias, UserID
- from synapse.util.stringutils import random_string
- from tests import unittest
- PATH_PREFIX = b"/_matrix/client/api/v1"
- class RoomBase(unittest.HomeserverTestCase):
- rmcreator_id = None
- servlets = [room.register_servlets, room.register_deprecated_servlets]
- def make_homeserver(self, reactor, clock):
- self.hs = self.setup_test_homeserver(
- "red", http_client=None, federation_client=Mock(),
- )
- self.hs.get_federation_handler = Mock(return_value=Mock())
- async def _insert_client_ip(*args, **kwargs):
- return None
- self.hs.get_datastore().insert_client_ip = _insert_client_ip
- return self.hs
- class RoomPermissionsTestCase(RoomBase):
- """ Tests room permissions. """
- user_id = "@sid1:red"
- rmcreator_id = "@notme:red"
- def prepare(self, reactor, clock, hs):
- self.helper.auth_user_id = self.rmcreator_id
- # create some rooms under the name rmcreator_id
- self.uncreated_rmid = "!aa:test"
- self.created_rmid = self.helper.create_room_as(
- self.rmcreator_id, is_public=False
- )
- self.created_public_rmid = self.helper.create_room_as(
- self.rmcreator_id, is_public=True
- )
- # send a message in one of the rooms
- self.created_rmid_msg_path = (
- "rooms/%s/send/m.room.message/a1" % (self.created_rmid)
- ).encode("ascii")
- request, channel = self.make_request(
- "PUT", self.created_rmid_msg_path, b'{"msgtype":"m.text","body":"test msg"}'
- )
- self.render(request)
- self.assertEquals(200, channel.code, channel.result)
- # set topic for public room
- request, channel = self.make_request(
- "PUT",
- ("rooms/%s/state/m.room.topic" % self.created_public_rmid).encode("ascii"),
- b'{"topic":"Public Room Topic"}',
- )
- self.render(request)
- self.assertEquals(200, channel.code, channel.result)
- # auth as user_id now
- self.helper.auth_user_id = self.user_id
- def test_can_do_action(self):
- msg_content = b'{"msgtype":"m.text","body":"hello"}'
- seq = iter(range(100))
- def send_msg_path():
- return "/rooms/%s/send/m.room.message/mid%s" % (
- self.created_rmid,
- str(next(seq)),
- )
- # send message in uncreated room, expect 403
- request, channel = self.make_request(
- "PUT",
- "/rooms/%s/send/m.room.message/mid2" % (self.uncreated_rmid,),
- msg_content,
- )
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # send message in created room not joined (no state), expect 403
- request, channel = self.make_request("PUT", send_msg_path(), msg_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # send message in created room and invited, expect 403
- self.helper.invite(
- room=self.created_rmid, src=self.rmcreator_id, targ=self.user_id
- )
- request, channel = self.make_request("PUT", send_msg_path(), msg_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # send message in created room and joined, expect 200
- self.helper.join(room=self.created_rmid, user=self.user_id)
- request, channel = self.make_request("PUT", send_msg_path(), msg_content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- # send message in created room and left, expect 403
- self.helper.leave(room=self.created_rmid, user=self.user_id)
- request, channel = self.make_request("PUT", send_msg_path(), msg_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- def test_topic_perms(self):
- topic_content = b'{"topic":"My Topic Name"}'
- topic_path = "/rooms/%s/state/m.room.topic" % self.created_rmid
- # set/get topic in uncreated room, expect 403
- request, channel = self.make_request(
- "PUT", "/rooms/%s/state/m.room.topic" % self.uncreated_rmid, topic_content
- )
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- request, channel = self.make_request(
- "GET", "/rooms/%s/state/m.room.topic" % self.uncreated_rmid
- )
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # set/get topic in created PRIVATE room not joined, expect 403
- request, channel = self.make_request("PUT", topic_path, topic_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("GET", topic_path)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # set topic in created PRIVATE room and invited, expect 403
- self.helper.invite(
- room=self.created_rmid, src=self.rmcreator_id, targ=self.user_id
- )
- request, channel = self.make_request("PUT", topic_path, topic_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # get topic in created PRIVATE room and invited, expect 403
- request, channel = self.make_request("GET", topic_path)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # set/get topic in created PRIVATE room and joined, expect 200
- self.helper.join(room=self.created_rmid, user=self.user_id)
- # Only room ops can set topic by default
- self.helper.auth_user_id = self.rmcreator_id
- request, channel = self.make_request("PUT", topic_path, topic_content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.helper.auth_user_id = self.user_id
- request, channel = self.make_request("GET", topic_path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.assert_dict(json.loads(topic_content.decode("utf8")), channel.json_body)
- # set/get topic in created PRIVATE room and left, expect 403
- self.helper.leave(room=self.created_rmid, user=self.user_id)
- request, channel = self.make_request("PUT", topic_path, topic_content)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("GET", topic_path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- # get topic in PUBLIC room, not joined, expect 403
- request, channel = self.make_request(
- "GET", "/rooms/%s/state/m.room.topic" % self.created_public_rmid
- )
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- # set topic in PUBLIC room, not joined, expect 403
- request, channel = self.make_request(
- "PUT",
- "/rooms/%s/state/m.room.topic" % self.created_public_rmid,
- topic_content,
- )
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- def _test_get_membership(self, room=None, members=[], expect_code=None):
- for member in members:
- path = "/rooms/%s/state/m.room.member/%s" % (room, member)
- request, channel = self.make_request("GET", path)
- self.render(request)
- self.assertEquals(expect_code, channel.code)
- def test_membership_basic_room_perms(self):
- # === room does not exist ===
- room = self.uncreated_rmid
- # get membership of self, get membership of other, uncreated room
- # expect all 403s
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=403
- )
- # trying to invite people to this room should 403
- self.helper.invite(
- room=room, src=self.user_id, targ=self.rmcreator_id, expect_code=403
- )
- # set [invite/join/left] of self, set [invite/join/left] of other,
- # expect all 404s because room doesn't exist on any server
- for usr in [self.user_id, self.rmcreator_id]:
- self.helper.join(room=room, user=usr, expect_code=404)
- self.helper.leave(room=room, user=usr, expect_code=404)
- def test_membership_private_room_perms(self):
- room = self.created_rmid
- # get membership of self, get membership of other, private room + invite
- # expect all 403s
- self.helper.invite(room=room, src=self.rmcreator_id, targ=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=403
- )
- # get membership of self, get membership of other, private room + joined
- # expect all 200s
- self.helper.join(room=room, user=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=200
- )
- # get membership of self, get membership of other, private room + left
- # expect all 200s
- self.helper.leave(room=room, user=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=200
- )
- def test_membership_public_room_perms(self):
- room = self.created_public_rmid
- # get membership of self, get membership of other, public room + invite
- # expect 403
- self.helper.invite(room=room, src=self.rmcreator_id, targ=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=403
- )
- # get membership of self, get membership of other, public room + joined
- # expect all 200s
- self.helper.join(room=room, user=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=200
- )
- # get membership of self, get membership of other, public room + left
- # expect 200.
- self.helper.leave(room=room, user=self.user_id)
- self._test_get_membership(
- members=[self.user_id, self.rmcreator_id], room=room, expect_code=200
- )
- def test_invited_permissions(self):
- room = self.created_rmid
- self.helper.invite(room=room, src=self.rmcreator_id, targ=self.user_id)
- # set [invite/join/left] of other user, expect 403s
- self.helper.invite(
- room=room, src=self.user_id, targ=self.rmcreator_id, expect_code=403
- )
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=self.rmcreator_id,
- membership=Membership.JOIN,
- expect_code=403,
- )
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=self.rmcreator_id,
- membership=Membership.LEAVE,
- expect_code=403,
- )
- def test_joined_permissions(self):
- room = self.created_rmid
- self.helper.invite(room=room, src=self.rmcreator_id, targ=self.user_id)
- self.helper.join(room=room, user=self.user_id)
- # set invited of self, expect 403
- self.helper.invite(
- room=room, src=self.user_id, targ=self.user_id, expect_code=403
- )
- # set joined of self, expect 200 (NOOP)
- self.helper.join(room=room, user=self.user_id)
- other = "@burgundy:red"
- # set invited of other, expect 200
- self.helper.invite(room=room, src=self.user_id, targ=other, expect_code=200)
- # set joined of other, expect 403
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=other,
- membership=Membership.JOIN,
- expect_code=403,
- )
- # set left of other, expect 403
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=other,
- membership=Membership.LEAVE,
- expect_code=403,
- )
- # set left of self, expect 200
- self.helper.leave(room=room, user=self.user_id)
- def test_leave_permissions(self):
- room = self.created_rmid
- self.helper.invite(room=room, src=self.rmcreator_id, targ=self.user_id)
- self.helper.join(room=room, user=self.user_id)
- self.helper.leave(room=room, user=self.user_id)
- # set [invite/join/left] of self, set [invite/join/left] of other,
- # expect all 403s
- for usr in [self.user_id, self.rmcreator_id]:
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=usr,
- membership=Membership.INVITE,
- expect_code=403,
- )
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=usr,
- membership=Membership.JOIN,
- expect_code=403,
- )
- # It is always valid to LEAVE if you've already left (currently.)
- self.helper.change_membership(
- room=room,
- src=self.user_id,
- targ=self.rmcreator_id,
- membership=Membership.LEAVE,
- expect_code=403,
- )
- class RoomsMemberListTestCase(RoomBase):
- """ Tests /rooms/$room_id/members/list REST events."""
- user_id = "@sid1:red"
- def test_get_member_list(self):
- room_id = self.helper.create_room_as(self.user_id)
- request, channel = self.make_request("GET", "/rooms/%s/members" % room_id)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- def test_get_member_list_no_room(self):
- request, channel = self.make_request("GET", "/rooms/roomdoesnotexist/members")
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- def test_get_member_list_no_permission(self):
- room_id = self.helper.create_room_as("@some_other_guy:red")
- request, channel = self.make_request("GET", "/rooms/%s/members" % room_id)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- def test_get_member_list_mixed_memberships(self):
- room_creator = "@some_other_guy:red"
- room_id = self.helper.create_room_as(room_creator)
- room_path = "/rooms/%s/members" % room_id
- self.helper.invite(room=room_id, src=room_creator, targ=self.user_id)
- # can't see list if you're just invited.
- request, channel = self.make_request("GET", room_path)
- self.render(request)
- self.assertEquals(403, channel.code, msg=channel.result["body"])
- self.helper.join(room=room_id, user=self.user_id)
- # can see list now joined
- request, channel = self.make_request("GET", room_path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.helper.leave(room=room_id, user=self.user_id)
- # can see old list once left
- request, channel = self.make_request("GET", room_path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- class RoomsCreateTestCase(RoomBase):
- """ Tests /rooms and /rooms/$room_id REST events. """
- user_id = "@sid1:red"
- def test_post_room_no_keys(self):
- # POST with no config keys, expect new room id
- request, channel = self.make_request("POST", "/createRoom", "{}")
- self.render(request)
- self.assertEquals(200, channel.code, channel.result)
- self.assertTrue("room_id" in channel.json_body)
- def test_post_room_visibility_key(self):
- # POST with visibility config key, expect new room id
- request, channel = self.make_request(
- "POST", "/createRoom", b'{"visibility":"private"}'
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertTrue("room_id" in channel.json_body)
- def test_post_room_custom_key(self):
- # POST with custom config keys, expect new room id
- request, channel = self.make_request(
- "POST", "/createRoom", b'{"custom":"stuff"}'
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertTrue("room_id" in channel.json_body)
- def test_post_room_known_and_unknown_keys(self):
- # POST with custom + known config keys, expect new room id
- request, channel = self.make_request(
- "POST", "/createRoom", b'{"visibility":"private","custom":"things"}'
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertTrue("room_id" in channel.json_body)
- def test_post_room_invalid_content(self):
- # POST with invalid content / paths, expect 400
- request, channel = self.make_request("POST", "/createRoom", b'{"visibili')
- self.render(request)
- self.assertEquals(400, channel.code)
- request, channel = self.make_request("POST", "/createRoom", b'["hello"]')
- self.render(request)
- self.assertEquals(400, channel.code)
- def test_post_room_invitees_invalid_mxid(self):
- # POST with invalid invitee, see https://github.com/matrix-org/synapse/issues/4088
- # Note the trailing space in the MXID here!
- request, channel = self.make_request(
- "POST", "/createRoom", b'{"invite":["@alice:example.com "]}'
- )
- self.render(request)
- self.assertEquals(400, channel.code)
- class RoomTopicTestCase(RoomBase):
- """ Tests /rooms/$room_id/topic REST events. """
- user_id = "@sid1:red"
- def prepare(self, reactor, clock, hs):
- # create the room
- self.room_id = self.helper.create_room_as(self.user_id)
- self.path = "/rooms/%s/state/m.room.topic" % (self.room_id,)
- def test_invalid_puts(self):
- # missing keys or invalid json
- request, channel = self.make_request("PUT", self.path, "{}")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", self.path, '{"_name":"bo"}')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", self.path, '{"nao')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request(
- "PUT", self.path, '[{"_name":"bo"},{"_name":"jill"}]'
- )
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", self.path, "text only")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", self.path, "")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- # valid key, wrong type
- content = '{"topic":["Topic name"]}'
- request, channel = self.make_request("PUT", self.path, content)
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- def test_rooms_topic(self):
- # nothing should be there
- request, channel = self.make_request("GET", self.path)
- self.render(request)
- self.assertEquals(404, channel.code, msg=channel.result["body"])
- # valid put
- content = '{"topic":"Topic name"}'
- request, channel = self.make_request("PUT", self.path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- # valid get
- request, channel = self.make_request("GET", self.path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.assert_dict(json.loads(content), channel.json_body)
- def test_rooms_topic_with_extra_keys(self):
- # valid put with extra keys
- content = '{"topic":"Seasons","subtopic":"Summer"}'
- request, channel = self.make_request("PUT", self.path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- # valid get
- request, channel = self.make_request("GET", self.path)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.assert_dict(json.loads(content), channel.json_body)
- class RoomMemberStateTestCase(RoomBase):
- """ Tests /rooms/$room_id/members/$user_id/state REST events. """
- user_id = "@sid1:red"
- def prepare(self, reactor, clock, hs):
- self.room_id = self.helper.create_room_as(self.user_id)
- def test_invalid_puts(self):
- path = "/rooms/%s/state/m.room.member/%s" % (self.room_id, self.user_id)
- # missing keys or invalid json
- request, channel = self.make_request("PUT", path, "{}")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, '{"_name":"bo"}')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, '{"nao')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request(
- "PUT", path, b'[{"_name":"bo"},{"_name":"jill"}]'
- )
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, "text only")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, "")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- # valid keys, wrong types
- content = '{"membership":["%s","%s","%s"]}' % (
- Membership.INVITE,
- Membership.JOIN,
- Membership.LEAVE,
- )
- request, channel = self.make_request("PUT", path, content.encode("ascii"))
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- def test_rooms_members_self(self):
- path = "/rooms/%s/state/m.room.member/%s" % (
- urlparse.quote(self.room_id),
- self.user_id,
- )
- # valid join message (NOOP since we made the room)
- content = '{"membership":"%s"}' % Membership.JOIN
- request, channel = self.make_request("PUT", path, content.encode("ascii"))
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("GET", path, None)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- expected_response = {"membership": Membership.JOIN}
- self.assertEquals(expected_response, channel.json_body)
- def test_rooms_members_other(self):
- self.other_id = "@zzsid1:red"
- path = "/rooms/%s/state/m.room.member/%s" % (
- urlparse.quote(self.room_id),
- self.other_id,
- )
- # valid invite message
- content = '{"membership":"%s"}' % Membership.INVITE
- request, channel = self.make_request("PUT", path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("GET", path, None)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.assertEquals(json.loads(content), channel.json_body)
- def test_rooms_members_other_custom_keys(self):
- self.other_id = "@zzsid1:red"
- path = "/rooms/%s/state/m.room.member/%s" % (
- urlparse.quote(self.room_id),
- self.other_id,
- )
- # valid invite message with custom key
- content = '{"membership":"%s","invite_text":"%s"}' % (
- Membership.INVITE,
- "Join us!",
- )
- request, channel = self.make_request("PUT", path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("GET", path, None)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- self.assertEquals(json.loads(content), channel.json_body)
- class RoomJoinRatelimitTestCase(RoomBase):
- user_id = "@sid1:red"
- servlets = [
- profile.register_servlets,
- room.register_servlets,
- ]
- @unittest.override_config(
- {"rc_joins": {"local": {"per_second": 3, "burst_count": 3}}}
- )
- def test_join_local_ratelimit(self):
- """Tests that local joins are actually rate-limited."""
- for i in range(5):
- self.helper.create_room_as(self.user_id)
- self.helper.create_room_as(self.user_id, expect_code=429)
- @unittest.override_config(
- {"rc_joins": {"local": {"per_second": 3, "burst_count": 3}}}
- )
- def test_join_local_ratelimit_profile_change(self):
- """Tests that sending a profile update into all of the user's joined rooms isn't
- rate-limited by the rate-limiter on joins."""
- # Create and join more rooms than the rate-limiting config allows in a second.
- room_ids = [
- self.helper.create_room_as(self.user_id),
- self.helper.create_room_as(self.user_id),
- self.helper.create_room_as(self.user_id),
- ]
- self.reactor.advance(1)
- room_ids = room_ids + [
- self.helper.create_room_as(self.user_id),
- self.helper.create_room_as(self.user_id),
- self.helper.create_room_as(self.user_id),
- ]
- # Create a profile for the user, since it hasn't been done on registration.
- store = self.hs.get_datastore()
- store.create_profile(UserID.from_string(self.user_id).localpart)
- # Update the display name for the user.
- path = "/_matrix/client/r0/profile/%s/displayname" % self.user_id
- request, channel = self.make_request("PUT", path, {"displayname": "John Doe"})
- self.render(request)
- self.assertEquals(channel.code, 200, channel.json_body)
- # Check that all the rooms have been sent a profile update into.
- for room_id in room_ids:
- path = "/_matrix/client/r0/rooms/%s/state/m.room.member/%s" % (
- room_id,
- self.user_id,
- )
- request, channel = self.make_request("GET", path)
- self.render(request)
- self.assertEquals(channel.code, 200)
- self.assertIn("displayname", channel.json_body)
- self.assertEquals(channel.json_body["displayname"], "John Doe")
- @unittest.override_config(
- {"rc_joins": {"local": {"per_second": 3, "burst_count": 3}}}
- )
- def test_join_local_ratelimit_idempotent(self):
- """Tests that the room join endpoints remain idempotent despite rate-limiting
- on room joins."""
- room_id = self.helper.create_room_as(self.user_id)
- # Let's test both paths to be sure.
- paths_to_test = [
- "/_matrix/client/r0/rooms/%s/join",
- "/_matrix/client/r0/join/%s",
- ]
- for path in paths_to_test:
- # Make sure we send more requests than the rate-limiting config would allow
- # if all of these requests ended up joining the user to a room.
- for i in range(6):
- request, channel = self.make_request("POST", path % room_id, {})
- self.render(request)
- self.assertEquals(channel.code, 200)
- class RoomMessagesTestCase(RoomBase):
- """ Tests /rooms/$room_id/messages/$user_id/$msg_id REST events. """
- user_id = "@sid1:red"
- def prepare(self, reactor, clock, hs):
- self.room_id = self.helper.create_room_as(self.user_id)
- def test_invalid_puts(self):
- path = "/rooms/%s/send/m.room.message/mid1" % (urlparse.quote(self.room_id))
- # missing keys or invalid json
- request, channel = self.make_request("PUT", path, b"{}")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, b'{"_name":"bo"}')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, b'{"nao')
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request(
- "PUT", path, b'[{"_name":"bo"},{"_name":"jill"}]'
- )
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, b"text only")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- request, channel = self.make_request("PUT", path, b"")
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- def test_rooms_messages_sent(self):
- path = "/rooms/%s/send/m.room.message/mid1" % (urlparse.quote(self.room_id))
- content = b'{"body":"test","msgtype":{"type":"a"}}'
- request, channel = self.make_request("PUT", path, content)
- self.render(request)
- self.assertEquals(400, channel.code, msg=channel.result["body"])
- # custom message types
- content = b'{"body":"test","msgtype":"test.custom.text"}'
- request, channel = self.make_request("PUT", path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- # m.text message type
- path = "/rooms/%s/send/m.room.message/mid2" % (urlparse.quote(self.room_id))
- content = b'{"body":"test2","msgtype":"m.text"}'
- request, channel = self.make_request("PUT", path, content)
- self.render(request)
- self.assertEquals(200, channel.code, msg=channel.result["body"])
- class RoomInitialSyncTestCase(RoomBase):
- """ Tests /rooms/$room_id/initialSync. """
- user_id = "@sid1:red"
- def prepare(self, reactor, clock, hs):
- # create the room
- self.room_id = self.helper.create_room_as(self.user_id)
- def test_initial_sync(self):
- request, channel = self.make_request(
- "GET", "/rooms/%s/initialSync" % self.room_id
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertEquals(self.room_id, channel.json_body["room_id"])
- self.assertEquals("join", channel.json_body["membership"])
- # Room state is easier to assert on if we unpack it into a dict
- state = {}
- for event in channel.json_body["state"]:
- if "state_key" not in event:
- continue
- t = event["type"]
- if t not in state:
- state[t] = []
- state[t].append(event)
- self.assertTrue("m.room.create" in state)
- self.assertTrue("messages" in channel.json_body)
- self.assertTrue("chunk" in channel.json_body["messages"])
- self.assertTrue("end" in channel.json_body["messages"])
- self.assertTrue("presence" in channel.json_body)
- presence_by_user = {
- e["content"]["user_id"]: e for e in channel.json_body["presence"]
- }
- self.assertTrue(self.user_id in presence_by_user)
- self.assertEquals("m.presence", presence_by_user[self.user_id]["type"])
- class RoomMessageListTestCase(RoomBase):
- """ Tests /rooms/$room_id/messages REST events. """
- user_id = "@sid1:red"
- def prepare(self, reactor, clock, hs):
- self.room_id = self.helper.create_room_as(self.user_id)
- def test_topo_token_is_accepted(self):
- token = "t1-0_0_0_0_0_0_0_0_0"
- request, channel = self.make_request(
- "GET", "/rooms/%s/messages?access_token=x&from=%s" % (self.room_id, token)
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertTrue("start" in channel.json_body)
- self.assertEquals(token, channel.json_body["start"])
- self.assertTrue("chunk" in channel.json_body)
- self.assertTrue("end" in channel.json_body)
- def test_stream_token_is_accepted_for_fwd_pagianation(self):
- token = "s0_0_0_0_0_0_0_0_0"
- request, channel = self.make_request(
- "GET", "/rooms/%s/messages?access_token=x&from=%s" % (self.room_id, token)
- )
- self.render(request)
- self.assertEquals(200, channel.code)
- self.assertTrue("start" in channel.json_body)
- self.assertEquals(token, channel.json_body["start"])
- self.assertTrue("chunk" in channel.json_body)
- self.assertTrue("end" in channel.json_body)
- def test_room_messages_purge(self):
- store = self.hs.get_datastore()
- pagination_handler = self.hs.get_pagination_handler()
- # Send a first message in the room, which will be removed by the purge.
- first_event_id = self.helper.send(self.room_id, "message 1")["event_id"]
- first_token = self.get_success(
- store.get_topological_token_for_event(first_event_id)
- )
- # Send a second message in the room, which won't be removed, and which we'll
- # use as the marker to purge events before.
- second_event_id = self.helper.send(self.room_id, "message 2")["event_id"]
- second_token = self.get_success(
- store.get_topological_token_for_event(second_event_id)
- )
- # Send a third event in the room to ensure we don't fall under any edge case
- # due to our marker being the latest forward extremity in the room.
- self.helper.send(self.room_id, "message 3")
- # Check that we get the first and second message when querying /messages.
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=x&from=%s&dir=b&filter=%s"
- % (self.room_id, second_token, json.dumps({"types": [EventTypes.Message]})),
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.json_body)
- chunk = channel.json_body["chunk"]
- self.assertEqual(len(chunk), 2, [event["content"] for event in chunk])
- # Purge every event before the second event.
- purge_id = random_string(16)
- pagination_handler._purges_by_id[purge_id] = PurgeStatus()
- self.get_success(
- pagination_handler._purge_history(
- purge_id=purge_id,
- room_id=self.room_id,
- token=second_token,
- delete_local_events=True,
- )
- )
- # Check that we only get the second message through /message now that the first
- # has been purged.
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=x&from=%s&dir=b&filter=%s"
- % (self.room_id, second_token, json.dumps({"types": [EventTypes.Message]})),
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.json_body)
- chunk = channel.json_body["chunk"]
- self.assertEqual(len(chunk), 1, [event["content"] for event in chunk])
- # Check that we get no event, but also no error, when querying /messages with
- # the token that was pointing at the first event, because we don't have it
- # anymore.
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=x&from=%s&dir=b&filter=%s"
- % (self.room_id, first_token, json.dumps({"types": [EventTypes.Message]})),
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.json_body)
- chunk = channel.json_body["chunk"]
- self.assertEqual(len(chunk), 0, [event["content"] for event in chunk])
- class RoomSearchTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- room.register_servlets,
- login.register_servlets,
- ]
- user_id = True
- hijack_auth = False
- def prepare(self, reactor, clock, hs):
- # Register the user who does the searching
- self.user_id = self.register_user("user", "pass")
- self.access_token = self.login("user", "pass")
- # Register the user who sends the message
- self.other_user_id = self.register_user("otheruser", "pass")
- self.other_access_token = self.login("otheruser", "pass")
- # Create a room
- self.room = self.helper.create_room_as(self.user_id, tok=self.access_token)
- # Invite the other person
- self.helper.invite(
- room=self.room,
- src=self.user_id,
- tok=self.access_token,
- targ=self.other_user_id,
- )
- # The other user joins
- self.helper.join(
- room=self.room, user=self.other_user_id, tok=self.other_access_token
- )
- def test_finds_message(self):
- """
- The search functionality will search for content in messages if asked to
- do so.
- """
- # The other user sends some messages
- self.helper.send(self.room, body="Hi!", tok=self.other_access_token)
- self.helper.send(self.room, body="There!", tok=self.other_access_token)
- request, channel = self.make_request(
- "POST",
- "/search?access_token=%s" % (self.access_token,),
- {
- "search_categories": {
- "room_events": {"keys": ["content.body"], "search_term": "Hi"}
- }
- },
- )
- self.render(request)
- # Check we get the results we expect -- one search result, of the sent
- # messages
- self.assertEqual(channel.code, 200)
- results = channel.json_body["search_categories"]["room_events"]
- self.assertEqual(results["count"], 1)
- self.assertEqual(results["results"][0]["result"]["content"]["body"], "Hi!")
- # No context was requested, so we should get none.
- self.assertEqual(results["results"][0]["context"], {})
- def test_include_context(self):
- """
- When event_context includes include_profile, profile information will be
- included in the search response.
- """
- # The other user sends some messages
- self.helper.send(self.room, body="Hi!", tok=self.other_access_token)
- self.helper.send(self.room, body="There!", tok=self.other_access_token)
- request, channel = self.make_request(
- "POST",
- "/search?access_token=%s" % (self.access_token,),
- {
- "search_categories": {
- "room_events": {
- "keys": ["content.body"],
- "search_term": "Hi",
- "event_context": {"include_profile": True},
- }
- }
- },
- )
- self.render(request)
- # Check we get the results we expect -- one search result, of the sent
- # messages
- self.assertEqual(channel.code, 200)
- results = channel.json_body["search_categories"]["room_events"]
- self.assertEqual(results["count"], 1)
- self.assertEqual(results["results"][0]["result"]["content"]["body"], "Hi!")
- # We should get context info, like the two users, and the display names.
- context = results["results"][0]["context"]
- self.assertEqual(len(context["profile_info"].keys()), 2)
- self.assertEqual(
- context["profile_info"][self.other_user_id]["displayname"], "otheruser"
- )
- class PublicRoomsRestrictedTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- room.register_servlets,
- login.register_servlets,
- ]
- def make_homeserver(self, reactor, clock):
- self.url = b"/_matrix/client/r0/publicRooms"
- config = self.default_config()
- config["allow_public_rooms_without_auth"] = False
- self.hs = self.setup_test_homeserver(config=config)
- return self.hs
- def test_restricted_no_auth(self):
- request, channel = self.make_request("GET", self.url)
- self.render(request)
- self.assertEqual(channel.code, 401, channel.result)
- def test_restricted_auth(self):
- self.register_user("user", "pass")
- tok = self.login("user", "pass")
- request, channel = self.make_request("GET", self.url, access_token=tok)
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- class PerRoomProfilesForbiddenTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- room.register_servlets,
- login.register_servlets,
- profile.register_servlets,
- ]
- def make_homeserver(self, reactor, clock):
- config = self.default_config()
- config["allow_per_room_profiles"] = False
- self.hs = self.setup_test_homeserver(config=config)
- return self.hs
- def prepare(self, reactor, clock, homeserver):
- self.user_id = self.register_user("test", "test")
- self.tok = self.login("test", "test")
- # Set a profile for the test user
- self.displayname = "test user"
- data = {"displayname": self.displayname}
- request_data = json.dumps(data)
- request, channel = self.make_request(
- "PUT",
- "/_matrix/client/r0/profile/%s/displayname" % (self.user_id,),
- request_data,
- access_token=self.tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self.room_id = self.helper.create_room_as(self.user_id, tok=self.tok)
- def test_per_room_profile_forbidden(self):
- data = {"membership": "join", "displayname": "other test user"}
- request_data = json.dumps(data)
- request, channel = self.make_request(
- "PUT",
- "/_matrix/client/r0/rooms/%s/state/m.room.member/%s"
- % (self.room_id, self.user_id),
- request_data,
- access_token=self.tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- event_id = channel.json_body["event_id"]
- request, channel = self.make_request(
- "GET",
- "/_matrix/client/r0/rooms/%s/event/%s" % (self.room_id, event_id),
- access_token=self.tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- res_displayname = channel.json_body["content"]["displayname"]
- self.assertEqual(res_displayname, self.displayname, channel.result)
- class RoomMembershipReasonTestCase(unittest.HomeserverTestCase):
- """Tests that clients can add a "reason" field to membership events and
- that they get correctly added to the generated events and propagated.
- """
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- room.register_servlets,
- login.register_servlets,
- ]
- def prepare(self, reactor, clock, homeserver):
- self.creator = self.register_user("creator", "test")
- self.creator_tok = self.login("creator", "test")
- self.second_user_id = self.register_user("second", "test")
- self.second_tok = self.login("second", "test")
- self.room_id = self.helper.create_room_as(self.creator, tok=self.creator_tok)
- def test_join_reason(self):
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/join".format(self.room_id),
- content={"reason": reason},
- access_token=self.second_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_leave_reason(self):
- self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/leave".format(self.room_id),
- content={"reason": reason},
- access_token=self.second_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_kick_reason(self):
- self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/kick".format(self.room_id),
- content={"reason": reason, "user_id": self.second_user_id},
- access_token=self.second_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_ban_reason(self):
- self.helper.join(self.room_id, user=self.second_user_id, tok=self.second_tok)
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/ban".format(self.room_id),
- content={"reason": reason, "user_id": self.second_user_id},
- access_token=self.creator_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_unban_reason(self):
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/unban".format(self.room_id),
- content={"reason": reason, "user_id": self.second_user_id},
- access_token=self.creator_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_invite_reason(self):
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/invite".format(self.room_id),
- content={"reason": reason, "user_id": self.second_user_id},
- access_token=self.creator_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def test_reject_invite_reason(self):
- self.helper.invite(
- self.room_id,
- src=self.creator,
- targ=self.second_user_id,
- tok=self.creator_tok,
- )
- reason = "hello"
- request, channel = self.make_request(
- "POST",
- "/_matrix/client/r0/rooms/{}/leave".format(self.room_id),
- content={"reason": reason},
- access_token=self.second_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- self._check_for_reason(reason)
- def _check_for_reason(self, reason):
- request, channel = self.make_request(
- "GET",
- "/_matrix/client/r0/rooms/{}/state/m.room.member/{}".format(
- self.room_id, self.second_user_id
- ),
- access_token=self.creator_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, 200, channel.result)
- event_content = channel.json_body
- self.assertEqual(event_content.get("reason"), reason, channel.result)
- class LabelsTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- room.register_servlets,
- login.register_servlets,
- profile.register_servlets,
- ]
- # Filter that should only catch messages with the label "#fun".
- FILTER_LABELS = {
- "types": [EventTypes.Message],
- "org.matrix.labels": ["#fun"],
- }
- # Filter that should only catch messages without the label "#fun".
- FILTER_NOT_LABELS = {
- "types": [EventTypes.Message],
- "org.matrix.not_labels": ["#fun"],
- }
- # Filter that should only catch messages with the label "#work" but without the label
- # "#notfun".
- FILTER_LABELS_NOT_LABELS = {
- "types": [EventTypes.Message],
- "org.matrix.labels": ["#work"],
- "org.matrix.not_labels": ["#notfun"],
- }
- def prepare(self, reactor, clock, homeserver):
- self.user_id = self.register_user("test", "test")
- self.tok = self.login("test", "test")
- self.room_id = self.helper.create_room_as(self.user_id, tok=self.tok)
- def test_context_filter_labels(self):
- """Test that we can filter by a label on a /context request."""
- event_id = self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/context/%s?filter=%s"
- % (self.room_id, event_id, json.dumps(self.FILTER_LABELS)),
- 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), 1, [event["content"] for event in events_before]
- )
- self.assertEqual(
- events_before[0]["content"]["body"], "with right label", events_before[0]
- )
- events_after = channel.json_body["events_before"]
- self.assertEqual(
- len(events_after), 1, [event["content"] for event in events_after]
- )
- self.assertEqual(
- events_after[0]["content"]["body"], "with right label", events_after[0]
- )
- def test_context_filter_not_labels(self):
- """Test that we can filter by the absence of a label on a /context request."""
- event_id = self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/context/%s?filter=%s"
- % (self.room_id, event_id, json.dumps(self.FILTER_NOT_LABELS)),
- 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), 1, [event["content"] for event in events_before]
- )
- self.assertEqual(
- events_before[0]["content"]["body"], "without label", events_before[0]
- )
- events_after = channel.json_body["events_after"]
- self.assertEqual(
- len(events_after), 2, [event["content"] for event in events_after]
- )
- self.assertEqual(
- events_after[0]["content"]["body"], "with wrong label", events_after[0]
- )
- self.assertEqual(
- events_after[1]["content"]["body"], "with two wrong labels", events_after[1]
- )
- def test_context_filter_labels_not_labels(self):
- """Test that we can filter by both a label and the absence of another label on a
- /context request.
- """
- event_id = self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/context/%s?filter=%s"
- % (self.room_id, event_id, json.dumps(self.FILTER_LABELS_NOT_LABELS)),
- 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), 0, [event["content"] for event in events_before]
- )
- events_after = channel.json_body["events_after"]
- self.assertEqual(
- len(events_after), 1, [event["content"] for event in events_after]
- )
- self.assertEqual(
- events_after[0]["content"]["body"], "with wrong label", events_after[0]
- )
- def test_messages_filter_labels(self):
- """Test that we can filter by a label on a /messages request."""
- self._send_labelled_messages_in_room()
- token = "s0_0_0_0_0_0_0_0_0"
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=%s&from=%s&filter=%s"
- % (self.room_id, self.tok, token, json.dumps(self.FILTER_LABELS)),
- )
- self.render(request)
- events = channel.json_body["chunk"]
- self.assertEqual(len(events), 2, [event["content"] for event in events])
- self.assertEqual(events[0]["content"]["body"], "with right label", events[0])
- self.assertEqual(events[1]["content"]["body"], "with right label", events[1])
- def test_messages_filter_not_labels(self):
- """Test that we can filter by the absence of a label on a /messages request."""
- self._send_labelled_messages_in_room()
- token = "s0_0_0_0_0_0_0_0_0"
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=%s&from=%s&filter=%s"
- % (self.room_id, self.tok, token, json.dumps(self.FILTER_NOT_LABELS)),
- )
- self.render(request)
- events = channel.json_body["chunk"]
- self.assertEqual(len(events), 4, [event["content"] for event in events])
- self.assertEqual(events[0]["content"]["body"], "without label", events[0])
- self.assertEqual(events[1]["content"]["body"], "without label", events[1])
- self.assertEqual(events[2]["content"]["body"], "with wrong label", events[2])
- self.assertEqual(
- events[3]["content"]["body"], "with two wrong labels", events[3]
- )
- def test_messages_filter_labels_not_labels(self):
- """Test that we can filter by both a label and the absence of another label on a
- /messages request.
- """
- self._send_labelled_messages_in_room()
- token = "s0_0_0_0_0_0_0_0_0"
- request, channel = self.make_request(
- "GET",
- "/rooms/%s/messages?access_token=%s&from=%s&filter=%s"
- % (
- self.room_id,
- self.tok,
- token,
- json.dumps(self.FILTER_LABELS_NOT_LABELS),
- ),
- )
- self.render(request)
- events = channel.json_body["chunk"]
- self.assertEqual(len(events), 1, [event["content"] for event in events])
- self.assertEqual(events[0]["content"]["body"], "with wrong label", events[0])
- def test_search_filter_labels(self):
- """Test that we can filter by a label on a /search request."""
- request_data = json.dumps(
- {
- "search_categories": {
- "room_events": {
- "search_term": "label",
- "filter": self.FILTER_LABELS,
- }
- }
- }
- )
- self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "POST", "/search?access_token=%s" % self.tok, request_data
- )
- self.render(request)
- results = channel.json_body["search_categories"]["room_events"]["results"]
- self.assertEqual(
- len(results), 2, [result["result"]["content"] for result in results],
- )
- self.assertEqual(
- results[0]["result"]["content"]["body"],
- "with right label",
- results[0]["result"]["content"]["body"],
- )
- self.assertEqual(
- results[1]["result"]["content"]["body"],
- "with right label",
- results[1]["result"]["content"]["body"],
- )
- def test_search_filter_not_labels(self):
- """Test that we can filter by the absence of a label on a /search request."""
- request_data = json.dumps(
- {
- "search_categories": {
- "room_events": {
- "search_term": "label",
- "filter": self.FILTER_NOT_LABELS,
- }
- }
- }
- )
- self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "POST", "/search?access_token=%s" % self.tok, request_data
- )
- self.render(request)
- results = channel.json_body["search_categories"]["room_events"]["results"]
- self.assertEqual(
- len(results), 4, [result["result"]["content"] for result in results],
- )
- self.assertEqual(
- results[0]["result"]["content"]["body"],
- "without label",
- results[0]["result"]["content"]["body"],
- )
- self.assertEqual(
- results[1]["result"]["content"]["body"],
- "without label",
- results[1]["result"]["content"]["body"],
- )
- self.assertEqual(
- results[2]["result"]["content"]["body"],
- "with wrong label",
- results[2]["result"]["content"]["body"],
- )
- self.assertEqual(
- results[3]["result"]["content"]["body"],
- "with two wrong labels",
- results[3]["result"]["content"]["body"],
- )
- def test_search_filter_labels_not_labels(self):
- """Test that we can filter by both a label and the absence of another label on a
- /search request.
- """
- request_data = json.dumps(
- {
- "search_categories": {
- "room_events": {
- "search_term": "label",
- "filter": self.FILTER_LABELS_NOT_LABELS,
- }
- }
- }
- )
- self._send_labelled_messages_in_room()
- request, channel = self.make_request(
- "POST", "/search?access_token=%s" % self.tok, request_data
- )
- self.render(request)
- results = channel.json_body["search_categories"]["room_events"]["results"]
- self.assertEqual(
- len(results), 1, [result["result"]["content"] for result in results],
- )
- self.assertEqual(
- results[0]["result"]["content"]["body"],
- "with wrong label",
- results[0]["result"]["content"]["body"],
- )
- def _send_labelled_messages_in_room(self):
- """Sends several messages to a room with different labels (or without any) to test
- filtering by label.
- Returns:
- The ID of the event to use if we're testing filtering on /context.
- """
- self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={
- "msgtype": "m.text",
- "body": "with right label",
- EventContentFields.LABELS: ["#fun"],
- },
- tok=self.tok,
- )
- self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={"msgtype": "m.text", "body": "without label"},
- tok=self.tok,
- )
- res = self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={"msgtype": "m.text", "body": "without label"},
- tok=self.tok,
- )
- # Return this event's ID when we test filtering in /context requests.
- event_id = res["event_id"]
- self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={
- "msgtype": "m.text",
- "body": "with wrong label",
- EventContentFields.LABELS: ["#work"],
- },
- tok=self.tok,
- )
- self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={
- "msgtype": "m.text",
- "body": "with two wrong labels",
- EventContentFields.LABELS: ["#work", "#notfun"],
- },
- tok=self.tok,
- )
- self.helper.send_event(
- room_id=self.room_id,
- type=EventTypes.Message,
- content={
- "msgtype": "m.text",
- "body": "with right label",
- EventContentFields.LABELS: ["#fun"],
- },
- tok=self.tok,
- )
- 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, is_public=False
- )
- 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])
- class RoomAliasListTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- directory.register_servlets,
- login.register_servlets,
- room.register_servlets,
- ]
- def prepare(self, reactor, clock, homeserver):
- self.room_owner = self.register_user("room_owner", "test")
- self.room_owner_tok = self.login("room_owner", "test")
- self.room_id = self.helper.create_room_as(
- self.room_owner, tok=self.room_owner_tok
- )
- def test_no_aliases(self):
- res = self._get_aliases(self.room_owner_tok)
- self.assertEqual(res["aliases"], [])
- def test_not_in_room(self):
- self.register_user("user", "test")
- user_tok = self.login("user", "test")
- res = self._get_aliases(user_tok, expected_code=403)
- self.assertEqual(res["errcode"], "M_FORBIDDEN")
- def test_admin_user(self):
- alias1 = self._random_alias()
- self._set_alias_via_directory(alias1)
- self.register_user("user", "test", admin=True)
- user_tok = self.login("user", "test")
- res = self._get_aliases(user_tok)
- self.assertEqual(res["aliases"], [alias1])
- def test_with_aliases(self):
- alias1 = self._random_alias()
- alias2 = self._random_alias()
- self._set_alias_via_directory(alias1)
- self._set_alias_via_directory(alias2)
- res = self._get_aliases(self.room_owner_tok)
- self.assertEqual(set(res["aliases"]), {alias1, alias2})
- def test_peekable_room(self):
- alias1 = self._random_alias()
- self._set_alias_via_directory(alias1)
- self.helper.send_state(
- self.room_id,
- EventTypes.RoomHistoryVisibility,
- body={"history_visibility": "world_readable"},
- tok=self.room_owner_tok,
- )
- self.register_user("user", "test")
- user_tok = self.login("user", "test")
- res = self._get_aliases(user_tok)
- self.assertEqual(res["aliases"], [alias1])
- def _get_aliases(self, access_token: str, expected_code: int = 200) -> JsonDict:
- """Calls the endpoint under test. returns the json response object."""
- request, channel = self.make_request(
- "GET",
- "/_matrix/client/unstable/org.matrix.msc2432/rooms/%s/aliases"
- % (self.room_id,),
- access_token=access_token,
- )
- self.render(request)
- self.assertEqual(channel.code, expected_code, channel.result)
- res = channel.json_body
- self.assertIsInstance(res, dict)
- if expected_code == 200:
- self.assertIsInstance(res["aliases"], list)
- return res
- def _random_alias(self) -> str:
- return RoomAlias(random_string(5), self.hs.hostname).to_string()
- def _set_alias_via_directory(self, alias: str, expected_code: int = 200):
- url = "/_matrix/client/r0/directory/room/" + alias
- data = {"room_id": self.room_id}
- request_data = json.dumps(data)
- request, channel = self.make_request(
- "PUT", url, request_data, access_token=self.room_owner_tok
- )
- self.render(request)
- self.assertEqual(channel.code, expected_code, channel.result)
- class RoomCanonicalAliasTestCase(unittest.HomeserverTestCase):
- servlets = [
- synapse.rest.admin.register_servlets_for_client_rest_resource,
- directory.register_servlets,
- login.register_servlets,
- room.register_servlets,
- ]
- def prepare(self, reactor, clock, homeserver):
- self.room_owner = self.register_user("room_owner", "test")
- self.room_owner_tok = self.login("room_owner", "test")
- self.room_id = self.helper.create_room_as(
- self.room_owner, tok=self.room_owner_tok
- )
- self.alias = "#alias:test"
- self._set_alias_via_directory(self.alias)
- def _set_alias_via_directory(self, alias: str, expected_code: int = 200):
- url = "/_matrix/client/r0/directory/room/" + alias
- data = {"room_id": self.room_id}
- request_data = json.dumps(data)
- request, channel = self.make_request(
- "PUT", url, request_data, access_token=self.room_owner_tok
- )
- self.render(request)
- self.assertEqual(channel.code, expected_code, channel.result)
- def _get_canonical_alias(self, expected_code: int = 200) -> JsonDict:
- """Calls the endpoint under test. returns the json response object."""
- request, channel = self.make_request(
- "GET",
- "rooms/%s/state/m.room.canonical_alias" % (self.room_id,),
- access_token=self.room_owner_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, expected_code, channel.result)
- res = channel.json_body
- self.assertIsInstance(res, dict)
- return res
- def _set_canonical_alias(self, content: str, expected_code: int = 200) -> JsonDict:
- """Calls the endpoint under test. returns the json response object."""
- request, channel = self.make_request(
- "PUT",
- "rooms/%s/state/m.room.canonical_alias" % (self.room_id,),
- json.dumps(content),
- access_token=self.room_owner_tok,
- )
- self.render(request)
- self.assertEqual(channel.code, expected_code, channel.result)
- res = channel.json_body
- self.assertIsInstance(res, dict)
- return res
- def test_canonical_alias(self):
- """Test a basic alias message."""
- # There is no canonical alias to start with.
- self._get_canonical_alias(expected_code=404)
- # Create an alias.
- self._set_canonical_alias({"alias": self.alias})
- # Canonical alias now exists!
- res = self._get_canonical_alias()
- self.assertEqual(res, {"alias": self.alias})
- # Now remove the alias.
- self._set_canonical_alias({})
- # There is an alias event, but it is empty.
- res = self._get_canonical_alias()
- self.assertEqual(res, {})
- def test_alt_aliases(self):
- """Test a canonical alias message with alt_aliases."""
- # Create an alias.
- self._set_canonical_alias({"alt_aliases": [self.alias]})
- # Canonical alias now exists!
- res = self._get_canonical_alias()
- self.assertEqual(res, {"alt_aliases": [self.alias]})
- # Now remove the alt_aliases.
- self._set_canonical_alias({})
- # There is an alias event, but it is empty.
- res = self._get_canonical_alias()
- self.assertEqual(res, {})
- def test_alias_alt_aliases(self):
- """Test a canonical alias message with an alias and alt_aliases."""
- # Create an alias.
- self._set_canonical_alias({"alias": self.alias, "alt_aliases": [self.alias]})
- # Canonical alias now exists!
- res = self._get_canonical_alias()
- self.assertEqual(res, {"alias": self.alias, "alt_aliases": [self.alias]})
- # Now remove the alias and alt_aliases.
- self._set_canonical_alias({})
- # There is an alias event, but it is empty.
- res = self._get_canonical_alias()
- self.assertEqual(res, {})
- def test_partial_modify(self):
- """Test removing only the alt_aliases."""
- # Create an alias.
- self._set_canonical_alias({"alias": self.alias, "alt_aliases": [self.alias]})
- # Canonical alias now exists!
- res = self._get_canonical_alias()
- self.assertEqual(res, {"alias": self.alias, "alt_aliases": [self.alias]})
- # Now remove the alt_aliases.
- self._set_canonical_alias({"alias": self.alias})
- # There is an alias event, but it is empty.
- res = self._get_canonical_alias()
- self.assertEqual(res, {"alias": self.alias})
- def test_add_alias(self):
- """Test removing only the alt_aliases."""
- # Create an additional alias.
- second_alias = "#second:test"
- self._set_alias_via_directory(second_alias)
- # Add the canonical alias.
- self._set_canonical_alias({"alias": self.alias, "alt_aliases": [self.alias]})
- # Then add the second alias.
- self._set_canonical_alias(
- {"alias": self.alias, "alt_aliases": [self.alias, second_alias]}
- )
- # Canonical alias now exists!
- res = self._get_canonical_alias()
- self.assertEqual(
- res, {"alias": self.alias, "alt_aliases": [self.alias, second_alias]}
- )
- def test_bad_data(self):
- """Invalid data for alt_aliases should cause errors."""
- self._set_canonical_alias({"alt_aliases": "@bad:test"}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": None}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": 0}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": 1}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": False}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": True}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": {}}, expected_code=400)
- def test_bad_alias(self):
- """An alias which does not point to the room raises a SynapseError."""
- self._set_canonical_alias({"alias": "@unknown:test"}, expected_code=400)
- self._set_canonical_alias({"alt_aliases": ["@unknown:test"]}, expected_code=400)
|