1
use serde::{Deserialize, Serialize};
2
use zbus::zvariant;
3

            
4
#[derive(Debug, zvariant::Type, PartialEq, Eq, Copy, Clone)]
5
#[zvariant(signature = "s")]
6
/// Algorithm used to start a new session.
7
///
8
/// The communication between the Secret Service and the application can either
9
/// be encrypted or the items can be sent in plain text.
10
pub enum Algorithm {
11
    /// Plain text, per <https://specifications.freedesktop.org/secret-service-spec/latest/ch07s02.html>.
12
    Plain,
13
    /// Encrypted, per <https://specifications.freedesktop.org/secret-service-spec/latest/ch07s03.html>.
14
    Encrypted,
15
}
16

            
17
const PLAIN_ALGORITHM: &str = "plain";
18
const ENCRYPTED_ALGORITHM: &str = "dh-ietf1024-sha256-aes128-cbc-pkcs7";
19

            
20
impl Serialize for Algorithm {
21
62
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22
    where
23
        S: serde::Serializer,
24
    {
25
60
        match self {
26
57
            Self::Plain => str::serialize(PLAIN_ALGORITHM, serializer),
27
37
            Self::Encrypted => str::serialize(ENCRYPTED_ALGORITHM, serializer),
28
        }
29
    }
30
}
31

            
32
impl<'de> Deserialize<'de> for Algorithm {
33
32
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
34
    where
35
        D: serde::Deserializer<'de>,
36
    {
37
54
        match String::deserialize(deserializer)?.as_str() {
38
57
            PLAIN_ALGORITHM => Ok(Self::Plain),
39
53
            ENCRYPTED_ALGORITHM => Ok(Self::Encrypted),
40
4
            e => Err(serde::de::Error::custom(format!("Invalid algorithm {e}"))),
41
        }
42
    }
43
}
44

            
45
#[cfg(test)]
46
mod tests {
47
    use zbus::zvariant::{Endian, serialized::Context, to_bytes};
48

            
49
    use super::*;
50

            
51
    #[test]
52
    fn serialization() {
53
        let ctxt = Context::new_dbus(Endian::Little, 0);
54

            
55
        // Test serializing Plain
56
        let encoded = to_bytes(ctxt, &Algorithm::Plain).unwrap();
57
        let value: String = encoded.deserialize().unwrap().0;
58
        assert_eq!(value, "plain");
59

            
60
        // Test serializing Encrypted
61
        let encoded = to_bytes(ctxt, &Algorithm::Encrypted).unwrap();
62
        let value: String = encoded.deserialize().unwrap().0;
63
        assert_eq!(value, "dh-ietf1024-sha256-aes128-cbc-pkcs7");
64

            
65
        // Test deserializing plain
66
        let encoded = to_bytes(ctxt, &PLAIN_ALGORITHM).unwrap();
67
        let algo: Algorithm = encoded.deserialize().unwrap().0;
68
        assert_eq!(algo, Algorithm::Plain);
69

            
70
        // Test deserializing encrypted
71
        let encoded = to_bytes(ctxt, &ENCRYPTED_ALGORITHM).unwrap();
72
        let algo: Algorithm = encoded.deserialize().unwrap().0;
73
        assert_eq!(algo, Algorithm::Encrypted);
74

            
75
        // Test deserializing invalid algorithm
76
        let encoded = to_bytes(ctxt, &"invalid-algorithm").unwrap();
77
        let result: Result<(Algorithm, _), _> = encoded.deserialize();
78
        assert!(result.is_err());
79
        assert!(
80
            result
81
                .unwrap_err()
82
                .to_string()
83
                .contains("Invalid algorithm")
84
        );
85

            
86
        // Test roundtrip for Plain
87
        let original = Algorithm::Plain;
88
        let encoded = to_bytes(ctxt, &original).unwrap();
89
        let decoded: Algorithm = encoded.deserialize().unwrap().0;
90
        assert_eq!(original, decoded);
91

            
92
        // Test roundtrip for Encrypted
93
        let original = Algorithm::Encrypted;
94
        let encoded = to_bytes(ctxt, &original).unwrap();
95
        let decoded: Algorithm = encoded.deserialize().unwrap().0;
96
        assert_eq!(original, decoded);
97
    }
98
}