Add unstable backup and keys/upload_signing/signature endpoints

Co-authored-by: Timo Kosters <timo@koesters.xyz>
This commit is contained in:
Ragotzy.devin 2020-07-15 09:53:35 -04:00 committed by GitHub
parent 7cfec8631a
commit 24b0068213
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 383 additions and 0 deletions

View File

@ -31,3 +31,6 @@ strum = { version = "0.18.0", features = ["derive"] }
[dev-dependencies]
maplit = "1.0.2"
matches = "0.1.8"
[features]
unstable-pre-spec = []

View File

@ -3,6 +3,8 @@
pub mod account;
pub mod alias;
pub mod appservice;
#[cfg(feature = "unstable-pre-spec")]
pub mod backup;
pub mod capabilities;
pub mod config;
pub mod contact;

View File

@ -0,0 +1,53 @@
//! Endpoints for server-side key backups.
pub mod add_backup_keys;
pub mod create_backup;
pub mod get_backup;
pub mod get_backup_keys;
pub mod get_latest_backup;
pub mod update_backup;
use js_int::UInt;
use ruma_identifiers::UserId;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::r0::keys::AlgorithmAndDeviceId;
/// The algorithm used for storing backups.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "algorithm", content = "auth_data")]
pub enum BackupAlgorithm {
/// `m.megolm_backup.v1.curve25519-aes-sha2` backup algorithm.
#[serde(rename = "m.megolm_backup.v1.curve25519-aes-sha2")]
MegolmBackupV1Curve25519AesSha2 {
/// The curve25519 public key used to encrypt the backups, encoded in unpadded base64.
public_key: String,
/// Signatures of the auth_data as Signed JSON.
signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
},
}
/// The key data.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KeyData {
/// The index of the first message in the session that the key can decrypt.
first_message_index: UInt,
/// The number of times this key has been forwarded via key-sharing between devices.
forwarded_count: UInt,
/// Whether the device backing up the key verified the device that the key is from.
is_verified: bool,
/// Data about the session.
session_data: SessionData,
}
/// The algorithm used for storing backups.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SessionData {
/// Unpadded base64-encoded public half of the ephemeral key.
ephemeral: String,
/// Ciphertext, encrypted using AES-CBC-256 with PKCS#7 padding, encoded in base64.
ciphertext: String,
/// First 8 bytes of MAC key, encoded in base64.
mac: String,
}

View File

@ -0,0 +1,52 @@
//! [PUT /_matrix/client/r0/room_keys/keys](https://matrix.org/docs/spec/client_server/unstable#put-matrix-client-r0-room-keys-keys)
use std::collections::BTreeMap;
use js_int::UInt;
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};
use super::KeyData;
ruma_api! {
metadata: {
description: "Store several keys in the backup.",
method: PUT,
name: "add_backup_keys",
path: "/_matrix/client/r0/room_keys/keys",
rate_limited: true,
requires_authentication: true,
}
request: {
/// The backup version. Must be the current backup.
#[ruma_api(query)]
pub version: String,
/// A map from room IDs to session IDs to key data.
///
/// Note: synapse has the `sessions: {}` wrapper, the Matrix spec does not.
pub rooms: BTreeMap<RoomId, Sessions>,
}
response: {
/// An opaque string representing stored keys in the backup. Clients can compare it with
/// the etag value they received in the request of their last key storage request.
pub etag: String,
/// The number of keys stored in the backup.
pub count: UInt,
}
error: crate::Error
}
// TODO: remove
/// A wrapper around a mapping of session IDs to key data.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Sessions {
// TODO: remove
/// A map of session IDs to key data.
pub sessions: BTreeMap<String, KeyData>,
}

View File

