diff --git a/synapse/rest/client/v2_alpha/keys.py b/synapse/rest/client/v2_alpha/keys.py
index 4cbfbf5631..f7ed4daf90 100644
--- a/synapse/rest/client/v2_alpha/keys.py
+++ b/synapse/rest/client/v2_alpha/keys.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2016 OpenMarket Ltd
+# Copyright 2019 New Vector Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,8 +16,6 @@
import logging
-from twisted.internet import defer
-
from synapse.api.errors import SynapseError
from synapse.http.servlet import (
RestServlet,
@@ -24,9 +23,10 @@ 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
+from ._base import client_patterns, interactive_auth_handler
logger = logging.getLogger(__name__)
@@ -56,6 +56,7 @@ class KeyUploadServlet(RestServlet):
},
}
"""
+
PATTERNS = client_patterns("/keys/upload(/(?P<device_id>[^/]+))?$")
def __init__(self, hs):
@@ -67,33 +68,42 @@ class KeyUploadServlet(RestServlet):
self.auth = hs.get_auth()
self.e2e_keys_handler = hs.get_e2e_keys_handler()
- @defer.inlineCallbacks
- def on_POST(self, request, device_id):
- requester = yield self.auth.get_user_by_req(request, allow_guest=True)
+ @trace(opname="upload_keys")
+ async def on_POST(self, request, device_id):
+ requester = await self.auth.get_user_by_req(request, allow_guest=True)
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)
if device_id is not None:
# passing the device_id here is deprecated; however, we allow it
# for now for compatibility with older clients.
- if (requester.device_id is not None and
- device_id != requester.device_id):
- logger.warning("Client uploading keys for a different device "
- "(logged in as %s, uploading for %s)",
- requester.device_id, device_id)
+ 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)",
+ requester.device_id,
+ device_id,
+ )
else:
device_id = requester.device_id
if device_id is None:
raise SynapseError(
- 400,
- "To upload keys, you must pass device_id when authenticating"
+ 400, "To upload keys, you must pass device_id when authenticating"
)
- result = yield self.e2e_keys_handler.upload_keys_for_user(
+ result = await self.e2e_keys_handler.upload_keys_for_user(
user_id, device_id, body
)
- defer.returnValue((200, result))
+ return 200, result
class KeyQueryServlet(RestServlet):
@@ -141,13 +151,13 @@ class KeyQueryServlet(RestServlet):
self.auth = hs.get_auth()
self.e2e_keys_handler = hs.get_e2e_keys_handler()
- @defer.inlineCallbacks
- def on_POST(self, request):
- yield self.auth.get_user_by_req(request, allow_guest=True)
+ async def on_POST(self, request):
+ requester = await self.auth.get_user_by_req(request, allow_guest=True)
+ user_id = requester.user.to_string()
timeout = parse_integer(request, "timeout", 10 * 1000)
body = parse_json_object_from_request(request)
- result = yield self.e2e_keys_handler.query_devices(body, timeout)
- defer.returnValue((200, result))
+ result = await self.e2e_keys_handler.query_devices(body, timeout, user_id)
+ return 200, result
class KeyChangesServlet(RestServlet):
@@ -159,6 +169,7 @@ class KeyChangesServlet(RestServlet):
200 OK
{ "changed": ["@foo:example.com"] }
"""
+
PATTERNS = client_patterns("/keys/changes$")
def __init__(self, hs):
@@ -170,25 +181,23 @@ class KeyChangesServlet(RestServlet):
self.auth = hs.get_auth()
self.device_handler = hs.get_device_handler()
- @defer.inlineCallbacks
- def on_GET(self, request):
- requester = yield self.auth.get_user_by_req(request, allow_guest=True)
+ async def on_GET(self, request):
+ requester = await 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)
user_id = requester.user.to_string()
- results = yield self.device_handler.get_user_ids_changed(
- user_id, from_token,
- )
+ results = await self.device_handler.get_user_ids_changed(user_id, from_token)
- defer.returnValue((200, results))
+ return 200, results
class OneTimeKeyServlet(RestServlet):
@@ -209,6 +218,7 @@ class OneTimeKeyServlet(RestServlet):
} } } }
"""
+
PATTERNS = client_patterns("/keys/claim$")
def __init__(self, hs):
@@ -216,16 +226,97 @@ class OneTimeKeyServlet(RestServlet):
self.auth = hs.get_auth()
self.e2e_keys_handler = hs.get_e2e_keys_handler()
- @defer.inlineCallbacks
- def on_POST(self, request):
- yield self.auth.get_user_by_req(request, allow_guest=True)
+ async def on_POST(self, request):
+ await self.auth.get_user_by_req(request, allow_guest=True)
timeout = parse_integer(request, "timeout", 10 * 1000)
body = parse_json_object_from_request(request)
- result = yield self.e2e_keys_handler.claim_one_time_keys(
- body,
- timeout,
+ result = await self.e2e_keys_handler.claim_one_time_keys(body, timeout)
+ return 200, result
+
+
+class SigningKeyUploadServlet(RestServlet):
+ """
+ POST /keys/device_signing/upload HTTP/1.1
+ Content-Type: application/json
+
+ {
+ }
+ """
+
+ PATTERNS = client_patterns("/keys/device_signing/upload$", releases=())
+
+ def __init__(self, hs):
+ """
+ Args:
+ hs (synapse.server.HomeServer): server
+ """
+ super(SigningKeyUploadServlet, self).__init__()
+ self.hs = hs
+ self.auth = hs.get_auth()
+ self.e2e_keys_handler = hs.get_e2e_keys_handler()
+ self.auth_handler = hs.get_auth_handler()
+
+ @interactive_auth_handler
+ async def on_POST(self, request):
+ requester = await self.auth.get_user_by_req(request)
+ user_id = requester.user.to_string()
+ body = parse_json_object_from_request(request)
+
+ await self.auth_handler.validate_user_via_ui_auth(
+ requester, body, self.hs.get_ip_from_request(request)
+ )
+
+ result = await self.e2e_keys_handler.upload_signing_keys_for_user(user_id, body)
+ return 200, result
+
+
+class SignaturesUploadServlet(RestServlet):
+ """
+ POST /keys/signatures/upload HTTP/1.1
+ Content-Type: application/json
+
+ {
+ "@alice:example.com": {
+ "<device_id>": {
+ "user_id": "<user_id>",
+ "device_id": "<device_id>",
+ "algorithms": [
+ "m.olm.curve25519-aes-sha256",
+ "m.megolm.v1.aes-sha"
+ ],
+ "keys": {
+ "<algorithm>:<device_id>": "<key_base64>",
+ },
+ "signatures": {
+ "<signing_user_id>": {
+ "<algorithm>:<signing_key_base64>": "<signature_base64>>"
+ }
+ }
+ }
+ }
+ }
+ """
+
+ PATTERNS = client_patterns("/keys/signatures/upload$")
+
+ def __init__(self, hs):
+ """
+ Args:
+ hs (synapse.server.HomeServer): server
+ """
+ super(SignaturesUploadServlet, self).__init__()
+ self.auth = hs.get_auth()
+ self.e2e_keys_handler = hs.get_e2e_keys_handler()
+
+ async def on_POST(self, request):
+ requester = await self.auth.get_user_by_req(request, allow_guest=True)
+ user_id = requester.user.to_string()
+ body = parse_json_object_from_request(request)
+
+ result = await self.e2e_keys_handler.upload_signatures_for_device_keys(
+ user_id, body
)
- defer.returnValue((200, result))
+ return 200, result
def register_servlets(hs, http_server):
@@ -233,3 +324,5 @@ def register_servlets(hs, http_server):
KeyQueryServlet(hs).register(http_server)
KeyChangesServlet(hs).register(http_server)
OneTimeKeyServlet(hs).register(http_server)
+ SigningKeyUploadServlet(hs).register(http_server)
+ SignaturesUploadServlet(hs).register(http_server)
|