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

Commit

Permalink
apply provided patch
Browse files Browse the repository at this point in the history
  • Loading branch information
H-Shay committed Jul 19, 2023
1 parent 0f49f81 commit cc2022d
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 64 deletions.
4 changes: 3 additions & 1 deletion synapse/handlers/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,7 @@ async def notify_user_signature_update(
async def store_dehydrated_device(
self,
user_id: str,
device_id: Optional[str],
device_data: JsonDict,
initial_device_display_name: Optional[str] = None,
) -> str:
Expand All @@ -661,14 +662,15 @@ async def store_dehydrated_device(
Args:
user_id: the user that we are storing the device for
device_id: device id supplied by client
device_data: the dehydrated device information
initial_device_display_name: The display name to use for the device
Returns:
device id of the dehydrated device
"""
device_id = await self.check_device_registered(
user_id,
None,
device_id,
initial_device_display_name,
)
old_device_id = await self.store.store_dehydrated_device(
Expand Down
8 changes: 1 addition & 7 deletions synapse/handlers/devicemessage.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ async def get_events_for_dehydrated_device(
) -> JsonDict:
"""Fetches up to `limit` events sent to `device_id` starting from `since_token`
and returns the new since token. If there are no more messages, returns an empty
array and deletes the dehydrated device associated with the user/device_id.
array.
Args:
requester: the user requesting the messages
Expand Down Expand Up @@ -397,12 +397,6 @@ async def get_events_for_dehydrated_device(
device_id,
)

if messages == []:
# we've fetched all the messages, delete the dehydrated device
await self.store.remove_dehydrated_device(
requester.user.to_string(), device_id
)

return {
"events": messages,
"next_batch": f"d{stream_id}",
Expand Down
125 changes: 121 additions & 4 deletions synapse/rest/client/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from http import HTTPStatus
from typing import TYPE_CHECKING, List, Optional, Tuple

from pydantic import Extra, StrictStr

from synapse.api import errors
from synapse.api.errors import NotFoundError, UnrecognizedRequestError
from synapse.api.errors import NotFoundError, SynapseError, UnrecognizedRequestError
from synapse.handlers.device import DeviceHandler
from synapse.http.server import HttpServer
from synapse.http.servlet import (
Expand All @@ -28,6 +28,7 @@
parse_integer,
)
from synapse.http.site import SynapseRequest
from synapse.replication.http.devices import ReplicationUploadKeysForUserRestServlet
from synapse.rest.client._base import client_patterns, interactive_auth_handler
from synapse.rest.client.models import AuthenticationData
from synapse.rest.models import RequestBodyModel
Expand Down Expand Up @@ -228,7 +229,7 @@ class Config:


class DehydratedDeviceServlet(RestServlet):
"""Retrieve or store a dehydrated device.
"""Retrieve, store or delete a dehydrated device.
Implements either MSC2697 and MSC3814.
Expand Down Expand Up @@ -262,6 +263,75 @@ class DehydratedDeviceServlet(RestServlet):
"device_id": "dehydrated_device_id"
}
GET /org.matrix.msc3814.v1/dehydrated_device
HTTP/1.1 200 OK
Content-Type: application/json
{
"device_id": "dehydrated_device_id",
"device_data": {
"algorithm": "org.matrix.msc2697.v1.dehydration.v1.olm",
"account": "dehydrated_device"
}
}
PUT /org.matrix.msc3814.v1/dehydrated_device
Content-Type: application/json
{
"device_id": "dehydrated_device_id",
"device_data": {
"algorithm": "org.matrix.msc2697.v1.dehydration.v1.olm",
"account": "dehydrated_device"
},
"device_keys": {
"user_id": "<user_id>",
"device_id": "<device_id>",
"valid_until_ts": <millisecond_timestamp>,
"algorithms": [
"m.olm.curve25519-aes-sha2",
]
"keys": {
"<algorithm>:<device_id>": "<key_base64>",
},
"signatures:" {
"<user_id>" {
"<algorithm>:<device_id>": "<signature_base64>"
}
}
},
"fallback_keys": {
"<algorithm>:<device_id>": "<key_base64>",
"signed_<algorithm>:<device_id>": {
"fallback": true,
"key": "<key_base64>",
"signatures": {
"<user_id>": {
"<algorithm>:<device_id>": "<key_base64>"
}
}
}
}
"one_time_keys": {
"<algorithm>:<key_id>": "<key_base64>"
},
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"device_id": "dehydrated_device_id"
}
DELETE /org.matrix.msc3814.v1/dehydrated_device
HTTP/1.1 200 OK
Content-Type: application/json
{
"device_id": "dehydrated_device_id",
}
"""

def __init__(self, hs: "HomeServer", msc2697: bool = True):
Expand All @@ -270,6 +340,7 @@ def __init__(self, hs: "HomeServer", msc2697: bool = True):
self.auth = hs.get_auth()
handler = hs.get_device_handler()
assert isinstance(handler, DeviceHandler)
self.e2e_keys_handler = hs.get_e2e_keys_handler()
self.device_handler = handler

self.PATTERNS = client_patterns(
Expand All @@ -279,6 +350,13 @@ def __init__(self, hs: "HomeServer", msc2697: bool = True):
releases=(),
)

if hs.config.worker.worker_app is None:
# if main process
self.key_uploader = self.e2e_keys_handler.upload_keys_for_user
else:
# then a worker
self.key_uploader = ReplicationUploadKeysForUserRestServlet.make_client(hs)

async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request)
dehydrated_device = await self.device_handler.get_dehydrated_device(
Expand All @@ -291,19 +369,58 @@ async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
else:
raise errors.NotFoundError("No dehydrated device available")

async def on_DELETE(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
requester = await self.auth.get_user_by_req(request)

dehydrated_device = await self.device_handler.get_dehydrated_device(
requester.user.to_string()
)

if dehydrated_device is not None:
(device_id, device_data) = dehydrated_device

await self.device_handler.rehydrate_device(
requester.user.to_string(),
self.auth.get_access_token_from_request(request),
device_id,
)

result = {"device_id": device_id}

return 200, result
else:
raise errors.NotFoundError("No dehydrated device available")

class PutBody(RequestBodyModel):
device_data: DehydratedDeviceDataModel
device_id: Optional[StrictStr]
initial_device_display_name: Optional[StrictStr]

class Config:
extra = Extra.allow

async def on_PUT(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
submission = parse_and_validate_json_object_from_request(request, self.PutBody)
requester = await self.auth.get_user_by_req(request)
user_id = requester.user.to_string()

device_id = await self.device_handler.store_dehydrated_device(
requester.user.to_string(),
user_id,
submission.device_id,
submission.device_data.dict(),
submission.initial_device_display_name,
)

device_info = submission.dict()
if "device_keys" not in device_info.keys():
raise SynapseError(
HTTPStatus.BAD_REQUEST,
"Device key(s) not found, these must be provided.",
)

# TODO: Do we need to do something with the result here?
await self.key_uploader(user_id=user_id, device_id=device_id, keys=device_info)

return 200, {"device_id": device_id}


Expand Down
20 changes: 2 additions & 18 deletions tests/handlers/test_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ def test_dehydrate_and_rehydrate_device(self) -> None:
stored_dehydrated_device_id = self.get_success(
self.handler.store_dehydrated_device(
user_id=user_id,
device_id=None,
device_data={"device_data": {"foo": "bar"}},
initial_device_display_name="dehydrated device",
)
Expand Down Expand Up @@ -506,6 +507,7 @@ def test_dehydrate_v2_and_fetch_events(self) -> None:
stored_dehydrated_device_id = self.get_success(
self.handler.store_dehydrated_device(
user_id=user_id,
device_id=None,
device_data={"device_data": {"foo": "bar"}},
initial_device_display_name="dehydrated device",
)
Expand Down Expand Up @@ -576,21 +578,3 @@ def test_dehydrate_v2_and_fetch_events(self) -> None:
)
self.assertTrue(len(res["next_batch"]) > 1)
self.assertEqual(len(res["events"]), 0)

# Fetching messages again should fail, since the messages and dehydrated device
# were deleted
self.get_failure(
self.message_handler.get_events_for_dehydrated_device(
requester=requester,
device_id=stored_dehydrated_device_id,
since_token=None,
limit=10,
),
SynapseError,
)

# make sure that the dehydrated device ID is deleted after fetching messages
res2 = self.get_success(
self.handler.get_dehydrated_device(requester.user.to_string()),
)
self.assertEqual(res2, None)
Loading

0 comments on commit cc2022d

Please sign in to comment.