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-msc2967 = []
|
||||||
unstable-msc3488 = []
|
unstable-msc3488 = []
|
||||||
unstable-msc3575 = []
|
unstable-msc3575 = []
|
||||||
|
unstable-msc3814 = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
assign = { workspace = true }
|
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 backup;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
|
#[cfg(feature = "unstable-msc3814")]
|
||||||
|
pub mod dehydrated_device;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod directory;
|
pub mod directory;
|
||||||
pub mod discovery;
|
pub mod discovery;
|
||||||
|
@ -181,6 +181,7 @@ unstable-msc3554 = ["ruma-common/unstable-msc3554"]
|
|||||||
unstable-msc3575 = ["ruma-client-api?/unstable-msc3575"]
|
unstable-msc3575 = ["ruma-client-api?/unstable-msc3575"]
|
||||||
unstable-msc3618 = ["ruma-federation-api?/unstable-msc3618"]
|
unstable-msc3618 = ["ruma-federation-api?/unstable-msc3618"]
|
||||||
unstable-msc3723 = ["ruma-federation-api?/unstable-msc3723"]
|
unstable-msc3723 = ["ruma-federation-api?/unstable-msc3723"]
|
||||||
|
unstable-msc3814 = ["ruma-client-api?/unstable-msc3814"]
|
||||||
unstable-msc3927 = ["ruma-common/unstable-msc3927"]
|
unstable-msc3927 = ["ruma-common/unstable-msc3927"]
|
||||||
unstable-msc3931 = ["ruma-common/unstable-msc3931"]
|
unstable-msc3931 = ["ruma-common/unstable-msc3931"]
|
||||||
unstable-msc3932 = ["ruma-common/unstable-msc3932"]
|
unstable-msc3932 = ["ruma-common/unstable-msc3932"]
|
||||||
@ -222,6 +223,7 @@ __ci = [
|
|||||||
"unstable-msc3575",
|
"unstable-msc3575",
|
||||||
"unstable-msc3618",
|
"unstable-msc3618",
|
||||||
"unstable-msc3723",
|
"unstable-msc3723",
|
||||||
|
"unstable-msc3814",
|
||||||
"unstable-msc3927",
|
"unstable-msc3927",
|
||||||
"unstable-msc3932",
|
"unstable-msc3932",
|
||||||
"unstable-msc3954",
|
"unstable-msc3954",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user