1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use crate::shared::account::Account;
use crate::shared::crypto::{AESEncrypted, AESKey};
use crate::shared::{pubkey, symkey, SharedResult};
use libsecp256k1::PublicKey;
use serde::{Deserialize, Serialize};

pub type EncryptedUserAccessKey = AESEncrypted<AESKey>;
pub type EncryptedFolderAccessKey = AESEncrypted<AESKey>;

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Copy, Hash, PartialOrd, Ord)]
pub enum UserAccessMode {
    Read,
    Write,
    Owner, // todo: remove
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserAccessInfo {
    pub mode: UserAccessMode,
    pub encrypted_by: PublicKey,
    pub encrypted_for: PublicKey,
    pub access_key: EncryptedUserAccessKey,
    pub deleted: bool,
}

impl PartialEq for UserAccessInfo {
    fn eq(&self, other: &Self) -> bool {
        self.mode == other.mode
            && self.encrypted_for == other.encrypted_for
            && self.encrypted_by == other.encrypted_by
            && self.deleted == other.deleted
    }
}

impl UserAccessInfo {
    pub fn encrypt(
        account: &Account, encrypted_by: &PublicKey, encrypted_for: &PublicKey, key: &AESKey,
        mode: UserAccessMode,
    ) -> SharedResult<Self> {
        let private_key = account.private_key;
        let user_key = pubkey::get_aes_key(&private_key, encrypted_for)?;
        let encrypted_file_key = symkey::encrypt(&user_key, key)?;
        Ok(UserAccessInfo {
            mode,
            encrypted_by: *encrypted_by,
            encrypted_for: *encrypted_for,
            access_key: encrypted_file_key,
            deleted: false,
        })
    }

    pub fn decrypt(&self, account: &Account) -> SharedResult<AESKey> {
        let shared_secret = pubkey::get_aes_key(&account.private_key, &self.encrypted_by)?;
        let encrypted = &self.access_key;
        let decrypted = symkey::decrypt(&shared_secret, encrypted)?;
        Ok(decrypted)
    }
}

#[cfg(test)]
mod unit_tests {
    use crate::shared::access_info::{UserAccessInfo, UserAccessMode};
    use crate::shared::account::Account;
    use crate::shared::symkey;

    #[test]
    fn encrypt_decrypt_1() {
        let account = Account::new("test1".to_string(), "test2".to_string());
        let key = symkey::generate_key();
        let encrypted = UserAccessInfo::encrypt(
            &account,
            &account.public_key(),
            &account.public_key(),
            &key,
            UserAccessMode::Write,
        )
        .unwrap();
        let decrypted = encrypted.decrypt(&account).unwrap();
        assert_eq!(key, decrypted);
    }

    #[test]
    fn encrypt_decrypt_2() {
        let account1 = Account::new("test1".to_string(), "test2".to_string());
        let account2 = Account::new("test2".to_string(), "test2".to_string());
        let key = symkey::generate_key();
        let encrypted = UserAccessInfo::encrypt(
            &account1,
            &account1.public_key(),
            &account2.public_key(),
            &key,
            UserAccessMode::Write,
        )
        .unwrap();
        let decrypted = encrypted.decrypt(&account2).unwrap();
        assert_eq!(key, decrypted);
    }
}