Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
add etag and count to key backup endpoints (#5858)
Browse files Browse the repository at this point in the history
* commit '0d27aba90':
  add etag and count to key backup endpoints (#5858)
  • Loading branch information
anoadragon453 committed Mar 18, 2020
2 parents 6e79e33 + 0d27aba commit 8c493de
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 124 deletions.
1 change: 1 addition & 0 deletions changelog.d/5858.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add etag and count fields to key backup endpoints to help clients guess if there are new keys.
130 changes: 80 additions & 50 deletions synapse/handlers/e2e_room_keys.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2017, 2018 New Vector Ltd
# Copyright 2019 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.
Expand Down Expand Up @@ -103,14 +104,35 @@ def delete_room_keys(self, user_id, version, room_id=None, session_id=None):
rooms
session_id(string): session ID to delete keys for, for None to delete keys
for all sessions
Raises:
NotFoundError: if the backup version does not exist
Returns:
A deferred of the deletion transaction
A dict containing the count and etag for the backup version
"""

# lock for consistency with uploading
with (yield self._upload_linearizer.queue(user_id)):
# make sure the backup version exists
try:
version_info = yield self.store.get_e2e_room_keys_version_info(
user_id, version
)
except StoreError as e:
if e.code == 404:
raise NotFoundError("Unknown backup version")
else:
raise

yield self.store.delete_e2e_room_keys(user_id, version, room_id, session_id)

version_etag = version_info["etag"] + 1
yield self.store.update_e2e_room_keys_version(
user_id, version, None, version_etag
)

count = yield self.store.count_e2e_room_keys(user_id, version)
return {"etag": str(version_etag), "count": count}

@trace
@defer.inlineCallbacks
def upload_room_keys(self, user_id, version, room_keys):
Expand Down Expand Up @@ -138,6 +160,9 @@ def upload_room_keys(self, user_id, version, room_keys):
}
}
Returns:
A dict containing the count and etag for the backup version
Raises:
NotFoundError: if there are no versions defined
RoomKeysVersionError: if the uploaded version is not the current version
Expand Down Expand Up @@ -171,59 +196,62 @@ def upload_room_keys(self, user_id, version, room_keys):
else:
raise

# go through the room_keys.
# XXX: this should/could be done concurrently, given we're in a lock.
# Fetch any existing room keys for the sessions that have been
# submitted. Then compare them with the submitted keys. If the
# key is new, insert it; if the key should be updated, then update
# it; otherwise, drop it.
existing_keys = yield self.store.get_e2e_room_keys_multi(
user_id, version, room_keys["rooms"]
)
to_insert = [] # batch the inserts together
changed = False # if anything has changed, we need to update the etag
for room_id, room in iteritems(room_keys["rooms"]):
for session_id, session in iteritems(room["sessions"]):
yield self._upload_room_key(
user_id, version, room_id, session_id, session
for session_id, room_key in iteritems(room["sessions"]):
log_kv(
{
"message": "Trying to upload room key",
"room_id": room_id,
"session_id": session_id,
"user_id": user_id,
}
)

@defer.inlineCallbacks
def _upload_room_key(self, user_id, version, room_id, session_id, room_key):
"""Upload a given room_key for a given room and session into a given
version of the backup. Merges the key with any which might already exist.
Args:
user_id(str): the user whose backup we're setting
version(str): the version ID of the backup we're updating
room_id(str): the ID of the room whose keys we're setting
session_id(str): the session whose room_key we're setting
room_key(dict): the room_key being set
"""
log_kv(
{
"message": "Trying to upload room key",
"room_id": room_id,
"session_id": session_id,
"user_id": user_id,
}
)
# get the room_key for this particular row
current_room_key = None
try:
current_room_key = yield self.store.get_e2e_room_key(
user_id, version, room_id, session_id
)
except StoreError as e:
if e.code == 404:
log_kv(
{
"message": "Room key not found.",
"room_id": room_id,
"user_id": user_id,
}
current_room_key = existing_keys.get(room_id, {}).get(session_id)
if current_room_key:
if self._should_replace_room_key(current_room_key, room_key):
log_kv({"message": "Replacing room key."})
# updates are done one at a time in the DB, so send
# updates right away rather than batching them up,
# like we do with the inserts
yield self.store.update_e2e_room_key(
user_id, version, room_id, session_id, room_key
)
changed = True
else:
log_kv({"message": "Not replacing room_key."})
else:
log_kv(
{
"message": "Room key not found.",
"room_id": room_id,
"user_id": user_id,
}
)
log_kv({"message": "Replacing room key."})
to_insert.append((room_id, session_id, room_key))
changed = True

if len(to_insert):
yield self.store.add_e2e_room_keys(user_id, version, to_insert)

version_etag = version_info["etag"]
if changed:
version_etag = version_etag + 1
yield self.store.update_e2e_room_keys_version(
user_id, version, None, version_etag
)
else:
raise

if self._should_replace_room_key(current_room_key, room_key):
log_kv({"message": "Replacing room key."})
yield self.store.set_e2e_room_key(
user_id, version, room_id, session_id, room_key
)
else:
log_kv({"message": "Not replacing room_key."})
count = yield self.store.count_e2e_room_keys(user_id, version)
return {"etag": str(version_etag), "count": count}

@staticmethod
def _should_replace_room_key(current_room_key, room_key):
Expand Down Expand Up @@ -314,6 +342,8 @@ def get_version_info(self, user_id, version=None):
raise NotFoundError("Unknown backup version")
else:
raise

res["count"] = yield self.store.count_e2e_room_keys(user_id, res["version"])
return res

@trace
Expand Down
8 changes: 4 additions & 4 deletions synapse/rest/client/v2_alpha/room_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ def on_PUT(self, request, room_id, session_id):
if room_id:
body = {"rooms": {room_id: body}}

yield self.e2e_room_keys_handler.upload_room_keys(user_id, version, body)
return 200, {}
ret = yield self.e2e_room_keys_handler.upload_room_keys(user_id, version, body)
return 200, ret

@defer.inlineCallbacks
def on_GET(self, request, room_id, session_id):
Expand Down Expand Up @@ -239,10 +239,10 @@ def on_DELETE(self, request, room_id, session_id):
user_id = requester.user.to_string()
version = parse_string(request, "version")

yield self.e2e_room_keys_handler.delete_room_keys(
ret = yield self.e2e_room_keys_handler.delete_room_keys(
user_id, version, room_id, session_id
)
return 200, {}
return 200, ret


class RoomKeysNewVersionServlet(RestServlet):
Expand Down
Loading

0 comments on commit 8c493de

Please sign in to comment.