palpo_core/federation/
key.rs

1/// Endpoints for handling keys for end-to-end encryption
2
3/// `POST /_matrix/federation/*/user/keys/claim`
4///
5/// Claim one-time keys for use in pre-key messages.
6/// `/v1/` ([spec])
7///
8/// [spec]: https://spec.matrix.org/latest/server-server-api/#post_matrixfederationv1userkeysclaim
9use std::collections::BTreeMap;
10use std::time::Duration;
11
12use reqwest::Url;
13use salvo::prelude::*;
14use serde::{Deserialize, Serialize};
15
16use crate::encryption::OneTimeKey;
17use crate::encryption::{CrossSigningKey, DeviceKeys};
18use crate::sending::{SendRequest, SendResult};
19use crate::serde::Base64;
20use crate::{DeviceKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId, OwnedUserId};
21
22pub fn get_server_key_request(origin: &str) -> SendResult<SendRequest> {
23    let url = Url::parse(&format!("{origin}/_matrix/key/v2/server"))?;
24    Ok(crate::sending::get(url))
25}
26
27// const METADATA: Metadata = metadata! {
28//     method: POST,
29//     rate_limited: false,
30//     authentication: ServerSignatures,
31//     history: {
32//         1.0 => "/_matrix/federation/v1/user/keys/claim",
33//     }
34// };
35
36// pub fn claim_keys_request(txn_id: &str, body: ClaimKeysReqBody) -> SendRequest {
37//     let url = registration
38//         .build_url(&format!("/app/v1/transactions/{}", txn_id))
39//     crate::sending::post(url)
40//         .stuff(req_body)
41// }
42
43pub fn claim_keys_request(origin: &str, body: ClaimKeysReqBody) -> SendResult<SendRequest> {
44    let url = Url::parse(&format!("{origin}/_matrix/client/v1/user/keys/claim"))?;
45    crate::sending::post(url).stuff(body)
46}
47
48/// Request type for the `claim_keys` endpoint.
49#[derive(ToSchema, Deserialize, Serialize, Debug)]
50pub struct ClaimKeysReqBody {
51    #[serde(
52        with = "crate::serde::duration::opt_ms",
53        default,
54        skip_serializing_if = "Option::is_none"
55    )]
56    pub timeout: Option<Duration>,
57
58    /// The keys to be claimed.
59    #[salvo(schema(value_type = Object, additional_properties = true))]
60    pub one_time_keys: OneTimeKeyClaims,
61}
62crate::json_body_modifier!(ClaimKeysReqBody);
63
64/// Response type for the `claim_keys` endpoint.
65#[derive(ToSchema, Deserialize, Serialize, Debug)]
66
67pub struct ClaimKeysResBody {
68    /// One-time keys for the queried devices
69    #[salvo(schema(value_type = Object, additional_properties = true))]
70    pub one_time_keys: OneTimeKeys,
71}
72impl ClaimKeysResBody {
73    /// Creates a new `Response` with the given one time keys.
74    pub fn new(one_time_keys: OneTimeKeys) -> Self {
75        Self { one_time_keys }
76    }
77}
78
79/// A claim for one time keys
80pub type OneTimeKeyClaims = BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>>;
81
82/// One time keys for use in pre-key messages
83pub type OneTimeKeys = BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, BTreeMap<OwnedDeviceKeyId, OneTimeKey>>>;
84
85/// A key and its signature
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct KeyObject {
88    /// The key, encoded using unpadded base64.
89    pub key: Base64,
90
91    /// Signature of the key object.
92    pub signatures: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceKeyId, String>>,
93}
94
95impl KeyObject {
96    /// Creates a new `KeyObject` with the given key and signatures.
97    pub fn new(key: Base64, signatures: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceKeyId, String>>) -> Self {
98        Self { key, signatures }
99    }
100}
101
102/// `POST /_matrix/federation/*/user/keys/query`
103///
104/// Get the current devices and identity keys for the given users.
105/// `/v1/` ([spec])
106///
107/// [spec]: https://spec.matrix.org/latest/server-server-api/#post_matrixfederationv1userkeysquery
108// const METADATA: Metadata = metadata! {
109//     method: POST,
110//     rate_limited: false,
111//     authentication: ServerSignatures,
112//     history: {
113//         1.0 => "/_matrix/federation/v1/user/keys/query",
114//     }
115// };
116
117pub fn query_keys_request(origin: &str, body: QueryKeysReqBody) -> SendResult<SendRequest> {
118    let url = Url::parse(&format!("{origin}/_matrix/federation/v1/user/keys/query"))?;
119    crate::sending::post(url).stuff(body)
120}
121
122/// Request type for the `get_keys` endpoint.
123
124#[derive(ToSchema, Deserialize, Serialize, Debug)]
125pub struct QueryKeysReqBody {
126    /// The keys to be downloaded.
127    ///
128    /// Gives all keys for a given user if the list of device ids is empty.
129    pub device_keys: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>>,
130}
131crate::json_body_modifier!(QueryKeysReqBody);
132
133/// Response type for the `get_keys` endpoint.
134#[derive(ToSchema, Deserialize, Serialize, Default, Debug)]
135
136pub struct QueryKeysResBody {
137    /// Keys from the queried devices.
138    pub device_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeys>>,
139
140    /// Information on the master cross-signing keys of the queried users.
141    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
142    pub master_keys: BTreeMap<OwnedUserId, CrossSigningKey>,
143
144    /// Information on the self-signing keys of the queried users.
145    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
146    pub self_signing_keys: BTreeMap<OwnedUserId, CrossSigningKey>,
147}
148impl QueryKeysResBody {
149    /// Creates a new `Response` with the given device keys.
150    pub fn new(device_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeys>>) -> Self {
151        Self {
152            device_keys,
153            ..Default::default()
154        }
155    }
156}