ruma_identifiers/
device_key_id.rs

1//! Identifiers for device keys for end-to-end encryption.
2
3use crate::{crypto_algorithms::DeviceKeyAlgorithm, DeviceId};
4
5/// A key algorithm and a device id, combined with a ':'.
6#[repr(transparent)]
7#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub struct DeviceKeyId(str);
9
10opaque_identifier_validated!(DeviceKeyId, ruma_identifiers_validation::device_key_id::validate);
11
12impl DeviceKeyId {
13    /// Create a `DeviceKeyId` from a `DeviceKeyAlgorithm` and a `DeviceId`.
14    pub fn from_parts(algorithm: DeviceKeyAlgorithm, device_id: &DeviceId) -> Box<Self> {
15        let algorithm: &str = algorithm.as_ref();
16        let device_id: &str = device_id.as_ref();
17
18        let mut res = String::with_capacity(algorithm.len() + 1 + device_id.len());
19        res.push_str(algorithm);
20        res.push(':');
21        res.push_str(device_id);
22
23        Self::from_owned(res.into())
24    }
25
26    /// Returns key algorithm of the device key ID.
27    pub fn algorithm(&self) -> DeviceKeyAlgorithm {
28        self.as_str()[..self.colon_idx()].into()
29    }
30
31    /// Returns device ID of the device key ID.
32    pub fn device_id(&self) -> &DeviceId {
33        self.as_str()[self.colon_idx() + 1..].into()
34    }
35
36    fn colon_idx(&self) -> usize {
37        self.as_str().find(':').unwrap()
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use std::convert::TryFrom;
44
45    use super::DeviceKeyId;
46    use crate::{crypto_algorithms::DeviceKeyAlgorithm, Error};
47
48    #[test]
49    fn convert_device_key_id() {
50        assert_eq!(
51            <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS")
52                .expect("Failed to create device key ID."),
53            "ed25519:JLAFKJWSCS"
54        );
55    }
56
57    #[cfg(feature = "serde")]
58    #[test]
59    fn serialize_device_key_id() {
60        let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
61        let serialized = serde_json::to_value(device_key_id).unwrap();
62
63        assert_eq!(serialized, serde_json::json!("ed25519:JLAFKJWSCS"));
64    }
65
66    #[cfg(feature = "serde")]
67    #[test]
68    fn deserialize_device_key_id() {
69        let deserialized: Box<DeviceKeyId> =
70            serde_json::from_value(serde_json::json!("ed25519:JLAFKJWSCS")).unwrap();
71
72        let expected = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
73        assert_eq!(deserialized, expected);
74    }
75
76    #[test]
77    fn missing_key_algorithm() {
78        assert_eq!(
79            <&DeviceKeyId>::try_from(":JLAFKJWSCS").unwrap_err(),
80            Error::InvalidKeyAlgorithm
81        );
82    }
83
84    #[test]
85    fn missing_delimiter() {
86        assert_eq!(
87            <&DeviceKeyId>::try_from("ed25519|JLAFKJWSCS").unwrap_err(),
88            Error::MissingDelimiter,
89        );
90    }
91
92    #[test]
93    fn empty_device_id_ok() {
94        assert!(<&DeviceKeyId>::try_from("ed25519:").is_ok());
95    }
96
97    #[test]
98    fn valid_key_algorithm() {
99        let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
100        assert_eq!(device_key_id.algorithm(), DeviceKeyAlgorithm::Ed25519);
101    }
102
103    #[test]
104    fn valid_device_id() {
105        let device_key_id = <&DeviceKeyId>::try_from("ed25519:JLAFKJWSCS").unwrap();
106        assert_eq!(device_key_id.device_id(), "JLAFKJWSCS");
107    }
108}