1use crate::access_info::UserAccessMode;
2use crate::account::Account;
3use crate::crypto::{AESKey, DecryptedDocument, EncryptedDocument};
4use crate::file_like::FileLike;
5use crate::file_metadata::{FileType, Owner};
6use crate::staged::StagedTree;
7use crate::tree_like::{TreeLike, TreeLikeMut};
8use crate::{compression_service, symkey, SharedErrorKind, SharedResult};
9use serde::{Deserialize, Serialize};
10use std::collections::{HashMap, HashSet};
11use uuid::Uuid;
12
13#[derive(Debug)]
14pub struct LazyTree<T: TreeLike> {
15 pub tree: T,
16 pub name: HashMap<Uuid, String>,
17 pub key: HashMap<Uuid, AESKey>,
18 pub implicit_deleted: HashMap<Uuid, bool>,
19 pub children: HashMap<Uuid, HashSet<Uuid>>,
20}
21
22impl<T: TreeLike> LazyTree<T> {
23 pub fn new(tree: T) -> Self {
24 Self {
25 name: HashMap::new(),
26 key: HashMap::new(),
27 implicit_deleted: HashMap::new(),
28 children: HashMap::new(),
29 tree,
30 }
31 }
32}
33
34impl<T: TreeLike> LazyTree<T> {
35 pub fn access_mode(&self, owner: Owner, id: &Uuid) -> SharedResult<Option<UserAccessMode>> {
36 let mut file = self.find(id)?;
37 let mut max_access_mode = None;
38 let mut visited_ids = vec![];
39 while !visited_ids.contains(file.id()) {
40 visited_ids.push(*file.id());
41 let access_mode = file.access_mode(&owner);
42 if access_mode > max_access_mode {
43 max_access_mode = access_mode;
44 }
45 if file.parent() == file.id() {
46 break; } else if let Some(parent) = self.maybe_find(file.parent()) {
48 file = parent
49 } else {
50 break; }
52 }
53 Ok(max_access_mode)
54 }
55
56 pub fn in_pending_share(&mut self, id: &Uuid) -> SharedResult<bool> {
57 let mut id = *id;
58 loop {
59 if self.find(&id)?.parent() == self.find(&id)?.id() {
60 return Ok(false); } else if let Some(link) = self.linked_by(&id)? {
62 id = link;
63 } else if self.maybe_find(self.find(&id)?.parent()).is_some() {
64 id = *self.find(&id)?.parent();
65 } else {
66 return Ok(true); }
68 }
69 }
70
71 pub fn all_children(&mut self) -> SharedResult<&HashMap<Uuid, HashSet<Uuid>>> {
72 if self.children.is_empty() {
73 let mut all_children: HashMap<Uuid, HashSet<Uuid>> = HashMap::new();
74 for file in self.all_files()? {
75 if !file.is_root() {
76 let mut children = all_children.remove(file.parent()).unwrap_or_default();
77 children.insert(*file.id());
78 all_children.insert(*file.parent(), children);
79 }
80 }
81 self.children = all_children;
82 }
83
84 Ok(&self.children)
85 }
86
87 pub fn calculate_deleted(&mut self, id: &Uuid) -> SharedResult<bool> {
88 let (visited_ids, deleted) = {
89 let mut file = self.find(id)?;
90 let mut visited_ids = vec![];
91 let mut deleted = false;
92
93 while !file.is_root()
94 && self.maybe_find(file.parent()).is_some()
95 && !visited_ids.contains(file.id())
96 {
97 visited_ids.push(*file.id());
98 if let Some(&implicit) = self.implicit_deleted.get(file.id()) {
99 deleted = implicit;
100 break;
101 }
102
103 if file.explicitly_deleted() {
104 deleted = true;
105 break;
106 }
107
108 file = match self.maybe_find_parent(file) {
109 Some(file) => file,
110 None => {
111 if !file.user_access_keys().is_empty() {
112 break;
113 } else {
114 return Err(SharedErrorKind::FileParentNonexistent.into());
115 }
116 }
117 }
118 }
119
120 (visited_ids, deleted)
121 };
122
123 for id in visited_ids {
124 self.implicit_deleted.insert(id, deleted);
125 }
126
127 Ok(deleted)
128 }
129
130 pub fn decrypt_key(&mut self, id: &Uuid, account: &Account) -> SharedResult<AESKey> {
131 let mut file_id = *self.find(id)?.id();
132 let mut visited_ids = vec![];
133
134 loop {
135 if self.key.get(&file_id).is_some() {
136 break;
137 }
138
139 let my_pk = account.public_key();
140
141 let maybe_file_key = if let Some(user_access) = self
142 .find(&file_id)?
143 .user_access_keys()
144 .iter()
145 .find(|access| access.encrypted_for == my_pk)
146 {
147 Some(user_access.decrypt(account)?)
148 } else {
149 None
150 };
151 if let Some(file_key) = maybe_file_key {
152 self.key.insert(file_id, file_key);
153 break;
154 }
155
156 visited_ids.push(file_id);
157 file_id = *self.find_parent(self.find(&file_id)?)?.id();
158 }
159
160 for id in visited_ids.iter().rev() {
161 let decrypted_key = {
162 let file = self.find(id)?;
163 let parent = self.find_parent(file)?;
164 let parent_key = self
165 .key
166 .get(parent.id())
167 .ok_or(SharedErrorKind::Unexpected(
168 "parent key should have been populated by prior routine",
169 ))?;
170 let encrypted_key = file.folder_access_key();
171 symkey::decrypt(parent_key, encrypted_key)?
172 };
173 self.key.insert(*id, decrypted_key);
174 }
175
176 Ok(*self.key.get(id).ok_or(SharedErrorKind::Unexpected(
177 "parent key should have been populated by prior routine (2)",
178 ))?)
179 }
180
181 pub fn name(&mut self, id: &Uuid, account: &Account) -> SharedResult<String> {
182 if let Some(name) = self.name.get(id) {
183 return Ok(name.clone());
184 }
185 let key = self.decrypt_key(id, account)?;
186 let name = self.find(id)?.secret_name().to_string(&key)?;
187 self.name.insert(*id, name.clone());
188 Ok(name)
189 }
190
191 pub fn name_using_links(&mut self, id: &Uuid, account: &Account) -> SharedResult<String> {
192 let id = if let Some(link) = self.linked_by(id)? { link } else { *id };
193 self.name(&id, account)
194 }
195
196 pub fn parent_using_links(&mut self, id: &Uuid) -> SharedResult<Uuid> {
197 let id = if let Some(link) = self.linked_by(id)? { link } else { *id };
198 Ok(*self.find(&id)?.parent())
199 }
200
201 pub fn linked_by(&mut self, id: &Uuid) -> SharedResult<Option<Uuid>> {
202 for link_id in self.owned_ids() {
203 if let FileType::Link { target } = self.find(&link_id)?.file_type() {
204 if id == &target && !self.calculate_deleted(&link_id)? {
205 return Ok(Some(link_id));
206 }
207 }
208 }
209 Ok(None)
210 }
211
212 pub fn children(&mut self, id: &Uuid) -> SharedResult<HashSet<Uuid>> {
215 if let Some(children) = self.children.get(id) {
217 return Ok(children.clone());
218 }
219
220 let file = self.find(id)?;
222 if !file.is_folder() {
223 return Ok(HashSet::default());
224 }
225
226 self.all_children()?;
228
229 if let Some(children) = self.children.get(id) {
231 return Ok(children.clone());
232 }
233
234 Ok(HashSet::new())
235 }
236
237 pub fn children_using_links(&mut self, id: &Uuid) -> SharedResult<HashSet<Uuid>> {
239 let mut children = HashSet::new();
240 for child in self.children(id)? {
241 if let FileType::Link { target } = self.find(&child)?.file_type() {
242 if !self.calculate_deleted(&child)? {
243 children.insert(target);
244 }
245 } else {
246 children.insert(child);
247 }
248 }
249
250 Ok(children)
251 }
252
253 pub fn descendants(&mut self, id: &Uuid) -> SharedResult<HashSet<Uuid>> {
256 let mut result = HashSet::new();
258 let mut to_process = vec![*id];
259 let mut i = 0;
260 while i < to_process.len() {
261 let new_descendents = self
262 .children(&to_process[i])?
263 .into_iter()
264 .filter(|f| !result.contains(f))
265 .collect::<Vec<Uuid>>();
266 to_process.extend(new_descendents.iter());
268 result.extend(new_descendents.into_iter());
269 i += 1;
270 }
271 Ok(result)
272 }
273
274 pub fn descendants_using_links(&mut self, id: &Uuid) -> SharedResult<HashSet<Uuid>> {
275 let mut result = HashSet::new();
277 let mut to_process = vec![*id];
278 let mut i = 0;
279 while i < to_process.len() {
280 let new_descendents = self
281 .children_using_links(&to_process[i])?
282 .into_iter()
283 .filter(|f| !result.contains(f))
284 .collect::<Vec<Uuid>>();
285 to_process.extend(new_descendents.iter());
287 result.extend(new_descendents.into_iter());
288 i += 1;
289 }
290 Ok(result)
291 }
292
293 pub fn ancestors(&self, id: &Uuid) -> SharedResult<HashSet<Uuid>> {
297 let mut result = HashSet::new();
298 let mut current_file = self.find(id)?;
299 while !current_file.is_root()
300 && self.maybe_find(current_file.parent()).is_some()
301 && !result.contains(current_file.parent())
302 {
303 result.insert(*current_file.parent());
304 current_file = self.find_parent(current_file)?;
305 }
306 Ok(result)
307 }
308
309 pub fn decrypt_document(
310 &mut self, id: &Uuid, encrypted: &EncryptedDocument, account: &Account,
311 ) -> SharedResult<DecryptedDocument> {
312 let key = self.decrypt_key(id, account)?;
313 let compressed = symkey::decrypt(&key, encrypted)?;
314 compression_service::decompress(&compressed)
315 }
316
317 pub fn stage<T2: TreeLikeMut<F = T::F>>(self, staged: T2) -> LazyTree<StagedTree<T, T2>> {
318 LazyTree::<StagedTree<T, T2>> {
320 tree: StagedTree::new(self.tree, staged),
321 name: HashMap::new(),
322 key: self.key,
323 implicit_deleted: HashMap::new(),
324 children: HashMap::new(),
325 }
326 }
327
328 pub fn stage_removals(self, removed: HashSet<Uuid>) -> LazyTree<StagedTree<T, Option<T::F>>> {
329 LazyTree::<StagedTree<T, Option<T::F>>> {
331 tree: StagedTree::removal(self.tree, removed),
332 name: HashMap::new(),
333 key: self.key,
334 implicit_deleted: HashMap::new(),
335 children: HashMap::new(),
336 }
337 }
338
339 pub fn assert_names_decryptable(&mut self, account: &Account) -> SharedResult<()> {
341 for id in self.owned_ids() {
342 if self.name(&id, account).is_err() {
343 return Err(SharedErrorKind::ValidationFailure(
344 ValidationFailure::NonDecryptableFileName(id),
345 )
346 .into());
347 }
348 }
349 Ok(())
350 }
351}
352
353pub type Stage1<Base, Local> = StagedTree<Base, Local>;
354pub type LazyStaged1<Base, Local> = LazyTree<Stage1<Base, Local>>;
355pub type Stage2<Base, Local, Staged> = StagedTree<StagedTree<Base, Local>, Staged>;
356pub type LazyStage2<Base, Local, Staged> = LazyTree<Stage2<Base, Local, Staged>>;
357
358#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Eq)]
359pub enum ValidationFailure {
360 Orphan(Uuid),
361 Cycle(HashSet<Uuid>),
362 PathConflict(HashSet<Uuid>),
363 FileNameTooLong(Uuid),
364 NonFolderWithChildren(Uuid),
365 FileWithDifferentOwnerParent(Uuid),
366 NonDecryptableFileName(Uuid),
367 SharedLink { link: Uuid, shared_ancestor: Uuid },
368 DuplicateLink { target: Uuid },
369 BrokenLink(Uuid),
370 OwnedLink(Uuid),
371}
372
373impl<T> LazyTree<T>
374where
375 T: TreeLikeMut,
376{
377 pub fn stage_and_promote<S: TreeLikeMut<F = T::F>>(
378 &mut self, mut staged: S,
379 ) -> SharedResult<()> {
380 for id in staged.owned_ids() {
381 if let Some(removed) = staged.remove(id)? {
382 self.tree.insert(removed)?;
383 }
384 }
385 self.name = HashMap::new();
387 self.implicit_deleted = HashMap::new();
388 self.children = HashMap::new();
389 Ok(())
390 }
391
392 pub fn stage_validate_and_promote<S: TreeLikeMut<F = T::F>>(
393 &mut self, mut staged: S, owner: Owner,
394 ) -> SharedResult<()> {
395 StagedTree::new(&self.tree, &mut staged)
396 .to_lazy()
397 .validate(owner)?;
398 self.stage_and_promote(staged)?;
399 Ok(())
400 }
401
402 pub fn stage_removals_and_promote(&mut self, removed: HashSet<Uuid>) -> SharedResult<()> {
403 for id in removed {
404 self.tree.remove(id)?;
405 }
406 self.name = HashMap::new();
408 self.implicit_deleted = HashMap::new();
409 self.children = HashMap::new();
410 Ok(())
411 }
412}
413
414impl<Base, Staged> LazyStaged1<Base, Staged>
415where
416 Base: TreeLikeMut,
417 Staged: TreeLikeMut<F = Base::F>,
418{
419 pub fn promote(self) -> SharedResult<LazyTree<Base>> {
421 let mut staged = self.tree.staged;
422 let mut base = self.tree.base;
423 for id in staged.owned_ids() {
424 if let Some(removed) = staged.remove(id)? {
425 base.insert(removed)?;
426 }
427 }
428 for id in self.tree.removed {
429 base.remove(id)?;
430 }
431
432 Ok(LazyTree {
433 tree: base,
434 name: HashMap::new(),
435 key: self.key,
436 implicit_deleted: HashMap::new(),
437 children: HashMap::new(),
438 })
439 }
440}
441
442impl<Base, Staged> LazyStaged1<Base, Staged>
443where
444 Base: TreeLike,
445 Staged: TreeLikeMut<F = Base::F>,
446{
447 pub fn unstage(self) -> (LazyTree<Base>, Staged) {
449 (
450 LazyTree {
451 tree: self.tree.base,
452 name: HashMap::new(),
453 key: self.key,
454 implicit_deleted: HashMap::new(),
455 children: HashMap::new(),
456 },
457 self.tree.staged,
458 )
459 }
460}
461
462impl<T: TreeLike> TreeLike for LazyTree<T> {
463 type F = T::F;
464
465 fn ids(&self) -> HashSet<&Uuid> {
466 self.tree.ids()
467 }
468
469 fn maybe_find(&self, id: &Uuid) -> Option<&Self::F> {
470 self.tree.maybe_find(id)
471 }
472}