use as_variant::as_variant;
use ruma::DeviceKeyAlgorithm;
use vodozemac::Ed25519Signature;
use crate::types::InvalidSignature;
#[cfg(feature = "experimental-x509-identity-verification")]
use crate::types::{X509_SIGNATURE_ALGORITHM, X509Signature};
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Signature {
Ed25519(Ed25519Signature),
#[cfg(feature = "experimental-x509-identity-verification")]
X509(X509Signature),
Other(String),
}
impl Signature {
pub fn ed25519(&self) -> Option<Ed25519Signature> {
as_variant!(self, Self::Ed25519).copied()
}
pub fn from_base64(algorithm: DeviceKeyAlgorithm, s: String) -> Result<Self, InvalidSignature> {
match algorithm {
DeviceKeyAlgorithm::Ed25519 => Ed25519Signature::from_base64(&s)
.map(|s| s.into())
.map_err(|_| InvalidSignature { source: s }),
#[cfg(feature = "experimental-x509-identity-verification")]
custom if custom.as_str() == X509_SIGNATURE_ALGORITHM => {
X509Signature::from_cms_pem(&s)
.map(Into::into)
.map_err(|_| InvalidSignature { source: s })
}
_ => Ok(Signature::Other(s)),
}
}
pub fn to_base64(&self) -> String {
match self {
Signature::Ed25519(s) => s.to_base64(),
#[cfg(feature = "experimental-x509-identity-verification")]
Signature::X509(s) => s.to_cms_pem(),
Signature::Other(s) => s.to_owned(),
}
}
}
impl From<Ed25519Signature> for Signature {
fn from(signature: Ed25519Signature) -> Self {
Self::Ed25519(signature)
}
}
#[cfg(feature = "experimental-x509-identity-verification")]
impl From<X509Signature> for Signature {
fn from(signature: X509Signature) -> Self {
Self::X509(signature)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn roundtrip_ed25519_signature() {
const BASE64_SIG: &str = "AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ";
let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
.expect("Failed to parse");
let ed25519 = parsed.ed25519().expect("Not parsed as Ed25519");
assert_eq!(ed25519.to_base64(), BASE64_SIG);
let encoded = parsed.to_base64();
assert_eq!(encoded, BASE64_SIG)
}
#[test]
fn parse_invalid_ed25519_signature() {
const BASE64_SIG: &str = "XXXX";
let parsed = Signature::from_base64(DeviceKeyAlgorithm::Ed25519, BASE64_SIG.to_owned())
.expect_err("Expected an invalid signature");
assert_eq!(parsed.source, BASE64_SIG);
}
#[test]
fn roundtrip_other_signature() {
const TEXT: &str = "abcd";
let parsed = Signature::from_base64(DeviceKeyAlgorithm::from("foo"), TEXT.to_owned())
.expect("Failed to parse");
let other = as_variant!(&parsed, Signature::Other).expect("Not parsed as Other");
assert_eq!(other, TEXT);
let encoded = parsed.to_base64();
assert_eq!(encoded, TEXT)
}
}