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