1use crate::ServerError::ClientError;
2use crate::billing::app_store_client::AppStoreClient;
3use crate::billing::billing_model::BillingPlatform;
4use crate::billing::google_play_client::GooglePlayClient;
5use crate::billing::stripe_client::StripeClient;
6use crate::document_service::DocumentService;
7use crate::schema::{Account, ServerDb};
8use crate::utils::username_is_valid;
9use crate::{RequestContext, ServerError, ServerState};
10use db_rs::Db;
11use lb_rs::model::account::Username;
12use lb_rs::model::api::NewAccountError::{FileIdTaken, PublicKeyTaken, UsernameTaken};
13use lb_rs::model::api::{
14 AccountFilter, AccountIdentifier, AccountInfo, AdminDisappearAccountError,
15 AdminDisappearAccountRequest, AdminGetAccountInfoError, AdminGetAccountInfoRequest,
16 AdminGetAccountInfoResponse, AdminListUsersError, AdminListUsersRequest,
17 AdminListUsersResponse, DeleteAccountError, DeleteAccountRequest, FileUsage, GetPublicKeyError,
18 GetPublicKeyRequest, GetPublicKeyResponse, GetUsageError, GetUsageRequest, GetUsageResponse,
19 GetUsernameError, GetUsernameRequest, GetUsernameResponse, METADATA_FEE, NewAccountError,
20 NewAccountRequest, NewAccountRequestV2, NewAccountResponse, PaymentPlatform,
21};
22use lb_rs::model::clock::get_time;
23use lb_rs::model::file_like::FileLike;
24use lb_rs::model::file_metadata::Owner;
25use lb_rs::model::lazy::LazyTree;
26use lb_rs::model::server_meta::{IntoServerMeta, ServerMeta};
27use lb_rs::model::server_tree::ServerTree;
28use lb_rs::model::signed_meta::SignedMeta;
29use lb_rs::model::tree_like::TreeLike;
30use lb_rs::model::usage::bytes_to_human;
31use libsecp256k1::PublicKey;
32use std::collections::HashSet;
33use std::fmt::Debug;
34use std::ops::DerefMut;
35use tracing::warn;
36
37impl<S, A, G, D> ServerState<S, A, G, D>
38where
39 S: StripeClient,
40 A: AppStoreClient,
41 G: GooglePlayClient,
42 D: DocumentService,
43{
44 pub async fn new_account(
48 &self, context: RequestContext<NewAccountRequest>,
49 ) -> Result<NewAccountResponse, ServerError<NewAccountError>> {
50 let request = context.request;
51 let request = NewAccountRequestV2 {
52 username: request.username.to_lowercase(),
53 public_key: request.public_key,
54 root_folder: SignedMeta::from(request.root_folder),
55 };
56
57 self.new_account_v2(RequestContext {
58 request,
59 public_key: context.public_key,
60 ip: context.ip,
61 })
62 .await
63 }
64
65 pub async fn new_account_v2(
69 &self, mut context: RequestContext<NewAccountRequestV2>,
70 ) -> Result<NewAccountResponse, ServerError<NewAccountError>> {
71 context.request.username = context.request.username.to_lowercase();
72 let request = &context.request;
73
74 tracing::info!("new-account attempt username: {}", request.username);
75
76 if !username_is_valid(&request.username) {
77 return Err(ClientError(NewAccountError::InvalidUsername));
78 }
79
80 if !&self.config.features.new_accounts {
81 return Err(ClientError(NewAccountError::Disabled));
82 }
83
84 let root = request.root_folder.clone();
85 let now = get_time().0 as u64;
86 let root = root.add_time(now);
87
88 let mut db = self.index_db.lock().await;
89 let handle = db.begin_transaction()?;
90
91 if let Some(ip) = context.ip {
92 if !self.can_create_account(ip.ip()).await {
93 return Err(ClientError(NewAccountError::RateLimited));
94 }
95 }
96
97 if db.accounts.get().contains_key(&Owner(request.public_key)) {
98 return Err(ClientError(PublicKeyTaken));
99 }
100
101 if db.usernames.get().contains_key(&request.username) {
102 return Err(ClientError(UsernameTaken));
103 }
104
105 if db.metas.get().contains_key(root.id()) {
106 return Err(ClientError(FileIdTaken));
107 }
108
109 if self.config.features.new_account_rate_limit {
110 if let Some(ip) = context.ip {
111 self.did_create_account(ip.ip()).await;
112 }
113 }
114
115 let username = &request.username;
116 let account = Account { username: username.clone(), billing_info: Default::default() };
117
118 let owner = Owner(request.public_key);
119
120 let mut owned_files = HashSet::new();
121 owned_files.insert(*root.id());
122
123 db.accounts.insert(owner, account)?;
124 db.usernames.insert(username.clone(), owner)?;
125 db.owned_files.insert(owner, *root.id())?;
126 db.shared_files.create_key(owner)?;
127 db.file_children.create_key(*root.id())?;
128 db.metas.insert(*root.id(), root.clone())?;
129
130 handle.drop_safely()?;
131
132 Ok(NewAccountResponse { last_synced: root.version })
133 }
134
135 pub async fn get_public_key(
136 &self, context: RequestContext<GetPublicKeyRequest>,
137 ) -> Result<GetPublicKeyResponse, ServerError<GetPublicKeyError>> {
138 let request = &context.request;
139 self.public_key_from_username(&request.username).await
140 }
141
142 pub async fn public_key_from_username(
143 &self, username: &str,
144 ) -> Result<GetPublicKeyResponse, ServerError<GetPublicKeyError>> {
145 self.index_db
146 .lock()
147 .await
148 .usernames
149 .get()
150 .get(username)
151 .map(|owner| Ok(GetPublicKeyResponse { key: owner.0 }))
152 .unwrap_or(Err(ClientError(GetPublicKeyError::UserNotFound)))
153 }
154
155 pub async fn get_username(
156 &self, context: RequestContext<GetUsernameRequest>,
157 ) -> Result<GetUsernameResponse, ServerError<GetUsernameError>> {
158 self.username_from_public_key(context.request.key).await
159 }
160
161 pub async fn username_from_public_key(
162 &self, key: PublicKey,
163 ) -> Result<GetUsernameResponse, ServerError<GetUsernameError>> {
164 self.index_db
165 .lock()
166 .await
167 .accounts
168 .get()
169 .get(&Owner(key))
170 .map(|account| Ok(GetUsernameResponse { username: account.username.clone() }))
171 .unwrap_or(Err(ClientError(GetUsernameError::UserNotFound)))
172 }
173
174 pub async fn get_usage(
175 &self, context: RequestContext<GetUsageRequest>,
176 ) -> Result<GetUsageResponse, ServerError<GetUsageError>> {
177 let mut lock = self.index_db.lock().await;
178 let db = lock.deref_mut();
179
180 let cap = Self::get_cap(db, &context.public_key)?;
181
182 let mut tree = ServerTree::new(
183 Owner(context.public_key),
184 &mut db.owned_files,
185 &mut db.shared_files,
186 &mut db.file_children,
187 &mut db.metas,
188 )?
189 .to_lazy();
190 let usages = Self::get_usage_helper(&mut tree)?;
191 Ok(GetUsageResponse { usages, cap })
192 }
193
194 pub fn get_usage_helper<T>(
195 tree: &mut LazyTree<T>,
196 ) -> Result<Vec<FileUsage>, ServerError<GetUsageHelperError>>
197 where
198 T: TreeLike<F = ServerMeta>,
199 {
200 let ids = tree.ids();
201 let root_id = ids
202 .iter()
203 .find(|file_id| match tree.find(file_id) {
204 Ok(f) => f.is_root(),
205 Err(_) => false,
206 })
207 .ok_or(ClientError(GetUsageHelperError::UserDeleted))?;
208
209 let root_owner = tree
210 .maybe_find(root_id)
211 .ok_or(ClientError(GetUsageHelperError::UserDeleted))?
212 .owner();
213
214 let result = ids
215 .iter()
216 .filter_map(|&file_id| {
217 let file = match tree.find(&file_id) {
218 Ok(file) => {
219 if file.owner() != root_owner {
220 return None;
221 }
222 file.clone()
223 }
224 _ => {
225 return None;
226 }
227 };
228
229 let file_size = match tree.calculate_deleted(&file_id).unwrap_or(true) {
230 true => 0,
231 false => file.file.timestamped_value.value.doc_size().unwrap_or(0),
232 } as u64;
233
234 Some(FileUsage { file_id, size_bytes: file_size + METADATA_FEE })
235 })
236 .collect();
237 Ok(result)
238 }
239
240 pub fn get_usage_helper_v2<T>(
241 _owner: &Owner, _tree: &mut LazyTree<T>,
242 ) -> Result<Vec<FileUsage>, ServerError<GetUsageHelperError>>
243 where
244 T: TreeLike<F = ServerMeta>,
245 {
246 todo!()
247 }
248
249 pub fn get_cap(
250 db: &ServerDb, public_key: &PublicKey,
251 ) -> Result<u64, ServerError<GetUsageHelperError>> {
252 Ok(db
253 .accounts
254 .get()
255 .get(&Owner(*public_key))
256 .ok_or(ServerError::ClientError(GetUsageHelperError::UserNotFound))?
257 .billing_info
258 .data_cap())
259 }
260
261 pub async fn delete_account(
262 &self, context: RequestContext<DeleteAccountRequest>,
263 ) -> Result<(), ServerError<DeleteAccountError>> {
264 self.delete_account_helper(&context.public_key, false)
265 .await?;
266
267 Ok(())
268 }
269
270 pub async fn admin_disappear_account(
271 &self, context: RequestContext<AdminDisappearAccountRequest>,
272 ) -> Result<(), ServerError<AdminDisappearAccountError>> {
273 let owner = {
274 let db = &self.index_db.lock().await;
275
276 if !Self::is_admin::<AdminDisappearAccountError>(
277 db,
278 &context.public_key,
279 &self.config.admin.admins,
280 )? {
281 return Err(ClientError(AdminDisappearAccountError::NotPermissioned));
282 }
283
284 let admin_username = db
285 .accounts
286 .get()
287 .get(&Owner(context.public_key))
288 .cloned()
289 .map(|account| account.username)
290 .unwrap_or_else(|| "~unknown~".to_string());
291
292 warn!("admin {} is disappearing account {}", admin_username, context.request.username);
293
294 *db.usernames
295 .get()
296 .get(&context.request.username)
297 .ok_or(ClientError(AdminDisappearAccountError::UserNotFound))?
298 };
299
300 self.delete_account_helper(&owner.0, true).await?;
301
302 Ok(())
303 }
304
305 pub async fn admin_list_users(
306 &self, context: RequestContext<AdminListUsersRequest>,
307 ) -> Result<AdminListUsersResponse, ServerError<AdminListUsersError>> {
308 let (db, request) = (&self.index_db.lock().await, &context.request);
309
310 if !Self::is_admin::<AdminListUsersError>(
311 db,
312 &context.public_key,
313 &self.config.admin.admins,
314 )? {
315 return Err(ClientError(AdminListUsersError::NotPermissioned));
316 }
317
318 let mut users: Vec<String> = vec![];
319
320 for account in db.accounts.get().values() {
321 match &request.filter {
322 Some(filter) => match filter {
323 AccountFilter::Premium => {
324 if account.billing_info.is_premium() {
325 users.push(account.username.clone());
326 }
327 }
328 AccountFilter::AppStorePremium => match account.billing_info.billing_platform {
329 Some(BillingPlatform::AppStore(_)) if account.billing_info.is_premium() => {
330 users.push(account.username.clone());
331 }
332 _ => {}
333 },
334 AccountFilter::StripePremium => match account.billing_info.billing_platform {
335 Some(BillingPlatform::Stripe(_)) if account.billing_info.is_premium() => {
336 users.push(account.username.clone());
337 }
338 _ => {}
339 },
340 AccountFilter::GooglePlayPremium => match account.billing_info.billing_platform
341 {
342 Some(BillingPlatform::GooglePlay(_))
343 if account.billing_info.is_premium() =>
344 {
345 users.push(account.username.clone());
346 }
347 _ => {}
348 },
349 },
350 None => users.push(account.username.clone()),
351 }
352 }
353
354 Ok(AdminListUsersResponse { users })
355 }
356
357 pub async fn admin_get_account_info(
358 &self, context: RequestContext<AdminGetAccountInfoRequest>,
359 ) -> Result<AdminGetAccountInfoResponse, ServerError<AdminGetAccountInfoError>> {
360 let (mut lock, request) = (self.index_db.lock().await, &context.request);
361 let db = lock.deref_mut();
362
363 if !Self::is_admin::<AdminGetAccountInfoError>(
364 db,
365 &context.public_key,
366 &self.config.admin.admins,
367 )? {
368 return Err(ClientError(AdminGetAccountInfoError::NotPermissioned));
369 }
370
371 let owner = match &request.identifier {
372 AccountIdentifier::PublicKey(public_key) => Owner(*public_key),
373 AccountIdentifier::Username(user) => *db
374 .usernames
375 .get()
376 .get(user)
377 .ok_or(ClientError(AdminGetAccountInfoError::UserNotFound))?,
378 };
379
380 let account = db
381 .accounts
382 .get()
383 .get(&owner)
384 .ok_or(ClientError(AdminGetAccountInfoError::UserNotFound))?
385 .clone();
386
387 let mut maybe_root = None;
388 if let Some(owned_ids) = db.owned_files.get().get(&owner) {
389 for id in owned_ids {
390 if let Some(meta) = db.metas.get().get(id) {
391 if meta.is_root() {
392 maybe_root = Some(*meta.id());
393 }
394 } else {
395 return Err(internal!(
396 "Nonexistent file indexed as owned, id: {}, owner: {:?}",
397 id,
398 owner
399 ));
400 }
401 }
402 } else {
403 return Err(internal!("Owned files not indexed for user, owner: {:?}", owner));
404 }
405 let root = if let Some(root) = maybe_root {
406 root
407 } else {
408 return Err(internal!("User root not found, owner: {:?}", owner));
409 };
410
411 let payment_platform = account
412 .billing_info
413 .billing_platform
414 .map(|billing_platform| match billing_platform {
415 BillingPlatform::Stripe(user_info) => {
416 PaymentPlatform::Stripe { card_last_4_digits: user_info.last_4 }
417 }
418 BillingPlatform::GooglePlay(user_info) => {
419 PaymentPlatform::GooglePlay { account_state: user_info.account_state }
420 }
421 BillingPlatform::AppStore(user_info) => {
422 PaymentPlatform::AppStore { account_state: user_info.account_state }
423 }
424 });
425
426 let mut tree = ServerTree::new(
427 owner,
428 &mut db.owned_files,
429 &mut db.shared_files,
430 &mut db.file_children,
431 &mut db.metas,
432 )?
433 .to_lazy();
434
435 let usage: u64 = Self::get_usage_helper(&mut tree)
436 .map_err(|err| {
437 internal!("Cannot find user's usage, owner: {:?}, err: {:?}", owner, err)
438 })?
439 .iter()
440 .map(|a| a.size_bytes)
441 .sum();
442
443 let usage_str = bytes_to_human(usage);
444
445 Ok(AdminGetAccountInfoResponse {
446 account: AccountInfo {
447 username: account.username,
448 root,
449 payment_platform,
450 usage: usage_str,
451 },
452 })
453 }
454
455 pub async fn delete_account_helper(
456 &self, public_key: &PublicKey, free_username: bool,
457 ) -> Result<(), ServerError<DeleteAccountHelperError>> {
458 let mut docs_to_delete = Vec::new();
459
460 {
461 let mut lock = self.index_db.lock().await;
462 let db = lock.deref_mut();
463 let tx = db.begin_transaction()?;
464
465 let mut tree = ServerTree::new(
466 Owner(*public_key),
467 &mut db.owned_files,
468 &mut db.shared_files,
469 &mut db.file_children,
470 &mut db.metas,
471 )?
472 .to_lazy();
473 let metas_to_delete = tree.ids();
474
475 for id in metas_to_delete.clone() {
476 if !tree.calculate_deleted(&id)? {
477 let meta = tree.find(&id)?;
478 if meta.is_document() && &(meta.owner().0) == public_key {
479 if let Some(hmac) = meta.document_hmac() {
480 docs_to_delete.push((*meta.id(), *hmac));
481 }
482 }
483 }
484 }
485 db.owned_files.clear_key(&Owner(*public_key))?;
486 db.shared_files.clear_key(&Owner(*public_key))?;
487 db.last_seen.remove(&Owner(*public_key))?;
488
489 for id in metas_to_delete {
490 if let Some(meta) = db.metas.get().get(&id) {
491 if &(meta.owner().0) == public_key {
492 for user_access_key in meta.user_access_keys() {
493 let sharee = Owner(user_access_key.encrypted_for);
494 db.shared_files.remove(&sharee, meta.id())?;
495 }
496 db.metas.remove(&id)?;
497 db.file_children.clear_key(&id)?;
498 }
499 }
500 }
501
502 if free_username {
503 let username = db
504 .accounts
505 .remove(&Owner(*public_key))?
506 .ok_or(ClientError(DeleteAccountHelperError::UserNotFound))?
507 .username;
508 db.usernames.remove(&username)?;
509 }
510
511 tx.drop_safely()?;
512 drop(lock);
513 }
514
515 for (id, version) in docs_to_delete {
516 self.document_service.delete(&id, &version).await?;
517 }
518 Ok(())
519 }
520
521 pub fn is_admin<E: Debug>(
522 db: &ServerDb, public_key: &PublicKey, admins: &HashSet<Username>,
523 ) -> Result<bool, ServerError<E>> {
524 let is_admin = match db.accounts.get().get(&Owner(*public_key)) {
525 None => false,
526 Some(account) => admins.contains(&account.username),
527 };
528
529 Ok(is_admin)
530 }
531}
532
533#[derive(Debug)]
534pub enum GetUsageHelperError {
535 UserNotFound,
536 UserDeleted,
537}
538
539#[derive(Debug)]
540pub enum DeleteAccountHelperError {
541 UserNotFound,
542}