Add support for the dehydrated devices endpoints (#1605)
This patch adds support for the endpoints used in [MSC3814]. One notable change to the MSC here is that the PUT endpoint uploads the device and one-time keys as well. [MSC3814]: https://github.com/matrix-org/matrix-spec-proposals/pull/3814 Co-authored-by: Kévin Commaille <76261501+zecakeh@users.noreply.github.com>
This commit is contained in:
parent
3bd58e3c89
commit
0a82459df6
@ -45,6 +45,7 @@ unstable-msc2965 = []
|
||||
unstable-msc2967 = []
|
||||
unstable-msc3488 = []
|
||||
unstable-msc3575 = []
|
||||
unstable-msc3814 = []
|
||||
|
||||
[dependencies]
|
||||
assign = { workspace = true }
|
||||
|
88
crates/ruma-client-api/src/dehydrated_device.rs
Normal file
88
crates/ruma-client-api/src/dehydrated_device.rs
Normal file
@ -0,0 +1,88 @@
|
||||
//! Endpoints for managing dehydrated devices.
|
||||
|
||||
use ruma_common::serde::StringEnum;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::PrivOwnedStr;
|
||||
|
||||
pub mod delete_dehydrated_device;
|
||||
pub mod get_dehydrated_device;
|
||||
pub mod get_events;
|
||||
pub mod put_dehydrated_device;
|
||||
|
||||
/// Data for a dehydrated device.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(try_from = "Helper", into = "Helper")]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub enum DehydratedDeviceData {
|
||||
/// The `org.matrix.msc3814.v1.olm` variant of a dehydrated device.
|
||||
V1(DehydratedDeviceV1),
|
||||
}
|
||||
|
||||
impl DehydratedDeviceData {
|
||||
/// Get the algorithm this dehydrated device uses.
|
||||
pub fn algorithm(&self) -> DeviceDehydrationAlgorithm {
|
||||
match self {
|
||||
DehydratedDeviceData::V1(_) => DeviceDehydrationAlgorithm::V1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The `org.matrix.msc3814.v1.olm` variant of a dehydrated device.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||
pub struct DehydratedDeviceV1 {
|
||||
/// The pickle of the `Olm` account of the device.
|
||||
///
|
||||
/// The pickle will contain the private parts of the long-term identity keys of the device as
|
||||
/// well as a collection of one-time keys.
|
||||
pub device_pickle: String,
|
||||
}
|
||||
|
||||
impl DehydratedDeviceV1 {
|
||||
/// Create a [`DehydratedDeviceV1`] struct from a device pickle.
|
||||
pub fn new(device_pickle: String) -> Self {
|
||||
Self { device_pickle }
|
||||
}
|
||||
}
|
||||
|
||||
/// The algorithms used for dehydrated devices.
|
||||
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
|
||||
#[derive(Clone, PartialEq, Eq, StringEnum)]
|
||||
#[non_exhaustive]
|
||||
pub enum DeviceDehydrationAlgorithm {
|
||||
/// The `org.matrix.msc3814.v1.olm` device dehydration algorithm.
|
||||
#[ruma_enum(rename = "org.matrix.msc3814.v1.olm")]
|
||||
V1,
|
||||
#[doc(hidden)]
|
||||
_Custom(PrivOwnedStr),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct Helper {
|
||||
algorithm: DeviceDehydrationAlgorithm,
|
||||
device_pickle: String,
|
||||
}
|
||||
|
||||
impl TryFrom<Helper> for DehydratedDeviceData {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn try_from(value: Helper) -> Result<Self, Self::Error> {
|
||||
match value.algorithm {
|
||||
DeviceDehydrationAlgorithm::V1 => Ok(DehydratedDeviceData::V1(DehydratedDeviceV1 {
|
||||
device_pickle: value.device_pickle,
|
||||
})),
|
||||
_ => Err(serde::de::Error::custom("Unsupported device dehydration algorithm.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DehydratedDeviceData> for Helper {
|
||||
fn from(value: DehydratedDeviceData) -> Self {
|
||||
let algorithm = value.algorithm();
|
||||
|
||||
match value {
|
||||
DehydratedDeviceData::V1(d) => Self { algorithm, device_pickle: d.device_pickle },
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
//! `DELETE /_matrix/client/*/dehydrated_device/`
|
||||
//!
|
||||
//! Delete a dehydrated device.
|
||||
|
||||
pub mod unstable {
|
||||
//! `msc3814` ([MSC])
|
||||
//!
|
||||
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3814
|
||||
|
||||
use ruma_common::{
|
||||
api::{request, response, Metadata},
|
||||
metadata, OwnedDeviceId,
|
||||
};
|
||||
|
||||
const METADATA: Metadata = metadata! {
|
||||
method: DELETE,
|
||||
rate_limited: false,
|
||||
authentication: AccessToken,
|
||||
history: {
|
||||
unstable => "/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device",
|
||||
}
|
||||
};
|
||||
|
||||
/// Request type for the `DELETE` `dehydrated_device` endpoint.
|
||||
#[request(error = crate::Error)]
|
||||
pub struct Request {}
|
||||
|
||||
/// Request type for the `DELETE` `dehydrated_device` endpoint.
|
||||
#[response(error = crate::Error)]
|
||||
pub struct Response {
|
||||
/// The unique ID of the device that was deleted.
|
||||
pub device_id: OwnedDeviceId,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Creates a new empty `Request`.
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Creates a new `Response` with the given device ID.
|
||||
pub fn new(device_id: OwnedDeviceId) -> Self {
|
||||
Self { device_id }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
//! `GET /_matrix/client/*/dehydrated_device/`
|
||||
//!
|
||||
//! Get a dehydrated device for rehydration.
|
||||
|
||||
pub mod unstable {
|
||||
//! `msc3814` ([MSC])
|
||||
//!
|
||||
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3814
|
||||
|
||||
use ruma_common::{
|
||||
api::{request, response, Metadata},
|
||||
metadata,
|
||||
serde::Raw,
|
||||
OwnedDeviceId,
|
||||
};
|
||||
|
||||
use crate::dehydrated_device::DehydratedDeviceData;
|
||||
|
||||
const METADATA: Metadata = metadata! {
|
||||
method: GET,
|
||||
rate_limited: false,
|
||||
authentication: AccessToken,
|
||||
history: {
|
||||
unstable => "/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device",
|
||||
}
|
||||
};
|
||||
|
||||
/// Request type for the `GET` `dehydrated_device` endpoint.
|
||||
#[request(error = crate::Error)]
|
||||
pub struct Request {}
|
||||
|
||||
/// Request type for the `GET` `dehydrated_device` endpoint.
|
||||
#[response(error = crate::Error)]
|
||||
pub struct Response {
|
||||
/// The unique ID of the device.
|
||||
pub device_id: OwnedDeviceId,
|
||||
/// Information about the device.
|
||||
pub device_data: Raw<DehydratedDeviceData>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Creates a new empty `Request`.
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Creates a new `Response` with the given device ID and device data.
|
||||
pub fn new(device_id: OwnedDeviceId, device_data: Raw<DehydratedDeviceData>) -> Self {
|
||||
Self { device_id, device_data }
|
||||
}
|
||||
}
|
||||
}
|
65
crates/ruma-client-api/src/dehydrated_device/get_events.rs
Normal file
65
crates/ruma-client-api/src/dehydrated_device/get_events.rs
Normal file
@ -0,0 +1,65 @@
|
||||
//! `POST /_matrix/client/*/dehydrated_device/{device_id}/events`
|
||||
//!
|
||||
//! Get to-device events for a dehydrated device.
|
||||
|
||||
pub mod unstable {
|
||||
//! `msc3814` ([MSC])
|
||||
//!
|
||||
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3814
|
||||
|
||||
use ruma_common::{
|
||||
api::{request, response, Metadata},
|
||||
events::AnyToDeviceEvent,
|
||||
metadata,
|
||||
serde::Raw,
|
||||
OwnedDeviceId,
|
||||
};
|
||||
|
||||
const METADATA: Metadata = metadata! {
|
||||
method: POST,
|
||||
rate_limited: false,
|
||||
authentication: AccessToken,
|
||||
history: {
|
||||
unstable => "/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/:device_id/events",
|
||||
}
|
||||
};
|
||||
|
||||
/// Request type for the `dehydrated_device/{device_id}/events` endpoint.
|
||||
#[request(error = crate::Error)]
|
||||
pub struct Request {
|
||||
/// The unique ID of the device for which we would like to fetch events.
|
||||
#[ruma_api(path)]
|
||||
pub device_id: OwnedDeviceId,
|
||||
/// A point in time to continue getting events from.
|
||||
///
|
||||
/// Should be a token from the `next_batch` field of a previous `/events`
|
||||
/// request.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub next_batch: Option<String>,
|
||||
}
|
||||
|
||||
/// Request type for the `dehydrated_device/{device_id}/events` endpoint.
|
||||
#[response(error = crate::Error)]
|
||||
pub struct Response {
|
||||
/// The batch token to supply in the `since` param of the next `/events` request. Will be
|
||||
/// none if no further events can be found.
|
||||
pub next_batch: Option<String>,
|
||||
|
||||
/// Messages sent directly between devices.
|
||||
pub events: Vec<Raw<AnyToDeviceEvent>>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Create a new request.
|
||||
pub fn new(device_id: OwnedDeviceId) -> Self {
|
||||
Self { device_id, next_batch: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Create a new response with the given events.
|
||||
pub fn new(events: Vec<Raw<AnyToDeviceEvent>>) -> Self {
|
||||
Self { next_batch: None, events }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
//! `PUT /_matrix/client/*/dehydrated_device/`
|
||||
//!
|
||||
//! Uploads a dehydrated device to the homeserver.
|
||||
|
||||
pub mod unstable {
|
||||
//! `msc3814` ([MSC])
|
||||
//!
|
||||
//! [MSC]: https://github.com/matrix-org/matrix-spec-proposals/pull/3814
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruma_common::{
|
||||
api::{request, response, Metadata},
|
||||
encryption::{DeviceKeys, OneTimeKey},
|
||||
metadata,
|
||||
serde::Raw,
|
||||
OwnedDeviceId, OwnedDeviceKeyId,
|
||||
};
|
||||
|
||||
use crate::dehydrated_device::DehydratedDeviceData;
|
||||
|
||||
const METADATA: Metadata = metadata! {
|
||||
method: PUT,
|
||||
rate_limited: false,
|
||||
authentication: AccessToken,
|
||||
history: {
|
||||
unstable => "/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device",
|
||||
}
|
||||
};
|
||||
|
||||
/// Request type for the `PUT` `dehydrated_device` endpoint.
|
||||
#[request(error = crate::Error)]
|
||||
pub struct Request {
|
||||
/// The unique ID of the device.
|
||||
pub device_id: OwnedDeviceId,
|
||||
|
||||
/// The display name of the device.
|
||||
pub initial_device_display_name: Option<String>,
|
||||
|
||||
/// The data of the dehydrated device, containing the serialized and encrypted private
|
||||
/// parts of the [`DeviceKeys`].
|
||||
pub device_data: Raw<DehydratedDeviceData>,
|
||||
|
||||
/// Identity keys for the dehydrated device.
|
||||
pub device_keys: Raw<DeviceKeys>,
|
||||
|
||||
/// One-time public keys for "pre-key" messages.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub one_time_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
|
||||
|
||||
/// Fallback public keys for "pre-key" messages.
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub fallback_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
|
||||
}
|
||||
|
||||
/// Response type for the `upload_keys` endpoint.
|
||||
#[response(error = crate::Error)]
|
||||
pub struct Response {
|
||||
/// The unique ID of the device.
|
||||
pub device_id: OwnedDeviceId,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Creates a new Request.
|
||||
pub fn new(
|
||||
device_id: OwnedDeviceId,
|
||||
device_data: Raw<DehydratedDeviceData>,
|
||||
device_keys: Raw<DeviceKeys>,
|
||||
) -> Self {
|
||||
Self {
|
||||
device_id,
|
||||
device_data,
|
||||
device_keys,
|
||||
initial_device_display_name: None,
|
||||
one_time_keys: Default::default(),
|
||||
fallback_keys: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Creates a new `Response` with the given one time key counts.
|
||||
pub fn new(device_id: OwnedDeviceId) -> Self {
|
||||
Self { device_id }
|
||||
}
|
||||
}
|
||||
}
|
@ -15,6 +15,8 @@ pub mod appservice;
|
||||
pub mod backup;
|
||||
pub mod config;
|
||||
pub mod context;
|
||||
#[cfg(feature = "unstable-msc3814")]
|
||||
pub mod dehydrated_device;
|
||||
pub mod device;
|
||||
pub mod directory;
|
||||
pub mod discovery;
|
||||
|
@ -181,6 +181,7 @@ unstable-msc3554 = ["ruma-common/unstable-msc3554"]
|
||||
unstable-msc3575 = ["ruma-client-api?/unstable-msc3575"]
|
||||
unstable-msc3618 = ["ruma-federation-api?/unstable-msc3618"]
|
||||
unstable-msc3723 = ["ruma-federation-api?/unstable-msc3723"]
|
||||
unstable-msc3814 = ["ruma-client-api?/unstable-msc3814"]
|
||||
unstable-msc3927 = ["ruma-common/unstable-msc3927"]
|
||||
unstable-msc3931 = ["ruma-common/unstable-msc3931"]
|
||||
unstable-msc3932 = ["ruma-common/unstable-msc3932"]
|
||||
@ -222,6 +223,7 @@ __ci = [
|
||||
"unstable-msc3575",
|
||||
"unstable-msc3618",
|
||||
"unstable-msc3723",
|
||||
"unstable-msc3814",
|
||||
"unstable-msc3927",
|
||||
"unstable-msc3932",
|
||||
"unstable-msc3954",
|
||||
|
Loading…
x
Reference in New Issue
Block a user