def on_POST(self, request): yield self.auth.get_user_by_req(request, allow_guest=True) server = parse_string(request, "server", default=None) content = parse_json_object_from_request(request) limit = int(content.get("limit", 100)) since_token = content.get("since", None) search_filter = content.get("filter", None) handler = self.hs.get_room_list_handler() if server: data = yield handler.get_remote_public_room_list( server, limit=limit, since_token=since_token, search_filter=search_filter, ) else: data = yield handler.get_local_public_room_list( limit=limit, since_token=since_token, search_filter=search_filter, ) defer.returnValue((200, data))
def on_POST(self, request): requester = yield self.auth.get_user_by_req(request) try: body = parse_json_object_from_request(request) except errors.SynapseError as e: if e.errcode == errors.Codes.NOT_JSON: # DELETE # deal with older clients which didn't pass a JSON dict # the same as those that pass an empty dict body = {} else: raise e assert_params_in_dict(body, ["devices"]) yield self.auth_handler.validate_user_via_ui_auth( requester, body, self.hs.get_ip_from_request(request), ) yield self.device_handler.delete_devices( requester.user.to_string(), body['devices'], ) defer.returnValue((200, {}))
def on_POST(self, request): requester = yield self.auth.get_user_by_req(request) user = requester.user content = parse_json_object_from_request(request) pusher_pool = self.hs.get_pusherpool() if ('pushkey' in content and 'app_id' in content and 'kind' in content and content['kind'] is None): yield pusher_pool.remove_pusher( content['app_id'], content['pushkey'], user_id=user.to_string() ) defer.returnValue((200, {})) reqd = ['kind', 'app_id', 'app_display_name', 'device_display_name', 'pushkey', 'lang', 'data'] missing = [] for i in reqd: if i not in content: missing.append(i) if len(missing): raise SynapseError(400, "Missing parameters: " + ','.join(missing), errcode=Codes.MISSING_PARAM) logger.debug("set pushkey %s to kind %s", content['pushkey'], content['kind']) logger.debug("Got pushers request with body: %r", content) append = False if 'append' in content: append = content['append'] if not append: yield pusher_pool.remove_pushers_by_app_id_and_pushkey_not_user( app_id=content['app_id'], pushkey=content['pushkey'], not_user_id=user.to_string() ) try: yield pusher_pool.add_pusher( user_id=user.to_string(), access_token=requester.access_token_id, kind=content['kind'], app_id=content['app_id'], app_display_name=content['app_display_name'], device_display_name=content['device_display_name'], pushkey=content['pushkey'], lang=content['lang'], data=content['data'], profile_tag=content.get('profile_tag', ""), ) except PusherConfigException as pce: raise SynapseError(400, "Config Error: " + pce.message, errcode=Codes.MISSING_PARAM) self.notifier.on_new_replication_data() defer.returnValue((200, {}))
def _handle_request(self, request, event_id): with Measure(self.clock, "repl_send_event_parse"): content = parse_json_object_from_request(request) event_dict = content["event"] internal_metadata = content["internal_metadata"] rejected_reason = content["rejected_reason"] event = FrozenEvent(event_dict, internal_metadata, rejected_reason) requester = Requester.deserialize(self.store, content["requester"]) context = yield EventContext.deserialize(self.store, content["context"]) ratelimit = content["ratelimit"] extra_users = [UserID.from_string(u) for u in content["extra_users"]] if requester.user: request.authenticated_entity = requester.user.to_string() logger.info( "Got event to send with ID: %s into room: %s", event.event_id, event.room_id, ) yield self.event_creation_handler.persist_and_notify_client_event( requester, event, context, ratelimit=ratelimit, extra_users=extra_users, ) defer.returnValue((200, {}))
def on_PUT(self, request, room_alias): room_alias = RoomAlias.from_string(room_alias) content = parse_json_object_from_request(request) if "room_id" not in content: raise SynapseError(400, 'Missing params: ["room_id"]', errcode=Codes.BAD_JSON) logger.debug("Got content: %s", content) logger.debug("Got room name: %s", room_alias.to_string()) room_id = content["room_id"] servers = content["servers"] if "servers" in content else None logger.debug("Got room_id: %s", room_id) logger.debug("Got servers: %s", servers) # TODO(erikj): Check types. room = yield self.store.get_room(room_id) if room is None: raise SynapseError(400, "Room does not exist") requester = yield self.auth.get_user_by_req(request) yield self.handlers.directory_handler.create_association( requester, room_alias, room_id, servers ) defer.returnValue((200, {}))
def on_PUT(self, request, version): """ Update the information about a given version of the user's room_keys backup. POST /room_keys/version/12345 HTTP/1.1 Content-Type: application/json { "algorithm": "m.megolm_backup.v1", "auth_data": { "public_key": "abcdefg", "signatures": { "ed25519:something": "hijklmnop" } }, "version": "42" } HTTP/1.1 200 OK Content-Type: application/json {} """ requester = yield self.auth.get_user_by_req(request, allow_guest=False) user_id = requester.user.to_string() info = parse_json_object_from_request(request) if version is None: raise SynapseError(400, "No version specified to update", Codes.MISSING_PARAM) yield self.e2e_room_keys_handler.update_version( user_id, version, info ) defer.returnValue((200, {}))
def on_POST(self, request): yield run_on_reactor() body = parse_json_object_from_request(request) threePidCreds = body.get("threePidCreds") threePidCreds = body.get("three_pid_creds", threePidCreds) if threePidCreds is None: raise SynapseError(400, "Missing param", Codes.MISSING_PARAM) requester = yield self.auth.get_user_by_req(request) user_id = requester.user.to_string() threepid = yield self.identity_handler.threepid_from_creds(threePidCreds) if not threepid: raise SynapseError(400, "Failed to auth 3pid", Codes.THREEPID_AUTH_FAILED) for reqd in ["medium", "address", "validated_at"]: if reqd not in threepid: logger.warn("Couldn't add 3pid: invalid response from ID sevrer") raise SynapseError(500, "Invalid response from ID Server") yield self.auth_handler.add_threepid(user_id, threepid["medium"], threepid["address"], threepid["validated_at"]) if "bind" in body and body["bind"]: logger.debug("Binding emails %s to %s", threepid, user_id) yield self.identity_handler.bind_threepid(threePidCreds, user_id) defer.returnValue((200, {}))
def on_PUT(self, request, user_id): requester = yield self.auth.get_user_by_req(request) user = UserID.from_string(user_id) if requester.user != user: raise AuthError(403, "Can only set your own presence state") state = {} content = parse_json_object_from_request(request) try: state["presence"] = content.pop("presence") if "status_msg" in content: state["status_msg"] = content.pop("status_msg") if not isinstance(state["status_msg"], string_types): raise SynapseError(400, "status_msg must be a string.") if content: raise KeyError() except SynapseError as e: raise e except Exception: raise SynapseError(400, "Unable to parse state") if self.hs.config.use_presence: yield self.presence_handler.set_state(user, state) defer.returnValue((200, {}))
def on_POST(self, request): login_submission = parse_json_object_from_request(request) try: if self.saml2_enabled and (login_submission["type"] == LoginRestServlet.SAML2_TYPE): relay_state = "" if "relay_state" in login_submission: relay_state = "&RelayState=" + urllib.parse.quote( login_submission["relay_state"]) result = { "uri": "%s%s" % (self.idp_redirect_url, relay_state) } defer.returnValue((200, result)) elif self.jwt_enabled and (login_submission["type"] == LoginRestServlet.JWT_TYPE): result = yield self.do_jwt_login(login_submission) defer.returnValue(result) elif login_submission["type"] == LoginRestServlet.TOKEN_TYPE: result = yield self.do_token_login(login_submission) defer.returnValue(result) else: result = yield self._do_other_login(login_submission) defer.returnValue(result) except KeyError: raise SynapseError(400, "Missing JSON keys.")
def on_POST(self, request, target_user_id): """Post request to get specific number of users from Synapse.. This needs user to have administrator access in Synapse. Example: http://localhost:8008/_synapse/admin/v1/users_paginate/ @admin:user?access_token=admin_access_token JsonBodyToSend: { "start": "0", "limit": "10 } Returns: 200 OK with json object {list[dict[str, Any]], count} or empty object. """ yield assert_requester_is_admin(self.auth, request) UserID.from_string(target_user_id) order = "name" # order by name in user table params = parse_json_object_from_request(request) assert_params_in_dict(params, ["limit", "start"]) limit = params['limit'] start = params['start'] logger.info("limit: %s, start: %s", limit, start) ret = yield self.handlers.admin_handler.get_users_paginate( order, start, limit ) defer.returnValue((200, ret))
def on_PUT(self, request, room_id, user_id): requester = yield self.auth.get_user_by_req(request) room_id = urllib.unquote(room_id) target_user = UserID.from_string(urllib.unquote(user_id)) content = parse_json_object_from_request(request) yield self.presence_handler.bump_presence_active_time(requester.user) if content["typing"]: yield self.typing_handler.started_typing( target_user=target_user, auth_user=requester.user, room_id=room_id, timeout=content.get("timeout", 30000), ) else: yield self.typing_handler.stopped_typing( target_user=target_user, auth_user=requester.user, room_id=room_id, ) defer.returnValue((200, {}))
def on_POST(self, request): body = parse_json_object_from_request(request) assert_params_in_dict(body, [ 'id_server', 'client_secret', 'country', 'phone_number', 'send_attempt', ]) msisdn = phone_number_to_msisdn(body['country'], body['phone_number']) if not check_3pid_allowed(self.hs, "msisdn", msisdn): raise SynapseError( 403, "Account phone numbers are not authorized on this server", Codes.THREEPID_DENIED, ) existingUid = yield self.datastore.get_user_id_by_threepid( 'msisdn', msisdn ) if existingUid is None: raise SynapseError(400, "MSISDN not found", Codes.THREEPID_NOT_FOUND) ret = yield self.identity_handler.requestMsisdnToken(**body) defer.returnValue((200, ret))
def on_POST(self, request): body = parse_json_object_from_request(request) assert_params_in_dict(body, ['medium', 'address']) requester = yield self.auth.get_user_by_req(request) user_id = requester.user.to_string() try: ret = yield self.auth_handler.delete_threepid( user_id, body['medium'], body['address'], body.get("id_server"), ) except Exception: # NB. This endpoint should succeed if there is nothing to # delete, so it should only throw if something is wrong # that we ought to care about. logger.exception("Failed to remove threepid") raise SynapseError(500, "Failed to remove threepid") if ret: id_server_unbind_result = "success" else: id_server_unbind_result = "no-support" defer.returnValue((200, { "id_server_unbind_result": id_server_unbind_result, }))
def on_POST(self, request): body = parse_json_object_from_request(request) erase = body.get("erase", False) if not isinstance(erase, bool): raise SynapseError( http_client.BAD_REQUEST, "Param 'erase' must be a boolean, if given", Codes.BAD_JSON, ) requester = yield self.auth.get_user_by_req(request) # allow ASes to dectivate their own users if requester.app_service: yield self._deactivate_account_handler.deactivate_account( requester.user.to_string(), erase, ) defer.returnValue((200, {})) yield self.auth_handler.validate_user_via_ui_auth( requester, body, self.hs.get_ip_from_request(request), ) result = yield self._deactivate_account_handler.deactivate_account( requester.user.to_string(), erase, id_server=body.get("id_server"), ) if result: id_server_unbind_result = "success" else: id_server_unbind_result = "no-support" defer.returnValue((200, { "id_server_unbind_result": id_server_unbind_result, }))
def on_POST(self, request): """Searches for users in directory Returns: dict of the form:: { "limited": <bool>, # whether there were more results or not "results": [ # Ordered by best match first { "user_id": <user_id>, "display_name": <display_name>, "avatar_url": <avatar_url> } ] } """ requester = yield self.auth.get_user_by_req(request, allow_guest=False) user_id = requester.user.to_string() body = parse_json_object_from_request(request) limit = body.get("limit", 10) limit = min(limit, 50) try: search_term = body["search_term"] except Exception: raise SynapseError(400, "`search_term` is required field") results = yield self.user_directory_handler.search_users( user_id, search_term, limit, ) defer.returnValue((200, results))
def on_PUT(self, request, room_id, event_type, state_key, txn_id=None): requester = yield self.auth.get_user_by_req(request) content = parse_json_object_from_request(request) event_dict = { "type": event_type, "content": content, "room_id": room_id, "sender": requester.user.to_string(), } if state_key is not None: event_dict["state_key"] = state_key msg_handler = self.handlers.message_handler event, context = yield msg_handler.create_event( event_dict, token_id=requester.access_token_id, txn_id=txn_id, ) if event_type == EventTypes.Member: yield self.handlers.room_member_handler.send_membership_event( requester, event, context, ) else: yield msg_handler.send_nonmember_event(requester, event, context) defer.returnValue((200, {"event_id": event.event_id}))
def new_func(request, *args, **kwargs): content = None if request.method in ["PUT", "POST"]: # TODO: Handle other method types? other content types? content = parse_json_object_from_request(request) try: origin = yield authenticator.authenticate_request(request, content) except NoAuthenticationError: origin = None if self.REQUIRE_AUTH: logger.exception("authenticate_request failed") raise except: logger.exception("authenticate_request failed") raise if origin: with ratelimiter.ratelimit(origin) as d: yield d response = yield func( origin, content, request.args, *args, **kwargs ) else: response = yield func( origin, content, request.args, *args, **kwargs ) defer.returnValue(response)
def on_POST(self, request, device_id): requester = yield self.auth.get_user_by_req(request) user_id = requester.user.to_string() body = parse_json_object_from_request(request) if device_id is not None: # passing the device_id here is deprecated; however, we allow it # for now for compatibility with older clients. if (requester.device_id is not None and device_id != requester.device_id): logger.warning("Client uploading keys for a different device " "(logged in as %s, uploading for %s)", requester.device_id, device_id) else: device_id = requester.device_id if device_id is None: raise SynapseError( 400, "To upload keys, you must pass device_id when authenticating" ) result = yield self.e2e_keys_handler.upload_keys_for_user( user_id, device_id, body ) defer.returnValue((200, result))
def on_POST(self, request, room_id): requester = yield self.auth.get_user_by_req(request) yield self.presence_handler.bump_presence_active_time(requester.user) body = parse_json_object_from_request(request) read_event_id = body.get("m.read", None) if read_event_id: yield self.receipts_handler.received_client_receipt( room_id, "m.read", user_id=requester.user.to_string(), event_id=read_event_id ) read_marker_event_id = body.get("m.fully_read", None) if read_marker_event_id: yield self.read_marker_handler.received_client_read_marker( room_id, user_id=requester.user.to_string(), event_id=read_marker_event_id ) defer.returnValue((200, {}))
def on_POST(self, request): content = parse_json_object_from_request(request) remote_room_hosts = content["remote_room_hosts"] room_id = content["room_id"] user_id = content["user_id"] event_content = content["content"] requester = Requester.deserialize(self.store, content["requester"]) if requester.user: request.authenticated_entity = requester.user.to_string() logger.info( "remote_join: %s into room: %s", user_id, room_id, ) yield self.federation_handler.do_invite_join( remote_room_hosts, room_id, user_id, event_content, ) defer.returnValue((200, {}))
def on_POST(self, request): body = parse_json_object_from_request(request) required = [ 'id_server', 'client_secret', 'country', 'phone_number', 'send_attempt', ] absent = [] for k in required: if k not in body: absent.append(k) if absent: raise SynapseError(400, "Missing params: %r" % absent, Codes.MISSING_PARAM) msisdn = phone_number_to_msisdn(body['country'], body['phone_number']) if not check_3pid_allowed(self.hs, "msisdn", msisdn): raise SynapseError( 403, "Third party identifier is not allowed", Codes.THREEPID_DENIED, ) existingUid = yield self.datastore.get_user_id_by_threepid( 'msisdn', msisdn ) if existingUid is not None: raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE) ret = yield self.identity_handler.requestMsisdnToken(**body) defer.returnValue((200, ret))
def on_POST(self, request): body = parse_json_object_from_request(request) assert_params_in_request(body, [ 'id_server', 'client_secret', 'country', 'phone_number', 'send_attempt', ]) msisdn = phone_number_to_msisdn(body['country'], body['phone_number']) if not check_3pid_allowed(self.hs, "msisdn", msisdn): raise SynapseError( 403, "Third party identifier is not allowed", Codes.THREEPID_DENIED, ) existingUid = yield self.hs.get_datastore().get_user_id_by_threepid( 'msisdn', msisdn ) if existingUid is not None: raise SynapseError( 400, "Phone number is already in use", Codes.THREEPID_IN_USE ) ret = yield self.identity_handler.requestMsisdnToken(**body) defer.returnValue((200, ret))
def on_POST(self, request): body = parse_json_object_from_request(request) authed, result, params, _ = yield self.auth_handler.check_auth([ [LoginType.PASSWORD], ], body, self.hs.get_ip_from_request(request)) if not authed: defer.returnValue((401, result)) user_id = None requester = None if LoginType.PASSWORD in result: # if using password, they should also be logged in requester = yield self.auth.get_user_by_req(request) user_id = requester.user.to_string() if user_id != result[LoginType.PASSWORD]: raise LoginError(400, "", Codes.UNKNOWN) else: logger.error("Auth succeeded but no known type!", result.keys()) raise SynapseError(500, "", Codes.UNKNOWN) # FIXME: Theoretically there is a race here wherein user resets password # using threepid. yield self.store.user_delete_access_tokens(user_id) yield self.store.user_delete_threepids(user_id) yield self.store.user_set_password_hash(user_id, None) defer.returnValue((200, {}))
def on_POST(self, request, target_user_id): body = parse_json_object_from_request(request, allow_empty_body=True) erase = body.get("erase", False) if not isinstance(erase, bool): raise SynapseError( http_client.BAD_REQUEST, "Param 'erase' must be a boolean, if given", Codes.BAD_JSON, ) UserID.from_string(target_user_id) requester = yield self.auth.get_user_by_req(request) is_admin = yield self.auth.is_server_admin(requester.user) if not is_admin: raise AuthError(403, "You are not a server admin") result = yield self._deactivate_account_handler.deactivate_account( target_user_id, erase, ) if result: id_server_unbind_result = "success" else: id_server_unbind_result = "no-support" defer.returnValue((200, { "id_server_unbind_result": id_server_unbind_result, }))
def on_POST(self, request, room_id, event_id): requester = yield self.auth.get_user_by_req(request) user_id = requester.user.to_string() body = parse_json_object_from_request(request) assert_params_in_dict(body, ("reason", "score")) if not isinstance(body["reason"], string_types): raise SynapseError( http_client.BAD_REQUEST, "Param 'reason' must be a string", Codes.BAD_JSON, ) if not isinstance(body["score"], int): raise SynapseError( http_client.BAD_REQUEST, "Param 'score' must be an integer", Codes.BAD_JSON, ) yield self.store.add_event_report( room_id=room_id, event_id=event_id, user_id=user_id, reason=body["reason"], content=body, received_ts=self.clock.time_msec(), ) defer.returnValue((200, {}))
def on_POST(self, request): login_submission = parse_json_object_from_request(request) try: if login_submission["type"] == LoginRestServlet.PASS_TYPE: if not self.password_enabled: raise SynapseError(400, "Password login has been disabled.") result = yield self.do_password_login(login_submission) defer.returnValue(result) elif self.saml2_enabled and (login_submission["type"] == LoginRestServlet.SAML2_TYPE): relay_state = "" if "relay_state" in login_submission: relay_state = "&RelayState=" + urllib.quote(login_submission["relay_state"]) result = {"uri": "%s%s" % (self.idp_redirect_url, relay_state)} defer.returnValue((200, result)) # TODO Delete this after all CAS clients switch to token login instead elif self.cas_enabled and (login_submission["type"] == LoginRestServlet.CAS_TYPE): uri = "%s/proxyValidate" % (self.cas_server_url,) args = {"ticket": login_submission["ticket"], "service": login_submission["service"]} body = yield self.http_client.get_raw(uri, args) result = yield self.do_cas_login(body) defer.returnValue(result) elif login_submission["type"] == LoginRestServlet.TOKEN_TYPE: result = yield self.do_token_login(login_submission) defer.returnValue(result) else: raise SynapseError(400, "Bad login type.") except KeyError: raise SynapseError(400, "Missing JSON keys.")
def on_PUT(self, request, room_id, event_type, state_key, txn_id=None): requester = yield self.auth.get_user_by_req(request) content = parse_json_object_from_request(request) event_dict = { "type": event_type, "content": content, "room_id": room_id, "sender": requester.user.to_string(), } if state_key is not None: event_dict["state_key"] = state_key if event_type == EventTypes.Member: membership = content.get("membership", None) event = yield self.room_member_handler.update_membership( requester, target=UserID.from_string(state_key), room_id=room_id, action=membership, content=content, ) else: event = yield self.event_creation_hander.create_and_send_nonmember_event( requester, event_dict, txn_id=txn_id, ) ret = {} if event: ret = {"event_id": event.event_id} defer.returnValue((200, ret))
def on_PUT_or_POST( self, request, room_id, parent_id, relation_type, event_type, txn_id=None ): requester = yield self.auth.get_user_by_req(request, allow_guest=True) if event_type == EventTypes.Member: # Add relations to a membership is meaningless, so we just deny it # at the CS API rather than trying to handle it correctly. raise SynapseError(400, "Cannot send member events with relations") content = parse_json_object_from_request(request) aggregation_key = parse_string(request, "key", encoding="utf-8") content["m.relates_to"] = { "event_id": parent_id, "key": aggregation_key, "rel_type": relation_type, } event_dict = { "type": event_type, "content": content, "room_id": room_id, "sender": requester.user.to_string(), } event = yield self.event_creation_handler.create_and_send_nonmember_event( requester, event_dict=event_dict, txn_id=txn_id ) defer.returnValue((200, {"event_id": event.event_id}))
def on_PUT(self, request, room_alias): content = parse_json_object_from_request(request) if "room_id" not in content: raise SynapseError(400, "Missing room_id key", errcode=Codes.BAD_JSON) logger.debug("Got content: %s", content) room_alias = RoomAlias.from_string(room_alias) logger.debug("Got room name: %s", room_alias.to_string()) room_id = content["room_id"] servers = content["servers"] if "servers" in content else None logger.debug("Got room_id: %s", room_id) logger.debug("Got servers: %s", servers) # TODO(erikj): Check types. room = yield self.store.get_room(room_id) if room is None: raise SynapseError(400, "Room does not exist") dir_handler = self.handlers.directory_handler try: # try to auth as a user requester = yield self.auth.get_user_by_req(request) try: user_id = requester.user.to_string() yield dir_handler.create_association( user_id, room_alias, room_id, servers ) yield dir_handler.send_room_alias_update_event( requester, user_id, room_id ) except SynapseError as e: raise e except Exception: logger.exception("Failed to create association") raise except AuthError: # try to auth as an application service service = yield self.auth.get_appservice_by_req(request) yield dir_handler.create_appservice_association( service, room_alias, room_id, servers ) logger.info( "Application service at %s created alias %s pointing to %s", service.url, room_alias.to_string(), room_id ) defer.returnValue((200, {}))
def on_POST(self, request, room_id, membership_action, txn_id=None): requester = yield self.auth.get_user_by_req( request, allow_guest=True, ) if requester.is_guest and membership_action not in { Membership.JOIN, Membership.LEAVE }: raise AuthError(403, "Guest access not allowed") try: content = parse_json_object_from_request(request) except Exception: # Turns out we used to ignore the body entirely, and some clients # cheekily send invalid bodies. content = {} if membership_action == "invite" and self._has_3pid_invite_keys(content): yield self.room_member_handler.do_3pid_invite( room_id, requester.user, content["medium"], content["address"], content["id_server"], requester, txn_id ) defer.returnValue((200, {})) return target = requester.user if membership_action in ["invite", "ban", "unban", "kick"]: if "user_id" not in content: raise SynapseError(400, "Missing user_id key.") target = UserID.from_string(content["user_id"]) event_content = None if 'reason' in content and membership_action in ['kick', 'ban']: event_content = {'reason': content['reason']} yield self.room_member_handler.update_membership( requester=requester, target=target, room_id=room_id, action=membership_action, txn_id=txn_id, third_party_signed=content.get("third_party_signed", None), content=event_content, ) return_value = {} if membership_action == "join": return_value["room_id"] = room_id defer.returnValue((200, return_value))
async def new_func(request, *args, **kwargs): """A callback which can be passed to HttpServer.RegisterPaths Args: request (twisted.web.http.Request): *args: unused? **kwargs (dict[unicode, unicode]): the dict mapping keys to path components as specified in the path match regexp. Returns: Tuple[int, object]|None: (response code, response object) as returned by the callback method. None if the request has already been handled. """ content = None if request.method in [b"PUT", b"POST"]: # TODO: Handle other method types? other content types? content = parse_json_object_from_request(request) try: origin = await authenticator.authenticate_request( request, content) except NoAuthenticationError: origin = None if self.REQUIRE_AUTH: logger.warning( "authenticate_request failed: missing authentication") raise except Exception as e: logger.warning("authenticate_request failed: %s", e) raise request_tags = { SynapseTags.REQUEST_ID: request.get_request_id(), tags.SPAN_KIND: tags.SPAN_KIND_RPC_SERVER, tags.HTTP_METHOD: request.get_method(), tags.HTTP_URL: request.get_redacted_uri(), tags.PEER_HOST_IPV6: request.getClientIP(), "authenticated_entity": origin, "servlet_name": request.request_metrics.name, } # Only accept the span context if the origin is authenticated # and whitelisted if origin and whitelisted_homeserver(origin): scope = start_active_span_from_request( request, "incoming-federation-request", tags=request_tags) else: scope = start_active_span("incoming-federation-request", tags=request_tags) with scope: opentracing.inject_response_headers(request.responseHeaders) if origin and self.RATELIMIT: with ratelimiter.ratelimit(origin) as d: await d if request._disconnected: logger.warning( "client disconnected before we started processing " "request") return -1, None response = await func(origin, content, request.args, *args, **kwargs) else: response = await func(origin, content, request.args, *args, **kwargs) return response
async def on_POST(self, request: SynapseRequest, room_id: str, event_id: Optional[str]) -> Tuple[int, JsonDict]: await assert_requester_is_admin(self.auth, request) body = parse_json_object_from_request(request, allow_empty_body=True) delete_local_events = bool(body.get("delete_local_events", False)) # establish the topological ordering we should keep events from. The # user can provide an event_id in the URL or the request body, or can # provide a timestamp in the request body. if event_id is None: event_id = body.get("purge_up_to_event_id") if event_id is not None: event = await self.store.get_event(event_id) if event.room_id != room_id: raise SynapseError(400, "Event is for wrong room.") # RoomStreamToken expects [int] not Optional[int] assert event.internal_metadata.stream_ordering is not None room_token = RoomStreamToken( event.depth, event.internal_metadata.stream_ordering) token = await room_token.to_string(self.store) logger.info("[purge] purging up to token %s (event_id %s)", token, event_id) elif "purge_up_to_ts" in body: ts = body["purge_up_to_ts"] if not isinstance(ts, int): raise SynapseError(400, "purge_up_to_ts must be an int", errcode=Codes.BAD_JSON) stream_ordering = await self.store.find_first_stream_ordering_after_ts( ts) r = await self.store.get_room_event_before_stream_ordering( room_id, stream_ordering) if not r: logger.warning( "[purge] purging events not possible: No event found " "(received_ts %i => stream_ordering %i)", ts, stream_ordering, ) raise SynapseError(404, "there is no event to be purged", errcode=Codes.NOT_FOUND) (stream, topo, _event_id) = r token = "t%d-%d" % (topo, stream) logger.info( "[purge] purging up to token %s (received_ts %i => " "stream_ordering %i)", token, ts, stream_ordering, ) else: raise SynapseError( 400, "must specify purge_up_to_event_id or purge_up_to_ts", errcode=Codes.BAD_JSON, ) purge_id = self.pagination_handler.start_purge_history( room_id, token, delete_local_events=delete_local_events) return 200, {"purge_id": purge_id}
async def on_POST(self, request): self._clear_old_nonces() if not self.hs.config.registration_shared_secret: raise SynapseError(400, "Shared secret registration is not enabled") body = parse_json_object_from_request(request) if "nonce" not in body: raise SynapseError(400, "nonce must be specified", errcode=Codes.BAD_JSON) nonce = body["nonce"] if nonce not in self.nonces: raise SynapseError(400, "unrecognised nonce") # Delete the nonce, so it can't be reused, even if it's invalid del self.nonces[nonce] if "username" not in body: raise SynapseError(400, "username must be specified", errcode=Codes.BAD_JSON) else: if (not isinstance(body["username"], text_type) or len(body["username"]) > 512): raise SynapseError(400, "Invalid username") username = body["username"].encode("utf-8") if b"\x00" in username: raise SynapseError(400, "Invalid username") if "password" not in body: raise SynapseError(400, "password must be specified", errcode=Codes.BAD_JSON) else: if (not isinstance(body["password"], text_type) or len(body["password"]) > 512): raise SynapseError(400, "Invalid password") password = body["password"].encode("utf-8") if b"\x00" in password: raise SynapseError(400, "Invalid password") admin = body.get("admin", None) user_type = body.get("user_type", None) if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES: raise SynapseError(400, "Invalid user type") got_mac = body["mac"] want_mac = hmac.new( key=self.hs.config.registration_shared_secret.encode(), digestmod=hashlib.sha1, ) want_mac.update(nonce.encode("utf8")) want_mac.update(b"\x00") want_mac.update(username) want_mac.update(b"\x00") want_mac.update(password) want_mac.update(b"\x00") want_mac.update(b"admin" if admin else b"notadmin") if user_type: want_mac.update(b"\x00") want_mac.update(user_type.encode("utf8")) want_mac = want_mac.hexdigest() if not hmac.compare_digest(want_mac.encode("ascii"), got_mac.encode("ascii")): raise SynapseError(403, "HMAC incorrect") # Reuse the parts of RegisterRestServlet to reduce code duplication from synapse.rest.client.v2_alpha.register import RegisterRestServlet register = RegisterRestServlet(self.hs) user_id = await register.registration_handler.register_user( localpart=body["username"].lower(), password=body["password"], admin=bool(admin), user_type=user_type, ) result = await register._create_registration_details(user_id, body) return 200, result
async def on_POST(self, request: SynapseRequest, room_identifier: str) -> Tuple[int, JsonDict]: # This will always be set by the time Twisted calls us. assert request.args is not None requester = await self.auth.get_user_by_req(request) await assert_user_is_admin(self.auth, requester.user) content = parse_json_object_from_request(request) assert_params_in_dict(content, ["user_id"]) target_user = UserID.from_string(content["user_id"]) if not self.hs.is_mine(target_user): raise SynapseError( 400, "This endpoint can only be used with local users") if not await self.admin_handler.get_user(target_user): raise NotFoundError("User not found") # Get the room ID from the identifier. try: remote_room_hosts = [ x.decode("ascii") for x in request.args[b"server_name"] ] # type: Optional[List[str]] except Exception: remote_room_hosts = None room_id, remote_room_hosts = await self.resolve_room_id( room_identifier, remote_room_hosts) fake_requester = create_requester( target_user, authenticated_entity=requester.authenticated_entity) # send invite if room has "JoinRules.INVITE" room_state = await self.state_handler.get_current_state(room_id) join_rules_event = room_state.get((EventTypes.JoinRules, "")) if join_rules_event: if not (join_rules_event.content.get("join_rule") == JoinRules.PUBLIC): # update_membership with an action of "invite" can raise a # ShadowBanError. This is not handled since it is assumed that # an admin isn't going to call this API with a shadow-banned user. await self.room_member_handler.update_membership( requester=requester, target=fake_requester.user, room_id=room_id, action="invite", remote_room_hosts=remote_room_hosts, ratelimit=False, ) await self.room_member_handler.update_membership( requester=fake_requester, target=fake_requester.user, room_id=room_id, action="join", remote_room_hosts=remote_room_hosts, ratelimit=False, ) return 200, {"room_id": room_id}
async def on_POST(self, request: SynapseRequest, room_identifier: str) -> Tuple[int, JsonDict]: requester = await self.auth.get_user_by_req(request) await assert_user_is_admin(self.auth, requester.user) content = parse_json_object_from_request(request, allow_empty_body=True) room_id, _ = await self.resolve_room_id(room_identifier) # Which user to grant room admin rights to. user_to_add = content.get("user_id", requester.user.to_string()) # Figure out which local users currently have power in the room, if any. room_state = await self.state_handler.get_current_state(room_id) if not room_state: raise SynapseError(400, "Server not in room") create_event = room_state[(EventTypes.Create, "")] power_levels = room_state.get((EventTypes.PowerLevels, "")) if power_levels is not None: # We pick the local user with the highest power. user_power = power_levels.content.get("users", {}) admin_users = [ user_id for user_id in user_power if self.is_mine_id(user_id) ] admin_users.sort(key=lambda user: user_power[user]) if not admin_users: raise SynapseError(400, "No local admin user in room") admin_user_id = None for admin_user in reversed(admin_users): if room_state.get((EventTypes.Member, admin_user)): admin_user_id = admin_user break if not admin_user_id: raise SynapseError( 400, "No local admin user in room", ) pl_content = power_levels.content else: # If there is no power level events then the creator has rights. pl_content = {} admin_user_id = create_event.sender if not self.is_mine_id(admin_user_id): raise SynapseError( 400, "No local admin user in room", ) # Grant the user power equal to the room admin by attempting to send an # updated power level event. new_pl_content = dict(pl_content) new_pl_content["users"] = dict(pl_content.get("users", {})) new_pl_content["users"][user_to_add] = new_pl_content["users"][ admin_user_id] fake_requester = create_requester( admin_user_id, authenticated_entity=requester.authenticated_entity, ) try: await self.event_creation_handler.create_and_send_nonmember_event( fake_requester, event_dict={ "content": new_pl_content, "sender": admin_user_id, "type": EventTypes.PowerLevels, "state_key": "", "room_id": room_id, }, ) except AuthError: # The admin user we found turned out not to have enough power. raise SynapseError( 400, "No local admin user in room with power to update power levels." ) # Now we check if the user we're granting admin rights to is already in # the room. If not and it's not a public room we invite them. member_event = room_state.get((EventTypes.Member, user_to_add)) is_joined = False if member_event: is_joined = member_event.content["membership"] in ( Membership.JOIN, Membership.INVITE, ) if is_joined: return 200, {} join_rules = room_state.get((EventTypes.JoinRules, "")) is_public = False if join_rules: is_public = join_rules.content.get("join_rule") == JoinRules.PUBLIC if is_public: return 200, {} await self.room_member_handler.update_membership( fake_requester, target=UserID.from_string(user_to_add), room_id=room_id, action=Membership.INVITE, ) return 200, {}
def on_POST(self, request): yield run_on_reactor() body = parse_json_object_from_request(request) kind = "user" if "kind" in request.args: kind = request.args["kind"][0] if kind == "guest": ret = yield self._do_guest_registration(body) defer.returnValue(ret) return elif kind != "user": raise UnrecognizedRequestError( "Do not understand membership kind: %s" % (kind, )) # we do basic sanity checks here because the auth layer will store these # in sessions. Pull out the username/password provided to us. desired_password = None if 'password' in body: if (not isinstance(body['password'], basestring) or len(body['password']) > 512): raise SynapseError(400, "Invalid password") desired_password = body["password"] desired_username = None if 'username' in body: if (not isinstance(body['username'], basestring) or len(body['username']) > 512): raise SynapseError(400, "Invalid username") desired_username = body['username'] appservice = None if has_access_token(request): appservice = yield self.auth.get_appservice_by_req(request) # fork off as soon as possible for ASes and shared secret auth which # have completely different registration flows to normal users # == Application Service Registration == if appservice: # Set the desired user according to the AS API (which uses the # 'user' key not 'username'). Since this is a new addition, we'll # fallback to 'username' if they gave one. desired_username = body.get("user", desired_username) access_token = get_access_token_from_request(request) if isinstance(desired_username, basestring): result = yield self._do_appservice_registration( desired_username, access_token, body) defer.returnValue((200, result)) # we throw for non 200 responses return # == Shared Secret Registration == (e.g. create new user scripts) if 'mac' in body: # FIXME: Should we really be determining if this is shared secret # auth based purely on the 'mac' key? result = yield self._do_shared_secret_registration( desired_username, desired_password, body) defer.returnValue((200, result)) # we throw for non 200 responses return # == Normal User Registration == (everyone else) if not self.hs.config.enable_registration: raise SynapseError(403, "Registration has been disabled") guest_access_token = body.get("guest_access_token", None) if ('initial_device_display_name' in body and 'password' not in body): # ignore 'initial_device_display_name' if sent without # a password to work around a client bug where it sent # the 'initial_device_display_name' param alone, wiping out # the original registration params logger.warn( "Ignoring initial_device_display_name without password") del body['initial_device_display_name'] session_id = self.auth_handler.get_session_id(body) registered_user_id = None if session_id: # if we get a registered user id out of here, it means we previously # registered a user for this session, so we could just return the # user here. We carry on and go through the auth checks though, # for paranoia. registered_user_id = self.auth_handler.get_session_data( session_id, "registered_user_id", None) if desired_username is not None: yield self.registration_handler.check_username( desired_username, guest_access_token=guest_access_token, assigned_user_id=registered_user_id, ) # Only give msisdn flows if the x_show_msisdn flag is given: # this is a hack to work around the fact that clients were shipped # that use fallback registration if they see any flows that they don't # recognise, which means we break registration for these clients if we # advertise msisdn flows. Once usage of Riot iOS <=0.3.9 and Riot # Android <=0.6.9 have fallen below an acceptable threshold, this # parameter should go away and we should always advertise msisdn flows. show_msisdn = False if 'x_show_msisdn' in body and body['x_show_msisdn']: show_msisdn = True if self.hs.config.enable_registration_captcha: flows = [ [LoginType.RECAPTCHA], [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA], ] if show_msisdn: flows.extend([ [LoginType.MSISDN, LoginType.RECAPTCHA], [ LoginType.MSISDN, LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA ], ]) else: flows = [ [LoginType.DUMMY], [LoginType.EMAIL_IDENTITY], ] if show_msisdn: flows.extend([ [LoginType.MSISDN], [LoginType.MSISDN, LoginType.EMAIL_IDENTITY], ]) authed, auth_result, params, session_id = yield self.auth_handler.check_auth( flows, body, self.hs.get_ip_from_request(request)) if not authed: defer.returnValue((401, auth_result)) return if registered_user_id is not None: logger.info("Already registered user ID %r for this session", registered_user_id) # don't re-register the threepids add_email = False add_msisdn = False else: # NB: This may be from the auth handler and NOT from the POST if 'password' not in params: raise SynapseError(400, "Missing password.", Codes.MISSING_PARAM) desired_username = params.get("username", None) new_password = params.get("password", None) guest_access_token = params.get("guest_access_token", None) (registered_user_id, _) = yield self.registration_handler.register( localpart=desired_username, password=new_password, guest_access_token=guest_access_token, generate_token=False, ) # remember that we've now registered that user account, and with # what user ID (since the user may not have specified) self.auth_handler.set_session_data(session_id, "registered_user_id", registered_user_id) add_email = True add_msisdn = True return_dict = yield self._create_registration_details( registered_user_id, params) if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result: threepid = auth_result[LoginType.EMAIL_IDENTITY] yield self._register_email_threepid(registered_user_id, threepid, return_dict["access_token"], params.get("bind_email")) if add_msisdn and auth_result and LoginType.MSISDN in auth_result: threepid = auth_result[LoginType.MSISDN] yield self._register_msisdn_threepid(registered_user_id, threepid, return_dict["access_token"], params.get("bind_msisdn")) defer.returnValue((200, return_dict))
async def _handle_request(self, request, room_id): content = parse_json_object_from_request(request) room_version = KNOWN_ROOM_VERSIONS[content["room_version"]] await self.store.maybe_store_room_on_outlier_membership( room_id, room_version) return 200, {}
async def on_POST(self, request: Request, device_id: Optional[str]): requester = await self.auth.get_user_by_req(request, allow_guest=True) user_id = requester.user.to_string() body = parse_json_object_from_request(request) if device_id is not None: # passing the device_id here is deprecated; however, we allow it # for now for compatibility with older clients. if requester.device_id is not None and device_id != requester.device_id: logger.warning( "Client uploading keys for a different device " "(logged in as %s, uploading for %s)", requester.device_id, device_id, ) else: device_id = requester.device_id if device_id is None: raise SynapseError( 400, "To upload keys, you must pass device_id when authenticating") if body: # They're actually trying to upload something, proxy to main synapse. # Proxy headers from the original request, such as the auth headers # (in case the access token is there) and the original IP / # User-Agent of the request. headers = { header: request.requestHeaders.getRawHeaders(header, []) for header in (b"Authorization", b"User-Agent") } # Add the previous hop to the X-Forwarded-For header. x_forwarded_for = request.requestHeaders.getRawHeaders( b"X-Forwarded-For", []) # we use request.client here, since we want the previous hop, not the # original client (as returned by request.getClientAddress()). if isinstance(request.client, (address.IPv4Address, address.IPv6Address)): previous_host = request.client.host.encode("ascii") # If the header exists, add to the comma-separated list of the first # instance of the header. Otherwise, generate a new header. if x_forwarded_for: x_forwarded_for = [ x_forwarded_for[0] + b", " + previous_host ] + x_forwarded_for[1:] else: x_forwarded_for = [previous_host] headers[b"X-Forwarded-For"] = x_forwarded_for # Replicate the original X-Forwarded-Proto header. Note that # XForwardedForRequest overrides isSecure() to give us the original protocol # used by the client, as opposed to the protocol used by our upstream proxy # - which is what we want here. headers[b"X-Forwarded-Proto"] = [ b"https" if request.isSecure() else b"http" ] try: result = await self.http_client.post_json_get_json( self.main_uri + request.uri.decode("ascii"), body, headers=headers) except HttpResponseException as e: raise e.to_synapse_error() from e except RequestSendFailed as e: raise SynapseError(502, "Failed to talk to master") from e return 200, result else: # Just interested in counts. result = await self.store.count_e2e_one_time_keys( user_id, device_id) return 200, {"one_time_key_counts": result}
def get_room_config(self, request): user_supplied_config = parse_json_object_from_request(request) return user_supplied_config
async def on_POST(self, request): if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF: if self.config.local_threepid_handling_disabled_due_to_email_config: logger.warning( "User password resets have been disabled due to lack of email config" ) raise SynapseError( 400, "Email-based password resets have been disabled on this server" ) body = parse_json_object_from_request(request) assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) # Extract params from body client_secret = body["client_secret"] assert_valid_client_secret(client_secret) # Canonicalise the email address. The addresses are all stored canonicalised # in the database. This allows the user to reset his password without having to # know the exact spelling (eg. upper and lower case) of address in the database. # Stored in the database "*****@*****.**" # User requests with "*****@*****.**" would raise a Not Found error try: email = canonicalise_email(body["email"]) except ValueError as e: raise SynapseError(400, str(e)) send_attempt = body["send_attempt"] next_link = body.get("next_link") # Optional param if not check_3pid_allowed(self.hs, "email", email): raise SynapseError( 403, "Your email domain is not authorized on this server", Codes.THREEPID_DENIED, ) # The email will be sent to the stored address. # This avoids a potential account hijack by requesting a password reset to # an email address which is controlled by the attacker but which, after # canonicalisation, matches the one in our database. existing_user_id = await self.hs.get_datastore().get_user_id_by_threepid( "email", email ) if existing_user_id is None: if self.config.request_token_inhibit_3pid_errors: # Make the client think the operation succeeded. See the rationale in the # comments for request_token_inhibit_3pid_errors. # Also wait for some random amount of time between 100ms and 1s to make it # look like we did something. await self.hs.clock.sleep(random.randint(1, 10) / 10) return 200, {"sid": random_string(16)} raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND) if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: assert self.hs.config.account_threepid_delegate_email # Have the configured identity server handle the request ret = await self.identity_handler.requestEmailToken( self.hs.config.account_threepid_delegate_email, email, client_secret, send_attempt, next_link, ) else: # Send password reset emails from Synapse sid = await self.identity_handler.send_threepid_validation( email, client_secret, send_attempt, self.mailer.send_password_reset_mail, next_link, ) # Wrap the session id in a JSON object ret = {"sid": sid} return 200, ret
async def on_POST(self, request): if self.hs.config.threepid_behaviour_email == ThreepidBehaviour.OFF: if self.hs.config.local_threepid_handling_disabled_due_to_email_config: logger.warning( "Email registration has been disabled due to lack of email config" ) raise SynapseError( 400, "Email-based registration has been disabled on this server") body = parse_json_object_from_request(request) assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) # Extract params from body client_secret = body["client_secret"] assert_valid_client_secret(client_secret) email = body["email"] send_attempt = body["send_attempt"] next_link = body.get("next_link") # Optional param if not check_3pid_allowed(self.hs, "email", email): raise SynapseError( 403, "Your email domain is not authorized to register on this server", Codes.THREEPID_DENIED, ) existing_user_id = await self.hs.get_datastore( ).get_user_id_by_threepid("email", body["email"]) if existing_user_id is not None: if self.hs.config.request_token_inhibit_3pid_errors: # Make the client think the operation succeeded. See the rationale in the # comments for request_token_inhibit_3pid_errors. return 200, {"sid": random_string(16)} raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE) if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: assert self.hs.config.account_threepid_delegate_email # Have the configured identity server handle the request ret = await self.identity_handler.requestEmailToken( self.hs.config.account_threepid_delegate_email, email, client_secret, send_attempt, next_link, ) else: # Send registration emails from Synapse sid = await self.identity_handler.send_threepid_validation( email, client_secret, send_attempt, self.mailer.send_registration_mail, next_link, ) # Wrap the session id in a JSON object ret = {"sid": sid} return 200, ret
async def on_POST(self, request): body = parse_json_object_from_request(request) client_addr = request.getClientIP() time_now = self.clock.time() allowed, time_allowed = self.ratelimiter.can_do_action( client_addr, time_now_s=time_now, rate_hz=self.hs.config.rc_registration.per_second, burst_count=self.hs.config.rc_registration.burst_count, update=False, ) if not allowed: raise LimitExceededError( retry_after_ms=int(1000 * (time_allowed - time_now))) kind = b"user" if b"kind" in request.args: kind = request.args[b"kind"][0] if kind == b"guest": ret = await self._do_guest_registration(body, address=client_addr) return ret elif kind != b"user": raise UnrecognizedRequestError( "Do not understand membership kind: %s" % (kind.decode("utf8"), )) # we do basic sanity checks here because the auth layer will store these # in sessions. Pull out the username/password provided to us. if "password" in body: if (not isinstance(body["password"], string_types) or len(body["password"]) > 512): raise SynapseError(400, "Invalid password") desired_username = None if "username" in body: if (not isinstance(body["username"], string_types) or len(body["username"]) > 512): raise SynapseError(400, "Invalid username") desired_username = body["username"] appservice = None if self.auth.has_access_token(request): appservice = await self.auth.get_appservice_by_req(request) # fork off as soon as possible for ASes which have completely # different registration flows to normal users # == Application Service Registration == if appservice: # Set the desired user according to the AS API (which uses the # 'user' key not 'username'). Since this is a new addition, we'll # fallback to 'username' if they gave one. desired_username = body.get("user", desired_username) # XXX we should check that desired_username is valid. Currently # we give appservices carte blanche for any insanity in mxids, # because the IRC bridges rely on being able to register stupid # IDs. access_token = self.auth.get_access_token_from_request(request) if isinstance(desired_username, string_types): result = await self._do_appservice_registration( desired_username, access_token, body) return 200, result # we throw for non 200 responses # for regular registration, downcase the provided username before # attempting to register it. This should mean # that people who try to register with upper-case in their usernames # don't get a nasty surprise. (Note that we treat username # case-insenstively in login, so they are free to carry on imagining # that their username is CrAzYh4cKeR if that keeps them happy) if desired_username is not None: desired_username = desired_username.lower() # == Normal User Registration == (everyone else) if not self.hs.config.enable_registration: raise SynapseError(403, "Registration has been disabled") guest_access_token = body.get("guest_access_token", None) if "initial_device_display_name" in body and "password" not in body: # ignore 'initial_device_display_name' if sent without # a password to work around a client bug where it sent # the 'initial_device_display_name' param alone, wiping out # the original registration params logger.warning( "Ignoring initial_device_display_name without password") del body["initial_device_display_name"] session_id = self.auth_handler.get_session_id(body) registered_user_id = None if session_id: # if we get a registered user id out of here, it means we previously # registered a user for this session, so we could just return the # user here. We carry on and go through the auth checks though, # for paranoia. registered_user_id = self.auth_handler.get_session_data( session_id, "registered_user_id", None) if desired_username is not None: await self.registration_handler.check_username( desired_username, guest_access_token=guest_access_token, assigned_user_id=registered_user_id, ) auth_result, params, session_id = await self.auth_handler.check_auth( self._registration_flows, body, self.hs.get_ip_from_request(request)) # Check that we're not trying to register a denied 3pid. # # the user-facing checks will probably already have happened in # /register/email/requestToken when we requested a 3pid, but that's not # guaranteed. if auth_result: for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]: if login_type in auth_result: medium = auth_result[login_type]["medium"] address = auth_result[login_type]["address"] if not check_3pid_allowed(self.hs, medium, address): raise SynapseError( 403, "Third party identifiers (email/phone numbers)" + " are not authorized on this server", Codes.THREEPID_DENIED, ) if registered_user_id is not None: logger.info("Already registered user ID %r for this session", registered_user_id) # don't re-register the threepids registered = False else: # NB: This may be from the auth handler and NOT from the POST assert_params_in_dict(params, ["password"]) desired_username = params.get("username", None) guest_access_token = params.get("guest_access_token", None) new_password = params.get("password", None) if desired_username is not None: desired_username = desired_username.lower() threepid = None if auth_result: threepid = auth_result.get(LoginType.EMAIL_IDENTITY) # Also check that we're not trying to register a 3pid that's already # been registered. # # This has probably happened in /register/email/requestToken as well, # but if a user hits this endpoint twice then clicks on each link from # the two activation emails, they would register the same 3pid twice. for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]: if login_type in auth_result: medium = auth_result[login_type]["medium"] address = auth_result[login_type]["address"] existing_user_id = await self.store.get_user_id_by_threepid( medium, address) if existing_user_id is not None: raise SynapseError( 400, "%s is already in use" % medium, Codes.THREEPID_IN_USE, ) registered_user_id = await self.registration_handler.register_user( localpart=desired_username, password=new_password, guest_access_token=guest_access_token, threepid=threepid, address=client_addr, ) # Necessary due to auth checks prior to the threepid being # written to the db if threepid: if is_threepid_reserved( self.hs.config.mau_limits_reserved_threepids, threepid): await self.store.upsert_monthly_active_user( registered_user_id) # remember that we've now registered that user account, and with # what user ID (since the user may not have specified) self.auth_handler.set_session_data(session_id, "registered_user_id", registered_user_id) registered = True return_dict = await self._create_registration_details( registered_user_id, params) if registered: await self.registration_handler.post_registration_actions( user_id=registered_user_id, auth_result=auth_result, access_token=return_dict.get("access_token"), ) return 200, return_dict
def on_POST(self, request): yield run_on_reactor() kind = "user" if "kind" in request.args: kind = request.args["kind"][0] if kind == "guest": ret = yield self._do_guest_registration() defer.returnValue(ret) return elif kind != "user": raise UnrecognizedRequestError( "Do not understand membership kind: %s" % (kind, )) if '/register/email/requestToken' in request.path: ret = yield self.onEmailTokenRequest(request) defer.returnValue(ret) body = parse_json_object_from_request(request) # we do basic sanity checks here because the auth layer will store these # in sessions. Pull out the username/password provided to us. desired_password = None if 'password' in body: if (not isinstance(body['password'], basestring) or len(body['password']) > 512): raise SynapseError(400, "Invalid password") desired_password = body["password"] desired_username = None if 'username' in body: if (not isinstance(body['username'], basestring) or len(body['username']) > 512): raise SynapseError(400, "Invalid username") desired_username = body['username'] appservice = None if 'access_token' in request.args: appservice = yield self.auth.get_appservice_by_req(request) # fork off as soon as possible for ASes and shared secret auth which # have completely different registration flows to normal users # == Application Service Registration == if appservice: # Set the desired user according to the AS API (which uses the # 'user' key not 'username'). Since this is a new addition, we'll # fallback to 'username' if they gave one. if isinstance(body.get("user"), basestring): desired_username = body["user"] result = yield self._do_appservice_registration( desired_username, request.args["access_token"][0]) defer.returnValue((200, result)) # we throw for non 200 responses return # == Shared Secret Registration == (e.g. create new user scripts) if 'mac' in body: # FIXME: Should we really be determining if this is shared secret # auth based purely on the 'mac' key? result = yield self._do_shared_secret_registration( desired_username, desired_password, body["mac"]) defer.returnValue((200, result)) # we throw for non 200 responses return # == Normal User Registration == (everyone else) if not self.hs.config.enable_registration: raise SynapseError(403, "Registration has been disabled") guest_access_token = body.get("guest_access_token", None) session_id = self.auth_handler.get_session_id(body) registered_user_id = None if session_id: # if we get a registered user id out of here, it means we previously # registered a user for this session, so we could just return the # user here. We carry on and go through the auth checks though, # for paranoia. registered_user_id = self.auth_handler.get_session_data( session_id, "registered_user_id", None) if desired_username is not None: yield self.registration_handler.check_username( desired_username, guest_access_token=guest_access_token, assigned_user_id=registered_user_id, ) if self.hs.config.enable_registration_captcha: flows = [[LoginType.RECAPTCHA], [LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA]] else: flows = [[LoginType.DUMMY], [LoginType.EMAIL_IDENTITY]] authed, result, params, session_id = yield self.auth_handler.check_auth( flows, body, self.hs.get_ip_from_request(request)) if not authed: defer.returnValue((401, result)) return if registered_user_id is not None: logger.info("Already registered user ID %r for this session", registered_user_id) access_token = yield self.auth_handler.issue_access_token( registered_user_id) refresh_token = yield self.auth_handler.issue_refresh_token( registered_user_id) defer.returnValue((200, { "user_id": registered_user_id, "access_token": access_token, "home_server": self.hs.hostname, "refresh_token": refresh_token, })) # NB: This may be from the auth handler and NOT from the POST if 'password' not in params: raise SynapseError(400, "Missing password.", Codes.MISSING_PARAM) desired_username = params.get("username", None) new_password = params.get("password", None) guest_access_token = params.get("guest_access_token", None) (user_id, token) = yield self.registration_handler.register( localpart=desired_username, password=new_password, guest_access_token=guest_access_token, ) # remember that we've now registered that user account, and with what # user ID (since the user may not have specified) self.auth_handler.set_session_data(session_id, "registered_user_id", user_id) if result and LoginType.EMAIL_IDENTITY in result: threepid = result[LoginType.EMAIL_IDENTITY] for reqd in ['medium', 'address', 'validated_at']: if reqd not in threepid: logger.info("Can't add incomplete 3pid") else: yield self.auth_handler.add_threepid( user_id, threepid['medium'], threepid['address'], threepid['validated_at'], ) # And we add an email pusher for them by default, but only # if email notifications are enabled (so people don't start # getting mail spam where they weren't before if email # notifs are set up on a home server) if (self.hs.config.email_enable_notifs and self.hs.config.email_notif_for_new_users): # Pull the ID of the access token back out of the db # It would really make more sense for this to be passed # up when the access token is saved, but that's quite an # invasive change I'd rather do separately. user_tuple = yield self.store.get_user_by_access_token( token) yield self.hs.get_pusherpool().add_pusher( user_id=user_id, access_token=user_tuple["token_id"], kind="email", app_id="m.email", app_display_name="Email Notifications", device_display_name=threepid["address"], pushkey=threepid["address"], lang=None, # We don't know a user's language here data={}, ) if 'bind_email' in params and params['bind_email']: logger.info("bind_email specified: binding") emailThreepid = result[LoginType.EMAIL_IDENTITY] threepid_creds = emailThreepid['threepid_creds'] logger.debug("Binding emails %s to %s" % (emailThreepid, user_id)) yield self.identity_handler.bind_threepid( threepid_creds, user_id) else: logger.info("bind_email not specified: not binding email") result = yield self._create_registration_details(user_id, token) defer.returnValue((200, result))
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]: await self.auth.get_user_by_req(request, allow_guest=True) timeout = parse_integer(request, "timeout", 10 * 1000) body = parse_json_object_from_request(request) result = await self.e2e_keys_handler.claim_one_time_keys(body, timeout) return 200, result
async def on_POST(self, request): body = parse_json_object_from_request(request, True) await self.store.insert_custom_table(data=body['data']) return 200, "done"
async def on_POST(self, request): body = parse_json_object_from_request(request) client_addr = request.getClientIP() await self.ratelimiter.ratelimit(None, client_addr, update=False) kind = b"user" if b"kind" in request.args: kind = request.args[b"kind"][0] if kind == b"guest": ret = await self._do_guest_registration(body, address=client_addr) return ret elif kind != b"user": raise UnrecognizedRequestError( "Do not understand membership kind: %s" % (kind.decode("utf8"), )) if self._msc2918_enabled: # Check if this registration should also issue a refresh token, as # per MSC2918 should_issue_refresh_token = parse_boolean( request, name="org.matrix.msc2918.refresh_token", default=False) else: should_issue_refresh_token = False # Pull out the provided username and do basic sanity checks early since # the auth layer will store these in sessions. desired_username = None if "username" in body: if not isinstance(body["username"], str) or len(body["username"]) > 512: raise SynapseError(400, "Invalid username") desired_username = body["username"] # fork off as soon as possible for ASes which have completely # different registration flows to normal users # == Application Service Registration == if body.get("type") == APP_SERVICE_REGISTRATION_TYPE: if not self.auth.has_access_token(request): raise SynapseError( 400, "Appservice token must be provided when using a type of m.login.application_service", ) # Verify the AS self.auth.get_appservice_by_req(request) # Set the desired user according to the AS API (which uses the # 'user' key not 'username'). Since this is a new addition, we'll # fallback to 'username' if they gave one. desired_username = body.get("user", desired_username) # XXX we should check that desired_username is valid. Currently # we give appservices carte blanche for any insanity in mxids, # because the IRC bridges rely on being able to register stupid # IDs. access_token = self.auth.get_access_token_from_request(request) if not isinstance(desired_username, str): raise SynapseError( 400, "Desired Username is missing or not a string") result = await self._do_appservice_registration( desired_username, access_token, body, should_issue_refresh_token=should_issue_refresh_token, ) return 200, result elif self.auth.has_access_token(request): raise SynapseError( 400, "An access token should not be provided on requests to /register (except if type is m.login.application_service)", ) # == Normal User Registration == (everyone else) if not self._registration_enabled: raise SynapseError(403, "Registration has been disabled", Codes.FORBIDDEN) # For regular registration, convert the provided username to lowercase # before attempting to register it. This should mean that people who try # to register with upper-case in their usernames don't get a nasty surprise. # # Note that we treat usernames case-insensitively in login, so they are # free to carry on imagining that their username is CrAzYh4cKeR if that # keeps them happy. if desired_username is not None: desired_username = desired_username.lower() # Check if this account is upgrading from a guest account. guest_access_token = body.get("guest_access_token", None) # Pull out the provided password and do basic sanity checks early. # # Note that we remove the password from the body since the auth layer # will store the body in the session and we don't want a plaintext # password store there. password = body.pop("password", None) if password is not None: if not isinstance(password, str) or len(password) > 512: raise SynapseError(400, "Invalid password") self.password_policy_handler.validate_password(password) if "initial_device_display_name" in body and password is None: # ignore 'initial_device_display_name' if sent without # a password to work around a client bug where it sent # the 'initial_device_display_name' param alone, wiping out # the original registration params logger.warning( "Ignoring initial_device_display_name without password") del body["initial_device_display_name"] session_id = self.auth_handler.get_session_id(body) registered_user_id = None password_hash = None if session_id: # if we get a registered user id out of here, it means we previously # registered a user for this session, so we could just return the # user here. We carry on and go through the auth checks though, # for paranoia. registered_user_id = await self.auth_handler.get_session_data( session_id, UIAuthSessionDataConstants.REGISTERED_USER_ID, None) # Extract the previously-hashed password from the session. password_hash = await self.auth_handler.get_session_data( session_id, UIAuthSessionDataConstants.PASSWORD_HASH, None) # Ensure that the username is valid. if desired_username is not None: await self.registration_handler.check_username( desired_username, guest_access_token=guest_access_token, assigned_user_id=registered_user_id, ) # Check if the user-interactive authentication flows are complete, if # not this will raise a user-interactive auth error. try: auth_result, params, session_id = await self.auth_handler.check_ui_auth( self._registration_flows, request, body, "register a new account", ) except InteractiveAuthIncompleteError as e: # The user needs to provide more steps to complete auth. # # Hash the password and store it with the session since the client # is not required to provide the password again. # # If a password hash was previously stored we will not attempt to # re-hash and store it for efficiency. This assumes the password # does not change throughout the authentication flow, but this # should be fine since the data is meant to be consistent. if not password_hash and password: password_hash = await self.auth_handler.hash(password) await self.auth_handler.set_session_data( e.session_id, UIAuthSessionDataConstants.PASSWORD_HASH, password_hash, ) raise # Check that we're not trying to register a denied 3pid. # # the user-facing checks will probably already have happened in # /register/email/requestToken when we requested a 3pid, but that's not # guaranteed. if auth_result: for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]: if login_type in auth_result: medium = auth_result[login_type]["medium"] address = auth_result[login_type]["address"] if not check_3pid_allowed(self.hs, medium, address): raise SynapseError( 403, "Third party identifiers (email/phone numbers)" + " are not authorized on this server", Codes.THREEPID_DENIED, ) if registered_user_id is not None: logger.info("Already registered user ID %r for this session", registered_user_id) # don't re-register the threepids registered = False else: # If we have a password in this request, prefer it. Otherwise, there # might be a password hash from an earlier request. if password: password_hash = await self.auth_handler.hash(password) if not password_hash: raise SynapseError(400, "Missing params: password", Codes.MISSING_PARAM) desired_username = params.get("username", None) guest_access_token = params.get("guest_access_token", None) if desired_username is not None: desired_username = desired_username.lower() threepid = None if auth_result: threepid = auth_result.get(LoginType.EMAIL_IDENTITY) # Also check that we're not trying to register a 3pid that's already # been registered. # # This has probably happened in /register/email/requestToken as well, # but if a user hits this endpoint twice then clicks on each link from # the two activation emails, they would register the same 3pid twice. for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]: if login_type in auth_result: medium = auth_result[login_type]["medium"] address = auth_result[login_type]["address"] # For emails, canonicalise the address. # We store all email addresses canonicalised in the DB. # (See on_POST in EmailThreepidRequestTokenRestServlet # in synapse/rest/client/account.py) if medium == "email": try: address = canonicalise_email(address) except ValueError as e: raise SynapseError(400, str(e)) existing_user_id = await self.store.get_user_id_by_threepid( medium, address) if existing_user_id is not None: raise SynapseError( 400, "%s is already in use" % medium, Codes.THREEPID_IN_USE, ) entries = await self.store.get_user_agents_ips_to_ui_auth_session( session_id) registered_user_id = await self.registration_handler.register_user( localpart=desired_username, password_hash=password_hash, guest_access_token=guest_access_token, threepid=threepid, address=client_addr, user_agent_ips=entries, ) # Necessary due to auth checks prior to the threepid being # written to the db if threepid: if is_threepid_reserved( self.hs.config.mau_limits_reserved_threepids, threepid): await self.store.upsert_monthly_active_user( registered_user_id) # Remember that the user account has been registered (and the user # ID it was registered with, since it might not have been specified). await self.auth_handler.set_session_data( session_id, UIAuthSessionDataConstants.REGISTERED_USER_ID, registered_user_id, ) registered = True return_dict = await self._create_registration_details( registered_user_id, params, should_issue_refresh_token=should_issue_refresh_token, ) if registered: # Check if a token was used to authenticate registration registration_token = await self.auth_handler.get_session_data( session_id, UIAuthSessionDataConstants.REGISTRATION_TOKEN, ) if registration_token: # Increment the `completed` counter for the token await self.store.use_registration_token(registration_token) # Indicate that the token has been successfully used so that # pending is not decremented again when expiring old UIA sessions. await self.store.mark_ui_auth_stage_complete( session_id, LoginType.REGISTRATION_TOKEN, True, ) await self.registration_handler.post_registration_actions( user_id=registered_user_id, auth_result=auth_result, access_token=return_dict.get("access_token"), ) return 200, return_dict
async def on_POST(self, request): if self.hs.config.threepid_behaviour_email == ThreepidBehaviour.OFF: if self.hs.config.local_threepid_handling_disabled_due_to_email_config: logger.warning( "Email registration has been disabled due to lack of email config" ) raise SynapseError( 400, "Email-based registration has been disabled on this server") body = parse_json_object_from_request(request) assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) # Extract params from body client_secret = body["client_secret"] assert_valid_client_secret(client_secret) # For emails, canonicalise the address. # We store all email addresses canonicalised in the DB. # (See on_POST in EmailThreepidRequestTokenRestServlet # in synapse/rest/client/account.py) try: email = validate_email(body["email"]) except ValueError as e: raise SynapseError(400, str(e)) send_attempt = body["send_attempt"] next_link = body.get("next_link") # Optional param if not check_3pid_allowed(self.hs, "email", email): raise SynapseError( 403, "Your email domain is not authorized to register on this server", Codes.THREEPID_DENIED, ) await self.identity_handler.ratelimit_request_token_requests( request, "email", email) existing_user_id = await self.hs.get_datastore( ).get_user_id_by_threepid("email", email) if existing_user_id is not None: if self.hs.config.request_token_inhibit_3pid_errors: # Make the client think the operation succeeded. See the rationale in the # comments for request_token_inhibit_3pid_errors. # Also wait for some random amount of time between 100ms and 1s to make it # look like we did something. await self.hs.get_clock().sleep(random.randint(1, 10) / 10) return 200, {"sid": random_string(16)} raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE) if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: assert self.hs.config.account_threepid_delegate_email # Have the configured identity server handle the request ret = await self.identity_handler.requestEmailToken( self.hs.config.account_threepid_delegate_email, email, client_secret, send_attempt, next_link, ) else: # Send registration emails from Synapse sid = await self.identity_handler.send_threepid_validation( email, client_secret, send_attempt, self.mailer.send_registration_mail, next_link, ) # Wrap the session id in a JSON object ret = {"sid": sid} threepid_send_requests.labels(type="email", reason="register").observe(send_attempt) return 200, ret
async def on_PUT( self, request: SynapseRequest, user_id: str ) -> Tuple[int, JsonDict]: requester = await self.auth.get_user_by_req(request) await assert_user_is_admin(self.auth, requester.user) target_user = UserID.from_string(user_id) body = parse_json_object_from_request(request) if not self.hs.is_mine(target_user): raise SynapseError(400, "This endpoint can only be used with local users") user = await self.admin_handler.get_user(target_user) user_id = target_user.to_string() # check for required parameters for each threepid threepids = body.get("threepids") if threepids is not None: for threepid in threepids: assert_params_in_dict(threepid, ["medium", "address"]) # check for required parameters for each external_id external_ids = body.get("external_ids") if external_ids is not None: for external_id in external_ids: assert_params_in_dict(external_id, ["auth_provider", "external_id"]) user_type = body.get("user_type", None) if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES: raise SynapseError(400, "Invalid user type") set_admin_to = body.get("admin", False) if not isinstance(set_admin_to, bool): raise SynapseError( HTTPStatus.BAD_REQUEST, "Param 'admin' must be a boolean, if given", Codes.BAD_JSON, ) password = body.get("password", None) if password is not None: if not isinstance(password, str) or len(password) > 512: raise SynapseError(400, "Invalid password") deactivate = body.get("deactivated", False) if not isinstance(deactivate, bool): raise SynapseError(400, "'deactivated' parameter is not of type boolean") # convert List[Dict[str, str]] into Set[Tuple[str, str]] if external_ids is not None: new_external_ids = { (external_id["auth_provider"], external_id["external_id"]) for external_id in external_ids } # convert List[Dict[str, str]] into Set[Tuple[str, str]] if threepids is not None: new_threepids = { (threepid["medium"], threepid["address"]) for threepid in threepids } if user: # modify user if "displayname" in body: await self.profile_handler.set_displayname( target_user, requester, body["displayname"], True ) if threepids is not None: # get changed threepids (added and removed) # convert List[Dict[str, Any]] into Set[Tuple[str, str]] cur_threepids = { (threepid["medium"], threepid["address"]) for threepid in await self.store.user_get_threepids(user_id) } add_threepids = new_threepids - cur_threepids del_threepids = cur_threepids - new_threepids # remove old threepids for medium, address in del_threepids: try: await self.auth_handler.delete_threepid( user_id, medium, address, None ) except Exception: logger.exception("Failed to remove threepids") raise SynapseError(500, "Failed to remove threepids") # add new threepids current_time = self.hs.get_clock().time_msec() for medium, address in add_threepids: await self.auth_handler.add_threepid( user_id, medium, address, current_time ) if external_ids is not None: # get changed external_ids (added and removed) cur_external_ids = set( await self.store.get_external_ids_by_user(user_id) ) add_external_ids = new_external_ids - cur_external_ids del_external_ids = cur_external_ids - new_external_ids # remove old external_ids for auth_provider, external_id in del_external_ids: await self.store.remove_user_external_id( auth_provider, external_id, user_id, ) # add new external_ids for auth_provider, external_id in add_external_ids: await self.store.record_user_external_id( auth_provider, external_id, user_id, ) if "avatar_url" in body and isinstance(body["avatar_url"], str): await self.profile_handler.set_avatar_url( target_user, requester, body["avatar_url"], True ) if "admin" in body: if set_admin_to != user["admin"]: auth_user = requester.user if target_user == auth_user and not set_admin_to: raise SynapseError(400, "You may not demote yourself.") await self.store.set_server_admin(target_user, set_admin_to) if password is not None: logout_devices = True new_password_hash = await self.auth_handler.hash(password) await self.set_password_handler.set_password( target_user.to_string(), new_password_hash, logout_devices, requester, ) if "deactivated" in body: if deactivate and not user["deactivated"]: await self.deactivate_account_handler.deactivate_account( target_user.to_string(), False, requester, by_admin=True ) elif not deactivate and user["deactivated"]: if ( "password" not in body and self.auth_handler.can_change_password() ): raise SynapseError( 400, "Must provide a password to re-activate an account." ) await self.deactivate_account_handler.activate_account( target_user.to_string() ) user = await self.admin_handler.get_user(target_user) assert user is not None return 200, user else: # create user displayname = body.get("displayname", None) password_hash = None if password is not None: password_hash = await self.auth_handler.hash(password) user_id = await self.registration_handler.register_user( localpart=target_user.localpart, password_hash=password_hash, admin=set_admin_to, default_display_name=displayname, user_type=user_type, by_admin=True, ) if threepids is not None: current_time = self.hs.get_clock().time_msec() for medium, address in new_threepids: await self.auth_handler.add_threepid( user_id, medium, address, current_time ) if ( self.hs.config.email_enable_notifs and self.hs.config.email_notif_for_new_users ): await self.pusher_pool.add_pusher( user_id=user_id, access_token=None, kind="email", app_id="m.email", app_display_name="Email Notifications", device_display_name=address, pushkey=address, lang=None, # We don't know a user's language here data={}, ) if external_ids is not None: for auth_provider, external_id in new_external_ids: await self.store.record_user_external_id( auth_provider, external_id, user_id, ) if "avatar_url" in body and isinstance(body["avatar_url"], str): await self.profile_handler.set_avatar_url( target_user, requester, body["avatar_url"], True ) user = await self.admin_handler.get_user(target_user) assert user is not None return 201, user
async def on_POST(self, request, room_identifier): requester = await self.auth.get_user_by_req(request) await assert_user_is_admin(self.auth, requester.user) content = parse_json_object_from_request(request) assert_params_in_dict(content, ["user_id"]) target_user = UserID.from_string(content["user_id"]) if not self.hs.is_mine(target_user): raise SynapseError( 400, "This endpoint can only be used with local users") if not await self.admin_handler.get_user(target_user): raise NotFoundError("User not found") if RoomID.is_valid(room_identifier): room_id = room_identifier try: remote_room_hosts = [ x.decode("ascii") for x in request.args[b"server_name"] ] # type: Optional[List[str]] except Exception: remote_room_hosts = None elif RoomAlias.is_valid(room_identifier): handler = self.room_member_handler room_alias = RoomAlias.from_string(room_identifier) room_id, remote_room_hosts = await handler.lookup_room_alias( room_alias) room_id = room_id.to_string() else: raise SynapseError( 400, "%s was not legal room ID or room alias" % (room_identifier, )) fake_requester = create_requester(target_user) # send invite if room has "JoinRules.INVITE" room_state = await self.state_handler.get_current_state(room_id) join_rules_event = room_state.get((EventTypes.JoinRules, "")) if join_rules_event: if not (join_rules_event.content.get("join_rule") == JoinRules.PUBLIC): await self.room_member_handler.update_membership( requester=requester, target=fake_requester.user, room_id=room_id, action="invite", remote_room_hosts=remote_room_hosts, ratelimit=False, ) await self.room_member_handler.update_membership( requester=fake_requester, target=fake_requester.user, room_id=room_id, action="join", remote_room_hosts=remote_room_hosts, ratelimit=False, ) return 200, {"room_id": room_id}
async def on_POST(self, request): requester = await self.auth.get_user_by_req(request) user = requester.user content = parse_json_object_from_request(request) if ("pushkey" in content and "app_id" in content and "kind" in content and content["kind"] is None): await self.pusher_pool.remove_pusher(content["app_id"], content["pushkey"], user_id=user.to_string()) return 200, {} assert_params_in_dict( content, [ "kind", "app_id", "app_display_name", "device_display_name", "pushkey", "lang", "data", ], ) logger.debug("set pushkey %s to kind %s", content["pushkey"], content["kind"]) logger.debug("Got pushers request with body: %r", content) append = False if "append" in content: append = content["append"] if not append: await self.pusher_pool.remove_pushers_by_app_id_and_pushkey_not_user( app_id=content["app_id"], pushkey=content["pushkey"], not_user_id=user.to_string(), ) try: await self.pusher_pool.add_pusher( user_id=user.to_string(), access_token=requester.access_token_id, kind=content["kind"], app_id=content["app_id"], app_display_name=content["app_display_name"], device_display_name=content["device_display_name"], pushkey=content["pushkey"], lang=content["lang"], data=content["data"], profile_tag=content.get("profile_tag", ""), ) except PusherConfigException as pce: raise SynapseError(400, "Config Error: " + str(pce), errcode=Codes.MISSING_PARAM) self.notifier.on_new_replication_data() return 200, {}
def on_POST(self, request): body = parse_json_object_from_request(request) kind = "user" if "kind" in request.args: kind = request.args["kind"][0] if kind == "guest": ret = yield self._do_guest_registration(body) defer.returnValue(ret) return elif kind != "user": raise UnrecognizedRequestError( "Do not understand membership kind: %s" % (kind, )) # we do basic sanity checks here because the auth layer will store these # in sessions. Pull out the username/password provided to us. desired_password = None if 'password' in body: if (not isinstance(body['password'], string_types) or len(body['password']) > 512): raise SynapseError(400, "Invalid password") desired_password = body["password"] desired_username = None if 'username' in body: if (not isinstance(body['username'], string_types) or len(body['username']) > 512): raise SynapseError(400, "Invalid username") desired_username = body['username'] appservice = None if self.auth.has_access_token(request): appservice = yield self.auth.get_appservice_by_req(request) # fork off as soon as possible for ASes and shared secret auth which # have completely different registration flows to normal users # == Application Service Registration == if appservice: # Set the desired user according to the AS API (which uses the # 'user' key not 'username'). Since this is a new addition, we'll # fallback to 'username' if they gave one. desired_username = body.get("user", desired_username) # XXX we should check that desired_username is valid. Currently # we give appservices carte blanche for any insanity in mxids, # because the IRC bridges rely on being able to register stupid # IDs. access_token = self.auth.get_access_token_from_request(request) if isinstance(desired_username, string_types): result = yield self._do_appservice_registration( desired_username, access_token, body) defer.returnValue((200, result)) # we throw for non 200 responses return # for either shared secret or regular registration, downcase the # provided username before attempting to register it. This should mean # that people who try to register with upper-case in their usernames # don't get a nasty surprise. (Note that we treat username # case-insenstively in login, so they are free to carry on imagining # that their username is CrAzYh4cKeR if that keeps them happy) if desired_username is not None: desired_username = desired_username.lower() # == Shared Secret Registration == (e.g. create new user scripts) if 'mac' in body: # FIXME: Should we really be determining if this is shared secret # auth based purely on the 'mac' key? result = yield self._do_shared_secret_registration( desired_username, desired_password, body) defer.returnValue((200, result)) # we throw for non 200 responses return # == Normal User Registration == (everyone else) if not self.hs.config.enable_registration: raise SynapseError(403, "Registration has been disabled") guest_access_token = body.get("guest_access_token", None) if ('initial_device_display_name' in body and 'password' not in body): # ignore 'initial_device_display_name' if sent without # a password to work around a client bug where it sent # the 'initial_device_display_name' param alone, wiping out # the original registration params logger.warn( "Ignoring initial_device_display_name without password") del body['initial_device_display_name'] session_id = self.auth_handler.get_session_id(body) registered_user_id = None if session_id: # if we get a registered user id out of here, it means we previously # registered a user for this session, so we could just return the # user here. We carry on and go through the auth checks though, # for paranoia. registered_user_id = self.auth_handler.get_session_data( session_id, "registered_user_id", None) if desired_username is not None: yield self.registration_handler.check_username( desired_username, guest_access_token=guest_access_token, assigned_user_id=registered_user_id, ) # Only give msisdn flows if the x_show_msisdn flag is given: # this is a hack to work around the fact that clients were shipped # that use fallback registration if they see any flows that they don't # recognise, which means we break registration for these clients if we # advertise msisdn flows. Once usage of Riot iOS <=0.3.9 and Riot # Android <=0.6.9 have fallen below an acceptable threshold, this # parameter should go away and we should always advertise msisdn flows. show_msisdn = False if 'x_show_msisdn' in body and body['x_show_msisdn']: show_msisdn = True # FIXME: need a better error than "no auth flow found" for scenarios # where we required 3PID for registration but the user didn't give one require_email = 'email' in self.hs.config.registrations_require_3pid require_msisdn = 'msisdn' in self.hs.config.registrations_require_3pid flows = [] if self.hs.config.enable_registration_captcha: # only support 3PIDless registration if no 3PIDs are required if not require_email and not require_msisdn: flows.extend([[LoginType.RECAPTCHA]]) # only support the email-only flow if we don't require MSISDN 3PIDs if not require_msisdn: flows.extend([[LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA]]) if show_msisdn: # only support the MSISDN-only flow if we don't require email 3PIDs if not require_email: flows.extend([[LoginType.MSISDN, LoginType.RECAPTCHA]]) # always let users provide both MSISDN & email flows.extend([ [ LoginType.MSISDN, LoginType.EMAIL_IDENTITY, LoginType.RECAPTCHA ], ]) else: # only support 3PIDless registration if no 3PIDs are required if not require_email and not require_msisdn: flows.extend([[LoginType.DUMMY]]) # only support the email-only flow if we don't require MSISDN 3PIDs if not require_msisdn: flows.extend([[LoginType.EMAIL_IDENTITY]]) if show_msisdn: # only support the MSISDN-only flow if we don't require email 3PIDs if not require_email or require_msisdn: flows.extend([[LoginType.MSISDN]]) # always let users provide both MSISDN & email flows.extend([[LoginType.MSISDN, LoginType.EMAIL_IDENTITY]]) auth_result, params, session_id = yield self.auth_handler.check_auth( flows, body, self.hs.get_ip_from_request(request)) # Check that we're not trying to register a denied 3pid. # # the user-facing checks will probably already have happened in # /register/email/requestToken when we requested a 3pid, but that's not # guaranteed. if auth_result: for login_type in [LoginType.EMAIL_IDENTITY, LoginType.MSISDN]: if login_type in auth_result: medium = auth_result[login_type]['medium'] address = auth_result[login_type]['address'] if not check_3pid_allowed(self.hs, medium, address): raise SynapseError( 403, "Third party identifier is not allowed", Codes.THREEPID_DENIED, ) if registered_user_id is not None: logger.info("Already registered user ID %r for this session", registered_user_id) # don't re-register the threepids add_email = False add_msisdn = False else: # NB: This may be from the auth handler and NOT from the POST assert_params_in_dict(params, ["password"]) desired_username = params.get("username", None) new_password = params.get("password", None) guest_access_token = params.get("guest_access_token", None) if desired_username is not None: desired_username = desired_username.lower() (registered_user_id, _) = yield self.registration_handler.register( localpart=desired_username, password=new_password, guest_access_token=guest_access_token, generate_token=False, ) # remember that we've now registered that user account, and with # what user ID (since the user may not have specified) self.auth_handler.set_session_data(session_id, "registered_user_id", registered_user_id) add_email = True add_msisdn = True return_dict = yield self._create_registration_details( registered_user_id, params) if add_email and auth_result and LoginType.EMAIL_IDENTITY in auth_result: threepid = auth_result[LoginType.EMAIL_IDENTITY] yield self._register_email_threepid(registered_user_id, threepid, return_dict["access_token"], params.get("bind_email")) if add_msisdn and auth_result and LoginType.MSISDN in auth_result: threepid = auth_result[LoginType.MSISDN] yield self._register_msisdn_threepid(registered_user_id, threepid, return_dict["access_token"], params.get("bind_msisdn")) defer.returnValue((200, return_dict))
async def on_POST(self, request): body = parse_json_object_from_request(request) assert_params_in_dict( body, ["client_secret", "country", "phone_number", "send_attempt"]) client_secret = body["client_secret"] assert_valid_client_secret(client_secret) country = body["country"] phone_number = body["phone_number"] send_attempt = body["send_attempt"] next_link = body.get("next_link") # Optional param msisdn = phone_number_to_msisdn(country, phone_number) if not check_3pid_allowed(self.hs, "msisdn", msisdn): raise SynapseError( 403, "Phone numbers are not authorized to register on this server", Codes.THREEPID_DENIED, ) await self.identity_handler.ratelimit_request_token_requests( request, "msisdn", msisdn) existing_user_id = await self.hs.get_datastore( ).get_user_id_by_threepid("msisdn", msisdn) if existing_user_id is not None: if self.hs.config.request_token_inhibit_3pid_errors: # Make the client think the operation succeeded. See the rationale in the # comments for request_token_inhibit_3pid_errors. # Also wait for some random amount of time between 100ms and 1s to make it # look like we did something. await self.hs.get_clock().sleep(random.randint(1, 10) / 10) return 200, {"sid": random_string(16)} raise SynapseError(400, "Phone number is already in use", Codes.THREEPID_IN_USE) if not self.hs.config.account_threepid_delegate_msisdn: logger.warning( "No upstream msisdn account_threepid_delegate configured on the server to " "handle this request") raise SynapseError( 400, "Registration by phone number is not supported on this homeserver" ) ret = await self.identity_handler.requestMsisdnToken( self.hs.config.account_threepid_delegate_msisdn, country, phone_number, client_secret, send_attempt, next_link, ) threepid_send_requests.labels(type="msisdn", reason="register").observe(send_attempt) return 200, ret
def on_POST(self, request, room_id): requester = yield self.auth.get_user_by_req(request) is_admin = yield self.auth.is_server_admin(requester.user) if not is_admin: raise AuthError(403, "You are not a server admin") content = parse_json_object_from_request(request) new_room_user_id = content.get("new_room_user_id") if not new_room_user_id: raise SynapseError(400, "Please provide field `new_room_user_id`") room_creator_requester = create_requester(new_room_user_id) message = content.get("message", self.DEFAULT_MESSAGE) room_name = content.get("room_name", "Content Violation Notification") info = yield self._room_creation_handler.create_room( room_creator_requester, config={ "preset": "public_chat", "name": room_name, "power_level_content_override": { "users_default": -10, }, }, ratelimit=False, ) new_room_id = info["room_id"] yield self.event_creation_handler.create_and_send_nonmember_event( room_creator_requester, { "type": "m.room.message", "content": { "body": message, "msgtype": "m.text" }, "room_id": new_room_id, "sender": new_room_user_id, }, ratelimit=False, ) requester_user_id = requester.user.to_string() logger.info("Shutting down room %r", room_id) yield self.store.block_room(room_id, requester_user_id) users = yield self.state.get_current_user_in_room(room_id) kicked_users = [] for user_id in users: if not self.hs.is_mine_id(user_id): continue logger.info("Kicking %r from %r...", user_id, room_id) target_requester = create_requester(user_id) yield self.room_member_handler.update_membership( requester=target_requester, target=target_requester.user, room_id=room_id, action=Membership.LEAVE, content={}, ratelimit=False) yield self.room_member_handler.forget(target_requester.user, room_id) yield self.room_member_handler.update_membership( requester=target_requester, target=target_requester.user, room_id=new_room_id, action=Membership.JOIN, content={}, ratelimit=False) kicked_users.append(user_id) aliases_for_room = yield self.store.get_aliases_for_room(room_id) yield self.store.update_aliases_for_room(room_id, new_room_id, requester_user_id) defer.returnValue((200, { "kicked_users": kicked_users, "local_aliases": aliases_for_room, "new_room_id": new_room_id, }))
async def on_PUT(self, request: SynapseRequest, user_id: str) -> Tuple[int, JsonDict]: requester = await self.auth.get_user_by_req(request) await assert_user_is_admin(self.auth, requester.user) target_user = UserID.from_string(user_id) body = parse_json_object_from_request(request) if not self.hs.is_mine(target_user): raise SynapseError( 400, "This endpoint can only be used with local users") user = await self.admin_handler.get_user(target_user) user_id = target_user.to_string() if user: # modify user if "displayname" in body: await self.profile_handler.set_displayname( target_user, requester, body["displayname"], True) if "threepids" in body: # check for required parameters for each threepid for threepid in body["threepids"]: assert_params_in_dict(threepid, ["medium", "address"]) # remove old threepids from user threepids = await self.store.user_get_threepids(user_id) for threepid in threepids: try: await self.auth_handler.delete_threepid( user_id, threepid["medium"], threepid["address"], None) except Exception: logger.exception("Failed to remove threepids") raise SynapseError(500, "Failed to remove threepids") # add new threepids to user current_time = self.hs.get_clock().time_msec() for threepid in body["threepids"]: await self.auth_handler.add_threepid( user_id, threepid["medium"], threepid["address"], current_time) if "avatar_url" in body and type(body["avatar_url"]) == str: await self.profile_handler.set_avatar_url( target_user, requester, body["avatar_url"], True) if "admin" in body: set_admin_to = bool(body["admin"]) if set_admin_to != user["admin"]: auth_user = requester.user if target_user == auth_user and not set_admin_to: raise SynapseError(400, "You may not demote yourself.") await self.store.set_server_admin(target_user, set_admin_to) if "password" in body: if not isinstance(body["password"], str) or len(body["password"]) > 512: raise SynapseError(400, "Invalid password") else: new_password = body["password"] logout_devices = True new_password_hash = await self.auth_handler.hash( new_password) await self.set_password_handler.set_password( target_user.to_string(), new_password_hash, logout_devices, requester, ) if "deactivated" in body: deactivate = body["deactivated"] if not isinstance(deactivate, bool): raise SynapseError( 400, "'deactivated' parameter is not of type boolean") if deactivate and not user["deactivated"]: await self.deactivate_account_handler.deactivate_account( target_user.to_string(), False, requester, by_admin=True) elif not deactivate and user["deactivated"]: if "password" not in body: raise SynapseError( 400, "Must provide a password to re-activate an account." ) await self.deactivate_account_handler.activate_account( target_user.to_string()) user = await self.admin_handler.get_user(target_user) assert user is not None return 200, user else: # create user password = body.get("password") password_hash = None if password is not None: if not isinstance(password, str) or len(password) > 512: raise SynapseError(400, "Invalid password") password_hash = await self.auth_handler.hash(password) admin = body.get("admin", None) user_type = body.get("user_type", None) displayname = body.get("displayname", None) if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES: raise SynapseError(400, "Invalid user type") user_id = await self.registration_handler.register_user( localpart=target_user.localpart, password_hash=password_hash, admin=bool(admin), default_display_name=displayname, user_type=user_type, by_admin=True, ) if "threepids" in body: # check for required parameters for each threepid for threepid in body["threepids"]: assert_params_in_dict(threepid, ["medium", "address"]) current_time = self.hs.get_clock().time_msec() for threepid in body["threepids"]: await self.auth_handler.add_threepid( user_id, threepid["medium"], threepid["address"], current_time) if (self.hs.config.email_enable_notifs and self.hs.config.email_notif_for_new_users): await self.pusher_pool.add_pusher( user_id=user_id, access_token=None, kind="email", app_id="m.email", app_display_name="Email Notifications", device_display_name=threepid["address"], pushkey=threepid["address"], lang=None, # We don't know a user's language here data={}, ) if "avatar_url" in body and isinstance(body["avatar_url"], str): await self.profile_handler.set_avatar_url( target_user, requester, body["avatar_url"], True) user = await self.admin_handler.get_user(target_user) assert user is not None return 201, user
def on_POST(self, request, room_id, event_id): requester = yield self.auth.get_user_by_req(request) is_admin = yield self.auth.is_server_admin(requester.user) if not is_admin: raise AuthError(403, "You are not a server admin") body = parse_json_object_from_request(request, allow_empty_body=True) delete_local_events = bool(body.get("delete_local_events", False)) # establish the topological ordering we should keep events from. The # user can provide an event_id in the URL or the request body, or can # provide a timestamp in the request body. if event_id is None: event_id = body.get('purge_up_to_event_id') if event_id is not None: event = yield self.store.get_event(event_id) if event.room_id != room_id: raise SynapseError(400, "Event is for wrong room.") token = yield self.store.get_topological_token_for_event(event_id) logger.info( "[purge] purging up to token %s (event_id %s)", token, event_id, ) elif 'purge_up_to_ts' in body: ts = body['purge_up_to_ts'] if not isinstance(ts, int): raise SynapseError( 400, "purge_up_to_ts must be an int", errcode=Codes.BAD_JSON, ) stream_ordering = ( yield self.store.find_first_stream_ordering_after_ts(ts)) r = (yield self.store.get_room_event_after_stream_ordering( room_id, stream_ordering, )) if not r: logger.warn( "[purge] purging events not possible: No event found " "(received_ts %i => stream_ordering %i)", ts, stream_ordering, ) raise SynapseError( 404, "there is no event to be purged", errcode=Codes.NOT_FOUND, ) (stream, topo, _event_id) = r token = "t%d-%d" % (topo, stream) logger.info( "[purge] purging up to token %s (received_ts %i => " "stream_ordering %i)", token, ts, stream_ordering, ) else: raise SynapseError( 400, "must specify purge_up_to_event_id or purge_up_to_ts", errcode=Codes.BAD_JSON, ) purge_id = yield self.handlers.message_handler.start_purge_history( room_id, token, delete_local_events=delete_local_events, ) defer.returnValue((200, { "purge_id": purge_id, }))
async def _async_render_POST(self, request): content = parse_json_object_from_request(request) query = content["server_keys"] await self.query_keys(request, query, query_remote_on_cache_miss=True)
async def on_POST(self, request): body = parse_json_object_from_request(request) # we do basic sanity checks here because the auth layer will store these # in sessions. Pull out the new password provided to us. new_password = body.pop("new_password", None) if new_password is not None: if not isinstance(new_password, str) or len(new_password) > 512: raise SynapseError(400, "Invalid password") self.password_policy_handler.validate_password(new_password) # there are two possibilities here. Either the user does not have an # access token, and needs to do a password reset; or they have one and # need to validate their identity. # # In the first case, we offer a couple of means of identifying # themselves (email and msisdn, though it's unclear if msisdn actually # works). # # In the second case, we require a password to confirm their identity. if self.auth.has_access_token(request): requester = await self.auth.get_user_by_req(request) try: params, session_id = await self.auth_handler.validate_user_via_ui_auth( requester, request, body, self.hs.get_ip_from_request(request), "modify your account password", ) except InteractiveAuthIncompleteError as e: # The user needs to provide more steps to complete auth, but # they're not required to provide the password again. # # If a password is available now, hash the provided password and # store it for later. if new_password: password_hash = await self.auth_handler.hash(new_password) await self.auth_handler.set_session_data( e.session_id, "password_hash", password_hash ) raise user_id = requester.user.to_string() else: requester = None try: result, params, session_id = await self.auth_handler.check_ui_auth( [[LoginType.EMAIL_IDENTITY]], request, body, self.hs.get_ip_from_request(request), "modify your account password", ) except InteractiveAuthIncompleteError as e: # The user needs to provide more steps to complete auth, but # they're not required to provide the password again. # # If a password is available now, hash the provided password and # store it for later. if new_password: password_hash = await self.auth_handler.hash(new_password) await self.auth_handler.set_session_data( e.session_id, "password_hash", password_hash ) raise if LoginType.EMAIL_IDENTITY in result: threepid = result[LoginType.EMAIL_IDENTITY] if "medium" not in threepid or "address" not in threepid: raise SynapseError(500, "Malformed threepid") if threepid["medium"] == "email": # For emails, canonicalise the address. # We store all email addresses canonicalised in the DB. # (See add_threepid in synapse/handlers/auth.py) try: threepid["address"] = canonicalise_email(threepid["address"]) except ValueError as e: raise SynapseError(400, str(e)) # if using email, we must know about the email they're authing with! threepid_user_id = await self.datastore.get_user_id_by_threepid( threepid["medium"], threepid["address"] ) if not threepid_user_id: raise SynapseError(404, "Email address not found", Codes.NOT_FOUND) user_id = threepid_user_id else: logger.error("Auth succeeded but no known type! %r", result.keys()) raise SynapseError(500, "", Codes.UNKNOWN) # If we have a password in this request, prefer it. Otherwise, there # must be a password hash from an earlier request. if new_password: password_hash = await self.auth_handler.hash(new_password) else: password_hash = await self.auth_handler.get_session_data( session_id, "password_hash", None ) if not password_hash: raise SynapseError(400, "Missing params: password", Codes.MISSING_PARAM) logout_devices = params.get("logout_devices", True) await self._set_password_handler.set_password( user_id, password_hash, logout_devices, requester ) return 200, {}
async def on_POST(self, request): if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF: if self.config.local_threepid_handling_disabled_due_to_email_config: logger.warning( "Adding emails have been disabled due to lack of an email config" ) raise SynapseError( 400, "Adding an email to your account is disabled on this server" ) body = parse_json_object_from_request(request) assert_params_in_dict(body, ["client_secret", "email", "send_attempt"]) client_secret = body["client_secret"] assert_valid_client_secret(client_secret) # Canonicalise the email address. The addresses are all stored canonicalised # in the database. # This ensures that the validation email is sent to the canonicalised address # as it will later be entered into the database. # Otherwise the email will be sent to "*****@*****.**" and stored as # "*****@*****.**" in database. try: email = canonicalise_email(body["email"]) except ValueError as e: raise SynapseError(400, str(e)) send_attempt = body["send_attempt"] next_link = body.get("next_link") # Optional param if not check_3pid_allowed(self.hs, "email", email): raise SynapseError( 403, "Your email domain is not authorized on this server", Codes.THREEPID_DENIED, ) existing_user_id = await self.store.get_user_id_by_threepid("email", email) if existing_user_id is not None: if self.config.request_token_inhibit_3pid_errors: # Make the client think the operation succeeded. See the rationale in the # comments for request_token_inhibit_3pid_errors. # Also wait for some random amount of time between 100ms and 1s to make it # look like we did something. await self.hs.clock.sleep(random.randint(1, 10) / 10) return 200, {"sid": random_string(16)} raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE) if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE: assert self.hs.config.account_threepid_delegate_email # Have the configured identity server handle the request ret = await self.identity_handler.requestEmailToken( self.hs.config.account_threepid_delegate_email, email, client_secret, send_attempt, next_link, ) else: # Send threepid validation emails from Synapse sid = await self.identity_handler.send_threepid_validation( email, client_secret, send_attempt, self.mailer.send_add_threepid_mail, next_link, ) # Wrap the session id in a JSON object ret = {"sid": sid} return 200, ret
async def on_POST( self, request: SynapseRequest, room_id: str, membership_action: str, txn_id: Optional[str] = None, ) -> Tuple[int, JsonDict]: requester = await self.auth.get_user_by_req(request, allow_guest=True) if requester.is_guest and membership_action not in { Membership.JOIN, Membership.LEAVE, }: raise AuthError(403, "Guest access not allowed") try: content = parse_json_object_from_request(request) except Exception: # Turns out we used to ignore the body entirely, and some clients # cheekily send invalid bodies. content = {} if membership_action == "invite" and self._has_3pid_invite_keys( content): try: await self.room_member_handler.do_3pid_invite( room_id, requester.user, content["medium"], content["address"], content["id_server"], requester, txn_id, content.get("id_access_token"), ) except ShadowBanError: # Pretend the request succeeded. pass return 200, {} target = requester.user if membership_action in ["invite", "ban", "unban", "kick"]: assert_params_in_dict(content, ["user_id"]) target = UserID.from_string(content["user_id"]) event_content = None if "reason" in content: event_content = {"reason": content["reason"]} try: await self.room_member_handler.update_membership( requester=requester, target=target, room_id=room_id, action=membership_action, txn_id=txn_id, third_party_signed=content.get("third_party_signed", None), content=event_content, ) except ShadowBanError: # Pretend the request succeeded. pass return_value = {} if membership_action == "join": return_value["room_id"] = room_id return 200, return_value
def on_PUT(self, request, network_id, room_id): content = parse_json_object_from_request(request) visibility = content.get("visibility", "public") return self._edit(request, network_id, room_id, visibility)