lb_rs/model/
meta.rs

1use libsecp256k1::PublicKey;
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5use crate::LbResult;
6use crate::service::keychain::Keychain;
7
8use super::access_info::{EncryptedFolderAccessKey, UserAccessInfo, UserAccessMode};
9use super::account::Account;
10use super::clock::get_time;
11use super::crypto::AESKey;
12use super::file_metadata::{DocumentHmac, FileType, Owner};
13use super::secret_filename::SecretFileName;
14use super::signed_meta::SignedMeta;
15use super::{pubkey, symkey};
16
17#[derive(Serialize, Deserialize, Clone, Debug)]
18pub enum Meta {
19    V1 {
20        id: Uuid,
21        file_type: FileType,
22        parent: Uuid,
23        name: SecretFileName,
24        owner: Owner,
25        is_deleted: bool,
26        doc_size: Option<usize>,
27        doc_hmac: Option<DocumentHmac>,
28        user_access_keys: Vec<UserAccessInfo>,
29        folder_access_key: EncryptedFolderAccessKey,
30    },
31}
32
33impl Meta {
34    pub fn create_root(account: &Account) -> LbResult<Self> {
35        let id = Uuid::new_v4();
36        let key = symkey::generate_key();
37        let pub_key = account.public_key();
38
39        Ok(Meta::V1 {
40            id,
41            file_type: FileType::Folder,
42            parent: id,
43            name: SecretFileName::from_str(&account.username, &key, &key)?,
44            owner: Owner(pub_key),
45            is_deleted: false,
46            doc_hmac: None,
47            doc_size: None,
48            user_access_keys: vec![UserAccessInfo::encrypt(
49                account,
50                &pub_key,
51                &pub_key,
52                &key,
53                UserAccessMode::Write,
54            )?],
55            folder_access_key: symkey::encrypt(&key, &key)?,
56        })
57    }
58
59    pub fn create(
60        id: Uuid, key: AESKey, owner: &PublicKey, parent: Uuid, parent_key: &AESKey, name: &str,
61        file_type: FileType,
62    ) -> LbResult<Self> {
63        Ok(Meta::V1 {
64            id,
65            file_type,
66            parent,
67            name: SecretFileName::from_str(name, &key, parent_key)?,
68            owner: Owner(*owner),
69            is_deleted: false,
70            doc_hmac: None,
71            doc_size: None,
72            user_access_keys: Default::default(),
73            folder_access_key: symkey::encrypt(parent_key, &key)?,
74        })
75    }
76
77    pub fn set_parent(&mut self, new_parent: Uuid) {
78        match self {
79            Meta::V1 { parent, .. } => *parent = new_parent,
80        }
81    }
82
83    pub fn set_name(&mut self, new_name: SecretFileName) {
84        match self {
85            Meta::V1 { name, .. } => *name = new_name,
86        }
87    }
88
89    pub fn set_owner(&mut self, new_owner: Owner) {
90        match self {
91            Meta::V1 { owner, .. } => *owner = new_owner,
92        }
93    }
94
95    pub fn set_deleted(&mut self, new_is_deleted: bool) {
96        match self {
97            Meta::V1 { is_deleted, .. } => *is_deleted = new_is_deleted,
98        }
99    }
100
101    pub fn set_folder_access_keys(&mut self, new_keys: EncryptedFolderAccessKey) {
102        match self {
103            Meta::V1 { folder_access_key, .. } => *folder_access_key = new_keys,
104        }
105    }
106
107    pub fn user_access_keys_mut(&mut self) -> &mut Vec<UserAccessInfo> {
108        match self {
109            Meta::V1 { user_access_keys, .. } => user_access_keys,
110        }
111    }
112
113    pub fn set_hmac_and_size(&mut self, new_hmac: Option<DocumentHmac>, new_size: Option<usize>) {
114        match self {
115            Meta::V1 { doc_hmac, doc_size, .. } => {
116                *doc_hmac = new_hmac;
117                *doc_size = new_size;
118            }
119        }
120    }
121
122    pub fn set_type(&mut self, new_type: FileType) {
123        match self {
124            Meta::V1 { file_type, .. } => *file_type = new_type,
125        }
126    }
127
128    pub fn set_id(&mut self, new_id: Uuid) {
129        match self {
130            Meta::V1 { id, .. } => *id = new_id,
131        }
132    }
133
134    // todo move to FileLike when possible
135    pub fn doc_size(&self) -> &Option<usize> {
136        match self {
137            Meta::V1 { doc_size, .. } => doc_size,
138        }
139    }
140
141    pub fn sign(self, keychain: &Keychain) -> LbResult<SignedMeta> {
142        pubkey::sign(&keychain.get_account()?.private_key, &keychain.get_pk()?, self, get_time)
143    }
144
145    pub fn sign_with(self, account: &Account) -> LbResult<SignedMeta> {
146        pubkey::sign(&account.private_key, &account.public_key(), self, get_time)
147    }
148}
149
150// This is impl'd to avoid comparing encrypted values
151impl PartialEq for Meta {
152    fn eq(&self, other: &Self) -> bool {
153        match (self, other) {
154            (
155                Meta::V1 {
156                    id,
157                    file_type,
158                    parent,
159                    name,
160                    owner,
161                    is_deleted,
162                    doc_hmac,
163                    user_access_keys,
164                    // todo: verify that ignoring this is intentional
165                    folder_access_key: _,
166                    doc_size,
167                },
168                Meta::V1 {
169                    id: other_id,
170                    file_type: other_file_type,
171                    parent: other_parent,
172                    name: other_name,
173                    owner: other_owner,
174                    is_deleted: other_is_deleted,
175                    doc_hmac: other_doc_hmac,
176                    user_access_keys: other_user_access_keys,
177                    // todo: verify that ignoring this is intentional
178                    folder_access_key: _other_folder_access_key,
179                    doc_size: other_doc_size,
180                },
181            ) => {
182                id == other_id
183                    && file_type == other_file_type
184                    && parent == other_parent
185                    && name == other_name
186                    && owner == other_owner
187                    && is_deleted == other_is_deleted
188                    && doc_hmac == other_doc_hmac
189                    && user_access_keys == other_user_access_keys
190                    && doc_size == other_doc_size
191            }
192        }
193    }
194}