make /room_keys/version work

This commit is contained in:
Matthew Hodgson 2017-12-06 10:02:49 +01:00 committed by Hubert Chathi
parent 8ae64b270f
commit 69e51c7ba4
4 changed files with 38 additions and 15 deletions

View File

@ -48,13 +48,16 @@ class E2eRoomKeysHandler(object):
# TODO: Validate the JSON to make sure it has the right keys. # TODO: Validate the JSON to make sure it has the right keys.
# Check that the version we're trying to upload is the current version # Check that the version we're trying to upload is the current version
try: try:
version_info = yield self.get_version_info(user_id, version) version_info = yield self.get_version_info(user_id, version)
except StoreError as e: except StoreError as e:
if e.code == 404: if e.code == 404:
raise SynapseError(404, "Version '%d' not found" % (version,)) raise SynapseError(404, "Version '%s' not found" % (version,))
else:
raise e
if version_info.version != version: if version_info['version'] != version:
raise RoomKeysVersionError(current_version=version_info.version) raise RoomKeysVersionError(current_version=version_info.version)
# XXX: perhaps we should use a finer grained lock here? # XXX: perhaps we should use a finer grained lock here?
@ -81,7 +84,7 @@ class E2eRoomKeysHandler(object):
if e.code == 404: if e.code == 404:
pass pass
else: else:
raise raise e
# check whether we merge or not. spelling it out with if/elifs rather # check whether we merge or not. spelling it out with if/elifs rather
# than lots of booleans for legibility. # than lots of booleans for legibility.
@ -106,20 +109,21 @@ class E2eRoomKeysHandler(object):
) )
@defer.inlineCallbacks @defer.inlineCallbacks
def create_version(self, user_id, version, version_info): def create_version(self, user_id, version_info):
# TODO: Validate the JSON to make sure it has the right keys. # TODO: Validate the JSON to make sure it has the right keys.
# lock everyone out until we've switched version # lock everyone out until we've switched version
with (yield self._upload_linearizer.queue(user_id)): with (yield self._upload_linearizer.queue(user_id)):
yield self.store.create_version( new_version = yield self.store.create_e2e_room_key_version(
user_id, version, version_info user_id, version_info
) )
defer.returnValue(new_version)
@defer.inlineCallbacks @defer.inlineCallbacks
def get_version_info(self, user_id, version): def get_version_info(self, user_id, version):
with (yield self._upload_linearizer.queue(user_id)): with (yield self._upload_linearizer.queue(user_id)):
results = yield self.store.get_e2e_room_key_version( results = yield self.store.get_e2e_room_key_version_info(
user_id, version user_id, version
) )
defer.returnValue(results) defer.returnValue(results)

View File

@ -17,6 +17,7 @@ import logging
from twisted.internet import defer from twisted.internet import defer
from synapse.api.errors import SynapseError
from synapse.http.servlet import ( from synapse.http.servlet import (
RestServlet, parse_json_object_from_request RestServlet, parse_json_object_from_request
) )
@ -237,15 +238,21 @@ class RoomKeysVersionServlet(RestServlet):
@defer.inlineCallbacks @defer.inlineCallbacks
def on_POST(self, request, version): def on_POST(self, request, version):
if version:
raise SynapseError(405, "Cannot POST to a specific version")
requester = yield self.auth.get_user_by_req(request, allow_guest=False) requester = yield self.auth.get_user_by_req(request, allow_guest=False)
user_id = requester.user.to_string() user_id = requester.user.to_string()
info = parse_json_object_from_request(request) info = parse_json_object_from_request(request)
new_version = yield self.e2e_room_keys_handler.create_version( new_version = yield self.e2e_room_keys_handler.create_version(
user_id, version, info user_id, info
) )
defer.returnValue((200, {"version": new_version})) defer.returnValue((200, {"version": new_version}))
# we deliberately don't have a PUT /version, as these things really should
# be immutable to avoid people footgunning
@defer.inlineCallbacks @defer.inlineCallbacks
def on_GET(self, request, version): def on_GET(self, request, version):
requester = yield self.auth.get_user_by_req(request, allow_guest=False) requester = yield self.auth.get_user_by_req(request, allow_guest=False)

View File

@ -172,7 +172,7 @@ class EndToEndRoomKeyStore(SQLBaseStore):
) )
@defer.inlineCallbacks @defer.inlineCallbacks
def get_e2e_room_key_version(self, user_id, version): def get_e2e_room_key_version_info(self, user_id, version):
row = yield self._simple_select_one( row = yield self._simple_select_one(
table="e2e_room_key_versions", table="e2e_room_key_versions",
@ -191,23 +191,35 @@ class EndToEndRoomKeyStore(SQLBaseStore):
defer.returnValue(row) defer.returnValue(row)
def create_e2e_room_key_version(self, user_id, version, info): def create_e2e_room_key_version(self, user_id, info):
"""Atomically creates a new version of this user's e2e_room_keys store
with the given version info.
"""
def _create_e2e_room_key_version_txn(txn): def _create_e2e_room_key_version_txn(txn):
txn.execute(
"SELECT MAX(version) FROM e2e_room_key_versions WHERE user_id=?",
(user_id,)
)
current_version = txn.fetchone()[0]
if current_version is None:
current_version = 0
new_version = current_version + 1
self._simple_insert_txn( self._simple_insert_txn(
txn, txn,
table="e2e_room_key_versions", table="e2e_room_key_versions",
values={ values={
"user_id": user_id, "user_id": user_id,
"version": version, "version": new_version,
"algorithm": info["algorithm"], "algorithm": info["algorithm"],
"auth_data": info["auth_data"], "auth_data": info["auth_data"],
}, },
lock=False,
) )
return True return new_version
return self.runInteraction( return self.runInteraction(
"create_e2e_room_key_version_txn", _create_e2e_room_key_version_txn "create_e2e_room_key_version_txn", _create_e2e_room_key_version_txn

View File

@ -18,7 +18,7 @@ CREATE TABLE e2e_room_keys (
user_id TEXT NOT NULL, user_id TEXT NOT NULL,
room_id TEXT NOT NULL, room_id TEXT NOT NULL,
session_id TEXT NOT NULL, session_id TEXT NOT NULL,
version INT NOT NULL, version TEXT NOT NULL,
first_message_index INT, first_message_index INT,
forwarded_count INT, forwarded_count INT,
is_verified BOOLEAN, is_verified BOOLEAN,
@ -32,7 +32,7 @@ CREATE UNIQUE INDEX e2e_room_keys_session_idx ON e2e_room_keys(session_id);
-- the metadata for each generation of encrypted e2e session backups -- the metadata for each generation of encrypted e2e session backups
CREATE TABLE e2e_room_key_versions ( CREATE TABLE e2e_room_key_versions (
user_id TEXT NOT NULL, user_id TEXT NOT NULL,
version INT NOT NULL, version TEXT NOT NULL,
algorithm TEXT NOT NULL, algorithm TEXT NOT NULL,
auth_data TEXT NOT NULL auth_data TEXT NOT NULL
); );