summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Hodgson <matthew@matrix.org>2017-12-06 10:02:49 +0100
committerHubert Chathi <hubert@uhoreg.ca>2018-08-12 19:14:31 -0400
commit69e51c7ba48a84b48ab64c8c290a232d14193a18 (patch)
tree59d7a6647c398d63cb70611d11be45de93e2bcca
parentimplement /room_keys/version too (untested) (diff)
downloadsynapse-69e51c7ba48a84b48ab64c8c290a232d14193a18.tar.xz
make /room_keys/version work
-rw-r--r--synapse/handlers/e2e_room_keys.py18
-rw-r--r--synapse/rest/client/v2_alpha/room_keys.py9
-rw-r--r--synapse/storage/e2e_room_keys.py22
-rw-r--r--synapse/storage/schema/delta/46/e2e_room_keys.sql4
4 files changed, 38 insertions, 15 deletions
diff --git a/synapse/handlers/e2e_room_keys.py b/synapse/handlers/e2e_room_keys.py
index 4333ca610c..bd58be6558 100644
--- a/synapse/handlers/e2e_room_keys.py
+++ b/synapse/handlers/e2e_room_keys.py
@@ -48,13 +48,16 @@ class E2eRoomKeysHandler(object):
         # 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
+
         try:
             version_info = yield self.get_version_info(user_id, version)
         except StoreError as e:
             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)
 
         # XXX: perhaps we should use a finer grained lock here?
@@ -81,7 +84,7 @@ class E2eRoomKeysHandler(object):
             if e.code == 404:
                 pass
             else:
-                raise
+                raise e
 
         # check whether we merge or not. spelling it out with if/elifs rather
         # than lots of booleans for legibility.
@@ -106,20 +109,21 @@ class E2eRoomKeysHandler(object):
             )
 
     @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.
 
         # lock everyone out until we've switched version
         with (yield self._upload_linearizer.queue(user_id)):
-            yield self.store.create_version(
-                user_id, version, version_info
+            new_version = yield self.store.create_e2e_room_key_version(
+                user_id, version_info
             )
+            defer.returnValue(new_version)
 
     @defer.inlineCallbacks
     def get_version_info(self, user_id, version):
         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
             )
             defer.returnValue(results)
diff --git a/synapse/rest/client/v2_alpha/room_keys.py b/synapse/rest/client/v2_alpha/room_keys.py
index 4d76e1d824..128b732fb1 100644
--- a/synapse/rest/client/v2_alpha/room_keys.py
+++ b/synapse/rest/client/v2_alpha/room_keys.py
@@ -17,6 +17,7 @@ import logging
 
 from twisted.internet import defer
 
+from synapse.api.errors import SynapseError
 from synapse.http.servlet import (
     RestServlet, parse_json_object_from_request
 )
@@ -237,15 +238,21 @@ class RoomKeysVersionServlet(RestServlet):
 
     @defer.inlineCallbacks
     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)
         user_id = requester.user.to_string()
         info = parse_json_object_from_request(request)
 
         new_version = yield self.e2e_room_keys_handler.create_version(
-            user_id, version, info
+            user_id, info
         )
         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
     def on_GET(self, request, version):
         requester = yield self.auth.get_user_by_req(request, allow_guest=False)
diff --git a/synapse/storage/e2e_room_keys.py b/synapse/storage/e2e_room_keys.py
index 994878acf6..8efca11a8c 100644
--- a/synapse/storage/e2e_room_keys.py
+++ b/synapse/storage/e2e_room_keys.py
@@ -172,7 +172,7 @@ class EndToEndRoomKeyStore(SQLBaseStore):
         )
 
     @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(
             table="e2e_room_key_versions",
@@ -191,23 +191,35 @@ class EndToEndRoomKeyStore(SQLBaseStore):
 
         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):
 
+            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(
                 txn,
                 table="e2e_room_key_versions",
                 values={
                     "user_id": user_id,
-                    "version": version,
+                    "version": new_version,
                     "algorithm": info["algorithm"],
                     "auth_data": info["auth_data"],
                 },
-                lock=False,
             )
 
-            return True
+            return new_version
 
         return self.runInteraction(
             "create_e2e_room_key_version_txn", _create_e2e_room_key_version_txn
diff --git a/synapse/storage/schema/delta/46/e2e_room_keys.sql b/synapse/storage/schema/delta/46/e2e_room_keys.sql
index 463f828c66..0d2a85fbe6 100644
--- a/synapse/storage/schema/delta/46/e2e_room_keys.sql
+++ b/synapse/storage/schema/delta/46/e2e_room_keys.sql
@@ -18,7 +18,7 @@ CREATE TABLE e2e_room_keys (
     user_id TEXT NOT NULL,
     room_id TEXT NOT NULL,
     session_id TEXT NOT NULL,
-    version INT NOT NULL,
+    version TEXT NOT NULL,
     first_message_index INT,
     forwarded_count INT,
     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
 CREATE TABLE e2e_room_key_versions (
     user_id TEXT NOT NULL,
-    version INT NOT NULL,
+    version TEXT NOT NULL,
     algorithm TEXT NOT NULL,
     auth_data TEXT NOT NULL
 );