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