matrix_sdk_crypto/types/
one_time_keys.rs1use std::collections::BTreeMap;
22
23use ruma::{serde::Raw, OneTimeKeyAlgorithm};
24use serde::{Deserialize, Deserializer, Serialize};
25use serde_json::{value::to_raw_value, Value};
26use vodozemac::Curve25519PublicKey;
27
28use super::{deserialize_curve_key, serialize_curve_key, Signatures};
29
30#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
32pub struct SignedKey {
33 #[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
35 key: Curve25519PublicKey,
36
37 signatures: Signatures,
39
40 #[serde(default, skip_serializing_if = "Option::is_none", deserialize_with = "double_option")]
42 fallback: Option<Option<bool>>,
43
44 #[serde(flatten)]
45 other: BTreeMap<String, Value>,
46}
47
48fn double_option<'de, T, D>(de: D) -> Result<Option<Option<T>>, D::Error>
49where
50 T: Deserialize<'de>,
51 D: Deserializer<'de>,
52{
53 Deserialize::deserialize(de).map(Some)
54}
55
56impl SignedKey {
57 pub fn new(key: Curve25519PublicKey) -> Self {
59 Self { key, signatures: Signatures::new(), fallback: None, other: BTreeMap::new() }
60 }
61
62 pub fn new_fallback(key: Curve25519PublicKey) -> Self {
65 Self {
66 key,
67 signatures: Signatures::new(),
68 fallback: Some(Some(true)),
69 other: BTreeMap::new(),
70 }
71 }
72
73 pub fn key(&self) -> Curve25519PublicKey {
75 self.key
76 }
77
78 pub fn signatures(&self) -> &Signatures {
80 &self.signatures
81 }
82
83 pub fn signatures_mut(&mut self) -> &mut Signatures {
85 &mut self.signatures
86 }
87
88 pub fn fallback(&self) -> bool {
90 self.fallback.map(|f| f.unwrap_or_default()).unwrap_or_default()
91 }
92
93 pub fn into_raw<T>(self) -> Raw<T> {
95 let key = OneTimeKey::SignedKey(self);
96 Raw::from_json(to_raw_value(&key).expect("Couldn't serialize one-time key"))
97 }
98}
99
100#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
102#[serde(untagged)]
103pub enum OneTimeKey {
104 SignedKey(SignedKey),
106}
107
108impl OneTimeKey {
109 pub fn deserialize(
112 algorithm: OneTimeKeyAlgorithm,
113 key: &Raw<ruma::encryption::OneTimeKey>,
114 ) -> Result<Self, serde_json::Error> {
115 match algorithm {
116 OneTimeKeyAlgorithm::SignedCurve25519 => {
117 let key: SignedKey = key.deserialize_as()?;
118 Ok(OneTimeKey::SignedKey(key))
119 }
120 _ => Err(serde::de::Error::custom(format!("Unsupported key algorithm {algorithm}"))),
121 }
122 }
123}
124
125impl OneTimeKey {
126 pub fn fallback(&self) -> bool {
128 match self {
129 OneTimeKey::SignedKey(s) => s.fallback(),
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use ruma::{device_id, user_id, DeviceKeyAlgorithm, DeviceKeyId};
137 use serde_json::json;
138 use vodozemac::{Curve25519PublicKey, Ed25519Signature};
139
140 use crate::types::{Signature, SignedKey};
141
142 #[test]
143 fn serialization() {
144 let user_id = user_id!("@user:example.com");
145 let device_id = device_id!("EGURVBUNJP");
146
147 let json = json!({
148 "key":"XjhWTCjW7l59pbfx9tlCBQolfnIQWARoKOzjTOPSlWM",
149 "signatures": {
150 user_id: {
151 "ed25519:EGURVBUNJP": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg",
152 "other:EGURVBUNJP": "UnknownSignature"
153 }
154 },
155 "extra_key": "extra_value"
156 });
157
158 let curve_key =
159 Curve25519PublicKey::from_base64("XjhWTCjW7l59pbfx9tlCBQolfnIQWARoKOzjTOPSlWM")
160 .expect("Can't construct curve key from base64");
161
162 let signature = Ed25519Signature::from_base64(
163 "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
164 ).expect("The signature can always be decoded");
165
166 let custom_signature = Signature::Other("UnknownSignature".to_owned());
167
168 let key: SignedKey =
169 serde_json::from_value(json.clone()).expect("Can't deserialize a valid one-time key");
170
171 assert_eq!(key.key(), curve_key);
172 assert_eq!(
173 key.signatures().get_signature(
174 user_id,
175 &DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, device_id)
176 ),
177 Some(signature)
178 );
179 assert_eq!(
180 key.signatures()
181 .get(user_id)
182 .unwrap()
183 .get(&DeviceKeyId::from_parts("other".into(), device_id)),
184 Some(&Ok(custom_signature))
185 );
186
187 let serialized = serde_json::to_value(key).expect("Can't reserialize a signed key");
188
189 assert_eq!(json, serialized);
190 }
191}