matrix_sdk_crypto/types/
one_time_keys.rsuse std::collections::BTreeMap;
use ruma::{serde::Raw, OneTimeKeyAlgorithm};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json::{value::to_raw_value, Value};
use vodozemac::Curve25519PublicKey;
use super::{deserialize_curve_key, serialize_curve_key, Signatures};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SignedKey {
#[serde(deserialize_with = "deserialize_curve_key", serialize_with = "serialize_curve_key")]
key: Curve25519PublicKey,
signatures: Signatures,
#[serde(default, skip_serializing_if = "Option::is_none", deserialize_with = "double_option")]
fallback: Option<Option<bool>>,
#[serde(flatten)]
other: BTreeMap<String, Value>,
}
fn double_option<'de, T, D>(de: D) -> Result<Option<Option<T>>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
Deserialize::deserialize(de).map(Some)
}
impl SignedKey {
pub fn new(key: Curve25519PublicKey) -> Self {
Self { key, signatures: Signatures::new(), fallback: None, other: BTreeMap::new() }
}
pub fn new_fallback(key: Curve25519PublicKey) -> Self {
Self {
key,
signatures: Signatures::new(),
fallback: Some(Some(true)),
other: BTreeMap::new(),
}
}
pub fn key(&self) -> Curve25519PublicKey {
self.key
}
pub fn signatures(&self) -> &Signatures {
&self.signatures
}
pub fn signatures_mut(&mut self) -> &mut Signatures {
&mut self.signatures
}
pub fn fallback(&self) -> bool {
self.fallback.map(|f| f.unwrap_or_default()).unwrap_or_default()
}
pub fn into_raw<T>(self) -> Raw<T> {
let key = OneTimeKey::SignedKey(self);
Raw::from_json(to_raw_value(&key).expect("Couldn't serialize one-time key"))
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
#[serde(untagged)]
pub enum OneTimeKey {
SignedKey(SignedKey),
}
impl OneTimeKey {
pub fn deserialize(
algorithm: OneTimeKeyAlgorithm,
key: &Raw<ruma::encryption::OneTimeKey>,
) -> Result<Self, serde_json::Error> {
match algorithm {
OneTimeKeyAlgorithm::SignedCurve25519 => {
let key: SignedKey = key.deserialize_as()?;
Ok(OneTimeKey::SignedKey(key))
}
_ => Err(serde::de::Error::custom(format!("Unsupported key algorithm {algorithm}"))),
}
}
}
impl OneTimeKey {
pub fn fallback(&self) -> bool {
match self {
OneTimeKey::SignedKey(s) => s.fallback(),
}
}
}
#[cfg(test)]
mod tests {
use ruma::{device_id, user_id, DeviceKeyAlgorithm, DeviceKeyId};
use serde_json::json;
use vodozemac::{Curve25519PublicKey, Ed25519Signature};
use crate::types::{Signature, SignedKey};
#[test]
fn serialization() {
let user_id = user_id!("@user:example.com");
let device_id = device_id!("EGURVBUNJP");
let json = json!({
"key":"XjhWTCjW7l59pbfx9tlCBQolfnIQWARoKOzjTOPSlWM",
"signatures": {
user_id: {
"ed25519:EGURVBUNJP": "mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg",
"other:EGURVBUNJP": "UnknownSignature"
}
},
"extra_key": "extra_value"
});
let curve_key =
Curve25519PublicKey::from_base64("XjhWTCjW7l59pbfx9tlCBQolfnIQWARoKOzjTOPSlWM")
.expect("Can't construct curve key from base64");
let signature = Ed25519Signature::from_base64(
"mia28GKixFzOWKJ0h7Bdrdy2fjxiHCsst1qpe467FbW85H61UlshtKBoAXfTLlVfi0FX+/noJ8B3noQPnY+9Cg"
).expect("The signature can always be decoded");
let custom_signature = Signature::Other("UnknownSignature".to_owned());
let key: SignedKey =
serde_json::from_value(json.clone()).expect("Can't deserialize a valid one-time key");
assert_eq!(key.key(), curve_key);
assert_eq!(
key.signatures().get_signature(
user_id,
&DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, device_id)
),
Some(signature)
);
assert_eq!(
key.signatures()
.get(user_id)
.unwrap()
.get(&DeviceKeyId::from_parts("other".into(), device_id)),
Some(&Ok(custom_signature))
);
let serialized = serde_json::to_value(key).expect("Can't reserialize a signed key");
assert_eq!(json, serialized);
}
}