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::{FileMetadata, FileType, Owner};
6use crate::model::lazy::LazyTree;
7use crate::model::secret_filename::{HmacSha256, SecretFileName};
8use crate::model::signed_file::SignedFile;
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;
20
21pub type TreeWithOp<Staged> = LazyTree<StagedTree<Staged, Option<SignedFile>>>;
22pub type TreeWithOps<Staged> = LazyTree<StagedTree<Staged, Vec<SignedFile>>>;
23
24impl<T> LazyTree<T>
25where
26 T: TreeLike<F = SignedFile>,
27{
28 pub fn decrypt(
30 &mut self, keychain: &Keychain, id: &Uuid, public_key_cache: &LookupTable<Owner, String>,
31 ) -> LbResult<File> {
32 let account = keychain.get_account()?;
33 let pk = keychain.get_pk()?;
34
35 let meta = self.find(id)?.clone();
36 let file_type = meta.file_type();
37 let last_modified = meta.timestamped_value.timestamp as u64;
38 let name = self.name_using_links(id, keychain)?;
39 let parent = self.parent_using_links(id)?;
40 let last_modified_by = public_key_cache
41 .get()
42 .get(&Owner(meta.public_key))
43 .cloned()
44 .unwrap_or_else(|| String::from("<unknown>"));
45
46 let id = *id;
47
48 let mut shares = Vec::new();
49 for user_access_key in meta.user_access_keys() {
50 if user_access_key.encrypted_by == user_access_key.encrypted_for {
51 continue;
52 }
53 let mode = match user_access_key.mode {
54 UserAccessMode::Read => ShareMode::Read,
55 UserAccessMode::Write => ShareMode::Write,
56 UserAccessMode::Owner => continue,
57 };
58 shares.push(Share {
59 mode,
60 shared_by: if user_access_key.encrypted_by == pk {
61 account.username.clone()
62 } else {
63 public_key_cache
64 .get()
65 .get(&Owner(user_access_key.encrypted_by))
66 .cloned()
67 .unwrap_or_else(|| String::from("<unknown>"))
68 },
69 shared_with: if user_access_key.encrypted_for == pk {
70 account.username.clone()
71 } else {
72 public_key_cache
73 .get()
74 .get(&Owner(user_access_key.encrypted_for))
75 .cloned()
76 .unwrap_or_else(|| String::from("<unknown>"))
77 },
78 });
79 }
80
81 Ok(File { id, parent, name, file_type, last_modified, last_modified_by, shares })
82 }
83
84 pub fn decrypt_all<I>(
86 &mut self, keychain: &Keychain, ids: I, public_key_cache: &LookupTable<Owner, String>,
87 skip_invisible: bool,
88 ) -> LbResult<Vec<File>>
89 where
90 I: Iterator<Item = Uuid>,
91 {
92 let mut files: Vec<File> = Vec::new();
93
94 for id in ids {
95 if skip_invisible && self.is_invisible_id(id)? {
96 continue;
97 }
98
99 let finalized = self.decrypt(keychain, &id, public_key_cache)?;
100 files.push(finalized);
101 }
102
103 Ok(files)
104 }
105
106 pub fn is_invisible_id(&mut self, id: Uuid) -> LbResult<bool> {
107 Ok(self.find(&id)?.is_link()
108 || self.calculate_deleted(&id)?
109 || self.in_pending_share(&id)?)
110 }
111
112 pub fn create_op(
113 &mut self, id: Uuid, key: AESKey, parent: &Uuid, name: &str, file_type: FileType,
114 keychain: &Keychain,
115 ) -> LbResult<(SignedFile, Uuid)> {
116 validate::file_name(name)?;
117
118 if self.maybe_find(parent).is_none() {
119 return Err(LbErrKind::FileParentNonexistent.into());
120 }
121 let parent_owner = self.find(parent)?.owner().0;
122 let parent_key = self.decrypt_key(parent, keychain)?;
123 let file =
124 FileMetadata::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<SignedFile> {
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.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<SignedFile>> {
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.owner = owner;
160 file.parent = *new_parent;
161 file.folder_access_key = symkey::encrypt(&parent_key, &key)?;
162 file.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.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<SignedFile> {
179 let mut file = self.find(id)?.timestamped_value.value.clone();
180
181 file.is_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<SignedFile> {
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 &mut 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
217 .retain(|k| k.encrypted_for != sharee.0);
218 }
219 file.user_access_keys.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<SignedFile>> {
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.iter_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.is_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<(SignedFile, 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: FileMetadata = 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 file.document_hmac = Some(hmac);
296 let file = file.sign(keychain)?;
297 let document = compression_service::compress(document)?;
298 let document = symkey::encrypt(&key, &document)?;
299
300 Ok((file, document))
301 }
302}
303
304impl<Base, Local, Staged> LazyTree<Staged>
305where
306 Staged: StagedTreeLike<Base = Base, Staged = Local, F = SignedFile> + 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}