1use crate::ServerError;
2use crate::ServerError::ClientError;
3use crate::billing::app_store_client::AppStoreClient;
4use crate::billing::google_play_client::GooglePlayClient;
5use crate::billing::stripe_client::StripeClient;
6use crate::defense::SERVER_BANDWIDTH_CAP;
7use crate::document_service::DocumentService;
8use crate::schema::ServerDb;
9
10use crate::{RequestContext, ServerState};
11use db_rs::Db;
12use lb_rs::model::api::{UpsertError, *};
13use lb_rs::model::clock::get_time;
14use lb_rs::model::errors::{LbErrKind, LbResult};
15use lb_rs::model::file_like::FileLike;
16use lb_rs::model::file_metadata::{Diff, Owner};
17use lb_rs::model::server_meta::{IntoServerMeta, ServerMeta};
18use lb_rs::model::server_tree::ServerTree;
19use lb_rs::model::tree_like::TreeLike;
20use std::collections::{HashMap, HashSet};
21use std::hash::Hash;
22use std::ops::DerefMut;
23use tracing::{debug, error, warn};
24
25impl<S, A, G, D> ServerState<S, A, G, D>
26where
27 S: StripeClient,
28 A: AppStoreClient,
29 G: GooglePlayClient,
30 D: DocumentService,
31{
32 pub async fn upsert_file_metadata_v2(
33 &self, context: RequestContext<UpsertRequestV2>,
34 ) -> Result<(), ServerError<UpsertError>> {
35 let request = context.request;
36 let req_owner = Owner(context.public_key);
37
38 {
39 let mut prior_deleted = HashSet::new();
40 let mut current_deleted = HashSet::new();
41
42 let mut lock = self.index_db.lock().await;
43 let db = lock.deref_mut();
44 let tx = db.begin_transaction()?;
45
46 let usage_cap =
47 Self::get_cap(db, &context.public_key).map_err(|err| internal!("{:?}", err))?;
48
49 let mut tree = ServerTree::new(
50 req_owner,
51 &mut db.owned_files,
52 &mut db.shared_files,
53 &mut db.file_children,
54 &mut db.metas,
55 )?
56 .to_lazy();
57
58 let old_usage = Self::get_usage_helper(&mut tree)
59 .map_err(|err| internal!("{:?}", err))?
60 .iter()
61 .map(|f| f.size_bytes)
62 .sum::<u64>();
63
64 for id in tree.ids() {
65 if tree.calculate_deleted(&id)? {
66 prior_deleted.insert(id);
67 }
68 }
69
70 let mut tree = tree.stage_diff_v2(request.updates.clone())?;
71 for id in tree.ids() {
72 if tree.calculate_deleted(&id)? {
73 current_deleted.insert(id);
74 }
75 }
76
77 tree.validate(req_owner)?;
78
79 let new_usage = Self::get_usage_helper(&mut tree)
80 .map_err(|err| internal!("{:?}", err))?
81 .iter()
82 .map(|f| f.size_bytes)
83 .sum::<u64>();
84
85 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on upsert");
86
87 if new_usage > usage_cap && new_usage >= old_usage {
88 warn!("user over cap");
89 return Err(ClientError(UpsertError::UsageIsOverDataCap));
90 }
91
92 let tree = tree.promote()?;
93
94 for id in tree.ids() {
95 if tree.find(&id)?.is_document()
96 && current_deleted.contains(&id)
97 && !prior_deleted.contains(&id)
98 {
99 let meta = tree.find(&id)?;
100 if let Some(hmac) = meta.file.timestamped_value.value.document_hmac().copied() {
101 db.scheduled_file_cleanups
102 .insert((*meta.id(), hmac), get_time().0)?;
103 }
104 }
105 }
106
107 let all_files: Vec<ServerMeta> = tree.all_files()?.into_iter().cloned().collect();
108 for meta in all_files {
109 let id = meta.id();
110 if current_deleted.contains(id) && !prior_deleted.contains(id) {
111 for user_access_info in meta.user_access_keys() {
112 db.shared_files
113 .remove(&Owner(user_access_info.encrypted_for), id)?;
114 }
115 }
116 }
117
118 db.last_seen.insert(req_owner, get_time().0 as u64)?;
119
120 tx.drop_safely()?;
121 }
122
123 Ok(())
124 }
125
126 pub async fn change_doc_v2(
127 &self, context: RequestContext<ChangeDocRequestV2>,
128 ) -> Result<(), ServerError<ChangeDocError>> {
129 use ChangeDocError::*;
130 let owner = Owner(context.public_key);
131 let request = context.request;
132 let id = *request.diff.id();
133
134 if request.diff.diff() != vec![Diff::Hmac] {
136 return Err(ClientError(DiffMalformed));
137 }
138
139 match request.diff.new.timestamped_value.value.doc_size() {
140 Some(size) => {
141 if *size != request.new_content.value.len() {
142 return Err(ClientError(NewSizeIncorrect));
143 }
144 }
145 None => {
146 if !request.new_content.value.is_empty() {
148 return Err(ClientError(NewSizeIncorrect));
149 }
150 }
151 }
152
153 let hmac = if let Some(hmac) = request.diff.new.document_hmac() {
154 base64::encode_config(hmac, base64::URL_SAFE)
155 } else {
156 return Err(ClientError(HmacMissing));
157 };
158
159 let req_pk = context.public_key;
160
161 {
162 let mut lock = self.index_db.lock().await;
163 let db = lock.deref_mut();
164 let usage_cap = Self::get_cap(db, &context.public_key)
165 .map_err(|err| internal!("{:?}", err))? as usize;
166
167 let meta = db
168 .metas
169 .get()
170 .get(request.diff.new.id())
171 .ok_or(ClientError(DocumentNotFound))?
172 .clone();
173
174 let mut tree = ServerTree::new(
175 owner,
176 &mut db.owned_files,
177 &mut db.shared_files,
178 &mut db.file_children,
179 &mut db.metas,
180 )?
181 .to_lazy();
182
183 let old_usage = Self::get_usage_helper(&mut tree)
184 .map_err(|err| internal!("{:?}", err))?
185 .iter()
186 .map(|f| f.size_bytes)
187 .sum::<u64>() as usize;
188 let old_size = *meta.file.timestamped_value.value.doc_size();
189
190 let new_size = request.new_content.value.len();
191
192 let new_usage = old_usage - old_size.unwrap_or_default() + new_size;
193
194 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on change doc");
195
196 if new_usage > usage_cap {
197 warn!("user over cap");
198 return Err(ClientError(UsageIsOverDataCap));
199 }
200
201 let meta_owner = meta.owner();
202
203 let direct_access = meta_owner.0 == req_pk;
204
205 if tree.maybe_find(request.diff.new.id()).is_none() {
206 return Err(ClientError(NotPermissioned));
207 }
208
209 let mut share_access = false;
210 if !direct_access {
211 for ancestor in tree
212 .ancestors(request.diff.id())?
213 .iter()
214 .chain(vec![request.diff.new.id()])
215 {
216 let meta = tree.find(ancestor)?;
217
218 if meta
219 .user_access_keys()
220 .iter()
221 .any(|access| access.encrypted_for == req_pk)
222 {
223 share_access = true;
224 break;
225 }
226 }
227 }
228
229 if !direct_access && !share_access {
230 return Err(ClientError(NotPermissioned));
231 }
232
233 let meta = &tree
234 .maybe_find(request.diff.new.id())
235 .ok_or(ClientError(DocumentNotFound))?
236 .file;
237
238 if let Some(old) = &request.diff.old {
239 if meta != old {
240 return Err(ClientError(OldVersionIncorrect));
241 }
242 }
243
244 if tree.calculate_deleted(request.diff.new.id())? {
245 return Err(ClientError(DocumentDeleted));
246 }
247
248 let id = request.diff.new.id();
249 let hmac = request.diff.new.document_hmac().unwrap();
250 db.scheduled_file_cleanups.remove(&(*id, *hmac))?;
251 }
252
253 let new_version = get_time().0 as u64;
254 let new = request.diff.new.clone().add_time(new_version);
255 self.document_service
256 .insert(
257 request.diff.new.id(),
258 request.diff.new.document_hmac().unwrap(),
259 &request.new_content,
260 )
261 .await?;
262 debug!(?id, ?hmac, "Inserted document contents");
263
264 let result = async {
265 let mut lock = self.index_db.lock().await;
266 let db = lock.deref_mut();
267 let tx = db.begin_transaction()?;
268
269 let mut tree = ServerTree::new(
270 owner,
271 &mut db.owned_files,
272 &mut db.shared_files,
273 &mut db.file_children,
274 &mut db.metas,
275 )?
276 .to_lazy();
277
278 if tree.calculate_deleted(request.diff.new.id())? {
279 return Err(ClientError(DocumentDeleted));
280 }
281
282 let meta = &tree
283 .maybe_find(request.diff.new.id())
284 .ok_or(ClientError(DocumentNotFound))?
285 .file;
286
287 if let Some(old) = &request.diff.old {
288 if meta != old {
289 return Err(ClientError(OldVersionIncorrect));
290 }
291 }
292
293 tree.stage(vec![new]).promote()?;
294 if let Some(old) = &request
295 .diff
296 .old
297 .and_then(|old| old.document_hmac().copied())
298 {
299 db.scheduled_file_cleanups
300 .insert((*request.diff.new.id(), *old), get_time().0)?;
301 }
302
303 tx.drop_safely()?;
304 drop(lock);
305 Ok(())
306 };
307
308 let result = result.await;
309
310 if result.is_err() {
311 self.document_service
313 .delete(request.diff.new.id(), request.diff.new.document_hmac().unwrap())
314 .await?;
315 debug!(?id, ?hmac, "Cleaned up new document contents after failed metadata update");
316 }
317
318 result?;
319
320 Ok(())
321 }
322
323 pub async fn get_document(
324 &self, context: RequestContext<GetDocRequest>,
325 ) -> Result<GetDocumentResponse, ServerError<GetDocumentError>> {
326 let request = &context.request;
327 let requester = Owner(context.public_key);
328 {
329 let mut lock = self.index_db.lock().await;
330 let db = lock.deref_mut();
331 let tx = db.begin_transaction()?;
332
333 let meta_exists = db.metas.get().get(&request.id).is_some();
334
335 let mut tree = ServerTree::new(
336 requester,
337 &mut db.owned_files,
338 &mut db.shared_files,
339 &mut db.file_children,
340 &mut db.metas,
341 )?
342 .to_lazy();
343
344 if tree.maybe_find(&request.id).is_none() {
345 return Err(if meta_exists {
346 ClientError(GetDocumentError::NotPermissioned)
347 } else {
348 ClientError(GetDocumentError::DocumentNotFound)
349 });
350 }
351
352 if tree.calculate_deleted(&request.id)? {
353 return Err(ClientError(GetDocumentError::DocumentNotFound));
354 }
355
356 tx.drop_safely()?;
357 };
358
359 let Some(content) = self
360 .document_service
361 .maybe_get(&request.id, &request.hmac)
362 .await?
363 else {
364 return Err(ClientError(GetDocumentError::DocumentNotFound));
365 };
366
367 let mut lock = self.index_db.lock().await;
368 let db = lock.deref_mut();
369 let tx = db.begin_transaction()?;
370
371 if self.config.features.bandwidth_controls {
372 let mut server_wide = db.server_egress.get().cloned().unwrap_or_default();
373 let mut account_bandwidth = db
374 .egress_by_owner
375 .get()
376 .get(&requester)
377 .cloned()
378 .unwrap_or_default();
379 let account_bandwidth_cap = db
380 .accounts
381 .get()
382 .get(&requester)
383 .map(|account| account.billing_info.bandwidth_cap())
384 .unwrap_or_default();
385
386 let doc_size = content.value.len();
387
388 if doc_size + server_wide.current_bandwidth() > SERVER_BANDWIDTH_CAP {
389 error!("Bandwidth caps are now being enforced");
390 if doc_size + account_bandwidth.current_bandwidth() > account_bandwidth_cap {
391 error!("User bandwidth cap exceeded");
392 return Err(ClientError(GetDocumentError::BandwidthExceeded));
393 }
394 }
395
396 server_wide.increase_by(doc_size);
397 account_bandwidth.increase_by(doc_size);
398
399 db.server_egress.insert(server_wide)?;
400 db.egress_by_owner.insert(requester, account_bandwidth)?;
401 }
402
403 tx.drop_safely()?;
404
405 Ok(GetDocumentResponse { content })
406 }
407
408 pub async fn get_file_ids(
409 &self, context: RequestContext<GetFileIdsRequest>,
410 ) -> Result<GetFileIdsResponse, ServerError<GetFileIdsError>> {
411 let owner = Owner(context.public_key);
412 let mut db = self.index_db.lock().await;
413 let db = db.deref_mut();
414
415 Ok(GetFileIdsResponse {
416 ids: ServerTree::new(
417 owner,
418 &mut db.owned_files,
419 &mut db.shared_files,
420 &mut db.file_children,
421 &mut db.metas,
422 )?
423 .ids()
424 .into_iter()
425 .collect(),
426 })
427 }
428
429 pub async fn get_updates_v2(
430 &self, context: RequestContext<GetUpdatesRequestV2>,
431 ) -> Result<GetUpdatesResponseV2, ServerError<GetUpdatesError>> {
432 let request = &context.request;
433 let owner = Owner(context.public_key);
434
435 let mut db = self.index_db.lock().await;
436 let db = db.deref_mut();
437 let mut tree = ServerTree::new(
438 owner,
439 &mut db.owned_files,
440 &mut db.shared_files,
441 &mut db.file_children,
442 &mut db.metas,
443 )?
444 .to_lazy();
445
446 let mut result_ids = HashSet::new();
447 for id in tree.ids() {
448 let file = tree.find(&id)?;
449 if file.version >= request.since_metadata_version {
450 result_ids.insert(id);
451 if file.owner() != owner
452 && file
453 .user_access_keys()
454 .iter()
455 .any(|k| !k.deleted && k.encrypted_for == context.public_key)
456 {
457 result_ids.insert(id);
458 result_ids.extend(tree.descendants(&id)?);
459 }
460 }
461 }
462
463 Ok(GetUpdatesResponseV2 {
464 as_of_metadata_version: get_time().0 as u64,
465 file_metadata: tree
466 .all_files()?
467 .into_iter()
468 .filter(|meta| result_ids.contains(meta.id()))
469 .map(|meta| meta.file.clone())
470 .collect(),
471 })
472 }
473
474 pub async fn admin_disappear_file(
475 &self, context: RequestContext<AdminDisappearFileRequest>,
476 ) -> Result<(), ServerError<AdminDisappearFileError>> {
477 let mut docs_to_delete = Vec::new();
478
479 {
480 let mut db = self.index_db.lock().await;
481 let db = db.deref_mut();
482 let tx = db.begin_transaction()?;
483
484 if !Self::is_admin::<AdminDisappearFileError>(
485 db,
486 &context.public_key,
487 &self.config.admin.admins,
488 )? {
489 return Err(ClientError(AdminDisappearFileError::NotPermissioned));
490 }
491
492 let owner = {
493 let meta = db
494 .metas
495 .get()
496 .get(&context.request.id)
497 .ok_or(ClientError(AdminDisappearFileError::FileNonexistent))?;
498 if meta.is_root() {
499 return Err(ClientError(AdminDisappearFileError::RootModificationInvalid));
500 }
501 meta.owner()
502 };
503 let mut tree = ServerTree::new(
504 owner,
505 &mut db.owned_files,
506 &mut db.shared_files,
507 &mut db.file_children,
508 &mut db.metas,
509 )?
510 .to_lazy();
511
512 let metas_to_delete = {
513 let mut metas_to_delete = tree.descendants(&context.request.id)?;
514 metas_to_delete.insert(context.request.id);
515 metas_to_delete
516 };
517 for id in metas_to_delete.clone() {
518 if !tree.calculate_deleted(&id)? {
519 let meta = tree.find(&id)?;
520 if meta.is_document() && meta.owner() == owner {
521 if let Some(hmac) = meta.document_hmac() {
522 docs_to_delete.push((*meta.id(), *hmac));
523 }
524 }
525 }
526 }
527
528 for id in metas_to_delete {
529 let meta = db
530 .metas
531 .remove(&id)?
532 .ok_or(ClientError(AdminDisappearFileError::FileNonexistent))?;
533
534 let owner = meta.owner();
536
537 if !db.owned_files.remove(&owner, &id)? {
538 error!(
539 ?id,
540 ?owner,
541 "attempted to disappear a file, owner or id not present in owned_files"
542 );
543 }
544
545 for user_access_key in meta.user_access_keys() {
547 let sharee = Owner(user_access_key.encrypted_for);
548 if !db.shared_files.remove(&sharee, &id)? {
549 error!(
550 ?id,
551 ?sharee,
552 "attempted to disappear a file, a sharee didn't have it shared"
553 );
554 }
555 }
556
557 let parent = *meta.parent();
559 if !db.file_children.remove(meta.parent(), &id)? {
560 error!(
561 ?id,
562 ?parent,
563 "attempted to disappear a file, the parent didn't have it as a child"
564 );
565 }
566 }
567
568 let username = db
569 .accounts
570 .get()
571 .get(&Owner(context.public_key))
572 .map(|account| account.username.clone())
573 .unwrap_or_else(|| "~unknown~".to_string());
574 warn!(?username, ?context.request.id, "Disappeared file");
575
576 tx.drop_safely()?;
577 }
578
579 for (id, version) in docs_to_delete {
580 self.document_service.delete(&id, &version).await?;
581 }
582
583 Ok(())
584 }
585
586 pub async fn admin_validate_account(
587 &self, context: RequestContext<AdminValidateAccountRequest>,
588 ) -> Result<AdminValidateAccount, ServerError<AdminValidateAccountError>> {
589 let request = &context.request;
590 let mut db = self.index_db.lock().await;
591 if !Self::is_admin::<AdminValidateAccountError>(
592 &db,
593 &context.public_key,
594 &self.config.admin.admins,
595 )? {
596 return Err(ClientError(AdminValidateAccountError::NotPermissioned));
597 }
598
599 let owner = *db
600 .usernames
601 .get()
602 .get(&request.username)
603 .ok_or(ClientError(AdminValidateAccountError::UserNotFound))?;
604
605 Ok(self.validate_account_helper(&mut db, owner)?)
606 }
607
608 pub fn validate_account_helper(
609 &self, db: &mut ServerDb, owner: Owner,
610 ) -> LbResult<AdminValidateAccount> {
611 let mut result = AdminValidateAccount::default();
612
613 let mut tree = ServerTree::new(
614 owner,
615 &mut db.owned_files,
616 &mut db.shared_files,
617 &mut db.file_children,
618 &mut db.metas,
619 )?
620 .to_lazy();
621
622 for id in tree.ids() {
623 if !tree.calculate_deleted(&id)? {
624 let file = tree.find(&id)?;
625 if file.is_document() && file.document_hmac().is_some() {
626 if file.file.timestamped_value.value.doc_size().is_none() {
627 result.documents_missing_size.push(id);
628 }
629
630 if !self
631 .document_service
632 .exists(&id, file.document_hmac().unwrap())
633 {
634 result.documents_missing_content.push(id);
635 }
636 }
637 }
638 }
639
640 let validation_res = tree.stage(None).validate(owner);
641 match validation_res {
642 Ok(_) => {}
643 Err(err) => match err.kind {
644 LbErrKind::Validation(validation) => {
645 result.tree_validation_failures.push(validation)
646 }
647 _ => {
648 error!(?owner, ?err, "Unexpected error while validating tree")
649 }
650 },
651 }
652
653 Ok(result)
654 }
655
656 pub async fn admin_validate_server(
657 &self, context: RequestContext<AdminValidateServerRequest>,
658 ) -> Result<AdminValidateServer, ServerError<AdminValidateServerError>> {
659 let mut db = self.index_db.lock().await;
660 let db = db.deref_mut();
661
662 if !Self::is_admin::<AdminValidateServerError>(
663 db,
664 &context.public_key,
665 &self.config.admin.admins,
666 )? {
667 return Err(ClientError(AdminValidateServerError::NotPermissioned));
668 }
669
670 let mut result: AdminValidateServer = Default::default();
671
672 let mut deleted_ids = HashSet::new();
673 for (id, meta) in db.metas.get().clone() {
674 let mut tree = ServerTree::new(
676 meta.owner(),
677 &mut db.owned_files,
678 &mut db.shared_files,
679 &mut db.file_children,
680 &mut db.metas,
681 )?
682 .to_lazy();
683 if tree.calculate_deleted(&id)? {
684 deleted_ids.insert(id);
685 }
686 }
687
688 for (owner, account) in db.accounts.get().clone() {
690 let validation = self.validate_account_helper(db, owner)?;
691 if !validation.is_empty() {
692 result
693 .users_with_validation_failures
694 .insert(account.username, validation);
695 }
696 }
697
698 for (username, owner) in db.usernames.get().clone() {
700 if let Some(account) = db.accounts.get().get(&owner) {
701 if username != account.username {
702 result
703 .usernames_mapped_to_wrong_accounts
704 .insert(username, account.username.clone());
705 }
706 } else {
707 result
708 .usernames_mapped_to_nonexistent_accounts
709 .insert(username, owner);
710 }
711 }
712 for (_, account) in db.accounts.get().clone() {
713 if db.usernames.get().get(&account.username).is_none() {
714 result
715 .usernames_unmapped_to_accounts
716 .insert(account.username.clone());
717 }
718 }
719
720 for (owner, ids) in db.owned_files.get().clone() {
722 for id in ids {
723 if let Some(meta) = db.metas.get().get(&id) {
724 if meta.owner() != owner {
725 insert(&mut result.owners_mapped_to_unowned_files, owner, id);
726 }
727 } else {
728 insert(&mut result.owners_mapped_to_nonexistent_files, owner, id);
729 }
730 }
731 }
732 for (id, meta) in db.metas.get().clone() {
733 if let Some(ids) = db.owned_files.get().get(&meta.owner()) {
734 if !ids.contains(&id) {
735 insert(&mut result.owners_unmapped_to_owned_files, meta.owner(), *meta.id());
736 }
737 } else {
738 result.owners_unmapped.insert(meta.owner());
739 }
740 }
741
742 for (sharee, ids) in db.shared_files.get().clone() {
744 for id in ids {
745 if let Some(meta) = db.metas.get().get(&id) {
746 if !meta.user_access_keys().iter().any(|k| {
747 !k.deleted && k.encrypted_for == sharee.0 && k.encrypted_by != sharee.0
748 }) {
749 insert(&mut result.sharees_mapped_to_unshared_files, sharee, id);
750 }
751 } else {
752 insert(&mut result.sharees_mapped_to_nonexistent_files, sharee, id);
753 }
754 if deleted_ids.contains(&id) {
755 insert(&mut result.sharees_mapped_for_deleted_files, sharee, id);
756 }
757 }
758 }
759 for (id, meta) in db.metas.get().clone() {
760 let mut deleted = false;
762 let mut ancestor = meta.clone();
763 loop {
764 if ancestor.explicitly_deleted() {
765 deleted = true;
766 break;
767 }
768 if ancestor.is_root() {
769 break;
770 }
771 match db.metas.get().get(ancestor.parent()) {
772 Some(parent) => ancestor = parent.clone(),
773 None => {
774 error!("missing parent for file {:?}", ancestor.parent());
775 deleted = true;
776 break;
777 }
778 }
779 }
780 if deleted {
781 continue;
782 }
783
784 for k in meta.user_access_keys() {
785 if k.deleted {
786 continue;
787 }
788 let sharee = Owner(k.encrypted_for);
789 if let Some(ids) = db.shared_files.get().get(&sharee) {
790 let self_share = k.encrypted_for == k.encrypted_by;
791 let indexed_share = ids.contains(&id);
792 if self_share && indexed_share {
793 insert(&mut result.sharees_mapped_for_owned_files, sharee, id);
794 } else if !self_share && !indexed_share {
795 insert(&mut result.sharees_unmapped_to_shared_files, sharee, id);
796 }
797 } else {
798 result.sharees_unmapped.insert(meta.owner());
799 }
800 }
801 }
802
803 for (parent_id, child_ids) in db.file_children.get().clone() {
805 for child_id in child_ids {
806 if let Some(meta) = db.metas.get().get(&child_id) {
807 if meta.parent() != &parent_id {
808 insert(
809 &mut result.files_mapped_as_parent_to_non_children,
810 parent_id,
811 child_id,
812 );
813 }
814 } else {
815 insert(
816 &mut result.files_mapped_as_parent_to_nonexistent_children,
817 parent_id,
818 child_id,
819 );
820 }
821 }
822 }
823 for (id, meta) in db.metas.get().clone() {
824 if let Some(child_ids) = db.file_children.get().get(meta.parent()) {
825 if meta.is_root() && child_ids.contains(&id) {
826 result.files_mapped_as_parent_to_self.insert(id);
827 } else if !meta.is_root() && !child_ids.contains(&id) {
828 insert(&mut result.files_unmapped_as_parent_to_children, *meta.parent(), id);
829 }
830 } else {
831 result.files_unmapped_as_parent.insert(*meta.parent());
832 }
833 }
834
835 for (id, meta) in db.metas.get().clone() {
837 if let Some(hmac) = meta.document_hmac() {
838 if !deleted_ids.contains(&id) && !self.document_service.exists(&id, hmac) {
839 result.files_with_hmacs_and_no_contents.insert(id);
840 }
841 }
842 }
843
844 Ok(result)
845 }
846
847 pub async fn admin_file_info(
848 &self, context: RequestContext<AdminFileInfoRequest>,
849 ) -> Result<AdminFileInfoResponse, ServerError<AdminFileInfoError>> {
850 let request = &context.request;
851 let mut db = self.index_db.lock().await;
852 let db = db.deref_mut();
853 if !Self::is_admin::<AdminFileInfoError>(
854 db,
855 &context.public_key,
856 &self.config.admin.admins,
857 )? {
858 return Err(ClientError(AdminFileInfoError::NotPermissioned));
859 }
860
861 let file = db
862 .metas
863 .get()
864 .get(&request.id)
865 .ok_or(ClientError(AdminFileInfoError::FileNonexistent))?
866 .clone();
867
868 let mut tree = ServerTree::new(
869 file.owner(),
870 &mut db.owned_files,
871 &mut db.shared_files,
872 &mut db.file_children,
873 &mut db.metas,
874 )?
875 .to_lazy();
876
877 let ancestors = tree
878 .ancestors(&request.id)?
879 .into_iter()
880 .filter_map(|id| tree.maybe_find(&id))
881 .cloned()
882 .collect();
883 let descendants = tree
884 .descendants(&request.id)?
885 .into_iter()
886 .filter_map(|id| tree.maybe_find(&id))
887 .cloned()
888 .collect();
889
890 Ok(AdminFileInfoResponse { file, ancestors, descendants })
891 }
892
893 pub async fn admin_rebuild_index(
894 &self, context: RequestContext<AdminRebuildIndexRequest>,
895 ) -> Result<(), ServerError<AdminRebuildIndexError>> {
896 let mut db = self.index_db.lock().await;
897
898 match context.request.index {
899 ServerIndex::OwnedFiles => {
900 db.owned_files.clear()?;
901 for owner in db.accounts.get().clone().keys() {
902 db.owned_files.create_key(*owner)?;
903 }
904 for (id, file) in db.metas.get().clone() {
905 db.owned_files.insert(file.owner(), id)?;
906 }
907 }
908 ServerIndex::SharedFiles => {
909 db.shared_files.clear()?;
910 for owner in db.accounts.get().clone().keys() {
911 db.shared_files.create_key(*owner)?;
912 }
913 for (id, file) in db.metas.get().clone() {
914 let mut deleted = false;
916 let mut ancestor = file.clone();
917 loop {
918 if ancestor.explicitly_deleted() {
919 deleted = true;
920 break;
921 }
922 if ancestor.is_root() {
923 break;
924 }
925 match db.metas.get().get(ancestor.parent()) {
926 Some(parent) => ancestor = parent.clone(),
927 None => {
928 error!("missing parent for file {:?}", ancestor.parent());
929 deleted = true;
930 break;
931 }
932 }
933 }
934
935 if !deleted {
936 for user_access_key in file.user_access_keys() {
937 if !user_access_key.deleted
938 && user_access_key.encrypted_for != user_access_key.encrypted_by
939 {
940 db.shared_files
941 .insert(Owner(user_access_key.encrypted_for), id)?;
942 }
943 }
944 }
945 }
946 }
947 ServerIndex::FileChildren => {
948 db.file_children.clear()?;
949 for id in db.metas.get().clone().keys() {
950 db.file_children.create_key(*id)?;
951 }
952 for (id, file) in db.metas.get().clone() {
953 db.file_children.insert(*file.parent(), id)?;
954 }
955 }
956 }
957 Ok(())
958 }
959}
960
961fn insert<K: Hash + Eq, V: Hash + Eq>(map: &mut HashMap<K, HashSet<V>>, k: K, v: V) {
962 map.entry(k).or_default().insert(v);
963}