mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-09-20 00:44:34 -04:00
Merge branch 'develop' into rav/saml_mapping_work
This commit is contained in:
commit
b65327ff66
363 changed files with 10632 additions and 5352 deletions
|
@ -73,7 +73,7 @@ class ClientRestResource(JsonResource):
|
|||
|
||||
@staticmethod
|
||||
def register_servlets(client_resource, hs):
|
||||
versions.register_servlets(client_resource)
|
||||
versions.register_servlets(hs, client_resource)
|
||||
|
||||
# Deprecated in r0
|
||||
initial_sync.register_servlets(hs, client_resource)
|
||||
|
|
|
@ -41,8 +41,10 @@ from synapse.rest.admin._base import (
|
|||
assert_user_is_admin,
|
||||
historical_admin_path_patterns,
|
||||
)
|
||||
from synapse.rest.admin.media import register_servlets_for_media_repo
|
||||
from synapse.rest.admin.media import ListMediaInRoom, register_servlets_for_media_repo
|
||||
from synapse.rest.admin.purge_room_servlet import PurgeRoomServlet
|
||||
from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet
|
||||
from synapse.rest.admin.users import UserAdminServlet
|
||||
from synapse.types import UserID, create_requester
|
||||
from synapse.util.versionstring import get_version_string
|
||||
|
||||
|
@ -50,7 +52,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class UsersRestServlet(RestServlet):
|
||||
PATTERNS = historical_admin_path_patterns("/users/(?P<user_id>[^/]*)")
|
||||
PATTERNS = historical_admin_path_patterns("/users/(?P<user_id>[^/]*)$")
|
||||
|
||||
def __init__(self, hs):
|
||||
self.hs = hs
|
||||
|
@ -67,7 +69,7 @@ class UsersRestServlet(RestServlet):
|
|||
|
||||
ret = yield self.handlers.admin_handler.get_users()
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class VersionServlet(RestServlet):
|
||||
|
@ -118,7 +120,7 @@ class UserRegisterServlet(RestServlet):
|
|||
|
||||
nonce = self.hs.get_secrets().token_hex(64)
|
||||
self.nonces[nonce] = int(self.reactor.seconds())
|
||||
return (200, {"nonce": nonce})
|
||||
return 200, {"nonce": nonce}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -210,7 +212,7 @@ class UserRegisterServlet(RestServlet):
|
|||
)
|
||||
|
||||
result = yield register._create_registration_details(user_id, body)
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class WhoisRestServlet(RestServlet):
|
||||
|
@ -235,7 +237,7 @@ class WhoisRestServlet(RestServlet):
|
|||
|
||||
ret = yield self.handlers.admin_handler.get_whois(target_user)
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class PurgeHistoryRestServlet(RestServlet):
|
||||
|
@ -320,7 +322,7 @@ class PurgeHistoryRestServlet(RestServlet):
|
|||
room_id, token, delete_local_events=delete_local_events
|
||||
)
|
||||
|
||||
return (200, {"purge_id": purge_id})
|
||||
return 200, {"purge_id": purge_id}
|
||||
|
||||
|
||||
class PurgeHistoryStatusRestServlet(RestServlet):
|
||||
|
@ -345,7 +347,7 @@ class PurgeHistoryStatusRestServlet(RestServlet):
|
|||
if purge_status is None:
|
||||
raise NotFoundError("purge id '%s' not found" % purge_id)
|
||||
|
||||
return (200, purge_status.asdict())
|
||||
return 200, purge_status.asdict()
|
||||
|
||||
|
||||
class DeactivateAccountRestServlet(RestServlet):
|
||||
|
@ -377,7 +379,7 @@ class DeactivateAccountRestServlet(RestServlet):
|
|||
else:
|
||||
id_server_unbind_result = "no-support"
|
||||
|
||||
return (200, {"id_server_unbind_result": id_server_unbind_result})
|
||||
return 200, {"id_server_unbind_result": id_server_unbind_result}
|
||||
|
||||
|
||||
class ShutdownRoomRestServlet(RestServlet):
|
||||
|
@ -547,7 +549,7 @@ class ResetPasswordRestServlet(RestServlet):
|
|||
yield self._set_password_handler.set_password(
|
||||
target_user_id, new_password, requester
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class GetUsersPaginatedRestServlet(RestServlet):
|
||||
|
@ -589,7 +591,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
logger.info("limit: %s, start: %s", limit, start)
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, target_user_id):
|
||||
|
@ -617,7 +619,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
logger.info("limit: %s, start: %s", limit, start)
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class SearchUsersRestServlet(RestServlet):
|
||||
|
@ -660,7 +662,7 @@ class SearchUsersRestServlet(RestServlet):
|
|||
logger.info("term: %s ", term)
|
||||
|
||||
ret = yield self.handlers.admin_handler.search_users(term)
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class DeleteGroupAdminRestServlet(RestServlet):
|
||||
|
@ -683,7 +685,7 @@ class DeleteGroupAdminRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Can only delete local groups")
|
||||
|
||||
yield self.group_server.delete_group(group_id, requester.user.to_string())
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class AccountValidityRenewServlet(RestServlet):
|
||||
|
@ -714,7 +716,7 @@ class AccountValidityRenewServlet(RestServlet):
|
|||
)
|
||||
|
||||
res = {"expiration_ts": expiration_ts}
|
||||
return (200, res)
|
||||
return 200, res
|
||||
|
||||
|
||||
########################################################################################
|
||||
|
@ -738,8 +740,10 @@ def register_servlets(hs, http_server):
|
|||
Register all the admin servlets.
|
||||
"""
|
||||
register_servlets_for_client_rest_resource(hs, http_server)
|
||||
PurgeRoomServlet(hs).register(http_server)
|
||||
SendServerNoticeServlet(hs).register(http_server)
|
||||
VersionServlet(hs).register(http_server)
|
||||
UserAdminServlet(hs).register(http_server)
|
||||
|
||||
|
||||
def register_servlets_for_client_rest_resource(hs, http_server):
|
||||
|
@ -757,9 +761,12 @@ def register_servlets_for_client_rest_resource(hs, http_server):
|
|||
DeleteGroupAdminRestServlet(hs).register(http_server)
|
||||
AccountValidityRenewServlet(hs).register(http_server)
|
||||
|
||||
# Load the media repo ones if we're using them.
|
||||
# Load the media repo ones if we're using them. Otherwise load the servlets which
|
||||
# don't need a media repo (typically readonly admin APIs).
|
||||
if hs.config.can_load_media_repo:
|
||||
register_servlets_for_media_repo(hs, http_server)
|
||||
else:
|
||||
ListMediaInRoom(hs).register(http_server)
|
||||
|
||||
# don't add more things here: new servlets should only be exposed on
|
||||
# /_synapse/admin so should not go here. Instead register them in AdminRestResource.
|
||||
|
|
|
@ -49,7 +49,7 @@ class QuarantineMediaInRoom(RestServlet):
|
|||
room_id, requester.user.to_string()
|
||||
)
|
||||
|
||||
return (200, {"num_quarantined": num_quarantined})
|
||||
return 200, {"num_quarantined": num_quarantined}
|
||||
|
||||
|
||||
class ListMediaInRoom(RestServlet):
|
||||
|
@ -60,6 +60,7 @@ class ListMediaInRoom(RestServlet):
|
|||
|
||||
def __init__(self, hs):
|
||||
self.store = hs.get_datastore()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, room_id):
|
||||
|
@ -70,7 +71,7 @@ class ListMediaInRoom(RestServlet):
|
|||
|
||||
local_mxcs, remote_mxcs = yield self.store.get_media_mxcs_in_room(room_id)
|
||||
|
||||
return (200, {"local": local_mxcs, "remote": remote_mxcs})
|
||||
return 200, {"local": local_mxcs, "remote": remote_mxcs}
|
||||
|
||||
|
||||
class PurgeMediaCacheRestServlet(RestServlet):
|
||||
|
@ -89,7 +90,7 @@ class PurgeMediaCacheRestServlet(RestServlet):
|
|||
|
||||
ret = yield self.media_repository.delete_old_remote_media(before_ts)
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
def register_servlets_for_media_repo(hs, http_server):
|
||||
|
|
57
synapse/rest/admin/purge_room_servlet.py
Normal file
57
synapse/rest/admin/purge_room_servlet.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import re
|
||||
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
assert_params_in_dict,
|
||||
parse_json_object_from_request,
|
||||
)
|
||||
from synapse.rest.admin import assert_requester_is_admin
|
||||
|
||||
|
||||
class PurgeRoomServlet(RestServlet):
|
||||
"""Servlet which will remove all trace of a room from the database
|
||||
|
||||
POST /_synapse/admin/v1/purge_room
|
||||
{
|
||||
"room_id": "!room:id"
|
||||
}
|
||||
|
||||
returns:
|
||||
|
||||
{}
|
||||
"""
|
||||
|
||||
PATTERNS = (re.compile("^/_synapse/admin/v1/purge_room$"),)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
self.hs = hs
|
||||
self.auth = hs.get_auth()
|
||||
self.pagination_handler = hs.get_pagination_handler()
|
||||
|
||||
async def on_POST(self, request):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ("room_id",))
|
||||
|
||||
await self.pagination_handler.purge_room(body["room_id"])
|
||||
|
||||
return 200, {}
|
|
@ -92,7 +92,7 @@ class SendServerNoticeServlet(RestServlet):
|
|||
event_content=body["content"],
|
||||
)
|
||||
|
||||
return (200, {"event_id": event.event_id})
|
||||
return 200, {"event_id": event.event_id}
|
||||
|
||||
def on_PUT(self, request, txn_id):
|
||||
return self.txns.fetch_or_execute_request(
|
||||
|
|
100
synapse/rest/admin/users.py
Normal file
100
synapse/rest/admin/users.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import re
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
assert_params_in_dict,
|
||||
parse_json_object_from_request,
|
||||
)
|
||||
from synapse.rest.admin import assert_requester_is_admin, assert_user_is_admin
|
||||
from synapse.types import UserID
|
||||
|
||||
|
||||
class UserAdminServlet(RestServlet):
|
||||
"""
|
||||
Get or set whether or not a user is a server administrator.
|
||||
|
||||
Note that only local users can be server administrators, and that an
|
||||
administrator may not demote themselves.
|
||||
|
||||
Only server administrators can use this API.
|
||||
|
||||
Examples:
|
||||
* Get
|
||||
GET /_synapse/admin/v1/users/@nonadmin:example.com/admin
|
||||
response on success:
|
||||
{
|
||||
"admin": false
|
||||
}
|
||||
* Set
|
||||
PUT /_synapse/admin/v1/users/@reivilibre:librepush.net/admin
|
||||
request body:
|
||||
{
|
||||
"admin": true
|
||||
}
|
||||
response on success:
|
||||
{}
|
||||
"""
|
||||
|
||||
PATTERNS = (re.compile("^/_synapse/admin/v1/users/(?P<user_id>@[^/]*)/admin$"),)
|
||||
|
||||
def __init__(self, hs):
|
||||
self.hs = hs
|
||||
self.auth = hs.get_auth()
|
||||
self.handlers = hs.get_handlers()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, user_id):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
|
||||
target_user = UserID.from_string(user_id)
|
||||
|
||||
if not self.hs.is_mine(target_user):
|
||||
raise SynapseError(400, "Only local users can be admins of this homeserver")
|
||||
|
||||
is_admin = yield self.handlers.admin_handler.get_user_server_admin(target_user)
|
||||
is_admin = bool(is_admin)
|
||||
|
||||
return 200, {"admin": is_admin}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(self.auth, requester.user)
|
||||
auth_user = requester.user
|
||||
|
||||
target_user = UserID.from_string(user_id)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(body, ["admin"])
|
||||
|
||||
if not self.hs.is_mine(target_user):
|
||||
raise SynapseError(400, "Only local users can be admins of this homeserver")
|
||||
|
||||
set_admin_to = bool(body["admin"])
|
||||
|
||||
if target_user == auth_user and not set_admin_to:
|
||||
raise SynapseError(400, "You may not demote yourself.")
|
||||
|
||||
yield self.handlers.admin_handler.set_user_server_admin(
|
||||
target_user, set_admin_to
|
||||
)
|
||||
|
||||
return 200, {}
|
|
@ -54,7 +54,7 @@ class ClientDirectoryServer(RestServlet):
|
|||
dir_handler = self.handlers.directory_handler
|
||||
res = yield dir_handler.get_association(room_alias)
|
||||
|
||||
return (200, res)
|
||||
return 200, res
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, room_alias):
|
||||
|
@ -87,7 +87,7 @@ class ClientDirectoryServer(RestServlet):
|
|||
requester, room_alias, room_id, servers
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, room_alias):
|
||||
|
@ -102,7 +102,7 @@ class ClientDirectoryServer(RestServlet):
|
|||
service.url,
|
||||
room_alias.to_string(),
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
except InvalidClientCredentialsError:
|
||||
# fallback to default user behaviour if they aren't an AS
|
||||
pass
|
||||
|
@ -118,7 +118,7 @@ class ClientDirectoryServer(RestServlet):
|
|||
"User %s deleted alias %s", user.to_string(), room_alias.to_string()
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ClientDirectoryListServer(RestServlet):
|
||||
|
@ -136,7 +136,7 @@ class ClientDirectoryListServer(RestServlet):
|
|||
if room is None:
|
||||
raise NotFoundError("Unknown room")
|
||||
|
||||
return (200, {"visibility": "public" if room["is_public"] else "private"})
|
||||
return 200, {"visibility": "public" if room["is_public"] else "private"}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, room_id):
|
||||
|
@ -149,7 +149,7 @@ class ClientDirectoryListServer(RestServlet):
|
|||
requester, room_id, visibility
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, room_id):
|
||||
|
@ -159,7 +159,7 @@ class ClientDirectoryListServer(RestServlet):
|
|||
requester, room_id, "private"
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ClientAppserviceDirectoryListServer(RestServlet):
|
||||
|
@ -193,4 +193,4 @@ class ClientAppserviceDirectoryListServer(RestServlet):
|
|||
requester.app_service.id, network_id, room_id, visibility
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
|
|
@ -67,10 +67,10 @@ class EventStreamRestServlet(RestServlet):
|
|||
is_guest=is_guest,
|
||||
)
|
||||
|
||||
return (200, chunk)
|
||||
return 200, chunk
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
# TODO: Unit test gets, with and without auth, with different kinds of events.
|
||||
|
@ -91,9 +91,9 @@ class EventRestServlet(RestServlet):
|
|||
time_now = self.clock.time_msec()
|
||||
if event:
|
||||
event = yield self._event_serializer.serialize_event(event, time_now)
|
||||
return (200, event)
|
||||
return 200, event
|
||||
else:
|
||||
return (404, "Event not found.")
|
||||
return 404, "Event not found."
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -42,7 +42,7 @@ class InitialSyncRestServlet(RestServlet):
|
|||
include_archived=include_archived,
|
||||
)
|
||||
|
||||
return (200, content)
|
||||
return 200, content
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -122,10 +122,10 @@ class LoginRestServlet(RestServlet):
|
|||
({"type": t} for t in self.auth_handler.get_supported_login_types())
|
||||
)
|
||||
|
||||
return (200, {"flows": flows})
|
||||
return 200, {"flows": flows}
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -153,7 +153,7 @@ class LoginRestServlet(RestServlet):
|
|||
well_known_data = self._well_known_builder.get_well_known()
|
||||
if well_known_data:
|
||||
result["well_known"] = well_known_data
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _do_other_login(self, login_submission):
|
||||
|
|
|
@ -33,7 +33,7 @@ class LogoutRestServlet(RestServlet):
|
|||
self._device_handler = hs.get_device_handler()
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -49,7 +49,7 @@ class LogoutRestServlet(RestServlet):
|
|||
requester.user.to_string(), requester.device_id
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class LogoutAllRestServlet(RestServlet):
|
||||
|
@ -62,7 +62,7 @@ class LogoutAllRestServlet(RestServlet):
|
|||
self._device_handler = hs.get_device_handler()
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -75,7 +75,7 @@ class LogoutAllRestServlet(RestServlet):
|
|||
# .. and then delete any access tokens which weren't associated with
|
||||
# devices.
|
||||
yield self._auth_handler.delete_access_tokens_for_user(user_id)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -56,7 +56,7 @@ class PresenceStatusRestServlet(RestServlet):
|
|||
state = yield self.presence_handler.get_state(target_user=user)
|
||||
state = format_user_presence_state(state, self.clock.time_msec())
|
||||
|
||||
return (200, state)
|
||||
return 200, state
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
|
@ -88,10 +88,10 @@ class PresenceStatusRestServlet(RestServlet):
|
|||
if self.hs.config.use_presence:
|
||||
yield self.presence_handler.set_state(user, state)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -48,7 +48,7 @@ class ProfileDisplaynameRestServlet(RestServlet):
|
|||
if displayname is not None:
|
||||
ret["displayname"] = displayname
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
|
@ -61,14 +61,14 @@ class ProfileDisplaynameRestServlet(RestServlet):
|
|||
try:
|
||||
new_name = content["displayname"]
|
||||
except Exception:
|
||||
return (400, "Unable to parse name")
|
||||
return 400, "Unable to parse name"
|
||||
|
||||
yield self.profile_handler.set_displayname(user, requester, new_name, is_admin)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_OPTIONS(self, request, user_id):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ProfileAvatarURLRestServlet(RestServlet):
|
||||
|
@ -98,7 +98,7 @@ class ProfileAvatarURLRestServlet(RestServlet):
|
|||
if avatar_url is not None:
|
||||
ret["avatar_url"] = avatar_url
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, user_id):
|
||||
|
@ -110,14 +110,14 @@ class ProfileAvatarURLRestServlet(RestServlet):
|
|||
try:
|
||||
new_name = content["avatar_url"]
|
||||
except Exception:
|
||||
return (400, "Unable to parse name")
|
||||
return 400, "Unable to parse name"
|
||||
|
||||
yield self.profile_handler.set_avatar_url(user, requester, new_name, is_admin)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_OPTIONS(self, request, user_id):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ProfileRestServlet(RestServlet):
|
||||
|
@ -150,7 +150,7 @@ class ProfileRestServlet(RestServlet):
|
|||
if avatar_url is not None:
|
||||
ret["avatar_url"] = avatar_url
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -69,7 +69,7 @@ class PushRuleRestServlet(RestServlet):
|
|||
if "attr" in spec:
|
||||
yield self.set_rule_attr(user_id, spec, content)
|
||||
self.notify_user(user_id)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
if spec["rule_id"].startswith("."):
|
||||
# Rule ids starting with '.' are reserved for server default rules.
|
||||
|
@ -106,7 +106,7 @@ class PushRuleRestServlet(RestServlet):
|
|||
except RuleNotFoundException as e:
|
||||
raise SynapseError(400, str(e))
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, path):
|
||||
|
@ -123,7 +123,7 @@ class PushRuleRestServlet(RestServlet):
|
|||
try:
|
||||
yield self.store.delete_push_rule(user_id, namespaced_rule_id)
|
||||
self.notify_user(user_id)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
except StoreError as e:
|
||||
if e.code == 404:
|
||||
raise NotFoundError()
|
||||
|
@ -151,10 +151,10 @@ class PushRuleRestServlet(RestServlet):
|
|||
)
|
||||
|
||||
if path[0] == "":
|
||||
return (200, rules)
|
||||
return 200, rules
|
||||
elif path[0] == "global":
|
||||
result = _filter_ruleset_with_path(rules["global"], path[1:])
|
||||
return (200, result)
|
||||
return 200, result
|
||||
else:
|
||||
raise UnrecognizedRequestError()
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ class PushersRestServlet(RestServlet):
|
|||
if k not in allowed_keys:
|
||||
del p[k]
|
||||
|
||||
return (200, {"pushers": pushers})
|
||||
return 200, {"pushers": pushers}
|
||||
|
||||
def on_OPTIONS(self, _):
|
||||
return 200, {}
|
||||
|
@ -94,7 +94,7 @@ class PushersSetRestServlet(RestServlet):
|
|||
yield self.pusher_pool.remove_pusher(
|
||||
content["app_id"], content["pushkey"], user_id=user.to_string()
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
assert_params_in_dict(
|
||||
content,
|
||||
|
@ -143,7 +143,7 @@ class PushersSetRestServlet(RestServlet):
|
|||
|
||||
self.notifier.on_new_replication_data()
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_OPTIONS(self, _):
|
||||
return 200, {}
|
||||
|
|
|
@ -91,14 +91,14 @@ class RoomCreateRestServlet(TransactionRestServlet):
|
|||
requester, self.get_room_config(request)
|
||||
)
|
||||
|
||||
return (200, info)
|
||||
return 200, info
|
||||
|
||||
def get_room_config(self, request):
|
||||
user_supplied_config = parse_json_object_from_request(request)
|
||||
return user_supplied_config
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
# TODO: Needs unit testing for generic events
|
||||
|
@ -173,9 +173,9 @@ class RoomStateEventRestServlet(TransactionRestServlet):
|
|||
|
||||
if format == "event":
|
||||
event = format_event_for_client_v2(data.get_dict())
|
||||
return (200, event)
|
||||
return 200, event
|
||||
elif format == "content":
|
||||
return (200, data.get_dict()["content"])
|
||||
return 200, data.get_dict()["content"]
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, room_id, event_type, state_key, txn_id=None):
|
||||
|
@ -210,7 +210,7 @@ class RoomStateEventRestServlet(TransactionRestServlet):
|
|||
ret = {}
|
||||
if event:
|
||||
ret = {"event_id": event.event_id}
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
# TODO: Needs unit testing for generic events + feedback
|
||||
|
@ -244,10 +244,10 @@ class RoomSendEventRestServlet(TransactionRestServlet):
|
|||
requester, event_dict, txn_id=txn_id
|
||||
)
|
||||
|
||||
return (200, {"event_id": event.event_id})
|
||||
return 200, {"event_id": event.event_id}
|
||||
|
||||
def on_GET(self, request, room_id, event_type, txn_id):
|
||||
return (200, "Not implemented")
|
||||
return 200, "Not implemented"
|
||||
|
||||
def on_PUT(self, request, room_id, event_type, txn_id):
|
||||
return self.txns.fetch_or_execute_request(
|
||||
|
@ -307,7 +307,7 @@ class JoinRoomAliasServlet(TransactionRestServlet):
|
|||
third_party_signed=content.get("third_party_signed", None),
|
||||
)
|
||||
|
||||
return (200, {"room_id": room_id})
|
||||
return 200, {"room_id": room_id}
|
||||
|
||||
def on_PUT(self, request, room_identifier, txn_id):
|
||||
return self.txns.fetch_or_execute_request(
|
||||
|
@ -360,7 +360,7 @@ class PublicRoomListRestServlet(TransactionRestServlet):
|
|||
limit=limit, since_token=since_token
|
||||
)
|
||||
|
||||
return (200, data)
|
||||
return 200, data
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -405,7 +405,7 @@ class PublicRoomListRestServlet(TransactionRestServlet):
|
|||
network_tuple=network_tuple,
|
||||
)
|
||||
|
||||
return (200, data)
|
||||
return 200, data
|
||||
|
||||
|
||||
# TODO: Needs unit testing
|
||||
|
@ -456,7 +456,7 @@ class RoomMemberListRestServlet(RestServlet):
|
|||
continue
|
||||
chunk.append(event)
|
||||
|
||||
return (200, {"chunk": chunk})
|
||||
return 200, {"chunk": chunk}
|
||||
|
||||
|
||||
# deprecated in favour of /members?membership=join?
|
||||
|
@ -477,7 +477,7 @@ class JoinedRoomMemberListRestServlet(RestServlet):
|
|||
requester, room_id
|
||||
)
|
||||
|
||||
return (200, {"joined": users_with_profile})
|
||||
return 200, {"joined": users_with_profile}
|
||||
|
||||
|
||||
# TODO: Needs better unit testing
|
||||
|
@ -510,7 +510,7 @@ class RoomMessageListRestServlet(RestServlet):
|
|||
event_filter=event_filter,
|
||||
)
|
||||
|
||||
return (200, msgs)
|
||||
return 200, msgs
|
||||
|
||||
|
||||
# TODO: Needs unit testing
|
||||
|
@ -531,7 +531,7 @@ class RoomStateRestServlet(RestServlet):
|
|||
user_id=requester.user.to_string(),
|
||||
is_guest=requester.is_guest,
|
||||
)
|
||||
return (200, events)
|
||||
return 200, events
|
||||
|
||||
|
||||
# TODO: Needs unit testing
|
||||
|
@ -550,7 +550,7 @@ class RoomInitialSyncRestServlet(RestServlet):
|
|||
content = yield self.initial_sync_handler.room_initial_sync(
|
||||
room_id=room_id, requester=requester, pagin_config=pagination_config
|
||||
)
|
||||
return (200, content)
|
||||
return 200, content
|
||||
|
||||
|
||||
class RoomEventServlet(RestServlet):
|
||||
|
@ -581,7 +581,7 @@ class RoomEventServlet(RestServlet):
|
|||
time_now = self.clock.time_msec()
|
||||
if event:
|
||||
event = yield self._event_serializer.serialize_event(event, time_now)
|
||||
return (200, event)
|
||||
return 200, event
|
||||
|
||||
return SynapseError(404, "Event not found.", errcode=Codes.NOT_FOUND)
|
||||
|
||||
|
@ -633,7 +633,7 @@ class RoomEventContextServlet(RestServlet):
|
|||
results["state"], time_now
|
||||
)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
class RoomForgetRestServlet(TransactionRestServlet):
|
||||
|
@ -652,7 +652,7 @@ class RoomForgetRestServlet(TransactionRestServlet):
|
|||
|
||||
yield self.room_member_handler.forget(user=requester.user, room_id=room_id)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_PUT(self, request, room_id, txn_id):
|
||||
return self.txns.fetch_or_execute_request(
|
||||
|
@ -701,9 +701,9 @@ class RoomMembershipRestServlet(TransactionRestServlet):
|
|||
content["id_server"],
|
||||
requester,
|
||||
txn_id,
|
||||
content.get("id_access_token"),
|
||||
)
|
||||
return (200, {})
|
||||
return
|
||||
return 200, {}
|
||||
|
||||
target = requester.user
|
||||
if membership_action in ["invite", "ban", "unban", "kick"]:
|
||||
|
@ -729,7 +729,7 @@ class RoomMembershipRestServlet(TransactionRestServlet):
|
|||
if membership_action == "join":
|
||||
return_value["room_id"] = room_id
|
||||
|
||||
return (200, return_value)
|
||||
return 200, return_value
|
||||
|
||||
def _has_3pid_invite_keys(self, content):
|
||||
for key in {"id_server", "medium", "address"}:
|
||||
|
@ -771,7 +771,7 @@ class RoomRedactEventRestServlet(TransactionRestServlet):
|
|||
txn_id=txn_id,
|
||||
)
|
||||
|
||||
return (200, {"event_id": event.event_id})
|
||||
return 200, {"event_id": event.event_id}
|
||||
|
||||
def on_PUT(self, request, room_id, event_id, txn_id):
|
||||
return self.txns.fetch_or_execute_request(
|
||||
|
@ -816,7 +816,7 @@ class RoomTypingRestServlet(RestServlet):
|
|||
target_user=target_user, auth_user=requester.user, room_id=room_id
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class SearchRestServlet(RestServlet):
|
||||
|
@ -838,7 +838,7 @@ class SearchRestServlet(RestServlet):
|
|||
requester.user, content, batch
|
||||
)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
class JoinedRoomsRestServlet(RestServlet):
|
||||
|
@ -854,7 +854,7 @@ class JoinedRoomsRestServlet(RestServlet):
|
|||
requester = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
||||
room_ids = yield self.store.get_rooms_for_user(requester.user.to_string())
|
||||
return (200, {"joined_rooms": list(room_ids)})
|
||||
return 200, {"joined_rooms": list(room_ids)}
|
||||
|
||||
|
||||
def register_txn_path(servlet, regex_string, http_server, with_get=False):
|
||||
|
|
|
@ -60,7 +60,7 @@ class VoipRestServlet(RestServlet):
|
|||
password = turnPassword
|
||||
|
||||
else:
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
return (
|
||||
200,
|
||||
|
@ -73,7 +73,7 @@ class VoipRestServlet(RestServlet):
|
|||
)
|
||||
|
||||
def on_OPTIONS(self, request):
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -37,6 +37,7 @@ def client_patterns(path_regex, releases=(0,), unstable=True, v1=False):
|
|||
SRE_Pattern
|
||||
"""
|
||||
patterns = []
|
||||
|
||||
if unstable:
|
||||
unstable_prefix = CLIENT_API_PREFIX + "/unstable"
|
||||
patterns.append(re.compile("^" + unstable_prefix + path_regex))
|
||||
|
@ -46,6 +47,7 @@ def client_patterns(path_regex, releases=(0,), unstable=True, v1=False):
|
|||
for release in releases:
|
||||
new_prefix = CLIENT_API_PREFIX + "/r%d" % (release,)
|
||||
patterns.append(re.compile("^" + new_prefix + path_regex))
|
||||
|
||||
return patterns
|
||||
|
||||
|
||||
|
|
|
@ -18,12 +18,11 @@ import logging
|
|||
|
||||
from six.moves import http_client
|
||||
|
||||
import jinja2
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.constants import LoginType
|
||||
from synapse.api.errors import Codes, SynapseError, ThreepidValidationError
|
||||
from synapse.config.emailconfig import ThreepidBehaviour
|
||||
from synapse.http.server import finish_request
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
|
@ -31,8 +30,8 @@ from synapse.http.servlet import (
|
|||
parse_json_object_from_request,
|
||||
parse_string,
|
||||
)
|
||||
from synapse.push.mailer import Mailer, load_jinja2_templates
|
||||
from synapse.util.msisdn import phone_number_to_msisdn
|
||||
from synapse.util.stringutils import random_string
|
||||
from synapse.util.threepids import check_3pid_allowed
|
||||
|
||||
from ._base import client_patterns, interactive_auth_handler
|
||||
|
@ -50,25 +49,28 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
self.config = hs.config
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
|
||||
if self.config.email_password_reset_behaviour == "local":
|
||||
from synapse.push.mailer import Mailer, load_jinja2_templates
|
||||
|
||||
templates = load_jinja2_templates(
|
||||
config=hs.config,
|
||||
template_html_name=hs.config.email_password_reset_template_html,
|
||||
template_text_name=hs.config.email_password_reset_template_text,
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
template_html, template_text = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[
|
||||
self.config.email_password_reset_template_html,
|
||||
self.config.email_password_reset_template_text,
|
||||
],
|
||||
apply_format_ts_filter=True,
|
||||
apply_mxc_to_http_filter=True,
|
||||
public_baseurl=self.config.public_baseurl,
|
||||
)
|
||||
self.mailer = Mailer(
|
||||
hs=self.hs,
|
||||
app_name=self.config.email_app_name,
|
||||
template_html=templates[0],
|
||||
template_text=templates[1],
|
||||
template_html=template_html,
|
||||
template_text=template_text,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
if self.config.email_password_reset_behaviour == "off":
|
||||
if self.config.password_resets_were_disabled_due_to_email_config:
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"User password resets have been disabled due to lack of email config"
|
||||
)
|
||||
|
@ -93,99 +95,45 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
existing_user_id = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
"email", email
|
||||
)
|
||||
|
||||
if existingUid is None:
|
||||
if existing_user_id is None:
|
||||
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
if self.config.email_password_reset_behaviour == "remote":
|
||||
if "id_server" not in body:
|
||||
raise SynapseError(400, "Missing 'id_server' param in body")
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
# Have the configured identity server handle the request
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Password reset by email is not supported on this homeserver"
|
||||
)
|
||||
|
||||
# Have the identity server handle the password reset flow
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
body["id_server"], email, client_secret, send_attempt, next_link
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
else:
|
||||
# Send password reset emails from Synapse
|
||||
sid = yield self.send_password_reset(
|
||||
email, client_secret, send_attempt, next_link
|
||||
sid = yield 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)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def send_password_reset(self, email, client_secret, send_attempt, next_link=None):
|
||||
"""Send a password reset email
|
||||
|
||||
Args:
|
||||
email (str): The user's email address
|
||||
client_secret (str): The provided client secret
|
||||
send_attempt (int): Which send attempt this is
|
||||
|
||||
Returns:
|
||||
The new session_id upon success
|
||||
|
||||
Raises:
|
||||
SynapseError is an error occurred when sending the email
|
||||
"""
|
||||
# Check that this email/client_secret/send_attempt combo is new or
|
||||
# greater than what we've seen previously
|
||||
session = yield self.datastore.get_threepid_validation_session(
|
||||
"email", client_secret, address=email, validated=False
|
||||
)
|
||||
|
||||
# Check to see if a session already exists and that it is not yet
|
||||
# marked as validated
|
||||
if session and session.get("validated_at") is None:
|
||||
session_id = session["session_id"]
|
||||
last_send_attempt = session["last_send_attempt"]
|
||||
|
||||
# Check that the send_attempt is higher than previous attempts
|
||||
if send_attempt <= last_send_attempt:
|
||||
# If not, just return a success without sending an email
|
||||
return session_id
|
||||
else:
|
||||
# An non-validated session does not exist yet.
|
||||
# Generate a session id
|
||||
session_id = random_string(16)
|
||||
|
||||
# Generate a new validation token
|
||||
token = random_string(32)
|
||||
|
||||
# Send the mail with the link containing the token, client_secret
|
||||
# and session_id
|
||||
try:
|
||||
yield self.mailer.send_password_reset_mail(
|
||||
email, token, client_secret, session_id
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Error sending a password reset email to %s", email)
|
||||
raise SynapseError(
|
||||
500, "An error was encountered when sending the password reset email"
|
||||
)
|
||||
|
||||
token_expires = (
|
||||
self.hs.clock.time_msec() + self.config.email_validation_token_lifetime
|
||||
)
|
||||
|
||||
yield self.datastore.start_or_continue_validation_session(
|
||||
"email",
|
||||
email,
|
||||
session_id,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
token,
|
||||
token_expires,
|
||||
)
|
||||
|
||||
return session_id
|
||||
return 200, ret
|
||||
|
||||
|
||||
class MsisdnPasswordRequestTokenRestServlet(RestServlet):
|
||||
|
@ -202,11 +150,15 @@ class MsisdnPasswordRequestTokenRestServlet(RestServlet):
|
|||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(
|
||||
body,
|
||||
["id_server", "client_secret", "country", "phone_number", "send_attempt"],
|
||||
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
||||
)
|
||||
client_secret = body["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(body["country"], body["phone_number"])
|
||||
msisdn = phone_number_to_msisdn(country, phone_number)
|
||||
|
||||
if not check_3pid_allowed(self.hs, "msisdn", msisdn):
|
||||
raise SynapseError(
|
||||
|
@ -215,13 +167,33 @@ class MsisdnPasswordRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existingUid = yield self.datastore.get_user_id_by_threepid("msisdn", msisdn)
|
||||
existing_user_id = yield self.datastore.get_user_id_by_threepid(
|
||||
"msisdn", msisdn
|
||||
)
|
||||
|
||||
if existingUid is None:
|
||||
if existing_user_id is None:
|
||||
raise SynapseError(400, "MSISDN not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(**body)
|
||||
return (200, ret)
|
||||
if not self.hs.config.account_threepid_delegate_msisdn:
|
||||
logger.warn(
|
||||
"No upstream msisdn account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400,
|
||||
"Password reset by phone number is not supported on this homeserver",
|
||||
)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(
|
||||
self.hs.config.account_threepid_delegate_msisdn,
|
||||
country,
|
||||
phone_number,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
class PasswordResetSubmitTokenServlet(RestServlet):
|
||||
|
@ -241,31 +213,32 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.datastore = hs.get_datastore()
|
||||
self.store = hs.get_datastore()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
# We currently only handle threepid token submissions for email
|
||||
if medium != "email":
|
||||
raise SynapseError(
|
||||
400, "This medium is currently not supported for password resets"
|
||||
)
|
||||
if self.config.email_password_reset_behaviour == "off":
|
||||
if self.config.password_resets_were_disabled_due_to_email_config:
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"User password resets have been disabled due to lack of email config"
|
||||
"Password reset emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Email-based password resets have been disabled on this server"
|
||||
400, "Email-based password resets are disabled on this server"
|
||||
)
|
||||
|
||||
sid = parse_string(request, "sid")
|
||||
client_secret = parse_string(request, "client_secret")
|
||||
token = parse_string(request, "token")
|
||||
sid = parse_string(request, "sid", required=True)
|
||||
client_secret = parse_string(request, "client_secret", required=True)
|
||||
token = parse_string(request, "token", required=True)
|
||||
|
||||
# Attempt to validate a 3PID sesssion
|
||||
# Attempt to validate a 3PID session
|
||||
try:
|
||||
# Mark the session as valid
|
||||
next_link = yield self.datastore.validate_threepid_session(
|
||||
next_link = yield self.store.validate_threepid_session(
|
||||
sid, client_secret, token, self.clock.time_msec()
|
||||
)
|
||||
|
||||
|
@ -282,38 +255,22 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
return None
|
||||
|
||||
# Otherwise show the success template
|
||||
html = self.config.email_password_reset_success_html_content
|
||||
html = self.config.email_password_reset_template_success_html
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
# Show a failure page with a reason
|
||||
html = self.load_jinja2_template(
|
||||
self.config.email_template_dir,
|
||||
self.config.email_password_reset_failure_template,
|
||||
template_vars={"failure_reason": e.msg},
|
||||
)
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
return None
|
||||
|
||||
def load_jinja2_template(self, template_dir, template_filename, template_vars):
|
||||
"""Loads a jinja2 template with variables to insert
|
||||
|
||||
Args:
|
||||
template_dir (str): The directory where templates are stored
|
||||
template_filename (str): The name of the template in the template_dir
|
||||
template_vars (Dict): Dictionary of keys in the template
|
||||
alongside their values to insert
|
||||
|
||||
Returns:
|
||||
str containing the contents of the rendered template
|
||||
"""
|
||||
loader = jinja2.FileSystemLoader(template_dir)
|
||||
env = jinja2.Environment(loader=loader)
|
||||
|
||||
template = env.get_template(template_filename)
|
||||
return template.render(**template_vars)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, medium):
|
||||
|
@ -325,12 +282,12 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["sid", "client_secret", "token"])
|
||||
|
||||
valid, _ = yield self.datastore.validate_threepid_validation_token(
|
||||
valid, _ = yield self.store.validate_threepid_session(
|
||||
body["sid"], body["client_secret"], body["token"], self.clock.time_msec()
|
||||
)
|
||||
response_code = 200 if valid else 400
|
||||
|
||||
return (response_code, {"success": valid})
|
||||
return response_code, {"success": valid}
|
||||
|
||||
|
||||
class PasswordRestServlet(RestServlet):
|
||||
|
@ -371,7 +328,6 @@ class PasswordRestServlet(RestServlet):
|
|||
[[LoginType.EMAIL_IDENTITY], [LoginType.MSISDN]],
|
||||
body,
|
||||
self.hs.get_ip_from_request(request),
|
||||
password_servlet=True,
|
||||
)
|
||||
|
||||
if LoginType.EMAIL_IDENTITY in result:
|
||||
|
@ -399,7 +355,7 @@ class PasswordRestServlet(RestServlet):
|
|||
|
||||
yield self._set_password_handler.set_password(user_id, new_password, requester)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
def on_OPTIONS(self, _):
|
||||
return 200, {}
|
||||
|
@ -434,7 +390,7 @@ class DeactivateAccountRestServlet(RestServlet):
|
|||
yield self._deactivate_account_handler.deactivate_account(
|
||||
requester.user.to_string(), erase
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
yield self.auth_handler.validate_user_via_ui_auth(
|
||||
requester, body, self.hs.get_ip_from_request(request)
|
||||
|
@ -447,17 +403,18 @@ class DeactivateAccountRestServlet(RestServlet):
|
|||
else:
|
||||
id_server_unbind_result = "no-support"
|
||||
|
||||
return (200, {"id_server_unbind_result": id_server_unbind_result})
|
||||
return 200, {"id_server_unbind_result": id_server_unbind_result}
|
||||
|
||||
|
||||
class EmailThreepidRequestTokenRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/email/requestToken$")
|
||||
|
||||
def __init__(self, hs):
|
||||
self.hs = hs
|
||||
super(EmailThreepidRequestTokenRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.config = hs.config
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.datastore = self.hs.get_datastore()
|
||||
self.store = self.hs.get_datastore()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -465,23 +422,30 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
assert_params_in_dict(
|
||||
body, ["id_server", "client_secret", "email", "send_attempt"]
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
client_secret = body["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", body["email"]):
|
||||
if not check_3pid_allowed(self.hs, "email", email):
|
||||
raise SynapseError(
|
||||
403,
|
||||
"Your email domain is not authorized on this server",
|
||||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existingUid = yield self.datastore.get_user_id_by_threepid(
|
||||
existing_user_id = yield self.store.get_user_id_by_threepid(
|
||||
"email", body["email"]
|
||||
)
|
||||
|
||||
if existingUid is not None:
|
||||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
ret = yield self.identity_handler.requestEmailToken(**body)
|
||||
return (200, ret)
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
id_server, email, client_secret, send_attempt, next_link
|
||||
)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
||||
|
@ -490,8 +454,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
def __init__(self, hs):
|
||||
self.hs = hs
|
||||
super(MsisdnThreepidRequestTokenRestServlet, self).__init__()
|
||||
self.store = self.hs.get_datastore()
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.datastore = self.hs.get_datastore()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
@ -500,8 +464,14 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
body,
|
||||
["id_server", "client_secret", "country", "phone_number", "send_attempt"],
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
client_secret = body["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(body["country"], body["phone_number"])
|
||||
msisdn = phone_number_to_msisdn(country, phone_number)
|
||||
|
||||
if not check_3pid_allowed(self.hs, "msisdn", msisdn):
|
||||
raise SynapseError(
|
||||
|
@ -510,13 +480,15 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existingUid = yield self.datastore.get_user_id_by_threepid("msisdn", msisdn)
|
||||
existing_user_id = yield self.store.get_user_id_by_threepid("msisdn", msisdn)
|
||||
|
||||
if existingUid is not None:
|
||||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(**body)
|
||||
return (200, ret)
|
||||
ret = yield self.identity_handler.requestMsisdnToken(
|
||||
id_server, country, phone_number, client_secret, send_attempt, next_link
|
||||
)
|
||||
return 200, ret
|
||||
|
||||
|
||||
class ThreepidRestServlet(RestServlet):
|
||||
|
@ -536,21 +508,23 @@ class ThreepidRestServlet(RestServlet):
|
|||
|
||||
threepids = yield self.datastore.user_get_threepids(requester.user.to_string())
|
||||
|
||||
return (200, {"threepids": threepids})
|
||||
return 200, {"threepids": threepids}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
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)
|
||||
threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds")
|
||||
if threepid_creds is None:
|
||||
raise SynapseError(
|
||||
400, "Missing param three_pid_creds", 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)
|
||||
# Specify None as the identity server to retrieve it from the request body instead
|
||||
threepid = yield self.identity_handler.threepid_from_creds(None, threepid_creds)
|
||||
|
||||
if not threepid:
|
||||
raise SynapseError(400, "Failed to auth 3pid", Codes.THREEPID_AUTH_FAILED)
|
||||
|
@ -566,9 +540,41 @@ class ThreepidRestServlet(RestServlet):
|
|||
|
||||
if "bind" in body and body["bind"]:
|
||||
logger.debug("Binding threepid %s to %s", threepid, user_id)
|
||||
yield self.identity_handler.bind_threepid(threePidCreds, user_id)
|
||||
yield self.identity_handler.bind_threepid(threepid_creds, user_id)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ThreepidUnbindRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/unbind$")
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidUnbindRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.auth = hs.get_auth()
|
||||
self.datastore = self.hs.get_datastore()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
"""Unbind the given 3pid from a specific identity server, or identity servers that are
|
||||
known to have this 3pid bound
|
||||
"""
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["medium", "address"])
|
||||
|
||||
medium = body.get("medium")
|
||||
address = body.get("address")
|
||||
id_server = body.get("id_server")
|
||||
|
||||
# Attempt to unbind the threepid from an identity server. If id_server is None, try to
|
||||
# unbind from all identity servers this threepid has been added to in the past
|
||||
result = yield self.identity_handler.try_unbind_threepid(
|
||||
requester.user.to_string(),
|
||||
{"address": address, "medium": medium, "id_server": id_server},
|
||||
)
|
||||
return 200, {"id_server_unbind_result": "success" if result else "no-support"}
|
||||
|
||||
|
||||
class ThreepidDeleteRestServlet(RestServlet):
|
||||
|
@ -603,7 +609,7 @@ class ThreepidDeleteRestServlet(RestServlet):
|
|||
else:
|
||||
id_server_unbind_result = "no-support"
|
||||
|
||||
return (200, {"id_server_unbind_result": id_server_unbind_result})
|
||||
return 200, {"id_server_unbind_result": id_server_unbind_result}
|
||||
|
||||
|
||||
class WhoamiRestServlet(RestServlet):
|
||||
|
@ -617,7 +623,7 @@ class WhoamiRestServlet(RestServlet):
|
|||
def on_GET(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
|
||||
return (200, {"user_id": requester.user.to_string()})
|
||||
return 200, {"user_id": requester.user.to_string()}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
@ -629,5 +635,6 @@ def register_servlets(hs, http_server):
|
|||
EmailThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
ThreepidRestServlet(hs).register(http_server)
|
||||
ThreepidUnbindRestServlet(hs).register(http_server)
|
||||
ThreepidDeleteRestServlet(hs).register(http_server)
|
||||
WhoamiRestServlet(hs).register(http_server)
|
||||
|
|
|
@ -55,7 +55,7 @@ class AccountDataServlet(RestServlet):
|
|||
|
||||
self.notifier.on_new_event("account_data_key", max_id, users=[user_id])
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, user_id, account_data_type):
|
||||
|
@ -70,7 +70,7 @@ class AccountDataServlet(RestServlet):
|
|||
if event is None:
|
||||
raise NotFoundError("Account data not found")
|
||||
|
||||
return (200, event)
|
||||
return 200, event
|
||||
|
||||
|
||||
class RoomAccountDataServlet(RestServlet):
|
||||
|
@ -112,7 +112,7 @@ class RoomAccountDataServlet(RestServlet):
|
|||
|
||||
self.notifier.on_new_event("account_data_key", max_id, users=[user_id])
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, user_id, room_id, account_data_type):
|
||||
|
@ -127,7 +127,7 @@ class RoomAccountDataServlet(RestServlet):
|
|||
if event is None:
|
||||
raise NotFoundError("Room account data not found")
|
||||
|
||||
return (200, event)
|
||||
return 200, event
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -58,7 +58,7 @@ class CapabilitiesRestServlet(RestServlet):
|
|||
"m.change_password": {"enabled": change_password},
|
||||
}
|
||||
}
|
||||
return (200, response)
|
||||
return 200, response
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -48,7 +48,7 @@ class DevicesRestServlet(RestServlet):
|
|||
devices = yield self.device_handler.get_devices_by_user(
|
||||
requester.user.to_string()
|
||||
)
|
||||
return (200, {"devices": devices})
|
||||
return 200, {"devices": devices}
|
||||
|
||||
|
||||
class DeleteDevicesRestServlet(RestServlet):
|
||||
|
@ -91,7 +91,7 @@ class DeleteDevicesRestServlet(RestServlet):
|
|||
yield self.device_handler.delete_devices(
|
||||
requester.user.to_string(), body["devices"]
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class DeviceRestServlet(RestServlet):
|
||||
|
@ -114,7 +114,7 @@ class DeviceRestServlet(RestServlet):
|
|||
device = yield self.device_handler.get_device(
|
||||
requester.user.to_string(), device_id
|
||||
)
|
||||
return (200, device)
|
||||
return 200, device
|
||||
|
||||
@interactive_auth_handler
|
||||
@defer.inlineCallbacks
|
||||
|
@ -137,7 +137,7 @@ class DeviceRestServlet(RestServlet):
|
|||
)
|
||||
|
||||
yield self.device_handler.delete_device(requester.user.to_string(), device_id)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, device_id):
|
||||
|
@ -147,7 +147,7 @@ class DeviceRestServlet(RestServlet):
|
|||
yield self.device_handler.update_device(
|
||||
requester.user.to_string(), device_id, body
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -56,7 +56,7 @@ class GetFilterRestServlet(RestServlet):
|
|||
user_localpart=target_user.localpart, filter_id=filter_id
|
||||
)
|
||||
|
||||
return (200, filter.get_filter_json())
|
||||
return 200, filter.get_filter_json()
|
||||
except (KeyError, StoreError):
|
||||
raise SynapseError(400, "No such filter", errcode=Codes.NOT_FOUND)
|
||||
|
||||
|
@ -89,7 +89,7 @@ class CreateFilterRestServlet(RestServlet):
|
|||
user_localpart=target_user.localpart, user_filter=content
|
||||
)
|
||||
|
||||
return (200, {"filter_id": str(filter_id)})
|
||||
return 200, {"filter_id": str(filter_id)}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -47,7 +47,7 @@ class GroupServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, group_description)
|
||||
return 200, group_description
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, group_id):
|
||||
|
@ -59,7 +59,7 @@ class GroupServlet(RestServlet):
|
|||
group_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class GroupSummaryServlet(RestServlet):
|
||||
|
@ -83,7 +83,7 @@ class GroupSummaryServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, get_group_summary)
|
||||
return 200, get_group_summary
|
||||
|
||||
|
||||
class GroupSummaryRoomsCatServlet(RestServlet):
|
||||
|
@ -120,7 +120,7 @@ class GroupSummaryRoomsCatServlet(RestServlet):
|
|||
content=content,
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, group_id, category_id, room_id):
|
||||
|
@ -131,7 +131,7 @@ class GroupSummaryRoomsCatServlet(RestServlet):
|
|||
group_id, requester_user_id, room_id=room_id, category_id=category_id
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
|
||||
class GroupCategoryServlet(RestServlet):
|
||||
|
@ -157,7 +157,7 @@ class GroupCategoryServlet(RestServlet):
|
|||
group_id, requester_user_id, category_id=category_id
|
||||
)
|
||||
|
||||
return (200, category)
|
||||
return 200, category
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, group_id, category_id):
|
||||
|
@ -169,7 +169,7 @@ class GroupCategoryServlet(RestServlet):
|
|||
group_id, requester_user_id, category_id=category_id, content=content
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, group_id, category_id):
|
||||
|
@ -180,7 +180,7 @@ class GroupCategoryServlet(RestServlet):
|
|||
group_id, requester_user_id, category_id=category_id
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
|
||||
class GroupCategoriesServlet(RestServlet):
|
||||
|
@ -204,7 +204,7 @@ class GroupCategoriesServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, category)
|
||||
return 200, category
|
||||
|
||||
|
||||
class GroupRoleServlet(RestServlet):
|
||||
|
@ -228,7 +228,7 @@ class GroupRoleServlet(RestServlet):
|
|||
group_id, requester_user_id, role_id=role_id
|
||||
)
|
||||
|
||||
return (200, category)
|
||||
return 200, category
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, group_id, role_id):
|
||||
|
@ -240,7 +240,7 @@ class GroupRoleServlet(RestServlet):
|
|||
group_id, requester_user_id, role_id=role_id, content=content
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, group_id, role_id):
|
||||
|
@ -251,7 +251,7 @@ class GroupRoleServlet(RestServlet):
|
|||
group_id, requester_user_id, role_id=role_id
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
|
||||
class GroupRolesServlet(RestServlet):
|
||||
|
@ -275,7 +275,7 @@ class GroupRolesServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, category)
|
||||
return 200, category
|
||||
|
||||
|
||||
class GroupSummaryUsersRoleServlet(RestServlet):
|
||||
|
@ -312,7 +312,7 @@ class GroupSummaryUsersRoleServlet(RestServlet):
|
|||
content=content,
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, group_id, role_id, user_id):
|
||||
|
@ -323,7 +323,7 @@ class GroupSummaryUsersRoleServlet(RestServlet):
|
|||
group_id, requester_user_id, user_id=user_id, role_id=role_id
|
||||
)
|
||||
|
||||
return (200, resp)
|
||||
return 200, resp
|
||||
|
||||
|
||||
class GroupRoomServlet(RestServlet):
|
||||
|
@ -347,7 +347,7 @@ class GroupRoomServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupUsersServlet(RestServlet):
|
||||
|
@ -371,7 +371,7 @@ class GroupUsersServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupInvitedUsersServlet(RestServlet):
|
||||
|
@ -395,7 +395,7 @@ class GroupInvitedUsersServlet(RestServlet):
|
|||
group_id, requester_user_id
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupSettingJoinPolicyServlet(RestServlet):
|
||||
|
@ -420,7 +420,7 @@ class GroupSettingJoinPolicyServlet(RestServlet):
|
|||
group_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupCreateServlet(RestServlet):
|
||||
|
@ -450,7 +450,7 @@ class GroupCreateServlet(RestServlet):
|
|||
group_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupAdminRoomsServlet(RestServlet):
|
||||
|
@ -477,7 +477,7 @@ class GroupAdminRoomsServlet(RestServlet):
|
|||
group_id, requester_user_id, room_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, group_id, room_id):
|
||||
|
@ -488,7 +488,7 @@ class GroupAdminRoomsServlet(RestServlet):
|
|||
group_id, requester_user_id, room_id
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupAdminRoomsConfigServlet(RestServlet):
|
||||
|
@ -516,7 +516,7 @@ class GroupAdminRoomsConfigServlet(RestServlet):
|
|||
group_id, requester_user_id, room_id, config_key, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupAdminUsersInviteServlet(RestServlet):
|
||||
|
@ -546,7 +546,7 @@ class GroupAdminUsersInviteServlet(RestServlet):
|
|||
group_id, user_id, requester_user_id, config
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupAdminUsersKickServlet(RestServlet):
|
||||
|
@ -573,7 +573,7 @@ class GroupAdminUsersKickServlet(RestServlet):
|
|||
group_id, user_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupSelfLeaveServlet(RestServlet):
|
||||
|
@ -598,7 +598,7 @@ class GroupSelfLeaveServlet(RestServlet):
|
|||
group_id, requester_user_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupSelfJoinServlet(RestServlet):
|
||||
|
@ -623,7 +623,7 @@ class GroupSelfJoinServlet(RestServlet):
|
|||
group_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupSelfAcceptInviteServlet(RestServlet):
|
||||
|
@ -648,7 +648,7 @@ class GroupSelfAcceptInviteServlet(RestServlet):
|
|||
group_id, requester_user_id, content
|
||||
)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupSelfUpdatePublicityServlet(RestServlet):
|
||||
|
@ -672,7 +672,7 @@ class GroupSelfUpdatePublicityServlet(RestServlet):
|
|||
publicise = content["publicise"]
|
||||
yield self.store.update_group_publicity(group_id, requester_user_id, publicise)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class PublicisedGroupsForUserServlet(RestServlet):
|
||||
|
@ -694,7 +694,7 @@ class PublicisedGroupsForUserServlet(RestServlet):
|
|||
|
||||
result = yield self.groups_handler.get_publicised_groups_for_user(user_id)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class PublicisedGroupsForUsersServlet(RestServlet):
|
||||
|
@ -719,7 +719,7 @@ class PublicisedGroupsForUsersServlet(RestServlet):
|
|||
|
||||
result = yield self.groups_handler.bulk_get_publicised_groups(user_ids)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class GroupsForUserServlet(RestServlet):
|
||||
|
@ -741,7 +741,7 @@ class GroupsForUserServlet(RestServlet):
|
|||
|
||||
result = yield self.groups_handler.get_joined_groups(requester_user_id)
|
||||
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -24,6 +24,7 @@ from synapse.http.servlet import (
|
|||
parse_json_object_from_request,
|
||||
parse_string,
|
||||
)
|
||||
from synapse.logging.opentracing import log_kv, set_tag, trace
|
||||
from synapse.types import StreamToken
|
||||
|
||||
from ._base import client_patterns
|
||||
|
@ -68,6 +69,7 @@ class KeyUploadServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.e2e_keys_handler = hs.get_e2e_keys_handler()
|
||||
|
||||
@trace(opname="upload_keys")
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, device_id):
|
||||
requester = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
@ -78,6 +80,14 @@ class KeyUploadServlet(RestServlet):
|
|||
# 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:
|
||||
set_tag("error", True)
|
||||
log_kv(
|
||||
{
|
||||
"message": "Client uploading keys for a different device",
|
||||
"logged_in_id": requester.device_id,
|
||||
"key_being_uploaded": device_id,
|
||||
}
|
||||
)
|
||||
logger.warning(
|
||||
"Client uploading keys for a different device "
|
||||
"(logged in as %s, uploading for %s)",
|
||||
|
@ -95,7 +105,7 @@ class KeyUploadServlet(RestServlet):
|
|||
result = yield self.e2e_keys_handler.upload_keys_for_user(
|
||||
user_id, device_id, body
|
||||
)
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class KeyQueryServlet(RestServlet):
|
||||
|
@ -149,7 +159,7 @@ class KeyQueryServlet(RestServlet):
|
|||
timeout = parse_integer(request, "timeout", 10 * 1000)
|
||||
body = parse_json_object_from_request(request)
|
||||
result = yield self.e2e_keys_handler.query_devices(body, timeout)
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
class KeyChangesServlet(RestServlet):
|
||||
|
@ -178,10 +188,11 @@ class KeyChangesServlet(RestServlet):
|
|||
requester = yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
||||
from_token_string = parse_string(request, "from")
|
||||
set_tag("from", from_token_string)
|
||||
|
||||
# We want to enforce they do pass us one, but we ignore it and return
|
||||
# changes after the "to" as well as before.
|
||||
parse_string(request, "to")
|
||||
set_tag("to", parse_string(request, "to"))
|
||||
|
||||
from_token = StreamToken.from_string(from_token_string)
|
||||
|
||||
|
@ -189,7 +200,7 @@ class KeyChangesServlet(RestServlet):
|
|||
|
||||
results = yield self.device_handler.get_user_ids_changed(user_id, from_token)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
class OneTimeKeyServlet(RestServlet):
|
||||
|
@ -224,7 +235,7 @@ class OneTimeKeyServlet(RestServlet):
|
|||
timeout = parse_integer(request, "timeout", 10 * 1000)
|
||||
body = parse_json_object_from_request(request)
|
||||
result = yield self.e2e_keys_handler.claim_one_time_keys(body, timeout)
|
||||
return (200, result)
|
||||
return 200, result
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -88,7 +88,7 @@ class NotificationsServlet(RestServlet):
|
|||
returned_push_actions.append(returned_pa)
|
||||
next_token = str(pa["stream_ordering"])
|
||||
|
||||
return (200, {"notifications": returned_push_actions, "next_token": next_token})
|
||||
return 200, {"notifications": returned_push_actions, "next_token": next_token}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -59,7 +59,7 @@ class ReadMarkerRestServlet(RestServlet):
|
|||
event_id=read_marker_event_id,
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -52,7 +52,7 @@ class ReceiptRestServlet(RestServlet):
|
|||
room_id, receipt_type, user_id=requester.user.to_string(), event_id=event_id
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
import hmac
|
||||
import logging
|
||||
from hashlib import sha1
|
||||
|
||||
from six import string_types
|
||||
|
||||
|
@ -29,16 +28,20 @@ from synapse.api.errors import (
|
|||
Codes,
|
||||
LimitExceededError,
|
||||
SynapseError,
|
||||
ThreepidValidationError,
|
||||
UnrecognizedRequestError,
|
||||
)
|
||||
from synapse.config.emailconfig import ThreepidBehaviour
|
||||
from synapse.config.ratelimiting import FederationRateLimitConfig
|
||||
from synapse.config.server import is_threepid_reserved
|
||||
from synapse.http.server import finish_request
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
assert_params_in_dict,
|
||||
parse_json_object_from_request,
|
||||
parse_string,
|
||||
)
|
||||
from synapse.push.mailer import load_jinja2_templates
|
||||
from synapse.util.msisdn import phone_number_to_msisdn
|
||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||
from synapse.util.threepids import check_3pid_allowed
|
||||
|
@ -71,31 +74,93 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
|
|||
super(EmailRegisterRequestTokenRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.config = hs.config
|
||||
|
||||
if self.hs.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
from synapse.push.mailer import Mailer, load_jinja2_templates
|
||||
|
||||
template_html, template_text = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[
|
||||
self.config.email_registration_template_html,
|
||||
self.config.email_registration_template_text,
|
||||
],
|
||||
apply_format_ts_filter=True,
|
||||
apply_mxc_to_http_filter=True,
|
||||
public_baseurl=self.config.public_baseurl,
|
||||
)
|
||||
self.mailer = Mailer(
|
||||
hs=self.hs,
|
||||
app_name=self.config.email_app_name,
|
||||
template_html=template_html,
|
||||
template_text=template_text,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
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.warn(
|
||||
"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, ["id_server", "client_secret", "email", "send_attempt"]
|
||||
)
|
||||
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
||||
|
||||
if not check_3pid_allowed(self.hs, "email", body["email"]):
|
||||
# Extract params from body
|
||||
client_secret = body["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,
|
||||
)
|
||||
|
||||
existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
existing_user_id = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
"email", body["email"]
|
||||
)
|
||||
|
||||
if existingUid is not None:
|
||||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
ret = yield self.identity_handler.requestEmailToken(**body)
|
||||
return (200, ret)
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
if not self.hs.config.account_threepid_delegate_email:
|
||||
logger.warn(
|
||||
"No upstream email account_threepid_delegate configured on the server to "
|
||||
"handle this request"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Registration by email is not supported on this homeserver"
|
||||
)
|
||||
|
||||
ret = yield 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 = yield 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
|
||||
|
||||
|
||||
class MsisdnRegisterRequestTokenRestServlet(RestServlet):
|
||||
|
@ -115,11 +180,15 @@ class MsisdnRegisterRequestTokenRestServlet(RestServlet):
|
|||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(
|
||||
body,
|
||||
["id_server", "client_secret", "country", "phone_number", "send_attempt"],
|
||||
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
||||
)
|
||||
client_secret = body["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(body["country"], body["phone_number"])
|
||||
msisdn = phone_number_to_msisdn(country, phone_number)
|
||||
|
||||
if not check_3pid_allowed(self.hs, "msisdn", msisdn):
|
||||
raise SynapseError(
|
||||
|
@ -128,17 +197,112 @@ class MsisdnRegisterRequestTokenRestServlet(RestServlet):
|
|||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existingUid = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
existing_user_id = yield self.hs.get_datastore().get_user_id_by_threepid(
|
||||
"msisdn", msisdn
|
||||
)
|
||||
|
||||
if existingUid is not None:
|
||||
if existing_user_id is not None:
|
||||
raise SynapseError(
|
||||
400, "Phone number is already in use", Codes.THREEPID_IN_USE
|
||||
)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(**body)
|
||||
return (200, ret)
|
||||
if not self.hs.config.account_threepid_delegate_msisdn:
|
||||
logger.warn(
|
||||
"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 = yield self.identity_handler.requestMsisdnToken(
|
||||
self.hs.config.account_threepid_delegate_msisdn,
|
||||
country,
|
||||
phone_number,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
class RegistrationSubmitTokenServlet(RestServlet):
|
||||
"""Handles registration 3PID validation token submission"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/registration/(?P<medium>[^/]*)/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super(RegistrationSubmitTokenServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.auth = hs.get_auth()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
if medium != "email":
|
||||
raise SynapseError(
|
||||
400, "This medium is currently not supported for registration"
|
||||
)
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"User registration via email has been disabled due to lack of email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Email-based registration is disabled on this server"
|
||||
)
|
||||
|
||||
sid = parse_string(request, "sid", required=True)
|
||||
client_secret = parse_string(request, "client_secret", required=True)
|
||||
token = parse_string(request, "token", required=True)
|
||||
|
||||
# Attempt to validate a 3PID session
|
||||
try:
|
||||
# Mark the session as valid
|
||||
next_link = yield self.store.validate_threepid_session(
|
||||
sid, client_secret, token, self.clock.time_msec()
|
||||
)
|
||||
|
||||
# Perform a 302 redirect if next_link is set
|
||||
if next_link:
|
||||
if next_link.startswith("file:///"):
|
||||
logger.warn(
|
||||
"Not redirecting to next_link as it is a local file: address"
|
||||
)
|
||||
else:
|
||||
request.setResponseCode(302)
|
||||
request.setHeader("Location", next_link)
|
||||
finish_request(request)
|
||||
return None
|
||||
|
||||
# Otherwise show the success template
|
||||
html = self.config.email_registration_template_success_html_content
|
||||
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
# Show a failure page with a reason
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
html_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = html_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
|
||||
class UsernameAvailabilityRestServlet(RestServlet):
|
||||
|
@ -178,7 +342,7 @@ class UsernameAvailabilityRestServlet(RestServlet):
|
|||
|
||||
yield self.registration_handler.check_username(username)
|
||||
|
||||
return (200, {"available": True})
|
||||
return 200, {"available": True}
|
||||
|
||||
|
||||
class RegisterRestServlet(RestServlet):
|
||||
|
@ -231,7 +395,6 @@ class RegisterRestServlet(RestServlet):
|
|||
if kind == b"guest":
|
||||
ret = yield self._do_guest_registration(body, address=client_addr)
|
||||
return ret
|
||||
return
|
||||
elif kind != b"user":
|
||||
raise UnrecognizedRequestError(
|
||||
"Do not understand membership kind: %s" % (kind,)
|
||||
|
@ -239,14 +402,12 @@ class RegisterRestServlet(RestServlet):
|
|||
|
||||
# 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:
|
||||
|
@ -261,8 +422,8 @@ class RegisterRestServlet(RestServlet):
|
|||
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
|
||||
# fork off as soon as possible for ASes which have completely
|
||||
# different registration flows to normal users
|
||||
|
||||
# == Application Service Registration ==
|
||||
if appservice:
|
||||
|
@ -282,11 +443,10 @@ class RegisterRestServlet(RestServlet):
|
|||
result = yield self._do_appservice_registration(
|
||||
desired_username, access_token, body
|
||||
)
|
||||
return (200, result) # we throw for non 200 responses
|
||||
return
|
||||
return 200, result # we throw for non 200 responses
|
||||
|
||||
# for either shared secret or regular registration, downcase the
|
||||
# provided username before attempting to register it. This should mean
|
||||
# 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
|
||||
|
@ -294,16 +454,6 @@ class RegisterRestServlet(RestServlet):
|
|||
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
|
||||
)
|
||||
return (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")
|
||||
|
@ -453,11 +603,11 @@ class RegisterRestServlet(RestServlet):
|
|||
medium = auth_result[login_type]["medium"]
|
||||
address = auth_result[login_type]["address"]
|
||||
|
||||
existingUid = yield self.store.get_user_id_by_threepid(
|
||||
existing_user_id = yield self.store.get_user_id_by_threepid(
|
||||
medium, address
|
||||
)
|
||||
|
||||
if existingUid is not None:
|
||||
if existing_user_id is not None:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"%s is already in use" % medium,
|
||||
|
@ -496,11 +646,9 @@ class RegisterRestServlet(RestServlet):
|
|||
user_id=registered_user_id,
|
||||
auth_result=auth_result,
|
||||
access_token=return_dict.get("access_token"),
|
||||
bind_email=params.get("bind_email"),
|
||||
bind_msisdn=params.get("bind_msisdn"),
|
||||
)
|
||||
|
||||
return (200, return_dict)
|
||||
return 200, return_dict
|
||||
|
||||
def on_OPTIONS(self, _):
|
||||
return 200, {}
|
||||
|
@ -512,42 +660,6 @@ class RegisterRestServlet(RestServlet):
|
|||
)
|
||||
return (yield self._create_registration_details(user_id, body))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _do_shared_secret_registration(self, username, password, body):
|
||||
if not self.hs.config.registration_shared_secret:
|
||||
raise SynapseError(400, "Shared secret registration is not enabled")
|
||||
if not username:
|
||||
raise SynapseError(
|
||||
400, "username must be specified", errcode=Codes.BAD_JSON
|
||||
)
|
||||
|
||||
# use the username from the original request rather than the
|
||||
# downcased one in `username` for the mac calculation
|
||||
user = body["username"].encode("utf-8")
|
||||
|
||||
# str() because otherwise hmac complains that 'unicode' does not
|
||||
# have the buffer interface
|
||||
got_mac = str(body["mac"])
|
||||
|
||||
# FIXME this is different to the /v1/register endpoint, which
|
||||
# includes the password and admin flag in the hashed text. Why are
|
||||
# these different?
|
||||
want_mac = hmac.new(
|
||||
key=self.hs.config.registration_shared_secret.encode(),
|
||||
msg=user,
|
||||
digestmod=sha1,
|
||||
).hexdigest()
|
||||
|
||||
if not compare_digest(want_mac, got_mac):
|
||||
raise SynapseError(403, "HMAC incorrect")
|
||||
|
||||
user_id = yield self.registration_handler.register_user(
|
||||
localpart=username, password=password
|
||||
)
|
||||
|
||||
result = yield self._create_registration_details(user_id, body)
|
||||
return result
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _create_registration_details(self, user_id, params):
|
||||
"""Complete registration of newly-registered user
|
||||
|
@ -603,4 +715,5 @@ def register_servlets(hs, http_server):
|
|||
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
UsernameAvailabilityRestServlet(hs).register(http_server)
|
||||
RegistrationSubmitTokenServlet(hs).register(http_server)
|
||||
RegisterRestServlet(hs).register(http_server)
|
||||
|
|
|
@ -118,7 +118,7 @@ class RelationSendServlet(RestServlet):
|
|||
requester, event_dict=event_dict, txn_id=txn_id
|
||||
)
|
||||
|
||||
return (200, {"event_id": event.event_id})
|
||||
return 200, {"event_id": event.event_id}
|
||||
|
||||
|
||||
class RelationPaginationServlet(RestServlet):
|
||||
|
@ -198,7 +198,7 @@ class RelationPaginationServlet(RestServlet):
|
|||
return_value["chunk"] = events
|
||||
return_value["original_event"] = original_event
|
||||
|
||||
return (200, return_value)
|
||||
return 200, return_value
|
||||
|
||||
|
||||
class RelationAggregationPaginationServlet(RestServlet):
|
||||
|
@ -270,7 +270,7 @@ class RelationAggregationPaginationServlet(RestServlet):
|
|||
to_token=to_token,
|
||||
)
|
||||
|
||||
return (200, pagination_chunk.to_dict())
|
||||
return 200, pagination_chunk.to_dict()
|
||||
|
||||
|
||||
class RelationAggregationGroupPaginationServlet(RestServlet):
|
||||
|
@ -356,7 +356,7 @@ class RelationAggregationGroupPaginationServlet(RestServlet):
|
|||
return_value = result.to_dict()
|
||||
return_value["chunk"] = events
|
||||
|
||||
return (200, return_value)
|
||||
return 200, return_value
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -72,7 +72,7 @@ class ReportEventRestServlet(RestServlet):
|
|||
received_ts=self.clock.time_msec(),
|
||||
)
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -135,7 +135,7 @@ class RoomKeysServlet(RestServlet):
|
|||
body = {"rooms": {room_id: body}}
|
||||
|
||||
yield self.e2e_room_keys_handler.upload_room_keys(user_id, version, body)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, room_id, session_id):
|
||||
|
@ -218,7 +218,7 @@ class RoomKeysServlet(RestServlet):
|
|||
else:
|
||||
room_keys = room_keys["rooms"][room_id]
|
||||
|
||||
return (200, room_keys)
|
||||
return 200, room_keys
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, room_id, session_id):
|
||||
|
@ -242,7 +242,7 @@ class RoomKeysServlet(RestServlet):
|
|||
yield self.e2e_room_keys_handler.delete_room_keys(
|
||||
user_id, version, room_id, session_id
|
||||
)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
class RoomKeysNewVersionServlet(RestServlet):
|
||||
|
@ -293,7 +293,7 @@ class RoomKeysNewVersionServlet(RestServlet):
|
|||
info = parse_json_object_from_request(request)
|
||||
|
||||
new_version = yield self.e2e_room_keys_handler.create_version(user_id, info)
|
||||
return (200, {"version": new_version})
|
||||
return 200, {"version": new_version}
|
||||
|
||||
# we deliberately don't have a PUT /version, as these things really should
|
||||
# be immutable to avoid people footgunning
|
||||
|
@ -338,7 +338,7 @@ class RoomKeysVersionServlet(RestServlet):
|
|||
except SynapseError as e:
|
||||
if e.code == 404:
|
||||
raise SynapseError(404, "No backup found", Codes.NOT_FOUND)
|
||||
return (200, info)
|
||||
return 200, info
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, version):
|
||||
|
@ -358,7 +358,7 @@ class RoomKeysVersionServlet(RestServlet):
|
|||
user_id = requester.user.to_string()
|
||||
|
||||
yield self.e2e_room_keys_handler.delete_version(user_id, version)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_PUT(self, request, version):
|
||||
|
@ -392,7 +392,7 @@ class RoomKeysVersionServlet(RestServlet):
|
|||
)
|
||||
|
||||
yield self.e2e_room_keys_handler.update_version(user_id, version, info)
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -80,7 +80,7 @@ class RoomUpgradeRestServlet(RestServlet):
|
|||
|
||||
ret = {"replacement_room": new_room_id}
|
||||
|
||||
return (200, ret)
|
||||
return 200, ret
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -19,6 +19,7 @@ from twisted.internet import defer
|
|||
|
||||
from synapse.http import servlet
|
||||
from synapse.http.servlet import parse_json_object_from_request
|
||||
from synapse.logging.opentracing import set_tag, trace
|
||||
from synapse.rest.client.transactions import HttpTransactionCache
|
||||
|
||||
from ._base import client_patterns
|
||||
|
@ -42,7 +43,10 @@ class SendToDeviceRestServlet(servlet.RestServlet):
|
|||
self.txns = HttpTransactionCache(hs)
|
||||
self.device_message_handler = hs.get_device_message_handler()
|
||||
|
||||
@trace(opname="sendToDevice")
|
||||
def on_PUT(self, request, message_type, txn_id):
|
||||
set_tag("message_type", message_type)
|
||||
set_tag("txn_id", txn_id)
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self._put, request, message_type, txn_id
|
||||
)
|
||||
|
|
|
@ -174,7 +174,7 @@ class SyncRestServlet(RestServlet):
|
|||
time_now, sync_result, requester.access_token_id, filter
|
||||
)
|
||||
|
||||
return (200, response_content)
|
||||
return 200, response_content
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def encode_response(self, time_now, sync_result, access_token_id, filter):
|
||||
|
|
|
@ -45,7 +45,7 @@ class TagListServlet(RestServlet):
|
|||
|
||||
tags = yield self.store.get_tags_for_room(user_id, room_id)
|
||||
|
||||
return (200, {"tags": tags})
|
||||
return 200, {"tags": tags}
|
||||
|
||||
|
||||
class TagServlet(RestServlet):
|
||||
|
@ -76,7 +76,7 @@ class TagServlet(RestServlet):
|
|||
|
||||
self.notifier.on_new_event("account_data_key", max_id, users=[user_id])
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_DELETE(self, request, user_id, room_id, tag):
|
||||
|
@ -88,7 +88,7 @@ class TagServlet(RestServlet):
|
|||
|
||||
self.notifier.on_new_event("account_data_key", max_id, users=[user_id])
|
||||
|
||||
return (200, {})
|
||||
return 200, {}
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -40,7 +40,7 @@ class ThirdPartyProtocolsServlet(RestServlet):
|
|||
yield self.auth.get_user_by_req(request, allow_guest=True)
|
||||
|
||||
protocols = yield self.appservice_handler.get_3pe_protocols()
|
||||
return (200, protocols)
|
||||
return 200, protocols
|
||||
|
||||
|
||||
class ThirdPartyProtocolServlet(RestServlet):
|
||||
|
@ -60,9 +60,9 @@ class ThirdPartyProtocolServlet(RestServlet):
|
|||
only_protocol=protocol
|
||||
)
|
||||
if protocol in protocols:
|
||||
return (200, protocols[protocol])
|
||||
return 200, protocols[protocol]
|
||||
else:
|
||||
return (404, {"error": "Unknown protocol"})
|
||||
return 404, {"error": "Unknown protocol"}
|
||||
|
||||
|
||||
class ThirdPartyUserServlet(RestServlet):
|
||||
|
@ -85,7 +85,7 @@ class ThirdPartyUserServlet(RestServlet):
|
|||
ThirdPartyEntityKind.USER, protocol, fields
|
||||
)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
class ThirdPartyLocationServlet(RestServlet):
|
||||
|
@ -108,7 +108,7 @@ class ThirdPartyLocationServlet(RestServlet):
|
|||
ThirdPartyEntityKind.LOCATION, protocol, fields
|
||||
)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -60,7 +60,7 @@ class UserDirectorySearchRestServlet(RestServlet):
|
|||
user_id = requester.user.to_string()
|
||||
|
||||
if not self.hs.config.user_directory_search_enabled:
|
||||
return (200, {"limited": False, "results": []})
|
||||
return 200, {"limited": False, "results": []}
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
|
@ -76,7 +76,7 @@ class UserDirectorySearchRestServlet(RestServlet):
|
|||
user_id, search_term, limit
|
||||
)
|
||||
|
||||
return (200, results)
|
||||
return 200, results
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
|
|
|
@ -24,6 +24,10 @@ logger = logging.getLogger(__name__)
|
|||
class VersionsRestServlet(RestServlet):
|
||||
PATTERNS = [re.compile("^/_matrix/client/versions$")]
|
||||
|
||||
def __init__(self, hs):
|
||||
super(VersionsRestServlet, self).__init__()
|
||||
self.config = hs.config
|
||||
|
||||
def on_GET(self, request):
|
||||
return (
|
||||
200,
|
||||
|
@ -49,5 +53,5 @@ class VersionsRestServlet(RestServlet):
|
|||
)
|
||||
|
||||
|
||||
def register_servlets(http_server):
|
||||
VersionsRestServlet().register(http_server)
|
||||
def register_servlets(hs, http_server):
|
||||
VersionsRestServlet(hs).register(http_server)
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
from io import BytesIO
|
||||
|
||||
from canonicaljson import encode_canonical_json, json
|
||||
from signedjson.sign import sign_json
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
|
@ -95,6 +97,7 @@ class RemoteKey(DirectServeResource):
|
|||
self.store = hs.get_datastore()
|
||||
self.clock = hs.get_clock()
|
||||
self.federation_domain_whitelist = hs.config.federation_domain_whitelist
|
||||
self.config = hs.config
|
||||
|
||||
@wrap_json_request_handler
|
||||
async def _async_render_GET(self, request):
|
||||
|
@ -214,15 +217,14 @@ class RemoteKey(DirectServeResource):
|
|||
yield self.fetcher.get_keys(cache_misses)
|
||||
yield self.query_keys(request, query, query_remote_on_cache_miss=False)
|
||||
else:
|
||||
result_io = BytesIO()
|
||||
result_io.write(b'{"server_keys":')
|
||||
sep = b"["
|
||||
for json_bytes in json_results:
|
||||
result_io.write(sep)
|
||||
result_io.write(json_bytes)
|
||||
sep = b","
|
||||
if sep == b"[":
|
||||
result_io.write(sep)
|
||||
result_io.write(b"]}")
|
||||
signed_keys = []
|
||||
for key_json in json_results:
|
||||
key_json = json.loads(key_json)
|
||||
for signing_key in self.config.key_server_signing_keys:
|
||||
key_json = sign_json(key_json, self.config.server_name, signing_key)
|
||||
|
||||
respond_with_json_bytes(request, 200, result_io.getvalue())
|
||||
signed_keys.append(key_json)
|
||||
|
||||
results = {"server_keys": signed_keys}
|
||||
|
||||
respond_with_json_bytes(request, 200, encode_canonical_json(results))
|
||||
|
|
|
@ -318,14 +318,14 @@ class MediaRepository(object):
|
|||
|
||||
responder = yield self.media_storage.fetch_media(file_info)
|
||||
if responder:
|
||||
return (responder, media_info)
|
||||
return responder, media_info
|
||||
|
||||
# Failed to find the file anywhere, lets download it.
|
||||
|
||||
media_info = yield self._download_remote_file(server_name, media_id, file_id)
|
||||
|
||||
responder = yield self.media_storage.fetch_media(file_info)
|
||||
return (responder, media_info)
|
||||
return responder, media_info
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _download_remote_file(self, server_name, media_id, file_id):
|
||||
|
@ -526,7 +526,7 @@ class MediaRepository(object):
|
|||
try:
|
||||
file_info = FileInfo(
|
||||
server_name=server_name,
|
||||
file_id=media_id,
|
||||
file_id=file_id,
|
||||
thumbnail=True,
|
||||
thumbnail_width=t_width,
|
||||
thumbnail_height=t_height,
|
||||
|
|
|
@ -183,7 +183,6 @@ class PreviewUrlResource(DirectServeResource):
|
|||
if isinstance(og, six.text_type):
|
||||
og = og.encode("utf8")
|
||||
return og
|
||||
return
|
||||
|
||||
media_info = yield self._download_url(url, user)
|
||||
|
||||
|
|
|
@ -78,9 +78,9 @@ class Thumbnailer(object):
|
|||
"""
|
||||
|
||||
if max_width * self.height < max_height * self.width:
|
||||
return (max_width, (max_width * self.height) // self.width)
|
||||
return max_width, (max_width * self.height) // self.width
|
||||
else:
|
||||
return ((max_height * self.width) // self.height, max_height)
|
||||
return (max_height * self.width) // self.height, max_height
|
||||
|
||||
def scale(self, width, height, output_type):
|
||||
"""Rescales the image to the given dimensions.
|
||||
|
|
|
@ -34,7 +34,7 @@ class WellKnownBuilder(object):
|
|||
self._config = hs.config
|
||||
|
||||
def get_well_known(self):
|
||||
# if we don't have a public_base_url, we can't help much here.
|
||||
# if we don't have a public_baseurl, we can't help much here.
|
||||
if self._config.public_baseurl is None:
|
||||
return None
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue