mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2025-12-15 16:21:00 -05:00
Merge branch 'develop' into cross-signing_sig_upload
This commit is contained in:
commit
36adfaedab
354 changed files with 9545 additions and 5267 deletions
|
|
@ -23,8 +23,6 @@ import re
|
|||
from six import text_type
|
||||
from six.moves import http_client
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
import synapse
|
||||
from synapse.api.constants import Membership, UserTypes
|
||||
from synapse.api.errors import Codes, NotFoundError, SynapseError
|
||||
|
|
@ -46,6 +44,7 @@ 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.async_helpers import maybe_awaitable
|
||||
from synapse.util.versionstring import get_version_string
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -59,15 +58,14 @@ class UsersRestServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.handlers = hs.get_handlers()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, user_id):
|
||||
async def on_GET(self, request, user_id):
|
||||
target_user = UserID.from_string(user_id)
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
if not self.hs.is_mine(target_user):
|
||||
raise SynapseError(400, "Can only users a local user")
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_users()
|
||||
ret = await self.handlers.admin_handler.get_users()
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
|
@ -122,8 +120,7 @@ class UserRegisterServlet(RestServlet):
|
|||
self.nonces[nonce] = int(self.reactor.seconds())
|
||||
return 200, {"nonce": nonce}
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
async def on_POST(self, request):
|
||||
self._clear_old_nonces()
|
||||
|
||||
if not self.hs.config.registration_shared_secret:
|
||||
|
|
@ -204,14 +201,14 @@ class UserRegisterServlet(RestServlet):
|
|||
|
||||
register = RegisterRestServlet(self.hs)
|
||||
|
||||
user_id = yield register.registration_handler.register_user(
|
||||
user_id = await register.registration_handler.register_user(
|
||||
localpart=body["username"].lower(),
|
||||
password=body["password"],
|
||||
admin=bool(admin),
|
||||
user_type=user_type,
|
||||
)
|
||||
|
||||
result = yield register._create_registration_details(user_id, body)
|
||||
result = await register._create_registration_details(user_id, body)
|
||||
return 200, result
|
||||
|
||||
|
||||
|
|
@ -223,19 +220,18 @@ class WhoisRestServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.handlers = hs.get_handlers()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, user_id):
|
||||
async def on_GET(self, request, user_id):
|
||||
target_user = UserID.from_string(user_id)
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
auth_user = requester.user
|
||||
|
||||
if target_user != auth_user:
|
||||
yield assert_user_is_admin(self.auth, auth_user)
|
||||
await assert_user_is_admin(self.auth, auth_user)
|
||||
|
||||
if not self.hs.is_mine(target_user):
|
||||
raise SynapseError(400, "Can only whois a local user")
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_whois(target_user)
|
||||
ret = await self.handlers.admin_handler.get_whois(target_user)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
|
@ -255,9 +251,8 @@ class PurgeHistoryRestServlet(RestServlet):
|
|||
self.store = hs.get_datastore()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_id, event_id):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_POST(self, request, room_id, event_id):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
body = parse_json_object_from_request(request, allow_empty_body=True)
|
||||
|
||||
|
|
@ -270,12 +265,12 @@ class PurgeHistoryRestServlet(RestServlet):
|
|||
event_id = body.get("purge_up_to_event_id")
|
||||
|
||||
if event_id is not None:
|
||||
event = yield self.store.get_event(event_id)
|
||||
event = await self.store.get_event(event_id)
|
||||
|
||||
if event.room_id != room_id:
|
||||
raise SynapseError(400, "Event is for wrong room.")
|
||||
|
||||
token = yield self.store.get_topological_token_for_event(event_id)
|
||||
token = await self.store.get_topological_token_for_event(event_id)
|
||||
|
||||
logger.info("[purge] purging up to token %s (event_id %s)", token, event_id)
|
||||
elif "purge_up_to_ts" in body:
|
||||
|
|
@ -285,12 +280,10 @@ class PurgeHistoryRestServlet(RestServlet):
|
|||
400, "purge_up_to_ts must be an int", errcode=Codes.BAD_JSON
|
||||
)
|
||||
|
||||
stream_ordering = (yield self.store.find_first_stream_ordering_after_ts(ts))
|
||||
stream_ordering = await self.store.find_first_stream_ordering_after_ts(ts)
|
||||
|
||||
r = (
|
||||
yield self.store.get_room_event_after_stream_ordering(
|
||||
room_id, stream_ordering
|
||||
)
|
||||
r = await self.store.get_room_event_after_stream_ordering(
|
||||
room_id, stream_ordering
|
||||
)
|
||||
if not r:
|
||||
logger.warn(
|
||||
|
|
@ -318,7 +311,7 @@ class PurgeHistoryRestServlet(RestServlet):
|
|||
errcode=Codes.BAD_JSON,
|
||||
)
|
||||
|
||||
purge_id = yield self.pagination_handler.start_purge_history(
|
||||
purge_id = self.pagination_handler.start_purge_history(
|
||||
room_id, token, delete_local_events=delete_local_events
|
||||
)
|
||||
|
||||
|
|
@ -339,9 +332,8 @@ class PurgeHistoryStatusRestServlet(RestServlet):
|
|||
self.pagination_handler = hs.get_pagination_handler()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, purge_id):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_GET(self, request, purge_id):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
purge_status = self.pagination_handler.get_purge_status(purge_id)
|
||||
if purge_status is None:
|
||||
|
|
@ -357,9 +349,8 @@ class DeactivateAccountRestServlet(RestServlet):
|
|||
self._deactivate_account_handler = hs.get_deactivate_account_handler()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, target_user_id):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_POST(self, request, target_user_id):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
body = parse_json_object_from_request(request, allow_empty_body=True)
|
||||
erase = body.get("erase", False)
|
||||
if not isinstance(erase, bool):
|
||||
|
|
@ -371,7 +362,7 @@ class DeactivateAccountRestServlet(RestServlet):
|
|||
|
||||
UserID.from_string(target_user_id)
|
||||
|
||||
result = yield self._deactivate_account_handler.deactivate_account(
|
||||
result = await self._deactivate_account_handler.deactivate_account(
|
||||
target_user_id, erase
|
||||
)
|
||||
if result:
|
||||
|
|
@ -405,10 +396,9 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
self.room_member_handler = hs.get_room_member_handler()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_id):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(self.auth, requester.user)
|
||||
async def on_POST(self, request, room_id):
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(self.auth, requester.user)
|
||||
|
||||
content = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(content, ["new_room_user_id"])
|
||||
|
|
@ -419,7 +409,7 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
message = content.get("message", self.DEFAULT_MESSAGE)
|
||||
room_name = content.get("room_name", "Content Violation Notification")
|
||||
|
||||
info = yield self._room_creation_handler.create_room(
|
||||
info = await self._room_creation_handler.create_room(
|
||||
room_creator_requester,
|
||||
config={
|
||||
"preset": "public_chat",
|
||||
|
|
@ -438,9 +428,9 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
|
||||
# This will work even if the room is already blocked, but that is
|
||||
# desirable in case the first attempt at blocking the room failed below.
|
||||
yield self.store.block_room(room_id, requester_user_id)
|
||||
await self.store.block_room(room_id, requester_user_id)
|
||||
|
||||
users = yield self.state.get_current_users_in_room(room_id)
|
||||
users = await self.state.get_current_users_in_room(room_id)
|
||||
kicked_users = []
|
||||
failed_to_kick_users = []
|
||||
for user_id in users:
|
||||
|
|
@ -451,7 +441,7 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
|
||||
try:
|
||||
target_requester = create_requester(user_id)
|
||||
yield self.room_member_handler.update_membership(
|
||||
await self.room_member_handler.update_membership(
|
||||
requester=target_requester,
|
||||
target=target_requester.user,
|
||||
room_id=room_id,
|
||||
|
|
@ -461,9 +451,9 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
require_consent=False,
|
||||
)
|
||||
|
||||
yield self.room_member_handler.forget(target_requester.user, room_id)
|
||||
await self.room_member_handler.forget(target_requester.user, room_id)
|
||||
|
||||
yield self.room_member_handler.update_membership(
|
||||
await self.room_member_handler.update_membership(
|
||||
requester=target_requester,
|
||||
target=target_requester.user,
|
||||
room_id=new_room_id,
|
||||
|
|
@ -480,7 +470,7 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
)
|
||||
failed_to_kick_users.append(user_id)
|
||||
|
||||
yield self.event_creation_handler.create_and_send_nonmember_event(
|
||||
await self.event_creation_handler.create_and_send_nonmember_event(
|
||||
room_creator_requester,
|
||||
{
|
||||
"type": "m.room.message",
|
||||
|
|
@ -491,9 +481,11 @@ class ShutdownRoomRestServlet(RestServlet):
|
|||
ratelimit=False,
|
||||
)
|
||||
|
||||
aliases_for_room = yield self.store.get_aliases_for_room(room_id)
|
||||
aliases_for_room = await maybe_awaitable(
|
||||
self.store.get_aliases_for_room(room_id)
|
||||
)
|
||||
|
||||
yield self.store.update_aliases_for_room(
|
||||
await self.store.update_aliases_for_room(
|
||||
room_id, new_room_id, requester_user_id
|
||||
)
|
||||
|
||||
|
|
@ -532,13 +524,12 @@ class ResetPasswordRestServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self._set_password_handler = hs.get_set_password_handler()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, target_user_id):
|
||||
async def on_POST(self, request, target_user_id):
|
||||
"""Post request to allow an administrator reset password for a user.
|
||||
This needs user to have administrator access in Synapse.
|
||||
"""
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(self.auth, requester.user)
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(self.auth, requester.user)
|
||||
|
||||
UserID.from_string(target_user_id)
|
||||
|
||||
|
|
@ -546,7 +537,7 @@ class ResetPasswordRestServlet(RestServlet):
|
|||
assert_params_in_dict(params, ["new_password"])
|
||||
new_password = params["new_password"]
|
||||
|
||||
yield self._set_password_handler.set_password(
|
||||
await self._set_password_handler.set_password(
|
||||
target_user_id, new_password, requester
|
||||
)
|
||||
return 200, {}
|
||||
|
|
@ -572,12 +563,11 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.handlers = hs.get_handlers()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, target_user_id):
|
||||
async def on_GET(self, request, target_user_id):
|
||||
"""Get request to get specific number of users from Synapse.
|
||||
This needs user to have administrator access in Synapse.
|
||||
"""
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
target_user = UserID.from_string(target_user_id)
|
||||
|
||||
|
|
@ -590,11 +580,10 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
|
||||
logger.info("limit: %s, start: %s", limit, start)
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
ret = await self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
return 200, ret
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, target_user_id):
|
||||
async def on_POST(self, request, target_user_id):
|
||||
"""Post request to get specific number of users from Synapse..
|
||||
This needs user to have administrator access in Synapse.
|
||||
Example:
|
||||
|
|
@ -608,7 +597,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
Returns:
|
||||
200 OK with json object {list[dict[str, Any]], count} or empty object.
|
||||
"""
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
UserID.from_string(target_user_id)
|
||||
|
||||
order = "name" # order by name in user table
|
||||
|
|
@ -618,7 +607,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
|
|||
start = params["start"]
|
||||
logger.info("limit: %s, start: %s", limit, start)
|
||||
|
||||
ret = yield self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
ret = await self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
||||
return 200, ret
|
||||
|
||||
|
||||
|
|
@ -641,13 +630,12 @@ class SearchUsersRestServlet(RestServlet):
|
|||
self.auth = hs.get_auth()
|
||||
self.handlers = hs.get_handlers()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, target_user_id):
|
||||
async def on_GET(self, request, target_user_id):
|
||||
"""Get request to search user table for specific users according to
|
||||
search term.
|
||||
This needs user to have a administrator access in Synapse.
|
||||
"""
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
target_user = UserID.from_string(target_user_id)
|
||||
|
||||
|
|
@ -661,7 +649,7 @@ class SearchUsersRestServlet(RestServlet):
|
|||
term = parse_string(request, "term", required=True)
|
||||
logger.info("term: %s ", term)
|
||||
|
||||
ret = yield self.handlers.admin_handler.search_users(term)
|
||||
ret = await self.handlers.admin_handler.search_users(term)
|
||||
return 200, ret
|
||||
|
||||
|
||||
|
|
@ -676,15 +664,14 @@ class DeleteGroupAdminRestServlet(RestServlet):
|
|||
self.is_mine_id = hs.is_mine_id
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, group_id):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(self.auth, requester.user)
|
||||
async def on_POST(self, request, group_id):
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(self.auth, requester.user)
|
||||
|
||||
if not self.is_mine_id(group_id):
|
||||
raise SynapseError(400, "Can only delete local groups")
|
||||
|
||||
yield self.group_server.delete_group(group_id, requester.user.to_string())
|
||||
await self.group_server.delete_group(group_id, requester.user.to_string())
|
||||
return 200, {}
|
||||
|
||||
|
||||
|
|
@ -700,16 +687,15 @@ class AccountValidityRenewServlet(RestServlet):
|
|||
self.account_activity_handler = hs.get_account_validity_handler()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_POST(self, request):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
if "user_id" not in body:
|
||||
raise SynapseError(400, "Missing property 'user_id' in the request body")
|
||||
|
||||
expiration_ts = yield self.account_activity_handler.renew_account_for_user(
|
||||
expiration_ts = await self.account_activity_handler.renew_account_for_user(
|
||||
body["user_id"],
|
||||
body.get("expiration_ts"),
|
||||
not body.get("enable_renewal_emails", True),
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
|
||||
import re
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.errors import AuthError
|
||||
|
||||
|
||||
|
|
@ -42,8 +40,7 @@ def historical_admin_path_patterns(path_regex):
|
|||
)
|
||||
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def assert_requester_is_admin(auth, request):
|
||||
async def assert_requester_is_admin(auth, request):
|
||||
"""Verify that the requester is an admin user
|
||||
|
||||
WARNING: MAKE SURE YOU YIELD ON THE RESULT!
|
||||
|
|
@ -58,12 +55,11 @@ def assert_requester_is_admin(auth, request):
|
|||
Raises:
|
||||
AuthError if the requester is not an admin
|
||||
"""
|
||||
requester = yield auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(auth, requester.user)
|
||||
requester = await auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(auth, requester.user)
|
||||
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def assert_user_is_admin(auth, user_id):
|
||||
async def assert_user_is_admin(auth, user_id):
|
||||
"""Verify that the given user is an admin user
|
||||
|
||||
WARNING: MAKE SURE YOU YIELD ON THE RESULT!
|
||||
|
|
@ -79,6 +75,6 @@ def assert_user_is_admin(auth, user_id):
|
|||
AuthError if the user is not an admin
|
||||
"""
|
||||
|
||||
is_admin = yield auth.is_server_admin(user_id)
|
||||
is_admin = await auth.is_server_admin(user_id)
|
||||
if not is_admin:
|
||||
raise AuthError(403, "You are not a server admin")
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
import logging
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.errors import AuthError
|
||||
from synapse.http.servlet import RestServlet, parse_integer
|
||||
from synapse.rest.admin._base import (
|
||||
|
|
@ -40,12 +38,11 @@ class QuarantineMediaInRoom(RestServlet):
|
|||
self.store = hs.get_datastore()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, room_id):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
yield assert_user_is_admin(self.auth, requester.user)
|
||||
async def on_POST(self, request, room_id):
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(self.auth, requester.user)
|
||||
|
||||
num_quarantined = yield self.store.quarantine_media_ids_in_room(
|
||||
num_quarantined = await self.store.quarantine_media_ids_in_room(
|
||||
room_id, requester.user.to_string()
|
||||
)
|
||||
|
||||
|
|
@ -62,14 +59,13 @@ class ListMediaInRoom(RestServlet):
|
|||
self.store = hs.get_datastore()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, room_id):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
is_admin = yield self.auth.is_server_admin(requester.user)
|
||||
async def on_GET(self, request, room_id):
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
is_admin = await self.auth.is_server_admin(requester.user)
|
||||
if not is_admin:
|
||||
raise AuthError(403, "You are not a server admin")
|
||||
|
||||
local_mxcs, remote_mxcs = yield self.store.get_media_mxcs_in_room(room_id)
|
||||
local_mxcs, remote_mxcs = await self.store.get_media_mxcs_in_room(room_id)
|
||||
|
||||
return 200, {"local": local_mxcs, "remote": remote_mxcs}
|
||||
|
||||
|
|
@ -81,14 +77,13 @@ class PurgeMediaCacheRestServlet(RestServlet):
|
|||
self.media_repository = hs.get_media_repository()
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_POST(self, request):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
|
||||
before_ts = parse_integer(request, "before_ts", required=True)
|
||||
logger.info("before_ts: %r", before_ts)
|
||||
|
||||
ret = yield self.media_repository.delete_old_remote_media(before_ts)
|
||||
ret = await self.media_repository.delete_old_remote_media(before_ts)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
# limitations under the License.
|
||||
import re
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.constants import EventTypes
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.http.servlet import (
|
||||
|
|
@ -69,9 +67,8 @@ class SendServerNoticeServlet(RestServlet):
|
|||
self.__class__.__name__,
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, txn_id=None):
|
||||
yield assert_requester_is_admin(self.auth, request)
|
||||
async def on_POST(self, request, txn_id=None):
|
||||
await assert_requester_is_admin(self.auth, request)
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ("user_id", "content"))
|
||||
event_type = body.get("type", EventTypes.Message)
|
||||
|
|
@ -85,7 +82,7 @@ class SendServerNoticeServlet(RestServlet):
|
|||
if not self.hs.is_mine_id(user_id):
|
||||
raise SynapseError(400, "Server notices can only be sent to local users")
|
||||
|
||||
event = yield self.snm.send_notice(
|
||||
event = await self.snm.send_notice(
|
||||
user_id=body["user_id"],
|
||||
type=event_type,
|
||||
state_key=state_key,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
# limitations under the License.
|
||||
import re
|
||||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
|
|
@ -59,24 +57,22 @@ class UserAdminServlet(RestServlet):
|
|||
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)
|
||||
async def on_GET(self, request, user_id):
|
||||
await 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 = await 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)
|
||||
async def on_PUT(self, request, user_id):
|
||||
requester = await self.auth.get_user_by_req(request)
|
||||
await assert_user_is_admin(self.auth, requester.user)
|
||||
auth_user = requester.user
|
||||
|
||||
target_user = UserID.from_string(user_id)
|
||||
|
|
@ -93,7 +89,7 @@ class UserAdminServlet(RestServlet):
|
|||
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(
|
||||
await self.handlers.admin_handler.set_user_server_admin(
|
||||
target_user, set_admin_to
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from synapse.http.servlet import (
|
|||
parse_json_object_from_request,
|
||||
parse_string,
|
||||
)
|
||||
from synapse.http.site import SynapseRequest
|
||||
from synapse.rest.client.v2_alpha._base import client_patterns
|
||||
from synapse.rest.well_known import WellKnownBuilder
|
||||
from synapse.types import UserID, map_username_to_mxid_localpart
|
||||
|
|
@ -376,6 +377,7 @@ class CasTicketServlet(RestServlet):
|
|||
super(CasTicketServlet, self).__init__()
|
||||
self.cas_server_url = hs.config.cas_server_url
|
||||
self.cas_service_url = hs.config.cas_service_url
|
||||
self.cas_displayname_attribute = hs.config.cas_displayname_attribute
|
||||
self.cas_required_attributes = hs.config.cas_required_attributes
|
||||
self._sso_auth_handler = SSOAuthHandler(hs)
|
||||
self._http_client = hs.get_simple_http_client()
|
||||
|
|
@ -399,6 +401,7 @@ class CasTicketServlet(RestServlet):
|
|||
|
||||
def handle_cas_response(self, request, cas_response_body, client_redirect_url):
|
||||
user, attributes = self.parse_cas_response(cas_response_body)
|
||||
displayname = attributes.pop(self.cas_displayname_attribute, None)
|
||||
|
||||
for required_attribute, required_value in self.cas_required_attributes.items():
|
||||
# If required attribute was not in CAS Response - Forbidden
|
||||
|
|
@ -413,7 +416,7 @@ class CasTicketServlet(RestServlet):
|
|||
raise LoginError(401, "Unauthorized", errcode=Codes.UNAUTHORIZED)
|
||||
|
||||
return self._sso_auth_handler.on_successful_auth(
|
||||
user, request, client_redirect_url
|
||||
user, request, client_redirect_url, displayname
|
||||
)
|
||||
|
||||
def parse_cas_response(self, cas_response_body):
|
||||
|
|
@ -507,6 +510,19 @@ class SSOAuthHandler(object):
|
|||
localpart=localpart, default_display_name=user_display_name
|
||||
)
|
||||
|
||||
self.complete_sso_login(registered_user_id, request, client_redirect_url)
|
||||
|
||||
def complete_sso_login(
|
||||
self, registered_user_id: str, request: SynapseRequest, client_redirect_url: str
|
||||
):
|
||||
"""Having figured out a mxid for this user, complete the HTTP request
|
||||
|
||||
Args:
|
||||
registered_user_id:
|
||||
request:
|
||||
client_redirect_url:
|
||||
"""
|
||||
|
||||
login_token = self._macaroon_gen.generate_short_term_login_token(
|
||||
registered_user_id
|
||||
)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ from synapse.http.servlet import (
|
|||
parse_json_object_from_request,
|
||||
parse_string,
|
||||
)
|
||||
from synapse.logging.opentracing import set_tag
|
||||
from synapse.rest.client.transactions import HttpTransactionCache
|
||||
from synapse.rest.client.v2_alpha._base import client_patterns
|
||||
from synapse.storage.state import StateFilter
|
||||
|
|
@ -81,6 +82,7 @@ class RoomCreateRestServlet(TransactionRestServlet):
|
|||
)
|
||||
|
||||
def on_PUT(self, request, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
return self.txns.fetch_or_execute_request(request, self.on_POST, request)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
|
|
@ -181,6 +183,9 @@ class RoomStateEventRestServlet(TransactionRestServlet):
|
|||
def on_PUT(self, request, room_id, event_type, state_key, txn_id=None):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
|
||||
if txn_id:
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
content = parse_json_object_from_request(request)
|
||||
|
||||
event_dict = {
|
||||
|
|
@ -209,6 +214,7 @@ class RoomStateEventRestServlet(TransactionRestServlet):
|
|||
|
||||
ret = {}
|
||||
if event:
|
||||
set_tag("event_id", event.event_id)
|
||||
ret = {"event_id": event.event_id}
|
||||
return 200, ret
|
||||
|
||||
|
|
@ -244,12 +250,15 @@ class RoomSendEventRestServlet(TransactionRestServlet):
|
|||
requester, event_dict, txn_id=txn_id
|
||||
)
|
||||
|
||||
set_tag("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"
|
||||
|
||||
def on_PUT(self, request, room_id, event_type, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self.on_POST, request, room_id, event_type, txn_id
|
||||
)
|
||||
|
|
@ -310,6 +319,8 @@ class JoinRoomAliasServlet(TransactionRestServlet):
|
|||
return 200, {"room_id": room_id}
|
||||
|
||||
def on_PUT(self, request, room_identifier, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self.on_POST, request, room_identifier, txn_id
|
||||
)
|
||||
|
|
@ -350,6 +361,10 @@ class PublicRoomListRestServlet(TransactionRestServlet):
|
|||
limit = parse_integer(request, "limit", 0)
|
||||
since_token = parse_string(request, "since", None)
|
||||
|
||||
if limit == 0:
|
||||
# zero is a special value which corresponds to no limit.
|
||||
limit = None
|
||||
|
||||
handler = self.hs.get_room_list_handler()
|
||||
if server:
|
||||
data = yield handler.get_remote_public_room_list(
|
||||
|
|
@ -387,6 +402,10 @@ class PublicRoomListRestServlet(TransactionRestServlet):
|
|||
else:
|
||||
network_tuple = ThirdPartyInstanceID.from_string(third_party_instance_id)
|
||||
|
||||
if limit == 0:
|
||||
# zero is a special value which corresponds to no limit.
|
||||
limit = None
|
||||
|
||||
handler = self.hs.get_room_list_handler()
|
||||
if server:
|
||||
data = yield handler.get_remote_public_room_list(
|
||||
|
|
@ -655,6 +674,8 @@ class RoomForgetRestServlet(TransactionRestServlet):
|
|||
return 200, {}
|
||||
|
||||
def on_PUT(self, request, room_id, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self.on_POST, request, room_id, txn_id
|
||||
)
|
||||
|
|
@ -701,6 +722,7 @@ class RoomMembershipRestServlet(TransactionRestServlet):
|
|||
content["id_server"],
|
||||
requester,
|
||||
txn_id,
|
||||
content.get("id_access_token"),
|
||||
)
|
||||
return 200, {}
|
||||
|
||||
|
|
@ -737,6 +759,8 @@ class RoomMembershipRestServlet(TransactionRestServlet):
|
|||
return True
|
||||
|
||||
def on_PUT(self, request, room_id, membership_action, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self.on_POST, request, room_id, membership_action, txn_id
|
||||
)
|
||||
|
|
@ -770,9 +794,12 @@ class RoomRedactEventRestServlet(TransactionRestServlet):
|
|||
txn_id=txn_id,
|
||||
)
|
||||
|
||||
set_tag("event_id", event.event_id)
|
||||
return 200, {"event_id": event.event_id}
|
||||
|
||||
def on_PUT(self, request, room_id, event_id, txn_id):
|
||||
set_tag("txn_id", txn_id)
|
||||
|
||||
return self.txns.fetch_or_execute_request(
|
||||
request, self.on_POST, request, room_id, event_id, txn_id
|
||||
)
|
||||
|
|
|
|||
|
|
@ -103,16 +103,9 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
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"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
|
@ -136,71 +129,11 @@ class EmailPasswordRequestTokenRestServlet(RestServlet):
|
|||
return 200, ret
|
||||
|
||||
|
||||
class MsisdnPasswordRequestTokenRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/password/msisdn/requestToken$")
|
||||
|
||||
def __init__(self, hs):
|
||||
super(MsisdnPasswordRequestTokenRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.datastore = self.hs.get_datastore()
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(
|
||||
body, ["client_secret", "country", "phone_number", "send_attempt"]
|
||||
)
|
||||
client_secret = body["client_secret"]
|
||||
country = body["country"]
|
||||
phone_number = body["phone_number"]
|
||||
send_attempt = body["send_attempt"]
|
||||
next_link = body.get("next_link") # Optional param
|
||||
|
||||
msisdn = phone_number_to_msisdn(country, phone_number)
|
||||
|
||||
if not check_3pid_allowed(self.hs, "msisdn", msisdn):
|
||||
raise SynapseError(
|
||||
403,
|
||||
"Account phone numbers are not authorized on this server",
|
||||
Codes.THREEPID_DENIED,
|
||||
)
|
||||
|
||||
existing_user_id = yield self.datastore.get_user_id_by_threepid(
|
||||
"msisdn", msisdn
|
||||
)
|
||||
|
||||
if existing_user_id is None:
|
||||
raise SynapseError(400, "MSISDN not found", Codes.THREEPID_NOT_FOUND)
|
||||
|
||||
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):
|
||||
"""Handles 3PID validation token submission"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/password_reset/(?P<medium>[^/]*)/submit_token/*$", releases=(), unstable=True
|
||||
"/password_reset/(?P<medium>[^/]*)/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
|
|
@ -214,6 +147,11 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_password_reset_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
|
|
@ -261,34 +199,12 @@ class PasswordResetSubmitTokenServlet(RestServlet):
|
|||
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)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request, medium):
|
||||
if medium != "email":
|
||||
raise SynapseError(
|
||||
400, "This medium is currently not supported for password resets"
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["sid", "client_secret", "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}
|
||||
|
||||
|
||||
class PasswordRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/password$")
|
||||
|
|
@ -325,9 +241,7 @@ class PasswordRestServlet(RestServlet):
|
|||
else:
|
||||
requester = None
|
||||
result, params, _ = yield self.auth_handler.check_auth(
|
||||
[[LoginType.EMAIL_IDENTITY], [LoginType.MSISDN]],
|
||||
body,
|
||||
self.hs.get_ip_from_request(request),
|
||||
[[LoginType.EMAIL_IDENTITY]], body, self.hs.get_ip_from_request(request)
|
||||
)
|
||||
|
||||
if LoginType.EMAIL_IDENTITY in result:
|
||||
|
|
@ -416,13 +330,35 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.store = self.hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
template_html, template_text = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[
|
||||
self.config.email_add_threepid_template_html,
|
||||
self.config.email_add_threepid_template_text,
|
||||
],
|
||||
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.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(
|
||||
body, ["id_server", "client_secret", "email", "send_attempt"]
|
||||
)
|
||||
id_server = "https://" + body["id_server"] # Assume https
|
||||
assert_params_in_dict(body, ["client_secret", "email", "send_attempt"])
|
||||
client_secret = body["client_secret"]
|
||||
email = body["email"]
|
||||
send_attempt = body["send_attempt"]
|
||||
|
|
@ -442,9 +378,30 @@ class EmailThreepidRequestTokenRestServlet(RestServlet):
|
|||
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(
|
||||
id_server, email, client_secret, send_attempt, next_link
|
||||
)
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
else:
|
||||
# Send threepid validation emails from Synapse
|
||||
sid = yield self.identity_handler.send_threepid_validation(
|
||||
email,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
self.mailer.send_add_threepid_mail,
|
||||
next_link,
|
||||
)
|
||||
|
||||
# Wrap the session id in a JSON object
|
||||
ret = {"sid": sid}
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
|
|
@ -461,10 +418,8 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
def on_POST(self, request):
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(
|
||||
body,
|
||||
["id_server", "client_secret", "country", "phone_number", "send_attempt"],
|
||||
body, ["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"]
|
||||
|
|
@ -485,12 +440,146 @@ class MsisdnThreepidRequestTokenRestServlet(RestServlet):
|
|||
if existing_user_id is not None:
|
||||
raise SynapseError(400, "MSISDN is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
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,
|
||||
"Adding phone numbers to user account is not supported by this homeserver",
|
||||
)
|
||||
|
||||
ret = yield self.identity_handler.requestMsisdnToken(
|
||||
id_server, country, phone_number, client_secret, send_attempt, next_link
|
||||
self.hs.config.account_threepid_delegate_msisdn,
|
||||
country,
|
||||
phone_number,
|
||||
client_secret,
|
||||
send_attempt,
|
||||
next_link,
|
||||
)
|
||||
|
||||
return 200, ret
|
||||
|
||||
|
||||
class AddThreepidEmailSubmitTokenServlet(RestServlet):
|
||||
"""Handles 3PID validation token submission for adding an email to a user's account"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/add_threepid/email/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super().__init__()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_add_threepid_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.OFF:
|
||||
if self.config.local_threepid_handling_disabled_due_to_email_config:
|
||||
logger.warn(
|
||||
"Adding emails have been disabled due to lack of an email config"
|
||||
)
|
||||
raise SynapseError(
|
||||
400, "Adding an email to your account is disabled on this server"
|
||||
)
|
||||
elif self.config.threepid_behaviour_email == ThreepidBehaviour.REMOTE:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"This homeserver is not validating threepids. Use an identity server "
|
||||
"instead.",
|
||||
)
|
||||
|
||||
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_add_threepid_template_success_html_content
|
||||
request.setResponseCode(200)
|
||||
except ThreepidValidationError as e:
|
||||
request.setResponseCode(e.code)
|
||||
|
||||
# Show a failure page with a reason
|
||||
template_vars = {"failure_reason": e.msg}
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
||||
|
||||
class AddThreepidMsisdnSubmitTokenServlet(RestServlet):
|
||||
"""Handles 3PID validation token submission for adding a phone number to a user's
|
||||
account
|
||||
"""
|
||||
|
||||
PATTERNS = client_patterns(
|
||||
"/add_threepid/msisdn/submit_token$", releases=(), unstable=True
|
||||
)
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super().__init__()
|
||||
self.config = hs.config
|
||||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
if not self.config.account_threepid_delegate_msisdn:
|
||||
raise SynapseError(
|
||||
400,
|
||||
"This homeserver is not validating phone numbers. Use an identity server "
|
||||
"instead.",
|
||||
)
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_dict(body, ["client_secret", "sid", "token"])
|
||||
|
||||
# Proxy submit_token request to msisdn threepid delegate
|
||||
response = yield self.identity_handler.proxy_msisdn_submit_token(
|
||||
self.config.account_threepid_delegate_msisdn,
|
||||
body["client_secret"],
|
||||
body["sid"],
|
||||
body["token"],
|
||||
)
|
||||
return 200, response
|
||||
|
||||
|
||||
class ThreepidRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid$")
|
||||
|
||||
|
|
@ -512,6 +601,8 @@ class ThreepidRestServlet(RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
threepid_creds = body.get("threePidCreds") or body.get("three_pid_creds")
|
||||
|
|
@ -519,33 +610,96 @@ class ThreepidRestServlet(RestServlet):
|
|||
raise SynapseError(
|
||||
400, "Missing param three_pid_creds", Codes.MISSING_PARAM
|
||||
)
|
||||
assert_params_in_dict(threepid_creds, ["client_secret", "sid"])
|
||||
|
||||
client_secret = threepid_creds["client_secret"]
|
||||
sid = threepid_creds["sid"]
|
||||
|
||||
validation_session = yield self.identity_handler.validate_threepid_session(
|
||||
client_secret, sid
|
||||
)
|
||||
if validation_session:
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id,
|
||||
validation_session["medium"],
|
||||
validation_session["address"],
|
||||
validation_session["validated_at"],
|
||||
)
|
||||
return 200, {}
|
||||
|
||||
raise SynapseError(
|
||||
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
|
||||
)
|
||||
|
||||
|
||||
class ThreepidAddRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/add$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidAddRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.auth = hs.get_auth()
|
||||
self.auth_handler = hs.get_auth_handler()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(body, ["client_secret", "sid"])
|
||||
client_secret = body["client_secret"]
|
||||
sid = body["sid"]
|
||||
|
||||
validation_session = yield self.identity_handler.validate_threepid_session(
|
||||
client_secret, sid
|
||||
)
|
||||
if validation_session:
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id,
|
||||
validation_session["medium"],
|
||||
validation_session["address"],
|
||||
validation_session["validated_at"],
|
||||
)
|
||||
return 200, {}
|
||||
|
||||
raise SynapseError(
|
||||
400, "No validated 3pid session found", Codes.THREEPID_AUTH_FAILED
|
||||
)
|
||||
|
||||
|
||||
class ThreepidBindRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/bind$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidBindRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.identity_handler = hs.get_handlers().identity_handler
|
||||
self.auth = hs.get_auth()
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
body = parse_json_object_from_request(request)
|
||||
|
||||
assert_params_in_dict(body, ["id_server", "sid", "client_secret"])
|
||||
id_server = body["id_server"]
|
||||
sid = body["sid"]
|
||||
client_secret = body["client_secret"]
|
||||
id_access_token = body.get("id_access_token") # optional
|
||||
|
||||
requester = yield self.auth.get_user_by_req(request)
|
||||
user_id = requester.user.to_string()
|
||||
|
||||
threepid = yield self.identity_handler.threepid_from_creds(threepid_creds)
|
||||
|
||||
if not threepid:
|
||||
raise SynapseError(400, "Failed to auth 3pid", Codes.THREEPID_AUTH_FAILED)
|
||||
|
||||
for reqd in ["medium", "address", "validated_at"]:
|
||||
if reqd not in threepid:
|
||||
logger.warn("Couldn't add 3pid: invalid response from ID server")
|
||||
raise SynapseError(500, "Invalid response from ID Server")
|
||||
|
||||
yield self.auth_handler.add_threepid(
|
||||
user_id, threepid["medium"], threepid["address"], threepid["validated_at"]
|
||||
yield self.identity_handler.bind_threepid(
|
||||
client_secret, sid, user_id, id_server, id_access_token
|
||||
)
|
||||
|
||||
if "bind" in body and body["bind"]:
|
||||
logger.debug("Binding threepid %s to %s", threepid, user_id)
|
||||
yield self.identity_handler.bind_threepid(threepid_creds, user_id)
|
||||
|
||||
return 200, {}
|
||||
|
||||
|
||||
class ThreepidUnbindRestServlet(RestServlet):
|
||||
PATTERNS = client_patterns("/account/3pid/unbind$")
|
||||
PATTERNS = client_patterns("/account/3pid/unbind$", releases=(), unstable=True)
|
||||
|
||||
def __init__(self, hs):
|
||||
super(ThreepidUnbindRestServlet, self).__init__()
|
||||
|
|
@ -627,13 +781,16 @@ class WhoamiRestServlet(RestServlet):
|
|||
|
||||
def register_servlets(hs, http_server):
|
||||
EmailPasswordRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnPasswordRequestTokenRestServlet(hs).register(http_server)
|
||||
PasswordResetSubmitTokenServlet(hs).register(http_server)
|
||||
PasswordRestServlet(hs).register(http_server)
|
||||
DeactivateAccountRestServlet(hs).register(http_server)
|
||||
EmailThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnThreepidRequestTokenRestServlet(hs).register(http_server)
|
||||
AddThreepidEmailSubmitTokenServlet(hs).register(http_server)
|
||||
AddThreepidMsisdnSubmitTokenServlet(hs).register(http_server)
|
||||
ThreepidRestServlet(hs).register(http_server)
|
||||
ThreepidAddRestServlet(hs).register(http_server)
|
||||
ThreepidBindRestServlet(hs).register(http_server)
|
||||
ThreepidUnbindRestServlet(hs).register(http_server)
|
||||
ThreepidDeleteRestServlet(hs).register(http_server)
|
||||
WhoamiRestServlet(hs).register(http_server)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import logging
|
|||
|
||||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.errors import AuthError, Codes, StoreError, SynapseError
|
||||
from synapse.api.errors import AuthError, NotFoundError, StoreError, SynapseError
|
||||
from synapse.http.servlet import RestServlet, parse_json_object_from_request
|
||||
from synapse.types import UserID
|
||||
|
||||
|
|
@ -52,13 +52,15 @@ class GetFilterRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Invalid filter_id")
|
||||
|
||||
try:
|
||||
filter = yield self.filtering.get_user_filter(
|
||||
filter_collection = yield self.filtering.get_user_filter(
|
||||
user_localpart=target_user.localpart, filter_id=filter_id
|
||||
)
|
||||
except StoreError as e:
|
||||
if e.code != 404:
|
||||
raise
|
||||
raise NotFoundError("No such filter")
|
||||
|
||||
return 200, filter.get_filter_json()
|
||||
except (KeyError, StoreError):
|
||||
raise SynapseError(400, "No such filter", errcode=Codes.NOT_FOUND)
|
||||
return 200, filter_collection.get_filter_json()
|
||||
|
||||
|
||||
class CreateFilterRestServlet(RestServlet):
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import hmac
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
from six import string_types
|
||||
|
||||
|
|
@ -31,9 +32,14 @@ from synapse.api.errors import (
|
|||
ThreepidValidationError,
|
||||
UnrecognizedRequestError,
|
||||
)
|
||||
from synapse.config import ConfigError
|
||||
from synapse.config.captcha import CaptchaConfig
|
||||
from synapse.config.consent_config import ConsentConfig
|
||||
from synapse.config.emailconfig import ThreepidBehaviour
|
||||
from synapse.config.ratelimiting import FederationRateLimitConfig
|
||||
from synapse.config.registration import RegistrationConfig
|
||||
from synapse.config.server import is_threepid_reserved
|
||||
from synapse.handlers.auth import AuthHandler
|
||||
from synapse.http.server import finish_request
|
||||
from synapse.http.servlet import (
|
||||
RestServlet,
|
||||
|
|
@ -131,15 +137,9 @@ class EmailRegisterRequestTokenRestServlet(RestServlet):
|
|||
raise SynapseError(400, "Email is already in use", Codes.THREEPID_IN_USE)
|
||||
|
||||
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"
|
||||
)
|
||||
assert self.hs.config.account_threepid_delegate_email
|
||||
|
||||
# Have the configured identity server handle the request
|
||||
ret = yield self.identity_handler.requestEmailToken(
|
||||
self.hs.config.account_threepid_delegate_email,
|
||||
email,
|
||||
|
|
@ -246,6 +246,18 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
self.clock = hs.get_clock()
|
||||
self.store = hs.get_datastore()
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
if self.config.threepid_behaviour_email == ThreepidBehaviour.LOCAL:
|
||||
self.failure_email_template, = load_jinja2_templates(
|
||||
self.config.email_template_dir,
|
||||
[self.config.email_registration_template_failure_html],
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request, medium):
|
||||
if medium != "email":
|
||||
|
|
@ -289,17 +301,11 @@ class RegistrationSubmitTokenServlet(RestServlet):
|
|||
|
||||
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)
|
||||
html = self.failure_email_template.render(**template_vars)
|
||||
|
||||
request.write(html.encode("utf-8"))
|
||||
finish_request(request)
|
||||
|
|
@ -334,6 +340,11 @@ class UsernameAvailabilityRestServlet(RestServlet):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
if not self.hs.config.enable_registration:
|
||||
raise SynapseError(
|
||||
403, "Registration has been disabled", errcode=Codes.FORBIDDEN
|
||||
)
|
||||
|
||||
ip = self.hs.get_ip_from_request(request)
|
||||
with self.ratelimiter.ratelimit(ip) as wait_deferred:
|
||||
yield wait_deferred
|
||||
|
|
@ -366,6 +377,10 @@ class RegisterRestServlet(RestServlet):
|
|||
self.ratelimiter = hs.get_registration_ratelimiter()
|
||||
self.clock = hs.get_clock()
|
||||
|
||||
self._registration_flows = _calculate_registration_flows(
|
||||
hs.config, self.auth_handler
|
||||
)
|
||||
|
||||
@interactive_auth_handler
|
||||
@defer.inlineCallbacks
|
||||
def on_POST(self, request):
|
||||
|
|
@ -486,69 +501,8 @@ class RegisterRestServlet(RestServlet):
|
|||
assigned_user_id=registered_user_id,
|
||||
)
|
||||
|
||||
# FIXME: need a better error than "no auth flow found" for scenarios
|
||||
# where we required 3PID for registration but the user didn't give one
|
||||
require_email = "email" in self.hs.config.registrations_require_3pid
|
||||
require_msisdn = "msisdn" in self.hs.config.registrations_require_3pid
|
||||
|
||||
show_msisdn = True
|
||||
if self.hs.config.disable_msisdn_registration:
|
||||
show_msisdn = False
|
||||
require_msisdn = False
|
||||
|
||||
flows = []
|
||||
if self.hs.config.enable_registration_captcha:
|
||||
# only support 3PIDless registration if no 3PIDs are required
|
||||
if not require_email and not require_msisdn:
|
||||
# Also add a dummy flow here, otherwise if a client completes
|
||||
# recaptcha first we'll assume they were going for this flow
|
||||
# and complete the request, when they could have been trying to
|
||||
# complete one of the flows with email/msisdn auth.
|
||||
flows.extend([[LoginType.RECAPTCHA, LoginType.DUMMY]])
|
||||
# only support the email-only flow if we don't require MSISDN 3PIDs
|
||||
if not require_msisdn:
|
||||
flows.extend([[LoginType.RECAPTCHA, LoginType.EMAIL_IDENTITY]])
|
||||
|
||||
if show_msisdn:
|
||||
# only support the MSISDN-only flow if we don't require email 3PIDs
|
||||
if not require_email:
|
||||
flows.extend([[LoginType.RECAPTCHA, LoginType.MSISDN]])
|
||||
# always let users provide both MSISDN & email
|
||||
flows.extend(
|
||||
[[LoginType.RECAPTCHA, LoginType.MSISDN, LoginType.EMAIL_IDENTITY]]
|
||||
)
|
||||
else:
|
||||
# only support 3PIDless registration if no 3PIDs are required
|
||||
if not require_email and not require_msisdn:
|
||||
flows.extend([[LoginType.DUMMY]])
|
||||
# only support the email-only flow if we don't require MSISDN 3PIDs
|
||||
if not require_msisdn:
|
||||
flows.extend([[LoginType.EMAIL_IDENTITY]])
|
||||
|
||||
if show_msisdn:
|
||||
# only support the MSISDN-only flow if we don't require email 3PIDs
|
||||
if not require_email or require_msisdn:
|
||||
flows.extend([[LoginType.MSISDN]])
|
||||
# always let users provide both MSISDN & email
|
||||
flows.extend([[LoginType.MSISDN, LoginType.EMAIL_IDENTITY]])
|
||||
|
||||
# Append m.login.terms to all flows if we're requiring consent
|
||||
if self.hs.config.user_consent_at_registration:
|
||||
new_flows = []
|
||||
for flow in flows:
|
||||
inserted = False
|
||||
# m.login.terms should go near the end but before msisdn or email auth
|
||||
for i, stage in enumerate(flow):
|
||||
if stage == LoginType.EMAIL_IDENTITY or stage == LoginType.MSISDN:
|
||||
flow.insert(i, LoginType.TERMS)
|
||||
inserted = True
|
||||
break
|
||||
if not inserted:
|
||||
flow.append(LoginType.TERMS)
|
||||
flows.extend(new_flows)
|
||||
|
||||
auth_result, params, session_id = yield self.auth_handler.check_auth(
|
||||
flows, body, self.hs.get_ip_from_request(request)
|
||||
self._registration_flows, body, self.hs.get_ip_from_request(request)
|
||||
)
|
||||
|
||||
# Check that we're not trying to register a denied 3pid.
|
||||
|
|
@ -711,6 +665,83 @@ class RegisterRestServlet(RestServlet):
|
|||
)
|
||||
|
||||
|
||||
def _calculate_registration_flows(
|
||||
# technically `config` has to provide *all* of these interfaces, not just one
|
||||
config: Union[RegistrationConfig, ConsentConfig, CaptchaConfig],
|
||||
auth_handler: AuthHandler,
|
||||
) -> List[List[str]]:
|
||||
"""Get a suitable flows list for registration
|
||||
|
||||
Args:
|
||||
config: server configuration
|
||||
auth_handler: authorization handler
|
||||
|
||||
Returns: a list of supported flows
|
||||
"""
|
||||
# FIXME: need a better error than "no auth flow found" for scenarios
|
||||
# where we required 3PID for registration but the user didn't give one
|
||||
require_email = "email" in config.registrations_require_3pid
|
||||
require_msisdn = "msisdn" in config.registrations_require_3pid
|
||||
|
||||
show_msisdn = True
|
||||
show_email = True
|
||||
|
||||
if config.disable_msisdn_registration:
|
||||
show_msisdn = False
|
||||
require_msisdn = False
|
||||
|
||||
enabled_auth_types = auth_handler.get_enabled_auth_types()
|
||||
if LoginType.EMAIL_IDENTITY not in enabled_auth_types:
|
||||
show_email = False
|
||||
if require_email:
|
||||
raise ConfigError(
|
||||
"Configuration requires email address at registration, but email "
|
||||
"validation is not configured"
|
||||
)
|
||||
|
||||
if LoginType.MSISDN not in enabled_auth_types:
|
||||
show_msisdn = False
|
||||
if require_msisdn:
|
||||
raise ConfigError(
|
||||
"Configuration requires msisdn at registration, but msisdn "
|
||||
"validation is not configured"
|
||||
)
|
||||
|
||||
flows = []
|
||||
|
||||
# only support 3PIDless registration if no 3PIDs are required
|
||||
if not require_email and not require_msisdn:
|
||||
# Add a dummy step here, otherwise if a client completes
|
||||
# recaptcha first we'll assume they were going for this flow
|
||||
# and complete the request, when they could have been trying to
|
||||
# complete one of the flows with email/msisdn auth.
|
||||
flows.append([LoginType.DUMMY])
|
||||
|
||||
# only support the email-only flow if we don't require MSISDN 3PIDs
|
||||
if show_email and not require_msisdn:
|
||||
flows.append([LoginType.EMAIL_IDENTITY])
|
||||
|
||||
# only support the MSISDN-only flow if we don't require email 3PIDs
|
||||
if show_msisdn and not require_email:
|
||||
flows.append([LoginType.MSISDN])
|
||||
|
||||
if show_email and show_msisdn:
|
||||
# always let users provide both MSISDN & email
|
||||
flows.append([LoginType.MSISDN, LoginType.EMAIL_IDENTITY])
|
||||
|
||||
# Prepend m.login.terms to all flows if we're requiring consent
|
||||
if config.user_consent_at_registration:
|
||||
for flow in flows:
|
||||
flow.insert(0, LoginType.TERMS)
|
||||
|
||||
# Prepend recaptcha to all flows if we're requiring captcha
|
||||
if config.enable_registration_captcha:
|
||||
for flow in flows:
|
||||
flow.insert(0, LoginType.RECAPTCHA)
|
||||
|
||||
return flows
|
||||
|
||||
|
||||
def register_servlets(hs, http_server):
|
||||
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ class RoomKeysVersionServlet(RestServlet):
|
|||
"ed25519:something": "hijklmnop"
|
||||
}
|
||||
},
|
||||
"version": "42"
|
||||
"version": "12345"
|
||||
}
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ from canonicaljson import json
|
|||
from twisted.internet import defer
|
||||
|
||||
from synapse.api.constants import PresenceState
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.api.errors import Codes, StoreError, SynapseError
|
||||
from synapse.api.filtering import DEFAULT_FILTER_COLLECTION, FilterCollection
|
||||
from synapse.events.utils import (
|
||||
format_event_for_client_v2_without_room_id,
|
||||
|
|
@ -119,25 +119,32 @@ class SyncRestServlet(RestServlet):
|
|||
|
||||
request_key = (user, timeout, since, filter_id, full_state, device_id)
|
||||
|
||||
if filter_id:
|
||||
if filter_id.startswith("{"):
|
||||
try:
|
||||
filter_object = json.loads(filter_id)
|
||||
set_timeline_upper_limit(
|
||||
filter_object, self.hs.config.filter_timeline_limit
|
||||
)
|
||||
except Exception:
|
||||
raise SynapseError(400, "Invalid filter JSON")
|
||||
self.filtering.check_valid_filter(filter_object)
|
||||
filter = FilterCollection(filter_object)
|
||||
else:
|
||||
filter = yield self.filtering.get_user_filter(user.localpart, filter_id)
|
||||
if filter_id is None:
|
||||
filter_collection = DEFAULT_FILTER_COLLECTION
|
||||
elif filter_id.startswith("{"):
|
||||
try:
|
||||
filter_object = json.loads(filter_id)
|
||||
set_timeline_upper_limit(
|
||||
filter_object, self.hs.config.filter_timeline_limit
|
||||
)
|
||||
except Exception:
|
||||
raise SynapseError(400, "Invalid filter JSON")
|
||||
self.filtering.check_valid_filter(filter_object)
|
||||
filter_collection = FilterCollection(filter_object)
|
||||
else:
|
||||
filter = DEFAULT_FILTER_COLLECTION
|
||||
try:
|
||||
filter_collection = yield self.filtering.get_user_filter(
|
||||
user.localpart, filter_id
|
||||
)
|
||||
except StoreError as err:
|
||||
if err.code != 404:
|
||||
raise
|
||||
# fix up the description and errcode to be more useful
|
||||
raise SynapseError(400, "No such filter", errcode=Codes.INVALID_PARAM)
|
||||
|
||||
sync_config = SyncConfig(
|
||||
user=user,
|
||||
filter_collection=filter,
|
||||
filter_collection=filter_collection,
|
||||
is_guest=requester.is_guest,
|
||||
request_key=request_key,
|
||||
device_id=device_id,
|
||||
|
|
@ -171,7 +178,7 @@ class SyncRestServlet(RestServlet):
|
|||
|
||||
time_now = self.clock.time_msec()
|
||||
response_content = yield self.encode_response(
|
||||
time_now, sync_result, requester.access_token_id, filter
|
||||
time_now, sync_result, requester.access_token_id, filter_collection
|
||||
)
|
||||
|
||||
return 200, response_content
|
||||
|
|
|
|||
|
|
@ -48,7 +48,24 @@ class VersionsRestServlet(RestServlet):
|
|||
"r0.5.0",
|
||||
],
|
||||
# as per MSC1497:
|
||||
"unstable_features": {"m.lazy_load_members": True},
|
||||
"unstable_features": {
|
||||
"m.lazy_load_members": True,
|
||||
# as per MSC2190, as amended by MSC2264
|
||||
# to be removed in r0.6.0
|
||||
"m.id_access_token": True,
|
||||
# Advertise to clients that they need not include an `id_server`
|
||||
# parameter during registration or password reset, as Synapse now decides
|
||||
# itself which identity server to use (or none at all).
|
||||
#
|
||||
# This is also used by a client when they wish to bind a 3PID to their
|
||||
# account, but not bind it to an identity server, the endpoint for which
|
||||
# also requires `id_server`. If the homeserver is handling 3PID
|
||||
# verification itself, there is no need to ask the user for `id_server` to
|
||||
# be supplied.
|
||||
"m.require_identity_server": False,
|
||||
# as per MSC2290
|
||||
"m.separate_add_and_bind": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ def respond_with_responder(request, responder, media_type, file_size, upload_nam
|
|||
respond_404(request)
|
||||
return
|
||||
|
||||
logger.debug("Responding to media request with responder %s")
|
||||
logger.debug("Responding to media request with responder %s", responder)
|
||||
add_file_headers(request, media_type, file_size, upload_name)
|
||||
try:
|
||||
with responder:
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ class PreviewUrlResource(DirectServeResource):
|
|||
|
||||
logger.debug("Calculated OG for %s as %s" % (url, og))
|
||||
|
||||
jsonog = json.dumps(og).encode("utf8")
|
||||
jsonog = json.dumps(og)
|
||||
|
||||
# store OG in history-aware DB cache
|
||||
yield self.store.store_url_cache(
|
||||
|
|
@ -283,7 +283,7 @@ class PreviewUrlResource(DirectServeResource):
|
|||
media_info["created_ts"],
|
||||
)
|
||||
|
||||
return jsonog
|
||||
return jsonog.encode("utf8")
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _download_url(self, url, user):
|
||||
|
|
|
|||
|
|
@ -82,13 +82,21 @@ class Thumbnailer(object):
|
|||
else:
|
||||
return (max_height * self.width) // self.height, max_height
|
||||
|
||||
def _resize(self, width, height):
|
||||
# 1-bit or 8-bit color palette images need converting to RGB
|
||||
# otherwise they will be scaled using nearest neighbour which
|
||||
# looks awful
|
||||
if self.image.mode in ["1", "P"]:
|
||||
self.image = self.image.convert("RGB")
|
||||
return self.image.resize((width, height), Image.ANTIALIAS)
|
||||
|
||||
def scale(self, width, height, output_type):
|
||||
"""Rescales the image to the given dimensions.
|
||||
|
||||
Returns:
|
||||
BytesIO: the bytes of the encoded image ready to be written to disk
|
||||
"""
|
||||
scaled = self.image.resize((width, height), Image.ANTIALIAS)
|
||||
scaled = self._resize(width, height)
|
||||
return self._encode_image(scaled, output_type)
|
||||
|
||||
def crop(self, width, height, output_type):
|
||||
|
|
@ -107,13 +115,13 @@ class Thumbnailer(object):
|
|||
"""
|
||||
if width * self.height > height * self.width:
|
||||
scaled_height = (width * self.height) // self.width
|
||||
scaled_image = self.image.resize((width, scaled_height), Image.ANTIALIAS)
|
||||
scaled_image = self._resize(width, scaled_height)
|
||||
crop_top = (scaled_height - height) // 2
|
||||
crop_bottom = height + crop_top
|
||||
cropped = scaled_image.crop((0, crop_top, width, crop_bottom))
|
||||
else:
|
||||
scaled_width = (height * self.width) // self.height
|
||||
scaled_image = self.image.resize((scaled_width, height), Image.ANTIALIAS)
|
||||
scaled_image = self._resize(scaled_width, height)
|
||||
crop_left = (scaled_width - width) // 2
|
||||
crop_right = width + crop_left
|
||||
cropped = scaled_image.crop((crop_left, 0, crop_right, height))
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import logging
|
|||
|
||||
from twisted.web.server import NOT_DONE_YET
|
||||
|
||||
from synapse.api.errors import SynapseError
|
||||
from synapse.api.errors import Codes, SynapseError
|
||||
from synapse.http.server import (
|
||||
DirectServeResource,
|
||||
respond_with_json,
|
||||
|
|
@ -56,7 +56,11 @@ class UploadResource(DirectServeResource):
|
|||
if content_length is None:
|
||||
raise SynapseError(msg="Request must specify a Content-Length", code=400)
|
||||
if int(content_length) > self.max_upload_size:
|
||||
raise SynapseError(msg="Upload request body is too large", code=413)
|
||||
raise SynapseError(
|
||||
msg="Upload request body is too large",
|
||||
code=413,
|
||||
errcode=Codes.TOO_LARGE,
|
||||
)
|
||||
|
||||
upload_name = parse_string(request, b"filename", encoding=None)
|
||||
if upload_name:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue