1
use std::sync::Arc;
2

            
3
use serde::{Deserialize, Serialize, ser::SerializeTuple};
4
use zbus::zvariant::{OwnedObjectPath, Type};
5
use zeroize::{Zeroize, ZeroizeOnDrop};
6

            
7
use super::Session;
8
use crate::{Key, Secret, crypto, dbus::Error, secret::ContentType};
9

            
10
#[derive(Debug, Serialize, Deserialize, Type, Zeroize, ZeroizeOnDrop)]
11
#[zvariant(signature = "(oayays)")]
12
/// Same as [`DBusSecret`] without tying the session path to a [`Session`] type.
13
pub struct DBusSecretInner(
14
    #[zeroize(skip)] pub OwnedObjectPath,
15
    #[serde(with = "serde_bytes")] pub Vec<u8>,
16
    #[serde(with = "serde_bytes")] pub Vec<u8>,
17
    #[zeroize(skip)] pub ContentType,
18
);
19

            
20
#[derive(Debug, Type, Zeroize, ZeroizeOnDrop)]
21
#[zvariant(signature = "(oayays)")]
22
pub struct DBusSecret {
23
    #[zeroize(skip)]
24
    pub(crate) session: Arc<Session>,
25
    pub(crate) parameters: Vec<u8>,
26
    pub(crate) value: Vec<u8>,
27
    #[zeroize(skip)]
28
    pub(crate) content_type: ContentType,
29
}
30

            
31
impl DBusSecret {
32
    /// Create a new plain (unencrypted) DBusSecret
33
11
    pub fn new(session: Arc<Session>, secret: impl Into<Secret>) -> Self {
34
12
        let secret = secret.into();
35
        Self {
36
            session,
37
11
            parameters: vec![],
38
23
            value: secret.as_bytes().to_vec(),
39
12
            content_type: secret.content_type(),
40
        }
41
    }
42

            
43
    /// Create a new encrypted DBusSecret
44
15
    pub fn new_encrypted(
45
        session: Arc<Session>,
46
        secret: impl Into<Secret>,
47
        aes_key: &Key,
48
    ) -> Result<Self, crate::dbus::Error> {
49
30
        let iv = crypto::generate_iv()?;
50
15
        let secret = secret.into();
51
16
        Ok(Self {
52
15
            session,
53
30
            value: crypto::encrypt(secret.as_bytes(), aes_key, &iv)?,
54
16
            parameters: iv,
55
16
            content_type: secret.content_type(),
56
        })
57
    }
58

            
59
54
    pub async fn from_inner(cnx: &zbus::Connection, inner: DBusSecretInner) -> Result<Self, Error> {
60
14
        Ok(Self {
61
28
            session: Arc::new(Session::new(cnx, inner.0.clone()).await?),
62
14
            parameters: inner.1.clone(),
63
14
            value: inner.2.clone(),
64
14
            content_type: inner.3,
65
        })
66
    }
67

            
68
14
    pub fn decrypt(&self, key: Option<&Arc<Key>>) -> Result<Secret, Error> {
69
14
        let value = match key {
70
36
            Some(key) => &crypto::decrypt(&self.value, key, &self.parameters)?,
71
16
            None => &self.value,
72
        };
73
24
        Ok(Secret::with_content_type(self.content_type, value))
74
    }
75

            
76
    /// Session used to encode the secret
77
16
    pub fn session(&self) -> &Session {
78
17
        &self.session
79
    }
80

            
81
    /// Algorithm dependent parameters for secret value encoding
82
18
    pub fn parameters(&self) -> &[u8] {
83
14
        &self.parameters
84
    }
85

            
86
    /// Possibly encoded secret value
87
14
    pub fn value(&self) -> &[u8] {
88
14
        &self.value
89
    }
90

            
91
    /// Content type of the secret
92
15
    pub fn content_type(&self) -> ContentType {
93
15
        self.content_type
94
    }
95
}
96

            
97
impl From<DBusSecret> for DBusSecretInner {
98
4
    fn from(secret: DBusSecret) -> Self {
99
        Self(
100
8
            secret.session().inner().path().to_owned().into(),
101
8
            secret.parameters().to_vec(),
102
8
            secret.value().to_vec(),
103
4
            secret.content_type(),
104
        )
105
    }
106
}
107

            
108
impl Serialize for DBusSecret {
109
35
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
110
    where
111
        S: serde::Serializer,
112
    {
113
30
        let mut tuple_serializer = serializer.serialize_tuple(4)?;
114
66
        tuple_serializer.serialize_element(self.session().inner().path())?;
115
33
        tuple_serializer.serialize_element(&serde_bytes::Bytes::new(self.parameters()))?;
116
28
        tuple_serializer.serialize_element(&serde_bytes::Bytes::new(self.value()))?;
117
30
        tuple_serializer.serialize_element(self.content_type().as_str())?;
118
30
        tuple_serializer.end()
119
    }
120
}
121

            
122
#[cfg(test)]
123
mod tests {
124
    use super::*;
125

            
126
    #[test]
127
    fn signature() {
128
        assert_eq!(DBusSecret::SIGNATURE, "(oayays)");
129
    }
130
}