@ -0,0 +1,27 @@
//! [POST /_matrix/client/r0/room_keys/version](https://matrix.org/docs/spec/client_server/unstable#post-matrix-client-r0-room-keys-version)
use ruma_api::ruma_api;
ruma_api! {
metadata: {
description: "Creates a new backup.",
method: POST,
name: "create_backup",
path: "/_matrix/client/r0/room_keys/version",
rate_limited: true,
requires_authentication: true,
}
request: {
/// The algorithm used for storing backups.
#[serde(flatten)]
pub algorithm: super::BackupAlgorithm,
}
response: {
/// The backup version. This is an opaque string.
pub version: String,
}
error: crate::Error
}

View File

@ -0,0 +1,39 @@
//! [GET /_matrix/client/r0/room_keys/version](https://matrix.org/docs/spec/client_server/unstable#post-matrix-client-r0-room-keys-version)
use js_int::UInt;
use ruma_api::ruma_api;
ruma_api! {
metadata: {
description: "Get information about an existing backup.",
method: GET,
name: "get_backup",
path: "/_matrix/client/r0/room_keys/version/:version",
rate_limited: true,
requires_authentication: true,
}
request: {
/// The backup version.
#[ruma_api(path)]
pub version: String,
}
response: {
/// The algorithm used for storing backups.
#[serde(flatten)]
pub algorithm: super::BackupAlgorithm,
/// The number of keys stored in the backup.
pub count: UInt,
/// An opaque string representing stored keys in the backup. Clients can compare it with
/// the etag value they received in the request of their last key storage request.
pub etag: String,
/// The backup version. This is an opaque string.
pub version: String,
}
error: crate::Error
}

View File

@ -0,0 +1,44 @@
//! [GET /_matrix/client/r0/room_keys/keys](https://matrix.org/docs/spec/client_server/unstable#get-matrix-client-r0-room-keys-keys)
use std::collections::BTreeMap;
use ruma_api::ruma_api;
use ruma_identifiers::RoomId;
use serde::{Deserialize, Serialize};
use super::KeyData;
ruma_api! {
metadata: {
description: "Retrieve all keys from a backup.",
method: GET,
name: "get_backup_keys",
path: "/_matrix/client/r0/room_keys/keys",
rate_limited: true,
requires_authentication: true,
}
request: {
/// The backup version. Must be the current backup.
#[ruma_api(query)]
pub version: String,
}
response: {
/// A map from room IDs to session IDs to key data.
///
/// Note: synapse has the `sessions: {}` wrapper, the Matrix spec does not.
pub rooms: BTreeMap<RoomId, Sessions>,
}
error: crate::Error
}
// TODO: remove
/// A wrapper around a mapping of session IDs to key data.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Sessions {
// TODO: remove
/// A map of session IDs to key data.
pub sessions: BTreeMap<String, KeyData>,
}

View File

@ -0,0 +1,35 @@
//! [GET /_matrix/client/r0/room_keys/version](https://matrix.org/docs/spec/client_server/unstable#post-matrix-client-r0-room-keys-version)
use js_int::UInt;
use ruma_api::ruma_api;
ruma_api! {
metadata: {
description: "Get information about the latest backup.",
method: GET,
name: "get_latest_backup",
path: "/_matrix/client/r0/room_keys/version",
rate_limited: true,
requires_authentication: true,
}
request: {}
response: {
/// The algorithm used for storing backups.
#[serde(flatten)]
pub algorithm: super::BackupAlgorithm,
/// The number of keys stored in the backup.
pub count: UInt,
/// An opaque string represetning stored keys in the backup. Clients can compare it with
/// the etag value they received in the request of their last key storage request.
pub etag: String,
/// The backup version. This is an opaque string.
pub version: String,
}
error: crate::Error
}

View File

