Skip to main content

lockbook_server_lib/
account_service.rs

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    /// Create a new account given a username, public_key, and root folder.
45    /// Checks that username is valid, and that username, public_key and root_folder are new.
46    /// Inserts all of these values into their respective keys along with the default free account tier size
47    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    /// Create a new account given a username, public_key, and root folder.
66    /// Checks that username is valid, and that username, public_key and root_folder are new.
67    /// Inserts all of these values into their respective keys along with the default free account tier size
68    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}