lb_rs/service/
share.rs

1use crate::model::api::GetPublicKeyRequest;
2use crate::model::errors::{LbErr, LbResult};
3use crate::model::file::{File, ShareMode};
4use crate::model::file_like::FileLike;
5use crate::model::file_metadata::Owner;
6use crate::model::tree_like::TreeLike;
7use crate::Lb;
8use libsecp256k1::PublicKey;
9use uuid::Uuid;
10
11impl Lb {
12    // todo: this can check whether the username is known already
13    #[instrument(level = "debug", skip(self))]
14    pub async fn share_file(&self, id: Uuid, username: &str, mode: ShareMode) -> LbResult<()> {
15        let account = self.get_account()?;
16        let username = username.to_lowercase();
17
18        let sharee = Owner(
19            self.client
20                .request(account, GetPublicKeyRequest { username: username.clone() })
21                .await
22                .map_err(LbErr::from)?
23                .key,
24        );
25
26        let mut tx = self.begin_tx().await;
27        let db = tx.db();
28
29        let mut tree = (&db.base_metadata)
30            .to_staged(&mut db.local_metadata)
31            .to_lazy();
32        db.pub_key_lookup.insert(sharee, username)?;
33
34        tree.add_share(id, sharee, mode, &self.keychain)?;
35
36        tx.end();
37
38        self.events.meta_changed(id);
39
40        Ok(())
41    }
42
43    // todo: move to tree
44    #[instrument(level = "debug", skip(self))]
45    pub async fn get_pending_shares(&self) -> LbResult<Vec<File>> {
46        let tx = self.ro_tx().await;
47        let db = tx.db();
48
49        let owner = Owner(self.keychain.get_pk()?);
50        let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
51
52        let mut result = Vec::new();
53        for id in tree.ids() {
54            // file must be owned by another user
55            if tree.find(&id)?.owner() == owner {
56                continue;
57            }
58
59            // file must be shared with this user
60            if tree.find(&id)?.access_mode(&owner).is_none() {
61                continue;
62            }
63
64            // file must not be deleted
65            if tree.calculate_deleted(&id)? {
66                continue;
67            }
68
69            // file must not have any links pointing to it
70            if tree.linked_by(&id)?.is_some() {
71                continue;
72            }
73
74            let file = tree.decrypt(&self.keychain, &id, &db.pub_key_lookup)?;
75
76            result.push(file);
77        }
78        Ok(result)
79    }
80
81    #[instrument(level = "debug", skip(self))]
82    async fn delete_share(
83        &self, id: &Uuid, maybe_encrypted_for: Option<PublicKey>,
84    ) -> LbResult<()> {
85        let mut tx = self.begin_tx().await;
86        let db = tx.db();
87
88        let mut tree = (&db.base_metadata)
89            .to_staged(&mut db.local_metadata)
90            .to_lazy();
91
92        tree.delete_share(id, maybe_encrypted_for, &self.keychain)?;
93
94        tx.end();
95        self.events.meta_changed(*id);
96
97        Ok(())
98    }
99
100    #[instrument(level = "debug", skip(self))]
101    pub async fn reject_share(&self, id: &Uuid) -> Result<(), LbErr> {
102        let pk = self.keychain.get_pk()?;
103        self.delete_share(id, Some(pk)).await
104    }
105}