@ -0,0 +1,28 @@
//! [POST /_matrix/client/r0/room_keys/version](https://matrix.org/docs/spec/client_server/unstable#post-matrix-client-r0-room-keys-version)
use ruma_api::ruma_api;
ruma_api! {
metadata: {
description: "Update information about an existing backup.",
method: POST,
name: "update_backup",
path: "/_matrix/client/r0/room_keys/version/:version",
rate_limited: true,
requires_authentication: true,
}
request: {
/// The backup version.
#[ruma_api(path)]
pub version: String,
/// The algorithm used for storing backups.
#[serde(flatten)]
pub algorithm: super::BackupAlgorithm,
}
response: {}
error: crate::Error
}

View File

@ -18,6 +18,11 @@ pub mod get_key_changes;
pub mod get_keys;
pub mod upload_keys;
#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signatures;
#[cfg(feature = "unstable-pre-spec")]
pub mod upload_signing_keys;
/// The basic key algorithms in the specification
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum KeyAlgorithm {
@ -161,3 +166,29 @@ pub enum OneTimeKey {
/// A string-valued key, for the Ed25519 and Curve25519 algorithms.
Key(String),
}
/// A cross signing key.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CrossSigningKey {
/// The ID of the user the key belongs to.
pub user_id: UserId,
/// What the key is used for.
pub usage: Vec<KeyUsage>,
/// The public key. The object must have exactly one property.
pub keys: BTreeMap<String, String>,
/// Signatures of the key. Only optional for master key.
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub signatures: BTreeMap<UserId, BTreeMap<String, String>>,
}
/// The usage of a cross signing key.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
/// Master key.
Master,
/// Self-signing key.
SelfSigning,
/// User-signing key.
UserSigning,
}

View File

@ -0,0 +1,27 @@
//! [POST /_matrix/client/r0/keys/signatures/upload](https://13301-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-signatures-upload)
use std::collections::BTreeMap;
use ruma_api::ruma_api;
use ruma_identifiers::UserId;
ruma_api! {
metadata: {
description: "Publishes cross-signing signatures for the user.",
method: POST,
name: "upload_signatures",
path: "/_matrix/client/r0/keys/signatures/upload",
rate_limited: false,
requires_authentication: true,
}
request: {
/// Signed keys.
#[ruma_api(body)]
pub signed_keys: BTreeMap<UserId, BTreeMap<String, serde_json::Value>>,
}
response: {}
error: crate::Error
}

View File

@ -0,0 +1,41 @@
//! [POST /_matrix/client/r0/keys/device_signing/upload](https://13301-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-device-signing-upload)
use ruma_api::ruma_api;
use super::CrossSigningKey;
use crate::r0::uiaa::AuthData;
ruma_api! {
metadata: {
description: "Publishes cross signing keys for the user.",
method: POST,
name: "upload_signing_keys",
path: "/_matrix/client/r0/keys/device_signing/upload",
rate_limited: false,
requires_authentication: true,
}
request: {
/// Additional authentication information for the user-interactive authentication API.
#[serde(skip_serializing_if = "Option::is_none")]
pub auth: Option<AuthData>,
/// The user's master key.
#[serde(skip_serializing_if = "Option::is_none")]
pub master_key: Option<CrossSigningKey>,
/// The user's self-signing key. Must be signed with the accompanied master, or by the
/// user's most recently uploaded master key if no master key is included in the request.
#[serde(skip_serializing_if = "Option::is_none")]
pub self_signing_key: Option<CrossSigningKey>,
/// The user's user-signing key. Must be signed with the accompanied master, or by the
/// user's most recently uploaded master key if no master key is included in the request.
#[serde(skip_serializing_if = "Option::is_none")]
pub user_signing_key: Option<CrossSigningKey>,
}
response: {}
error: crate::Error
}

View File

@ -15,6 +15,7 @@ edition = "2018"
[features]
either = ["ruma-identifiers/either"]
rand = ["ruma-identifiers/rand"]
unstable-pre-spec = ["ruma-client-api/unstable-pre-spec"]
appservice-api = ["ruma-api", "ruma-appservice-api", "ruma-events"]
client-api = ["ruma-api", "ruma-client-api", "ruma-events"]