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::crypto::Timestamped;
15use lb_rs::model::errors::{LbErrKind, LbResult};
16use lb_rs::model::file_like::FileLike;
17use lb_rs::model::file_metadata::{Diff, FileDiff, FileMetadata, Owner};
18use lb_rs::model::meta::Meta;
19use lb_rs::model::server_meta::{IntoServerMeta, ServerMeta};
20use lb_rs::model::server_tree::ServerTree;
21use lb_rs::model::signed_file::SignedFile;
22use lb_rs::model::tree_like::TreeLike;
23use std::collections::{HashMap, HashSet};
24use std::hash::Hash;
25use std::ops::DerefMut;
26use tracing::{debug, error, warn};
27
28impl<S, A, G, D> ServerState<S, A, G, D>
29where
30 S: StripeClient,
31 A: AppStoreClient,
32 G: GooglePlayClient,
33 D: DocumentService,
34{
35 pub async fn upsert_file_metadata(
36 &self, context: RequestContext<UpsertRequest>,
37 ) -> Result<(), ServerError<UpsertError>> {
38 let request = context.request;
39 let req_owner = Owner(context.public_key);
40
41 let mut new_deleted = vec![];
42 {
43 let mut prior_deleted = HashSet::new();
44 let mut current_deleted = HashSet::new();
45
46 let mut lock = self.index_db.lock().await;
47 let db = lock.deref_mut();
48 let tx = db.begin_transaction()?;
49
50 let usage_cap =
51 Self::get_cap(db, &context.public_key).map_err(|err| internal!("{:?}", err))?;
52
53 let mut tree = ServerTree::new(
54 req_owner,
55 &mut db.owned_files,
56 &mut db.shared_files,
57 &mut db.file_children,
58 &mut db.metas,
59 )?
60 .to_lazy();
61
62 let old_usage = Self::get_usage_helper(&mut tree)
63 .map_err(|err| internal!("{:?}", err))?
64 .iter()
65 .map(|f| f.size_bytes)
66 .sum::<u64>();
67
68 for id in tree.ids() {
69 if tree.calculate_deleted(&id)? {
70 prior_deleted.insert(id);
71 }
72 }
73
74 let mut tree = tree.stage_diff(request.updates.clone())?;
75 for id in tree.ids() {
76 if tree.calculate_deleted(&id)? {
77 current_deleted.insert(id);
78 }
79 }
80
81 tree.validate(req_owner)?;
82
83 let new_usage = Self::get_usage_helper(&mut tree)
84 .map_err(|err| internal!("{:?}", err))?
85 .iter()
86 .map(|f| f.size_bytes)
87 .sum::<u64>();
88
89 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on upsert");
90
91 if new_usage > usage_cap && new_usage >= old_usage {
92 warn!("usage over cap");
93 return Err(ClientError(UpsertError::UsageIsOverDataCap));
94 }
95
96 let tree = tree.promote()?;
97
98 for id in tree.ids() {
99 if tree.find(&id)?.is_document()
100 && current_deleted.contains(&id)
101 && !prior_deleted.contains(&id)
102 {
103 let meta = tree.find(&id)?;
104 if let Some(hmac) = meta.file.timestamped_value.value.document_hmac().copied() {
105 new_deleted.push((*meta.id(), hmac));
106 }
107 }
108 }
109
110 let all_files: Vec<ServerMeta> = tree.all_files()?.into_iter().cloned().collect();
111 for meta in all_files {
112 let id = meta.id();
113 if current_deleted.contains(id) && !prior_deleted.contains(id) {
114 for user_access_info in meta.user_access_keys() {
115 db.shared_files
116 .remove(&Owner(user_access_info.encrypted_for), id)?;
117 }
118 }
119 }
120
121 db.last_seen.insert(req_owner, get_time().0 as u64)?;
122
123 tx.drop_safely()?;
124 }
125
126 for (id, hmac) in new_deleted {
127 self.document_service.delete(&id, &hmac).await?;
128 let hmac = base64::encode_config(hmac, base64::URL_SAFE);
129 debug!(?id, ?hmac, "Deleted document contents");
130 }
131 Ok(())
132 }
133
134 pub async fn upsert_file_metadata_v2(
135 &self, context: RequestContext<UpsertRequestV2>,
136 ) -> Result<(), ServerError<UpsertError>> {
137 let request = context.request;
138 let req_owner = Owner(context.public_key);
139
140 {
141 let mut prior_deleted = HashSet::new();
142 let mut current_deleted = HashSet::new();
143
144 let mut lock = self.index_db.lock().await;
145 let db = lock.deref_mut();
146 let tx = db.begin_transaction()?;
147
148 let usage_cap =
149 Self::get_cap(db, &context.public_key).map_err(|err| internal!("{:?}", err))?;
150
151 let mut tree = ServerTree::new(
152 req_owner,
153 &mut db.owned_files,
154 &mut db.shared_files,
155 &mut db.file_children,
156 &mut db.metas,
157 )?
158 .to_lazy();
159
160 let old_usage = Self::get_usage_helper(&mut tree)
161 .map_err(|err| internal!("{:?}", err))?
162 .iter()
163 .map(|f| f.size_bytes)
164 .sum::<u64>();
165
166 for id in tree.ids() {
167 if tree.calculate_deleted(&id)? {
168 prior_deleted.insert(id);
169 }
170 }
171
172 let mut tree = tree.stage_diff_v2(request.updates.clone())?;
173 for id in tree.ids() {
174 if tree.calculate_deleted(&id)? {
175 current_deleted.insert(id);
176 }
177 }
178
179 tree.validate(req_owner)?;
180
181 let new_usage = Self::get_usage_helper(&mut tree)
182 .map_err(|err| internal!("{:?}", err))?
183 .iter()
184 .map(|f| f.size_bytes)
185 .sum::<u64>();
186
187 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on upsert");
188
189 if new_usage > usage_cap && new_usage >= old_usage {
190 warn!("user over cap");
191 return Err(ClientError(UpsertError::UsageIsOverDataCap));
192 }
193
194 let tree = tree.promote()?;
195
196 for id in tree.ids() {
197 if tree.find(&id)?.is_document()
198 && current_deleted.contains(&id)
199 && !prior_deleted.contains(&id)
200 {
201 let meta = tree.find(&id)?;
202 if let Some(hmac) = meta.file.timestamped_value.value.document_hmac().copied() {
203 db.scheduled_file_cleanups
204 .insert((*meta.id(), hmac), get_time().0)?;
205 }
206 }
207 }
208
209 let all_files: Vec<ServerMeta> = tree.all_files()?.into_iter().cloned().collect();
210 for meta in all_files {
211 let id = meta.id();
212 if current_deleted.contains(id) && !prior_deleted.contains(id) {
213 for user_access_info in meta.user_access_keys() {
214 db.shared_files
215 .remove(&Owner(user_access_info.encrypted_for), id)?;
216 }
217 }
218 }
219
220 db.last_seen.insert(req_owner, get_time().0 as u64)?;
221
222 tx.drop_safely()?;
223 }
224
225 Ok(())
226 }
227
228 pub async fn change_doc(
229 &self, context: RequestContext<ChangeDocRequest>,
230 ) -> Result<(), ServerError<ChangeDocError>> {
231 use ChangeDocError::*;
232 let request = context.request;
233 let mut request = ChangeDocRequestV2 {
234 diff: FileDiff {
235 old: request.diff.old.map(|f| f.into()),
236 new: request.diff.new.into(),
237 },
238 new_content: request.new_content,
239 };
240
241 let owner = Owner(context.public_key);
242 let id = *request.diff.id();
243
244 if request.diff.diff() != vec![Diff::Hmac] {
246 return Err(ClientError(DiffMalformed));
247 }
248 let hmac = if let Some(hmac) = request.diff.new.document_hmac() {
249 base64::encode_config(hmac, base64::URL_SAFE)
250 } else {
251 return Err(ClientError(HmacMissing));
252 };
253
254 let req_pk = context.public_key;
255
256 {
257 let mut lock = self.index_db.lock().await;
258 let db = lock.deref_mut();
259 let usage_cap = Self::get_cap(db, &context.public_key)
260 .map_err(|err| internal!("{:?}", err))? as usize;
261
262 let meta = db
263 .metas
264 .get()
265 .get(request.diff.new.id())
266 .ok_or(ClientError(DocumentNotFound))?
267 .clone();
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 let old_usage = Self::get_usage_helper(&mut tree)
279 .map_err(|err| internal!("{:?}", err))?
280 .iter()
281 .map(|f| f.size_bytes)
282 .sum::<u64>() as usize;
283 let old_size = *meta.file.timestamped_value.value.doc_size();
284
285 if let Some(old) = &mut request.diff.old {
287 match &mut old.timestamped_value.value {
288 Meta::V1 { doc_size, .. } => {
289 *doc_size = old_size;
290 }
291 }
292 }
293
294 match &mut request.diff.new.timestamped_value.value {
295 Meta::V1 { doc_size, .. } => {
296 *doc_size = Some(request.new_content.value.len());
297 }
298 }
299
300 let new_size = request.new_content.value.len();
301
302 let new_usage = old_usage - old_size.unwrap_or_default() + new_size;
303
304 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on change doc");
305
306 if new_usage > usage_cap {
307 return Err(ClientError(UsageIsOverDataCap));
308 }
309
310 let meta_owner = meta.owner();
311
312 let direct_access = meta_owner.0 == req_pk;
313
314 if tree.maybe_find(request.diff.new.id()).is_none() {
315 return Err(ClientError(NotPermissioned));
316 }
317
318 let mut share_access = false;
319 if !direct_access {
320 for ancestor in tree
321 .ancestors(request.diff.id())?
322 .iter()
323 .chain(vec![request.diff.new.id()])
324 {
325 let meta = tree.find(ancestor)?;
326
327 if meta
328 .user_access_keys()
329 .iter()
330 .any(|access| access.encrypted_for == req_pk)
331 {
332 share_access = true;
333 break;
334 }
335 }
336 }
337
338 if !direct_access && !share_access {
339 return Err(ClientError(NotPermissioned));
340 }
341
342 let meta = &tree
343 .maybe_find(request.diff.new.id())
344 .ok_or(ClientError(DocumentNotFound))?
345 .file;
346
347 if let Some(old) = &request.diff.old {
348 if meta != old {
349 return Err(ClientError(OldVersionIncorrect));
350 }
351 }
352
353 if tree.calculate_deleted(request.diff.new.id())? {
354 return Err(ClientError(DocumentDeleted));
355 }
356
357 }
361
362 let new_version = get_time().0 as u64;
363 let new = request.diff.new.clone().add_time(new_version);
364 self.document_service
365 .insert(
366 request.diff.new.id(),
367 request.diff.new.document_hmac().unwrap(),
368 &request.new_content,
369 )
370 .await?;
371 debug!(?id, ?hmac, "Inserted document contents");
372
373 let result = async {
374 let mut lock = self.index_db.lock().await;
375 let db = lock.deref_mut();
376 let tx = db.begin_transaction()?;
377
378 let mut tree = ServerTree::new(
379 owner,
380 &mut db.owned_files,
381 &mut db.shared_files,
382 &mut db.file_children,
383 &mut db.metas,
384 )?
385 .to_lazy();
386
387 if tree.calculate_deleted(request.diff.new.id())? {
388 return Err(ClientError(DocumentDeleted));
389 }
390
391 let meta = &tree
392 .maybe_find(request.diff.new.id())
393 .ok_or(ClientError(DocumentNotFound))?
394 .file;
395
396 if let Some(old) = &request.diff.old {
397 if meta != old {
398 return Err(ClientError(OldVersionIncorrect));
399 }
400 }
401
402 tree.stage(vec![new]).promote()?;
403 db.last_seen.insert(owner, get_time().0 as u64)?;
404
405 tx.drop_safely()?;
406 drop(lock);
407 Ok(())
408 };
409
410 let result = result.await;
411
412 if result.is_err() {
413 self.document_service
415 .delete(request.diff.new.id(), request.diff.new.document_hmac().unwrap())
416 .await?;
417 debug!(?id, ?hmac, "Cleaned up new document contents after failed metadata update");
418 }
419
420 result?;
421
422 if let Some(hmac) = request.diff.old.unwrap().document_hmac() {
424 self.document_service
425 .delete(request.diff.new.id(), hmac)
426 .await?;
427 let old_hmac = base64::encode_config(hmac, base64::URL_SAFE);
428 debug!(
429 ?id,
430 ?old_hmac,
431 "Cleaned up old document contents after successful metadata update"
432 );
433 }
434
435 Ok(())
436 }
437
438 pub async fn change_doc_v2(
439 &self, context: RequestContext<ChangeDocRequestV2>,
440 ) -> Result<(), ServerError<ChangeDocError>> {
441 use ChangeDocError::*;
442 let owner = Owner(context.public_key);
443 let request = context.request;
444 let id = *request.diff.id();
445
446 if request.diff.diff() != vec![Diff::Hmac] {
448 return Err(ClientError(DiffMalformed));
449 }
450
451 match request.diff.new.timestamped_value.value.doc_size() {
452 Some(size) => {
453 if *size != request.new_content.value.len() {
454 return Err(ClientError(NewSizeIncorrect));
455 }
456 }
457 None => {
458 if !request.new_content.value.is_empty() {
460 return Err(ClientError(NewSizeIncorrect));
461 }
462 }
463 }
464
465 let hmac = if let Some(hmac) = request.diff.new.document_hmac() {
466 base64::encode_config(hmac, base64::URL_SAFE)
467 } else {
468 return Err(ClientError(HmacMissing));
469 };
470
471 let req_pk = context.public_key;
472
473 {
474 let mut lock = self.index_db.lock().await;
475 let db = lock.deref_mut();
476 let usage_cap = Self::get_cap(db, &context.public_key)
477 .map_err(|err| internal!("{:?}", err))? as usize;
478
479 let meta = db
480 .metas
481 .get()
482 .get(request.diff.new.id())
483 .ok_or(ClientError(DocumentNotFound))?
484 .clone();
485
486 let mut tree = ServerTree::new(
487 owner,
488 &mut db.owned_files,
489 &mut db.shared_files,
490 &mut db.file_children,
491 &mut db.metas,
492 )?
493 .to_lazy();
494
495 let old_usage = Self::get_usage_helper(&mut tree)
496 .map_err(|err| internal!("{:?}", err))?
497 .iter()
498 .map(|f| f.size_bytes)
499 .sum::<u64>() as usize;
500 let old_size = *meta.file.timestamped_value.value.doc_size();
501
502 let new_size = request.new_content.value.len();
503
504 let new_usage = old_usage - old_size.unwrap_or_default() + new_size;
505
506 debug!(?old_usage, ?new_usage, ?usage_cap, "usage caps on change doc");
507
508 if new_usage > usage_cap {
509 warn!("user over cap");
510 return Err(ClientError(UsageIsOverDataCap));
511 }
512
513 let meta_owner = meta.owner();
514
515 let direct_access = meta_owner.0 == req_pk;
516
517 if tree.maybe_find(request.diff.new.id()).is_none() {
518 return Err(ClientError(NotPermissioned));
519 }
520
521 let mut share_access = false;
522 if !direct_access {
523 for ancestor in tree
524 .ancestors(request.diff.id())?
525 .iter()
526 .chain(vec![request.diff.new.id()])
527 {
528 let meta = tree.find(ancestor)?;
529
530 if meta
531 .user_access_keys()
532 .iter()
533 .any(|access| access.encrypted_for == req_pk)
534 {
535 share_access = true;
536 break;
537 }
538 }
539 }
540
541 if !direct_access && !share_access {
542 return Err(ClientError(NotPermissioned));
543 }
544
545 let meta = &tree
546 .maybe_find(request.diff.new.id())
547 .ok_or(ClientError(DocumentNotFound))?
548 .file;
549
550 if let Some(old) = &request.diff.old {
551 if meta != old {
552 return Err(ClientError(OldVersionIncorrect));
553 }
554 }
555
556 if tree.calculate_deleted(request.diff.new.id())? {
557 return Err(ClientError(DocumentDeleted));
558 }
559
560 let id = request.diff.new.id();
561 let hmac = request.diff.new.document_hmac().unwrap();
562 db.scheduled_file_cleanups.remove(&(*id, *hmac))?;
563 }
564
565 let new_version = get_time().0 as u64;
566 let new = request.diff.new.clone().add_time(new_version);
567 self.document_service
568 .insert(
569 request.diff.new.id(),
570 request.diff.new.document_hmac().unwrap(),
571 &request.new_content,
572 )
573 .await?;
574 debug!(?id, ?hmac, "Inserted document contents");
575
576 let result = async {
577 let mut lock = self.index_db.lock().await;
578 let db = lock.deref_mut();
579 let tx = db.begin_transaction()?;
580
581 let mut tree = ServerTree::new(
582 owner,
583 &mut db.owned_files,
584 &mut db.shared_files,
585 &mut db.file_children,
586 &mut db.metas,
587 )?
588 .to_lazy();
589
590 if tree.calculate_deleted(request.diff.new.id())? {
591 return Err(ClientError(DocumentDeleted));
592 }
593
594 let meta = &tree
595 .maybe_find(request.diff.new.id())
596 .ok_or(ClientError(DocumentNotFound))?
597 .file;
598
599 if let Some(old) = &request.diff.old {
600 if meta != old {
601 return Err(ClientError(OldVersionIncorrect));
602 }
603 }
604
605 tree.stage(vec![new]).promote()?;
606 if let Some(old) = &request
607 .diff
608 .old
609 .and_then(|old| old.document_hmac().copied())
610 {
611 db.scheduled_file_cleanups
612 .insert((*request.diff.new.id(), *old), get_time().0)?;
613 }
614
615 tx.drop_safely()?;
616 drop(lock);
617 Ok(())
618 };
619
620 let result = result.await;
621
622 if result.is_err() {
623 self.document_service
625 .delete(request.diff.new.id(), request.diff.new.document_hmac().unwrap())
626 .await?;
627 debug!(?id, ?hmac, "Cleaned up new document contents after failed metadata update");
628 }
629
630 result?;
631
632 Ok(())
633 }
634
635 pub async fn get_document(
636 &self, context: RequestContext<GetDocRequest>,
637 ) -> Result<GetDocumentResponse, ServerError<GetDocumentError>> {
638 let request = &context.request;
639 let requester = Owner(context.public_key);
640 {
641 let mut lock = self.index_db.lock().await;
642 let db = lock.deref_mut();
643 let tx = db.begin_transaction()?;
644
645 let meta_exists = db.metas.get().get(&request.id).is_some();
646
647 let mut tree = ServerTree::new(
648 requester,
649 &mut db.owned_files,
650 &mut db.shared_files,
651 &mut db.file_children,
652 &mut db.metas,
653 )?
654 .to_lazy();
655
656 if tree.maybe_find(&request.id).is_none() {
657 return Err(if meta_exists {
658 ClientError(GetDocumentError::NotPermissioned)
659 } else {
660 ClientError(GetDocumentError::DocumentNotFound)
661 });
662 }
663
664 if tree.calculate_deleted(&request.id)? {
665 return Err(ClientError(GetDocumentError::DocumentNotFound));
666 }
667
668 tx.drop_safely()?;
669 };
670
671 let Some(content) = self
672 .document_service
673 .maybe_get(&request.id, &request.hmac)
674 .await?
675 else {
676 return Err(ClientError(GetDocumentError::DocumentNotFound));
677 };
678
679 let mut lock = self.index_db.lock().await;
680 let db = lock.deref_mut();
681 let tx = db.begin_transaction()?;
682
683 if self.config.features.bandwidth_controls {
684 let mut server_wide = db.server_egress.get().cloned().unwrap_or_default();
685 let mut account_bandwidth = db
686 .egress_by_owner
687 .get()
688 .get(&requester)
689 .cloned()
690 .unwrap_or_default();
691 let account_bandwidth_cap = db
692 .accounts
693 .get()
694 .get(&requester)
695 .map(|account| account.billing_info.bandwidth_cap())
696 .unwrap_or_default();
697
698 let doc_size = content.value.len();
699
700 if doc_size + server_wide.current_bandwidth() > SERVER_BANDWIDTH_CAP {
701 error!("Bandwidth caps are now being enforced");
702 if doc_size + account_bandwidth.current_bandwidth() > account_bandwidth_cap {
703 error!("User bandwidth cap exceeded");
704 return Err(ClientError(GetDocumentError::BandwidthExceeded));
705 }
706 }
707
708 server_wide.increase_by(doc_size);
709 account_bandwidth.increase_by(doc_size);
710
711 db.server_egress.insert(server_wide)?;
712 db.egress_by_owner.insert(requester, account_bandwidth)?;
713 }
714
715 tx.drop_safely()?;
716
717 Ok(GetDocumentResponse { content })
718 }
719
720 pub async fn get_file_ids(
721 &self, context: RequestContext<GetFileIdsRequest>,
722 ) -> Result<GetFileIdsResponse, ServerError<GetFileIdsError>> {
723 let owner = Owner(context.public_key);
724 let mut db = self.index_db.lock().await;
725 let db = db.deref_mut();
726
727 Ok(GetFileIdsResponse {
728 ids: ServerTree::new(
729 owner,
730 &mut db.owned_files,
731 &mut db.shared_files,
732 &mut db.file_children,
733 &mut db.metas,
734 )?
735 .ids()
736 .into_iter()
737 .collect(),
738 })
739 }
740
741 pub async fn get_updates(
742 &self, context: RequestContext<GetUpdatesRequest>,
743 ) -> Result<GetUpdatesResponse, ServerError<GetUpdatesError>> {
744 let request = &context.request;
745 let owner = Owner(context.public_key);
746
747 let mut db = self.index_db.lock().await;
748 let db = db.deref_mut();
749 let mut tree = ServerTree::new(
750 owner,
751 &mut db.owned_files,
752 &mut db.shared_files,
753 &mut db.file_children,
754 &mut db.metas,
755 )?
756 .to_lazy();
757
758 let mut result_ids = HashSet::new();
759 for id in tree.ids() {
760 let file = tree.find(&id)?;
761 if file.version >= request.since_metadata_version {
762 result_ids.insert(id);
763 if file.owner() != owner
764 && file
765 .user_access_keys()
766 .iter()
767 .any(|k| !k.deleted && k.encrypted_for == context.public_key)
768 {
769 result_ids.insert(id);
770 result_ids.extend(tree.descendants(&id)?);
771 }
772 }
773 }
774
775 Ok(GetUpdatesResponse {
776 as_of_metadata_version: get_time().0 as u64,
777 file_metadata: tree
778 .all_files()?
779 .iter()
780 .filter(|meta| result_ids.contains(meta.id()))
781 .map(|meta| match meta.file.timestamped_value.value.clone() {
782 Meta::V1 {
783 id,
784 file_type,
785 parent,
786 name,
787 owner,
788 is_deleted,
789 doc_size: _,
790 doc_hmac,
791 user_access_keys,
792 folder_access_key,
793 } => SignedFile {
794 timestamped_value: Timestamped {
795 timestamp: meta.file.timestamped_value.timestamp,
796 value: FileMetadata {
797 id,
798 file_type,
799 parent,
800 name,
801 owner,
802 is_deleted,
803 document_hmac: doc_hmac,
804 user_access_keys,
805 folder_access_key,
806 },
807 },
808 signature: meta.file.signature.clone(),
809 public_key: meta.file.public_key,
810 },
811 })
812 .collect(),
813 })
814 }
815
816 pub async fn get_updates_v2(
817 &self, context: RequestContext<GetUpdatesRequestV2>,
818 ) -> Result<GetUpdatesResponseV2, ServerError<GetUpdatesError>> {
819 let request = &context.request;
820 let owner = Owner(context.public_key);
821
822 let mut db = self.index_db.lock().await;
823 let db = db.deref_mut();
824 let mut tree = ServerTree::new(
825 owner,
826 &mut db.owned_files,
827 &mut db.shared_files,
828 &mut db.file_children,
829 &mut db.metas,
830 )?
831 .to_lazy();
832
833 let mut result_ids = HashSet::new();
834 for id in tree.ids() {
835 let file = tree.find(&id)?;
836 if file.version >= request.since_metadata_version {
837 result_ids.insert(id);
838 if file.owner() != owner
839 && file
840 .user_access_keys()
841 .iter()
842 .any(|k| !k.deleted && k.encrypted_for == context.public_key)
843 {
844 result_ids.insert(id);
845 result_ids.extend(tree.descendants(&id)?);
846 }
847 }
848 }
849
850 Ok(GetUpdatesResponseV2 {
851 as_of_metadata_version: get_time().0 as u64,
852 file_metadata: tree
853 .all_files()?
854 .into_iter()
855 .filter(|meta| result_ids.contains(meta.id()))
856 .map(|meta| meta.file.clone())
857 .collect(),
858 })
859 }
860
861 pub async fn admin_disappear_file(
862 &self, context: RequestContext<AdminDisappearFileRequest>,
863 ) -> Result<(), ServerError<AdminDisappearFileError>> {
864 let mut docs_to_delete = Vec::new();
865
866 {
867 let mut db = self.index_db.lock().await;
868 let db = db.deref_mut();
869 let tx = db.begin_transaction()?;
870
871 if !Self::is_admin::<AdminDisappearFileError>(
872 db,
873 &context.public_key,
874 &self.config.admin.admins,
875 )? {
876 return Err(ClientError(AdminDisappearFileError::NotPermissioned));
877 }
878
879 let owner = {
880 let meta = db
881 .metas
882 .get()
883 .get(&context.request.id)
884 .ok_or(ClientError(AdminDisappearFileError::FileNonexistent))?;
885 if meta.is_root() {
886 return Err(ClientError(AdminDisappearFileError::RootModificationInvalid));
887 }
888 meta.owner()
889 };
890 let mut tree = ServerTree::new(
891 owner,
892 &mut db.owned_files,
893 &mut db.shared_files,
894 &mut db.file_children,
895 &mut db.metas,
896 )?
897 .to_lazy();
898
899 let metas_to_delete = {
900 let mut metas_to_delete = tree.descendants(&context.request.id)?;
901 metas_to_delete.insert(context.request.id);
902 metas_to_delete
903 };
904 for id in metas_to_delete.clone() {
905 if !tree.calculate_deleted(&id)? {
906 let meta = tree.find(&id)?;
907 if meta.is_document() && meta.owner() == owner {
908 if let Some(hmac) = meta.document_hmac() {
909 docs_to_delete.push((*meta.id(), *hmac));
910 }
911 }
912 }
913 }
914
915 for id in metas_to_delete {
916 let meta = db
917 .metas
918 .remove(&id)?
919 .ok_or(ClientError(AdminDisappearFileError::FileNonexistent))?;
920
921 let owner = meta.owner();
923
924 if !db.owned_files.remove(&owner, &id)? {
925 error!(
926 ?id,
927 ?owner,
928 "attempted to disappear a file, owner or id not present in owned_files"
929 );
930 }
931
932 for user_access_key in meta.user_access_keys() {
934 let sharee = Owner(user_access_key.encrypted_for);
935 if !db.shared_files.remove(&sharee, &id)? {
936 error!(
937 ?id,
938 ?sharee,
939 "attempted to disappear a file, a sharee didn't have it shared"
940 );
941 }
942 }
943
944 let parent = *meta.parent();
946 if !db.file_children.remove(meta.parent(), &id)? {
947 error!(
948 ?id,
949 ?parent,
950 "attempted to disappear a file, the parent didn't have it as a child"
951 );
952 }
953 }
954
955 let username = db
956 .accounts
957 .get()
958 .get(&Owner(context.public_key))
959 .map(|account| account.username.clone())
960 .unwrap_or_else(|| "~unknown~".to_string());
961 warn!(?username, ?context.request.id, "Disappeared file");
962
963 tx.drop_safely()?;
964 }
965
966 for (id, version) in docs_to_delete {
967 self.document_service.delete(&id, &version).await?;
968 }
969
970 Ok(())
971 }
972
973 pub async fn admin_validate_account(
974 &self, context: RequestContext<AdminValidateAccountRequest>,
975 ) -> Result<AdminValidateAccount, ServerError<AdminValidateAccountError>> {
976 let request = &context.request;
977 let mut db = self.index_db.lock().await;
978 if !Self::is_admin::<AdminValidateAccountError>(
979 &db,
980 &context.public_key,
981 &self.config.admin.admins,
982 )? {
983 return Err(ClientError(AdminValidateAccountError::NotPermissioned));
984 }
985
986 let owner = *db
987 .usernames
988 .get()
989 .get(&request.username)
990 .ok_or(ClientError(AdminValidateAccountError::UserNotFound))?;
991
992 Ok(self.validate_account_helper(&mut db, owner)?)
993 }
994
995 pub fn validate_account_helper(
996 &self, db: &mut ServerDb, owner: Owner,
997 ) -> LbResult<AdminValidateAccount> {
998 let mut result = AdminValidateAccount::default();
999
1000 let mut tree = ServerTree::new(
1001 owner,
1002 &mut db.owned_files,
1003 &mut db.shared_files,
1004 &mut db.file_children,
1005 &mut db.metas,
1006 )?
1007 .to_lazy();
1008
1009 for id in tree.ids() {
1010 if !tree.calculate_deleted(&id)? {
1011 let file = tree.find(&id)?;
1012 if file.is_document() && file.document_hmac().is_some() {
1013 if file.file.timestamped_value.value.doc_size().is_none() {
1014 result.documents_missing_size.push(id);
1015 }
1016
1017 if !self
1018 .document_service
1019 .exists(&id, file.document_hmac().unwrap())
1020 {
1021 result.documents_missing_content.push(id);
1022 }
1023 }
1024 }
1025 }
1026
1027 let validation_res = tree.stage(None).validate(owner);
1028 match validation_res {
1029 Ok(_) => {}
1030 Err(err) => match err.kind {
1031 LbErrKind::Validation(validation) => {
1032 result.tree_validation_failures.push(validation)
1033 }
1034 _ => {
1035 error!(?owner, ?err, "Unexpected error while validating tree")
1036 }
1037 },
1038 }
1039
1040 Ok(result)
1041 }
1042
1043 pub async fn admin_validate_server(
1044 &self, context: RequestContext<AdminValidateServerRequest>,
1045 ) -> Result<AdminValidateServer, ServerError<AdminValidateServerError>> {
1046 let mut db = self.index_db.lock().await;
1047 let db = db.deref_mut();
1048
1049 if !Self::is_admin::<AdminValidateServerError>(
1050 db,
1051 &context.public_key,
1052 &self.config.admin.admins,
1053 )? {
1054 return Err(ClientError(AdminValidateServerError::NotPermissioned));
1055 }
1056
1057 let mut result: AdminValidateServer = Default::default();
1058
1059 let mut deleted_ids = HashSet::new();
1060 for (id, meta) in db.metas.get().clone() {
1061 let mut tree = ServerTree::new(
1063 meta.owner(),
1064 &mut db.owned_files,
1065 &mut db.shared_files,
1066 &mut db.file_children,
1067 &mut db.metas,
1068 )?
1069 .to_lazy();
1070 if tree.calculate_deleted(&id)? {
1071 deleted_ids.insert(id);
1072 }
1073 }
1074
1075 for (owner, account) in db.accounts.get().clone() {
1077 let validation = self.validate_account_helper(db, owner)?;
1078 if !validation.is_empty() {
1079 result
1080 .users_with_validation_failures
1081 .insert(account.username, validation);
1082 }
1083 }
1084
1085 for (username, owner) in db.usernames.get().clone() {
1087 if let Some(account) = db.accounts.get().get(&owner) {
1088 if username != account.username {
1089 result
1090 .usernames_mapped_to_wrong_accounts
1091 .insert(username, account.username.clone());
1092 }
1093 } else {
1094 result
1095 .usernames_mapped_to_nonexistent_accounts
1096 .insert(username, owner);
1097 }
1098 }
1099 for (_, account) in db.accounts.get().clone() {
1100 if db.usernames.get().get(&account.username).is_none() {
1101 result
1102 .usernames_unmapped_to_accounts
1103 .insert(account.username.clone());
1104 }
1105 }
1106
1107 for (owner, ids) in db.owned_files.get().clone() {
1109 for id in ids {
1110 if let Some(meta) = db.metas.get().get(&id) {
1111 if meta.owner() != owner {
1112 insert(&mut result.owners_mapped_to_unowned_files, owner, id);
1113 }
1114 } else {
1115 insert(&mut result.owners_mapped_to_nonexistent_files, owner, id);
1116 }
1117 }
1118 }
1119 for (id, meta) in db.metas.get().clone() {
1120 if let Some(ids) = db.owned_files.get().get(&meta.owner()) {
1121 if !ids.contains(&id) {
1122 insert(&mut result.owners_unmapped_to_owned_files, meta.owner(), *meta.id());
1123 }
1124 } else {
1125 result.owners_unmapped.insert(meta.owner());
1126 }
1127 }
1128
1129 for (sharee, ids) in db.shared_files.get().clone() {
1131 for id in ids {
1132 if let Some(meta) = db.metas.get().get(&id) {
1133 if !meta.user_access_keys().iter().any(|k| {
1134 !k.deleted && k.encrypted_for == sharee.0 && k.encrypted_by != sharee.0
1135 }) {
1136 insert(&mut result.sharees_mapped_to_unshared_files, sharee, id);
1137 }
1138 } else {
1139 insert(&mut result.sharees_mapped_to_nonexistent_files, sharee, id);
1140 }
1141 if deleted_ids.contains(&id) {
1142 insert(&mut result.sharees_mapped_for_deleted_files, sharee, id);
1143 }
1144 }
1145 }
1146 for (id, meta) in db.metas.get().clone() {
1147 let mut deleted = false;
1149 let mut ancestor = meta.clone();
1150 loop {
1151 if ancestor.explicitly_deleted() {
1152 deleted = true;
1153 break;
1154 }
1155 if ancestor.is_root() {
1156 break;
1157 }
1158 match db.metas.get().get(ancestor.parent()) {
1159 Some(parent) => ancestor = parent.clone(),
1160 None => {
1161 error!("missing parent for file {:?}", ancestor.parent());
1162 deleted = true;
1163 break;
1164 }
1165 }
1166 }
1167 if deleted {
1168 continue;
1169 }
1170
1171 for k in meta.user_access_keys() {
1172 if k.deleted {
1173 continue;
1174 }
1175 let sharee = Owner(k.encrypted_for);
1176 if let Some(ids) = db.shared_files.get().get(&sharee) {
1177 let self_share = k.encrypted_for == k.encrypted_by;
1178 let indexed_share = ids.contains(&id);
1179 if self_share && indexed_share {
1180 insert(&mut result.sharees_mapped_for_owned_files, sharee, id);
1181 } else if !self_share && !indexed_share {
1182 insert(&mut result.sharees_unmapped_to_shared_files, sharee, id);
1183 }
1184 } else {
1185 result.sharees_unmapped.insert(meta.owner());
1186 }
1187 }
1188 }
1189
1190 for (parent_id, child_ids) in db.file_children.get().clone() {
1192 for child_id in child_ids {
1193 if let Some(meta) = db.metas.get().get(&child_id) {
1194 if meta.parent() != &parent_id {
1195 insert(
1196 &mut result.files_mapped_as_parent_to_non_children,
1197 parent_id,
1198 child_id,
1199 );
1200 }
1201 } else {
1202 insert(
1203 &mut result.files_mapped_as_parent_to_nonexistent_children,
1204 parent_id,
1205 child_id,
1206 );
1207 }
1208 }
1209 }
1210 for (id, meta) in db.metas.get().clone() {
1211 if let Some(child_ids) = db.file_children.get().get(meta.parent()) {
1212 if meta.is_root() && child_ids.contains(&id) {
1213 result.files_mapped_as_parent_to_self.insert(id);
1214 } else if !meta.is_root() && !child_ids.contains(&id) {
1215 insert(&mut result.files_unmapped_as_parent_to_children, *meta.parent(), id);
1216 }
1217 } else {
1218 result.files_unmapped_as_parent.insert(*meta.parent());
1219 }
1220 }
1221
1222 for (id, meta) in db.metas.get().clone() {
1224 if let Some(hmac) = meta.document_hmac() {
1225 if !deleted_ids.contains(&id) && !self.document_service.exists(&id, hmac) {
1226 result.files_with_hmacs_and_no_contents.insert(id);
1227 }
1228 }
1229 }
1230
1231 Ok(result)
1232 }
1233
1234 pub async fn admin_file_info(
1235 &self, context: RequestContext<AdminFileInfoRequest>,
1236 ) -> Result<AdminFileInfoResponse, ServerError<AdminFileInfoError>> {
1237 let request = &context.request;
1238 let mut db = self.index_db.lock().await;
1239 let db = db.deref_mut();
1240 if !Self::is_admin::<AdminFileInfoError>(
1241 db,
1242 &context.public_key,
1243 &self.config.admin.admins,
1244 )? {
1245 return Err(ClientError(AdminFileInfoError::NotPermissioned));
1246 }
1247
1248 let file = db
1249 .metas
1250 .get()
1251 .get(&request.id)
1252 .ok_or(ClientError(AdminFileInfoError::FileNonexistent))?
1253 .clone();
1254
1255 let mut tree = ServerTree::new(
1256 file.owner(),
1257 &mut db.owned_files,
1258 &mut db.shared_files,
1259 &mut db.file_children,
1260 &mut db.metas,
1261 )?
1262 .to_lazy();
1263
1264 let ancestors = tree
1265 .ancestors(&request.id)?
1266 .into_iter()
1267 .filter_map(|id| tree.maybe_find(&id))
1268 .cloned()
1269 .collect();
1270 let descendants = tree
1271 .descendants(&request.id)?
1272 .into_iter()
1273 .filter_map(|id| tree.maybe_find(&id))
1274 .cloned()
1275 .collect();
1276
1277 Ok(AdminFileInfoResponse { file, ancestors, descendants })
1278 }
1279
1280 pub async fn admin_rebuild_index(
1281 &self, context: RequestContext<AdminRebuildIndexRequest>,
1282 ) -> Result<(), ServerError<AdminRebuildIndexError>> {
1283 let mut db = self.index_db.lock().await;
1284
1285 match context.request.index {
1286 ServerIndex::OwnedFiles => {
1287 db.owned_files.clear()?;
1288 for owner in db.accounts.get().clone().keys() {
1289 db.owned_files.create_key(*owner)?;
1290 }
1291 for (id, file) in db.metas.get().clone() {
1292 db.owned_files.insert(file.owner(), id)?;
1293 }
1294 }
1295 ServerIndex::SharedFiles => {
1296 db.shared_files.clear()?;
1297 for owner in db.accounts.get().clone().keys() {
1298 db.shared_files.create_key(*owner)?;
1299 }
1300 for (id, file) in db.metas.get().clone() {
1301 let mut deleted = false;
1303 let mut ancestor = file.clone();
1304 loop {
1305 if ancestor.explicitly_deleted() {
1306 deleted = true;
1307 break;
1308 }
1309 if ancestor.is_root() {
1310 break;
1311 }
1312 match db.metas.get().get(ancestor.parent()) {
1313 Some(parent) => ancestor = parent.clone(),
1314 None => {
1315 error!("missing parent for file {:?}", ancestor.parent());
1316 deleted = true;
1317 break;
1318 }
1319 }
1320 }
1321
1322 if !deleted {
1323 for user_access_key in file.user_access_keys() {
1324 if !user_access_key.deleted
1325 && user_access_key.encrypted_for != user_access_key.encrypted_by
1326 {
1327 db.shared_files
1328 .insert(Owner(user_access_key.encrypted_for), id)?;
1329 }
1330 }
1331 }
1332 }
1333 }
1334 ServerIndex::FileChildren => {
1335 db.file_children.clear()?;
1336 for id in db.metas.get().clone().keys() {
1337 db.file_children.create_key(*id)?;
1338 }
1339 for (id, file) in db.metas.get().clone() {
1340 db.file_children.insert(*file.parent(), id)?;
1341 }
1342 }
1343 }
1344 Ok(())
1345 }
1346}
1347
1348fn insert<K: Hash + Eq, V: Hash + Eq>(map: &mut HashMap<K, HashSet<V>>, k: K, v: V) {
1349 map.entry(k).or_default().insert(v);
1350}