use std::collections::btree_map::Iter;
use ruma::{encryption::KeyUsage, OwnedDeviceKeyId, UserId};
use serde::{Deserialize, Serialize};
use vodozemac::Ed25519PublicKey;
use super::{CrossSigningKey, SigningKey};
use crate::{
olm::VerifyJson,
types::{DeviceKeys, SigningKeys},
DeviceData, SignatureError,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(try_from = "CrossSigningKey")]
pub struct SelfSigningPubkey(pub(super) CrossSigningKey);
impl SelfSigningPubkey {
pub fn user_id(&self) -> &UserId {
&self.0.user_id
}
pub fn keys(&self) -> &SigningKeys<OwnedDeviceKeyId> {
&self.0.keys
}
pub fn usage(&self) -> &[KeyUsage] {
&self.0.usage
}
pub fn get_first_key(&self) -> Option<Ed25519PublicKey> {
self.0.get_first_key_and_id().map(|(_, k)| k)
}
pub fn verify_device_keys(&self, device_keys: &DeviceKeys) -> Result<(), SignatureError> {
if let Some((key_id, key)) = self.0.get_first_key_and_id() {
key.verify_json(&self.0.user_id, key_id, device_keys)
} else {
Err(SignatureError::UnsupportedAlgorithm)
}
}
pub(crate) fn verify_device(&self, device: &DeviceData) -> Result<(), SignatureError> {
self.verify_device_keys(device.as_device_keys())
}
}
impl<'a> IntoIterator for &'a SelfSigningPubkey {
type Item = (&'a OwnedDeviceKeyId, &'a SigningKey);
type IntoIter = Iter<'a, OwnedDeviceKeyId, SigningKey>;
fn into_iter(self) -> Self::IntoIter {
self.keys().iter()
}
}
impl TryFrom<CrossSigningKey> for SelfSigningPubkey {
type Error = serde_json::Error;
fn try_from(key: CrossSigningKey) -> Result<Self, Self::Error> {
if key.usage.contains(&KeyUsage::SelfSigning) && key.usage.len() == 1 {
Ok(Self(key))
} else {
Err(serde::de::Error::custom(format!(
"Expected cross signing key usage {} was not found",
KeyUsage::SelfSigning
)))
}
}
}
impl AsRef<CrossSigningKey> for SelfSigningPubkey {
fn as_ref(&self) -> &CrossSigningKey {
&self.0
}
}
impl AsMut<CrossSigningKey> for SelfSigningPubkey {
fn as_mut(&mut self) -> &mut CrossSigningKey {
&mut self.0
}
}