Add endpoints for key management
This commit is contained in:
parent
c0e8e3a84c
commit
bc03dc6f2e
@ -20,6 +20,7 @@ Improvements:
|
||||
* Add `r0::room::get_room_event` (introduced in r0.4.0)
|
||||
* Add `r0::read_marker::set_read_marker` (introduced in r0.4.0)
|
||||
* Add `r0::capabilities::get_capabilities` (introduced in r0.5.0)
|
||||
* Add `r0::keys` endpoints (introduced in r0.3.0)
|
||||
|
||||
# 0.5.0
|
||||
|
||||
|
@ -10,6 +10,7 @@ pub mod context;
|
||||
pub mod device;
|
||||
pub mod directory;
|
||||
pub mod filter;
|
||||
pub mod keys;
|
||||
pub mod media;
|
||||
pub mod membership;
|
||||
pub mod message;
|
||||
|
152
src/r0/keys.rs
Normal file
152
src/r0/keys.rs
Normal file
@ -0,0 +1,152 @@
|
||||
//! Endpoints for key management
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::TryFrom,
|
||||
fmt::{Debug, Display, Error as FmtError, Formatter},
|
||||
};
|
||||
|
||||
use ruma_events::Algorithm;
|
||||
use ruma_identifiers::{DeviceId, UserId};
|
||||
use serde::{
|
||||
de::{self, Unexpected},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
|
||||
pub mod claim_keys;
|
||||
pub mod get_key_changes;
|
||||
pub mod get_keys;
|
||||
pub mod upload_keys;
|
||||
|
||||
/// The basic key algorithms in the specification
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum KeyAlgorithm {
|
||||
/// The Ed25519 signature algorithm.
|
||||
#[serde(rename = "ed25519")]
|
||||
Ed25519,
|
||||
|
||||
/// The Curve25519 ECDH algorithm.
|
||||
#[serde(rename = "curve25519")]
|
||||
Curve25519,
|
||||
|
||||
/// The Curve25519 ECDH algorithm, but the key also contains signatures
|
||||
#[serde(rename = "signed_curve25519")]
|
||||
SignedCurve25519,
|
||||
}
|
||||
|
||||
impl Display for KeyAlgorithm {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
let algorithm_str = match *self {
|
||||
KeyAlgorithm::Ed25519 => "ed25519",
|
||||
KeyAlgorithm::Curve25519 => "curve25519",
|
||||
KeyAlgorithm::SignedCurve25519 => "signed_curve25519",
|
||||
};
|
||||
write!(f, "{}", algorithm_str)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&'_ str> for KeyAlgorithm {
|
||||
type Error = &'static str;
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
match s {
|
||||
"ed25519" => Ok(KeyAlgorithm::Ed25519),
|
||||
"curve25519" => Ok(KeyAlgorithm::Curve25519),
|
||||
"signed_curve25519" => Ok(KeyAlgorithm::SignedCurve25519),
|
||||
_ => Err("Unknown algorithm"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A key algorithm and a device id, combined with a ':'
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct AlgorithmAndDeviceId(pub KeyAlgorithm, pub DeviceId);
|
||||
|
||||
impl Serialize for AlgorithmAndDeviceId {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let s = format!("{}:{}", self.0, self.1);
|
||||
serializer.serialize_str(&s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for AlgorithmAndDeviceId {
|
||||
#[allow(clippy::comparison_chain)]
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = String::deserialize(deserializer)?;
|
||||
let parts = value.split(':').collect::<Vec<_>>();
|
||||
|
||||
const EXPECTED: &str = "a string composed of an algorithm and a device id separated by ':'";
|
||||
|
||||
if parts.len() < 2 {
|
||||
return Err(de::Error::invalid_type(
|
||||
Unexpected::Other("string without a ':' separator"),
|
||||
&EXPECTED,
|
||||
));
|
||||
} else if parts.len() > 2 {
|
||||
return Err(de::Error::invalid_type(
|
||||
Unexpected::Other("string with more than one ':' separator"),
|
||||
&EXPECTED,
|
||||
));
|
||||
}
|
||||
|
||||
let algorithm_result = KeyAlgorithm::try_from(parts[0]);
|
||||
match algorithm_result {
|
||||
Ok(algorithm) => Ok(AlgorithmAndDeviceId(algorithm, parts[1].to_string())),
|
||||
Err(_) => Err(de::Error::invalid_value(
|
||||
Unexpected::Str(parts[0]),
|
||||
&"valid key algorithm",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Identity keys for a device.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DeviceKeys {
|
||||
/// The ID of the user the device belongs to. Must match the user ID used when logging in.
|
||||
pub user_id: UserId,
|
||||
/// The ID of the device these keys belong to. Must match the device ID used when logging in.
|
||||
pub device_id: DeviceId,
|
||||
/// The encryption algorithms supported by this device.
|
||||
pub algorithms: Vec<Algorithm>,
|
||||
/// Public identity keys.
|
||||
pub keys: HashMap<AlgorithmAndDeviceId, String>,
|
||||
/// Signatures for the device key object.
|
||||
pub signatures: HashMap<UserId, HashMap<AlgorithmAndDeviceId, String>>,
|
||||
/// Additional data added to the device key information by intermediate servers, and
|
||||
/// not covered by the signatures.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub unsigned: Option<UnsignedDeviceInfo>,
|
||||
}
|
||||
|
||||
/// Additional data added to device key information by intermediate servers.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UnsignedDeviceInfo {
|
||||
/// The display name which the user set on the device.
|
||||
device_display_name: String,
|
||||
}
|
||||
|
||||
/// A key for the SignedCurve25519 algorithm
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignedKey {
|
||||
/// Base64-encoded 32-byte Curve25519 public key.
|
||||
pub key: String,
|
||||
/// Signatures for the key object.
|
||||
pub signatures: HashMap<UserId, HashMap<AlgorithmAndDeviceId, String>>,
|
||||
}
|
||||
|
||||
/// A one-time public key for "pre-key" messages.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum OneTimeKey {
|
||||
/// A key containing signatures, for the SignedCurve25519 algorithm.
|
||||
SignedKey(SignedKey),
|
||||
/// A string-valued key, for the Ed25519 and Curve25519 algorithms.
|
||||
Key(String),
|
||||
}
|
40
src/r0/keys/claim_keys.rs
Normal file
40
src/r0/keys/claim_keys.rs
Normal file
@ -0,0 +1,40 @@
|
||||
//! [POST /_matrix/client/r0/keys/claim](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-claim)
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_identifiers::{DeviceId, UserId};
|
||||
use serde_json::Value;
|
||||
|
||||
use super::{AlgorithmAndDeviceId, KeyAlgorithm, OneTimeKey};
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Claims one-time keys for use in pre-key messages.",
|
||||
method: POST,
|
||||
name: "claim_keys",
|
||||
path: "/_matrix/client/r0/keys/claim",
|
||||
rate_limited: false,
|
||||
requires_authentication: true,
|
||||
}
|
||||
|
||||
request {
|
||||
/// The time (in milliseconds) to wait when downloading keys from remote servers.
|
||||
/// 10 seconds is the recommended default.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timeout: Option<UInt>,
|
||||
|
||||
/// The keys to be claimed.
|
||||
pub one_time_keys: HashMap<UserId, HashMap<DeviceId, KeyAlgorithm>>,
|
||||
}
|
||||
|
||||
response {
|
||||
/// If any remote homeservers could not be reached, they are recorded here.
|
||||
/// The names of the properties are the names of the unreachable servers.
|
||||
pub failures: HashMap<String, Value>,
|
||||
|
||||
/// One-time keys for the queried devices.
|
||||
pub one_time_keys: HashMap<UserId, HashMap<DeviceId, HashMap<AlgorithmAndDeviceId, OneTimeKey>>>,
|
||||
}
|
||||
}
|
36
src/r0/keys/get_key_changes.rs
Normal file
36
src/r0/keys/get_key_changes.rs
Normal file
@ -0,0 +1,36 @@
|
||||
//! [GET /_matrix/client/r0/keys/changes](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-keys-changes)
|
||||
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_identifiers::UserId;
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Gets a list of users who have updated their device identity keys since a previous sync token.",
|
||||
method: GET,
|
||||
name: "get_key_changes",
|
||||
path: "/_matrix/client/r0/keys/changes",
|
||||
rate_limited: false,
|
||||
requires_authentication: true,
|
||||
}
|
||||
|
||||
request {
|
||||
/// The desired start point of the list.
|
||||
/// Should be the next_batch field from a response to an earlier call to /sync.
|
||||
#[ruma_api(query)]
|
||||
pub from: String,
|
||||
|
||||
/// The desired end point of the list.
|
||||
/// Should be the next_batch field from a recent call to /sync - typically the most recent such call.
|
||||
#[ruma_api(query)]
|
||||
pub to: String,
|
||||
}
|
||||
|
||||
response {
|
||||
/// The Matrix User IDs of all users who updated their device identity keys.
|
||||
pub changed: Vec<UserId>,
|
||||
|
||||
/// The Matrix User IDs of all users who may have left all the end-to-end
|
||||
/// encrypted rooms they previously shared with the user.
|
||||
pub left: Vec<UserId>
|
||||
}
|
||||
}
|
46
src/r0/keys/get_keys.rs
Normal file
46
src/r0/keys/get_keys.rs
Normal file
@ -0,0 +1,46 @@
|
||||
//! [POST /_matrix/client/r0/keys/query](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-query)
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_api::ruma_api;
|
||||
use ruma_identifiers::{DeviceId, UserId};
|
||||
use serde_json::Value;
|
||||
|
||||
use super::DeviceKeys;
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Returns the current devices and identity keys for the given users.",
|
||||
method: POST,
|
||||
name: "get_keys",
|
||||
path: "/_matrix/client/r0/keys/query",
|
||||
rate_limited: false,
|
||||
requires_authentication: true,
|
||||
}
|
||||
|
||||
request {
|
||||
/// The time (in milliseconds) to wait when downloading keys from remote servers.
|
||||
/// 10 seconds is the recommended default.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub timeout: Option<UInt>,
|
||||
|
||||
/// The keys to be downloaded. An empty list indicates all devices for the corresponding user.
|
||||
pub device_keys: HashMap<UserId, Vec<DeviceId>>,
|
||||
|
||||
/// If the client is fetching keys as a result of a device update received in a sync request,
|
||||
/// this should be the 'since' token of that sync request, or any later sync token.
|
||||
/// This allows the server to ensure its response contains the keys advertised by the notification in that sync.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub token: Option<String>
|
||||
}
|
||||
|
||||
response {
|
||||
/// If any remote homeservers could not be reached, they are recorded here.
|
||||
/// The names of the properties are the names of the unreachable servers.
|
||||
pub failures: HashMap<String, Value>,
|
||||
|
||||
/// Information on the queried devices.
|
||||
pub device_keys: HashMap<UserId, HashMap<DeviceId, DeviceKeys>>,
|
||||
}
|
||||
}
|
35
src/r0/keys/upload_keys.rs
Normal file
35
src/r0/keys/upload_keys.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! [POST /_matrix/client/r0/keys/upload](https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-keys-upload)
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use js_int::UInt;
|
||||
use ruma_api::ruma_api;
|
||||
|
||||
use super::{AlgorithmAndDeviceId, DeviceKeys, KeyAlgorithm, OneTimeKey};
|
||||
|
||||
ruma_api! {
|
||||
metadata {
|
||||
description: "Publishes end-to-end encryption keys for the device.",
|
||||
method: POST,
|
||||
name: "upload_keys",
|
||||
path: "/_matrix/client/r0/keys/upload",
|
||||
rate_limited: false,
|
||||
requires_authentication: true,
|
||||
}
|
||||
|
||||
request {
|
||||
/// Identity keys for the device. May be absent if no new identity keys are required.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub device_keys: Option<DeviceKeys>,
|
||||
|
||||
/// One-time public keys for "pre-key" messages.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub one_time_keys: Option<HashMap<AlgorithmAndDeviceId, OneTimeKey>>,
|
||||
}
|
||||
|
||||
response {
|
||||
/// For each key algorithm, the number of unclaimed one-time keys of that
|
||||
/// type currently held on the server for this device.
|
||||
pub one_time_key_counts: HashMap<KeyAlgorithm, UInt>
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user