use std::{
collections::BTreeMap,
convert::TryFrom,
fmt::{self, Debug, Display, Formatter},
};
use ruma_events::Algorithm;
use ruma_identifiers::{DeviceId, UserId};
use serde::{
de::{self, Unexpected},
Deserialize, Deserializer, Serialize, Serializer,
};
pub mod claim_keys;
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;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum KeyAlgorithm {
#[serde(rename = "ed25519")]
Ed25519,
#[serde(rename = "curve25519")]
Curve25519,
#[serde(rename = "signed_curve25519")]
SignedCurve25519,
}
impl Display for KeyAlgorithm {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let algorithm_str = match *self {
KeyAlgorithm::Ed25519 => "ed25519",
KeyAlgorithm::Curve25519 => "curve25519",
KeyAlgorithm::SignedCurve25519 => "signed_curve25519",
};
write!(f, "{}", algorithm_str)?;
Ok(())
}
}
impl TryFrom<&'_ str> for KeyAlgorithm {
type Error = &'static str;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
"ed25519" => Ok(KeyAlgorithm::Ed25519),
"curve25519" => Ok(KeyAlgorithm::Curve25519),
"signed_curve25519" => Ok(KeyAlgorithm::SignedCurve25519),
_ => Err("Unknown algorithm"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct AlgorithmAndDeviceId(pub KeyAlgorithm, pub Box<DeviceId>);
impl Display for AlgorithmAndDeviceId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.0, self.1)
}
}
impl Serialize for AlgorithmAndDeviceId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl<'de> Deserialize<'de> for AlgorithmAndDeviceId {
#[allow(clippy::comparison_chain)]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = String::deserialize(deserializer)?;
let parts = value.split(':').collect::<Vec<_>>();
const EXPECTED: &str = "a string composed of an algorithm and a device id separated by ':'";
if parts.len() < 2 {
return Err(de::Error::invalid_type(
Unexpected::Other("string without a ':' separator"),
&EXPECTED,
));
} else if parts.len() > 2 {
return Err(de::Error::invalid_type(
Unexpected::Other("string with more than one ':' separator"),
&EXPECTED,
));
}
let algorithm_result = KeyAlgorithm::try_from(parts[0]);
match algorithm_result {
Ok(algorithm) => Ok(AlgorithmAndDeviceId(algorithm, parts[1].into())),
Err(_) => {
Err(de::Error::invalid_value(Unexpected::Str(parts[0]), &"valid key algorithm"))
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceKeys {
pub user_id: UserId,
pub device_id: Box<DeviceId>,
pub algorithms: Vec<Algorithm>,
pub keys: BTreeMap<AlgorithmAndDeviceId, String>,
pub signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unsigned: Option<UnsignedDeviceInfo>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnsignedDeviceInfo {
pub device_display_name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignedKey {
pub key: String,
pub signatures: BTreeMap<UserId, BTreeMap<AlgorithmAndDeviceId, String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneTimeKey {
SignedKey(SignedKey),
Key(String),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CrossSigningKey {
pub user_id: UserId,
pub usage: Vec<KeyUsage>,
pub keys: BTreeMap<String, String>,
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
pub signatures: BTreeMap<UserId, BTreeMap<String, String>>,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
Master,
SelfSigning,
UserSigning,
}