1use crate::model::access_info::{UserAccessInfo, UserAccessMode};
2use crate::model::crypto::{AESKey, DecryptedDocument, EncryptedDocument};
3use crate::model::errors::{LbErrKind, LbResult};
4use crate::model::file::{File, Share, ShareMode};
5use crate::model::file_metadata::{FileType, Owner};
6use crate::model::lazy::LazyTree;
7use crate::model::meta::Meta;
8use crate::model::secret_filename::{HmacSha256, SecretFileName};
9use crate::model::staged::{StagedTree, StagedTreeLike};
10use crate::model::tree_like::{TreeLike, TreeLikeMut};
11use crate::model::{compression_service, symkey, validate};
12use crate::service::keychain::Keychain;
13use db_rs::LookupTable;
14use hmac::{Mac, NewMac};
15use libsecp256k1::PublicKey;
16use tracing::debug;
17use uuid::Uuid;
18
19use super::file_like::FileLike;
20use super::signed_meta::SignedMeta;
21
22pub type TreeWithOp<Staged> = LazyTree<StagedTree<Staged, Option<SignedMeta>>>;
23pub type TreeWithOps<Staged> = LazyTree<StagedTree<Staged, Vec<SignedMeta>>>;
24
25impl<T> LazyTree<T>
26where
27 T: TreeLike<F = SignedMeta>,
28{
29 pub fn decrypt(
31 &mut self, keychain: &Keychain, id: &Uuid, public_key_cache: &LookupTable<Owner, String>,
32 ) -> LbResult<File> {
33 let account = keychain.get_account()?;
34 let pk = keychain.get_pk()?;
35
36 let meta = self.find(id)?.clone();
37 let file_type = meta.file_type();
38 let last_modified = meta.timestamped_value.timestamp as u64;
39 let name = self.name_using_links(id, keychain)?;
40 let parent = self.parent_using_links(id)?;
41 let last_modified_by = public_key_cache
42 .get()
43 .get(&Owner(meta.public_key))
44 .cloned()
45 .unwrap_or_else(|| String::from("<unknown>"));
46
47 let id = *id;
48
49 let mut shares = Vec::new();
50 for user_access_key in meta.user_access_keys() {
51 if user_access_key.encrypted_by == user_access_key.encrypted_for {
52 continue;
53 }
54 let mode = match user_access_key.mode {
55 UserAccessMode::Read => ShareMode::Read,
56 UserAccessMode::Write => ShareMode::Write,
57 UserAccessMode::Owner => continue,
58 };
59 shares.push(Share {
60 mode,
61 shared_by: if user_access_key.encrypted_by == pk {
62 account.username.clone()
63 } else {
64 public_key_cache
65 .get()
66 .get(&Owner(user_access_key.encrypted_by))
67 .cloned()
68 .unwrap_or_else(|| String::from("<unknown>"))
69 },
70 shared_with: if user_access_key.encrypted_for == pk {
71 account.username.clone()
72 } else {
73 public_key_cache
74 .get()
75 .get(&Owner(user_access_key.encrypted_for))
76 .cloned()
77 .unwrap_or_else(|| String::from("<unknown>"))
78 },
79 });
80 }
81
82 Ok(File { id, parent, name, file_type, last_modified, last_modified_by, shares })
83 }
84
85 pub fn decrypt_all<I>(
87 &mut self, keychain: &Keychain, ids: I, public_key_cache: &LookupTable<Owner, String>,
88 skip_invisible: bool,
89 ) -> LbResult<Vec<File>>
90 where
91 I: Iterator<Item = Uuid>,
92 {
93 let mut files: Vec<File> = Vec::new();
94
95 for id in ids {
96 if skip_invisible && self.is_invisible_id(id)? {
97 continue;
98 }
99
100 let finalized = self.decrypt(keychain, &id, public_key_cache)?;
101 files.push(finalized);
102 }
103
104 Ok(files)
105 }
106
107 pub fn is_invisible_id(&mut self, id: Uuid) -> LbResult<bool> {
108 Ok(self.find(&id)?.is_link()
109 || self.calculate_deleted(&id)?
110 || self.in_pending_share(&id)?)
111 }
112
113 pub fn create_op(
114 &mut self, id: Uuid, key: AESKey, parent: &Uuid, name: &str, file_type: FileType,
115 keychain: &Keychain,
116 ) -> LbResult<(SignedMeta, Uuid)> {
117 validate::file_name(name)?;
118
119 if self.maybe_find(parent).is_none() {
120 return Err(LbErrKind::FileParentNonexistent.into());
121 }
122 let parent_owner = self.find(parent)?.owner().0;
123 let parent_key = self.decrypt_key(parent, keychain)?;
124 let file = Meta::create(id, key, &parent_owner, *parent, &parent_key, name, file_type)?
125 .sign(keychain)?;
126 let id = *file.id();
127
128 debug!("new {:?} with id: {}", file_type, id);
129 Ok((file, id))
130 }
131
132 pub fn rename_op(
133 &mut self, id: &Uuid, name: &str, keychain: &Keychain,
134 ) -> LbResult<SignedMeta> {
135 let mut file = self.find(id)?.timestamped_value.value.clone();
136
137 validate::file_name(name)?;
138 if self.maybe_find(file.parent()).is_none() {
139 return Err(LbErrKind::InsufficientPermission.into());
140 }
141 let parent_key = self.decrypt_key(file.parent(), keychain)?;
142 let key = self.decrypt_key(id, keychain)?;
143 file.set_name(SecretFileName::from_str(name, &key, &parent_key)?);
144 let file = file.sign(keychain)?;
145
146 Ok(file)
147 }
148
149 pub fn move_op(
150 &mut self, id: &Uuid, new_parent: &Uuid, keychain: &Keychain,
151 ) -> LbResult<Vec<SignedMeta>> {
152 let mut file = self.find(id)?.timestamped_value.value.clone();
153 if self.maybe_find(new_parent).is_none() {
154 return Err(LbErrKind::FileParentNonexistent.into());
155 }
156 let key = self.decrypt_key(id, keychain)?;
157 let parent_key = self.decrypt_key(new_parent, keychain)?;
158 let owner = self.find(new_parent)?.owner();
159 file.set_owner(owner);
160 file.set_parent(*new_parent);
161 file.set_folder_access_keys(symkey::encrypt(&parent_key, &key)?);
162 file.set_name(SecretFileName::from_str(&self.name(id, keychain)?, &key, &parent_key)?);
163 let file = file.sign(keychain)?;
164
165 let mut result = vec![file];
166 for id in self.descendants(id)? {
167 if self.calculate_deleted(&id)? {
168 continue;
169 }
170 let mut descendant = self.find(&id)?.timestamped_value.value.clone();
171 descendant.set_owner(owner);
172 result.push(descendant.sign(keychain)?);
173 }
174
175 Ok(result)
176 }
177
178 pub fn delete_op(&self, id: &Uuid, keychain: &Keychain) -> LbResult<SignedMeta> {
179 let mut file = self.find(id)?.timestamped_value.value.clone();
180
181 file.set_deleted(true);
182 let file = file.sign(keychain)?;
183
184 Ok(file)
185 }
186
187 pub fn add_share_op(
188 &mut self, id: Uuid, sharee: Owner, mode: ShareMode, keychain: &Keychain,
189 ) -> LbResult<SignedMeta> {
190 let owner = Owner(keychain.get_pk()?);
191 let access_mode = match mode {
192 ShareMode::Write => UserAccessMode::Write,
193 ShareMode::Read => UserAccessMode::Read,
194 };
195 if self.calculate_deleted(&id)? {
196 return Err(LbErrKind::FileNonexistent.into());
197 }
198 let id =
199 if let FileType::Link { target } = self.find(&id)?.file_type() { target } else { id };
200 let mut file = self.find(&id)?.timestamped_value.value.clone();
201 validate::not_root(&file)?;
202 if mode == ShareMode::Write && file.owner().0 != owner.0 {
203 return Err(LbErrKind::InsufficientPermission.into());
204 }
205 let mut found = false;
207 for user_access in file.user_access_keys() {
208 if user_access.encrypted_for == sharee.0 {
209 found = true;
210 if user_access.mode == access_mode && !user_access.deleted {
211 return Err(LbErrKind::ShareAlreadyExists.into());
212 }
213 }
214 }
215 if found {
216 file.user_access_keys_mut()
217 .retain(|k| k.encrypted_for != sharee.0);
218 }
219 file.user_access_keys_mut().push(UserAccessInfo::encrypt(
220 keychain.get_account()?,
221 &owner.0,
222 &sharee.0,
223 &self.decrypt_key(&id, keychain)?,
224 access_mode,
225 )?);
226 let file = file.sign(keychain)?;
227
228 Ok(file)
229 }
230
231 pub fn delete_share_op(
232 &mut self, id: &Uuid, maybe_encrypted_for: Option<PublicKey>, keychain: &Keychain,
233 ) -> LbResult<Vec<SignedMeta>> {
234 let mut result = Vec::new();
235 let mut file = self.find(id)?.timestamped_value.value.clone();
236
237 let mut found = false;
238 for key in file.user_access_keys_mut() {
239 if let Some(encrypted_for) = maybe_encrypted_for {
240 if !key.deleted && key.encrypted_for == encrypted_for {
241 found = true;
242 key.deleted = true;
243 }
244 } else if !key.deleted {
245 found = true;
246 key.deleted = true;
247 }
248 }
249 if !found {
250 return Err(LbErrKind::ShareNonexistent.into());
251 }
252 result.push(file.sign(keychain)?);
253
254 if let Some(encrypted_for) = maybe_encrypted_for {
256 if encrypted_for == keychain.get_pk()? {
257 if let Some(link) = self.linked_by(id)? {
258 let mut link = self.find(&link)?.timestamped_value.value.clone();
259 link.set_deleted(true);
260 result.push(link.sign(keychain)?);
261 }
262 }
263 }
264
265 Ok(result)
266 }
267
268 pub fn decrypt_document(
269 &mut self, id: &Uuid, doc: &EncryptedDocument, keychain: &Keychain,
270 ) -> LbResult<DecryptedDocument> {
271 let key = self.decrypt_key(id, keychain)?;
272 let compressed = symkey::decrypt(&key, doc)?;
273 let doc = compression_service::decompress(&compressed)?;
274
275 Ok(doc)
276 }
277
278 pub fn update_document_op(
279 &mut self, id: &Uuid, document: &[u8], keychain: &Keychain,
280 ) -> LbResult<(SignedMeta, EncryptedDocument)> {
281 let id = match self.find(id)?.file_type() {
282 FileType::Document | FileType::Folder => *id,
283 FileType::Link { target } => target,
284 };
285 let mut file = self.find(&id)?.timestamped_value.value.clone();
286 validate::is_document(&file)?;
287 let key = self.decrypt_key(&id, keychain)?;
288 let hmac = {
289 let mut mac = HmacSha256::new_from_slice(&key)
290 .map_err(|err| LbErrKind::Unexpected(format!("hmac creation error: {err:?}")))?;
291 mac.update(document);
292 mac.finalize().into_bytes()
293 }
294 .into();
295 let document = compression_service::compress(document)?;
296 let document = symkey::encrypt(&key, &document)?;
297 file.set_hmac_and_size(Some(hmac), Some(document.value.len()));
298 let file = file.sign(keychain)?;
299
300 Ok((file, document))
301 }
302}
303
304impl<Base, Local, Staged> LazyTree<Staged>
305where
306 Staged: StagedTreeLike<Base = Base, Staged = Local, F = SignedMeta> + TreeLikeMut,
307 Base: TreeLike<F = Staged::F>,
308 Local: TreeLikeMut<F = Staged::F>,
309{
310 pub fn create_unvalidated(
311 &mut self, id: Uuid, key: AESKey, parent: &Uuid, name: &str, file_type: FileType,
312 keychain: &Keychain,
313 ) -> LbResult<Uuid> {
314 let (op, id) = self.create_op(id, key, parent, name, file_type, keychain)?;
315 self.stage_and_promote(Some(op))?;
316 Ok(id)
317 }
318
319 pub fn create(
320 &mut self, id: Uuid, key: AESKey, parent: &Uuid, name: &str, file_type: FileType,
321 keychain: &Keychain,
322 ) -> LbResult<Uuid> {
323 if self.calculate_deleted(parent)? {
324 return Err(LbErrKind::FileParentNonexistent.into());
325 }
326
327 let (op, id) = self.create_op(id, key, parent, name, file_type, keychain)?;
328 self.stage_validate_and_promote(Some(op), Owner(keychain.get_pk()?))?;
329 Ok(id)
330 }
331
332 pub fn rename_unvalidated(
333 &mut self, id: &Uuid, name: &str, keychain: &Keychain,
334 ) -> LbResult<()> {
335 let op = self.rename_op(id, name, keychain)?;
336 self.stage_and_promote(Some(op))?;
337 Ok(())
338 }
339
340 pub fn rename(&mut self, id: &Uuid, name: &str, keychain: &Keychain) -> LbResult<()> {
341 let op = self.rename_op(id, name, keychain)?;
342 self.stage_validate_and_promote(Some(op), Owner(keychain.get_pk()?))?;
343 Ok(())
344 }
345
346 pub fn move_unvalidated(
347 &mut self, id: &Uuid, new_parent: &Uuid, keychain: &Keychain,
348 ) -> LbResult<()> {
349 let op = self.move_op(id, new_parent, keychain)?;
350 self.stage_and_promote(op)?;
351 Ok(())
352 }
353
354 pub fn move_file(&mut self, id: &Uuid, new_parent: &Uuid, keychain: &Keychain) -> LbResult<()> {
355 if self.maybe_find(new_parent).is_none() || self.calculate_deleted(new_parent)? {
356 return Err(LbErrKind::FileParentNonexistent.into());
357 }
358 let op = self.move_op(id, new_parent, keychain)?;
359 self.stage_validate_and_promote(op, Owner(keychain.get_pk()?))?;
360 Ok(())
361 }
362
363 pub fn delete_unvalidated(&mut self, id: &Uuid, keychain: &Keychain) -> LbResult<()> {
364 let op = self.delete_op(id, keychain)?;
365 self.stage_and_promote(Some(op))?;
366 Ok(())
367 }
368
369 pub fn delete(&mut self, id: &Uuid, keychain: &Keychain) -> LbResult<()> {
370 let op = self.delete_op(id, keychain)?;
371 self.stage_validate_and_promote(Some(op), Owner(keychain.get_pk()?))?;
372 Ok(())
373 }
374
375 pub fn add_share_unvalidated(
376 &mut self, id: Uuid, sharee: Owner, mode: ShareMode, keychain: &Keychain,
377 ) -> LbResult<()> {
378 let op = self.add_share_op(id, sharee, mode, keychain)?;
379 self.stage_and_promote(Some(op))?;
380 Ok(())
381 }
382
383 pub fn add_share(
384 &mut self, id: Uuid, sharee: Owner, mode: ShareMode, keychain: &Keychain,
385 ) -> LbResult<()> {
386 let op = self.add_share_op(id, sharee, mode, keychain)?;
387 self.stage_validate_and_promote(Some(op), Owner(keychain.get_pk()?))?;
388 Ok(())
389 }
390
391 pub fn delete_share_unvalidated(
392 &mut self, id: &Uuid, maybe_encrypted_for: Option<PublicKey>, keychain: &Keychain,
393 ) -> LbResult<()> {
394 let op = self.delete_share_op(id, maybe_encrypted_for, keychain)?;
395 self.stage_and_promote(op)?;
396 Ok(())
397 }
398
399 pub fn delete_share(
400 &mut self, id: &Uuid, maybe_encrypted_for: Option<PublicKey>, keychain: &Keychain,
401 ) -> LbResult<()> {
402 let op = self.delete_share_op(id, maybe_encrypted_for, keychain)?;
403 self.stage_validate_and_promote(op, Owner(keychain.get_pk()?))?;
404 Ok(())
405 }
406
407 pub fn update_document_unvalidated(
408 &mut self, id: &Uuid, document: &[u8], keychain: &Keychain,
409 ) -> LbResult<EncryptedDocument> {
410 let (op, document) = self.update_document_op(id, document, keychain)?;
411 self.stage_and_promote(Some(op))?;
412 Ok(document)
413 }
414
415 pub fn update_document(
416 &mut self, id: &Uuid, document: &[u8], keychain: &Keychain,
417 ) -> LbResult<EncryptedDocument> {
418 let (op, document) = self.update_document_op(id, document, keychain)?;
419 self.stage_validate_and_promote(Some(op), Owner(keychain.get_pk()?))?;
420 Ok(document)
421 }
422}