mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-29 07:28:55 +03:00
handle empty backups according to latest spec proposal (#4123)
fixes #4056
This commit is contained in:
parent
efdcbbe46b
commit
f1087106cf
4 changed files with 71 additions and 52 deletions
1
changelog.d/4123.bugfix
Normal file
1
changelog.d/4123.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
fix return code of empty key backups
|
|
@ -19,7 +19,7 @@ from six import iteritems
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import RoomKeysVersionError, StoreError, SynapseError
|
from synapse.api.errors import NotFoundError, RoomKeysVersionError, StoreError
|
||||||
from synapse.util.async_helpers import Linearizer
|
from synapse.util.async_helpers import Linearizer
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -55,6 +55,8 @@ class E2eRoomKeysHandler(object):
|
||||||
room_id(string): room ID to get keys for, for None to get keys for all rooms
|
room_id(string): room ID to get keys for, for None to get keys for all rooms
|
||||||
session_id(string): session ID to get keys for, for None to get keys for all
|
session_id(string): session ID to get keys for, for None to get keys for all
|
||||||
sessions
|
sessions
|
||||||
|
Raises:
|
||||||
|
NotFoundError: if the backup version does not exist
|
||||||
Returns:
|
Returns:
|
||||||
A deferred list of dicts giving the session_data and message metadata for
|
A deferred list of dicts giving the session_data and message metadata for
|
||||||
these room keys.
|
these room keys.
|
||||||
|
@ -63,13 +65,19 @@ class E2eRoomKeysHandler(object):
|
||||||
# we deliberately take the lock to get keys so that changing the version
|
# we deliberately take the lock to get keys so that changing the version
|
||||||
# works atomically
|
# works atomically
|
||||||
with (yield self._upload_linearizer.queue(user_id)):
|
with (yield self._upload_linearizer.queue(user_id)):
|
||||||
|
# make sure the backup version exists
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
|
||||||
results = yield self.store.get_e2e_room_keys(
|
results = yield self.store.get_e2e_room_keys(
|
||||||
user_id, version, room_id, session_id
|
user_id, version, room_id, session_id
|
||||||
)
|
)
|
||||||
|
|
||||||
if results['rooms'] == {}:
|
|
||||||
raise SynapseError(404, "No room_keys found")
|
|
||||||
|
|
||||||
defer.returnValue(results)
|
defer.returnValue(results)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
|
@ -120,7 +128,7 @@ class E2eRoomKeysHandler(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
SynapseError: with code 404 if there are no versions defined
|
NotFoundError: if there are no versions defined
|
||||||
RoomKeysVersionError: if the uploaded version is not the current version
|
RoomKeysVersionError: if the uploaded version is not the current version
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -134,7 +142,7 @@ class E2eRoomKeysHandler(object):
|
||||||
version_info = yield self.store.get_e2e_room_keys_version_info(user_id)
|
version_info = yield self.store.get_e2e_room_keys_version_info(user_id)
|
||||||
except StoreError as e:
|
except StoreError as e:
|
||||||
if e.code == 404:
|
if e.code == 404:
|
||||||
raise SynapseError(404, "Version '%s' not found" % (version,))
|
raise NotFoundError("Version '%s' not found" % (version,))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -148,7 +156,7 @@ class E2eRoomKeysHandler(object):
|
||||||
raise RoomKeysVersionError(current_version=version_info['version'])
|
raise RoomKeysVersionError(current_version=version_info['version'])
|
||||||
except StoreError as e:
|
except StoreError as e:
|
||||||
if e.code == 404:
|
if e.code == 404:
|
||||||
raise SynapseError(404, "Version '%s' not found" % (version,))
|
raise NotFoundError("Version '%s' not found" % (version,))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import logging
|
||||||
|
|
||||||
from twisted.internet import defer
|
from twisted.internet import defer
|
||||||
|
|
||||||
from synapse.api.errors import Codes, SynapseError
|
from synapse.api.errors import Codes, NotFoundError, SynapseError
|
||||||
from synapse.http.servlet import (
|
from synapse.http.servlet import (
|
||||||
RestServlet,
|
RestServlet,
|
||||||
parse_json_object_from_request,
|
parse_json_object_from_request,
|
||||||
|
@ -208,10 +208,25 @@ class RoomKeysServlet(RestServlet):
|
||||||
user_id, version, room_id, session_id
|
user_id, version, room_id, session_id
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Convert room_keys to the right format to return.
|
||||||
if session_id:
|
if session_id:
|
||||||
room_keys = room_keys['rooms'][room_id]['sessions'][session_id]
|
# If the client requests a specific session, but that session was
|
||||||
|
# not backed up, then return an M_NOT_FOUND.
|
||||||
|
if room_keys['rooms'] == {}:
|
||||||
|
raise NotFoundError("No room_keys found")
|
||||||
|
else:
|
||||||
|
room_keys = room_keys['rooms'][room_id]['sessions'][session_id]
|
||||||
elif room_id:
|
elif room_id:
|
||||||
room_keys = room_keys['rooms'][room_id]
|
# If the client requests all sessions from a room, but no sessions
|
||||||
|
# are found, then return an empty result rather than an error, so
|
||||||
|
# that clients don't have to handle an error condition, and an
|
||||||
|
# empty result is valid. (Similarly if the client requests all
|
||||||
|
# sessions from the backup, but in that case, room_keys is already
|
||||||
|
# in the right format, so we don't need to do anything about it.)
|
||||||
|
if room_keys['rooms'] == {}:
|
||||||
|
room_keys = {'sessions': {}}
|
||||||
|
else:
|
||||||
|
room_keys = room_keys['rooms'][room_id]
|
||||||
|
|
||||||
defer.returnValue((200, room_keys))
|
defer.returnValue((200, room_keys))
|
||||||
|
|
||||||
|
|
|
@ -169,8 +169,8 @@ class E2eRoomKeysHandlerTestCase(unittest.TestCase):
|
||||||
self.assertEqual(res, 404)
|
self.assertEqual(res, 404)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def test_get_missing_room_keys(self):
|
def test_get_missing_backup(self):
|
||||||
"""Check that we get a 404 on querying missing room_keys
|
"""Check that we get a 404 on querying missing backup
|
||||||
"""
|
"""
|
||||||
res = None
|
res = None
|
||||||
try:
|
try:
|
||||||
|
@ -179,19 +179,20 @@ class E2eRoomKeysHandlerTestCase(unittest.TestCase):
|
||||||
res = e.code
|
res = e.code
|
||||||
self.assertEqual(res, 404)
|
self.assertEqual(res, 404)
|
||||||
|
|
||||||
# check we also get a 404 even if the version is valid
|
@defer.inlineCallbacks
|
||||||
|
def test_get_missing_room_keys(self):
|
||||||
|
"""Check we get an empty response from an empty backup
|
||||||
|
"""
|
||||||
version = yield self.handler.create_version(self.local_user, {
|
version = yield self.handler.create_version(self.local_user, {
|
||||||
"algorithm": "m.megolm_backup.v1",
|
"algorithm": "m.megolm_backup.v1",
|
||||||
"auth_data": "first_version_auth_data",
|
"auth_data": "first_version_auth_data",
|
||||||
})
|
})
|
||||||
self.assertEqual(version, "1")
|
self.assertEqual(version, "1")
|
||||||
|
|
||||||
res = None
|
res = yield self.handler.get_room_keys(self.local_user, version)
|
||||||
try:
|
self.assertDictEqual(res, {
|
||||||
yield self.handler.get_room_keys(self.local_user, version)
|
"rooms": {}
|
||||||
except errors.SynapseError as e:
|
})
|
||||||
res = e.code
|
|
||||||
self.assertEqual(res, 404)
|
|
||||||
|
|
||||||
# TODO: test the locking semantics when uploading room_keys,
|
# TODO: test the locking semantics when uploading room_keys,
|
||||||
# although this is probably best done in sytest
|
# although this is probably best done in sytest
|
||||||
|
@ -345,17 +346,15 @@ class E2eRoomKeysHandlerTestCase(unittest.TestCase):
|
||||||
# check for bulk-delete
|
# check for bulk-delete
|
||||||
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
||||||
yield self.handler.delete_room_keys(self.local_user, version)
|
yield self.handler.delete_room_keys(self.local_user, version)
|
||||||
res = None
|
res = yield self.handler.get_room_keys(
|
||||||
try:
|
self.local_user,
|
||||||
yield self.handler.get_room_keys(
|
version,
|
||||||
self.local_user,
|
room_id="!abc:matrix.org",
|
||||||
version,
|
session_id="c0ff33",
|
||||||
room_id="!abc:matrix.org",
|
)
|
||||||
session_id="c0ff33",
|
self.assertDictEqual(res, {
|
||||||
)
|
"rooms": {}
|
||||||
except errors.SynapseError as e:
|
})
|
||||||
res = e.code
|
|
||||||
self.assertEqual(res, 404)
|
|
||||||
|
|
||||||
# check for bulk-delete per room
|
# check for bulk-delete per room
|
||||||
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
||||||
|
@ -364,17 +363,15 @@ class E2eRoomKeysHandlerTestCase(unittest.TestCase):
|
||||||
version,
|
version,
|
||||||
room_id="!abc:matrix.org",
|
room_id="!abc:matrix.org",
|
||||||
)
|
)
|
||||||
res = None
|
res = yield self.handler.get_room_keys(
|
||||||
try:
|
self.local_user,
|
||||||
yield self.handler.get_room_keys(
|
version,
|
||||||
self.local_user,
|
room_id="!abc:matrix.org",
|
||||||
version,
|
session_id="c0ff33",
|
||||||
room_id="!abc:matrix.org",
|
)
|
||||||
session_id="c0ff33",
|
self.assertDictEqual(res, {
|
||||||
)
|
"rooms": {}
|
||||||
except errors.SynapseError as e:
|
})
|
||||||
res = e.code
|
|
||||||
self.assertEqual(res, 404)
|
|
||||||
|
|
||||||
# check for bulk-delete per session
|
# check for bulk-delete per session
|
||||||
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
yield self.handler.upload_room_keys(self.local_user, version, room_keys)
|
||||||
|
@ -384,14 +381,12 @@ class E2eRoomKeysHandlerTestCase(unittest.TestCase):
|
||||||
room_id="!abc:matrix.org",
|
room_id="!abc:matrix.org",
|
||||||
session_id="c0ff33",
|
session_id="c0ff33",
|
||||||
)
|
)
|
||||||
res = None
|
res = yield self.handler.get_room_keys(
|
||||||
try:
|
self.local_user,
|
||||||
yield self.handler.get_room_keys(
|
version,
|
||||||
self.local_user,
|
room_id="!abc:matrix.org",
|
||||||
version,
|
session_id="c0ff33",
|
||||||
room_id="!abc:matrix.org",
|
)
|
||||||
session_id="c0ff33",
|
self.assertDictEqual(res, {
|
||||||
)
|
"rooms": {}
|
||||||
except errors.SynapseError as e:
|
})
|
||||||
res = e.code
|
|
||||||
self.assertEqual(res, 404)
|
|
||||||
|
|
Loading…
Reference in a new issue