ouisync/access_control/
local_secret.rs

1use crate::crypto::{cipher::SecretKey, Password, PasswordSalt};
2use ouisync_macros::api;
3#[cfg(test)]
4use rand::{CryptoRng, Rng};
5use serde::{Deserialize, Serialize};
6
7/// Type of secret to unlock a repository.
8#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
9#[api]
10pub enum LocalSecret {
11    /// Password provided by the user
12    Password(Password),
13    /// Secret key generated by secure means (e.g., crypto-secure RNG, KDF, ...)
14    SecretKey(SecretKey),
15}
16
17#[cfg(test)]
18impl LocalSecret {
19    /// Generates random local secret containing a secret key.
20    pub fn random() -> Self {
21        Self::SecretKey(SecretKey::random())
22    }
23
24    /// Generates random local secret containing a secret key using the provided RNG.
25    pub fn generate<R: Rng + CryptoRng + ?Sized>(rng: &mut R) -> Self {
26        Self::SecretKey(SecretKey::generate(rng))
27    }
28}
29
30/// Used to set or change the read or write local secret of a repository.
31#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
32#[api]
33pub enum SetLocalSecret {
34    /// Password provided by the user
35    Password(Password),
36    /// Use to directly (without doing password hashing) set the `SecretKey` and `PasswordSalt` for
37    /// read or write access.
38    KeyAndSalt { key: SecretKey, salt: PasswordSalt },
39}
40
41#[cfg(test)]
42impl SetLocalSecret {
43    /// Generates random secret key and salt.
44    pub fn random() -> Self {
45        Self::KeyAndSalt {
46            key: SecretKey::random(),
47            salt: PasswordSalt::random(),
48        }
49    }
50}
51
52#[cfg(test)]
53impl From<SetLocalSecret> for LocalSecret {
54    fn from(local: SetLocalSecret) -> Self {
55        match local {
56            SetLocalSecret::Password(pwd) => Self::Password(pwd),
57            SetLocalSecret::KeyAndSalt { key, .. } => Self::SecretKey(key),
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn serialize_deserialize_bincode() {
68        let orig = LocalSecret::Password("mellon".to_string().into());
69        let expected_serialized_hex = "0000000006000000000000006d656c6c6f6e";
70
71        let serialized = bincode::serialize(&orig).unwrap();
72        assert_eq!(hex::encode(&serialized), expected_serialized_hex);
73
74        let deserialized: LocalSecret = bincode::deserialize(&serialized).unwrap();
75        assert_eq!(&deserialized, &orig);
76    }
77
78    #[test]
79    fn serialize_deserialize_msgpack() {
80        let orig = LocalSecret::Password("mellon".to_string().into());
81        let expected_serialized_hex = "81a850617373776f7264a66d656c6c6f6e";
82
83        let serialized = rmp_serde::to_vec(&orig).unwrap();
84        assert_eq!(hex::encode(&serialized), expected_serialized_hex);
85
86        let deserialized: LocalSecret = rmp_serde::from_slice(&serialized).unwrap();
87        assert_eq!(&deserialized, &orig);
88    }
89}