sos_server/
backend.rs

1use super::{Error, Result};
2use sos_backend::BackendTarget;
3use sos_core::{device::DevicePublicKey, AccountId, Paths};
4use sos_database::{async_sqlite::Client, entity::AccountEntity};
5use sos_server_storage::{ServerAccountStorage, ServerStorage};
6use sos_signer::ed25519::{self, Verifier, VerifyingKey};
7use sos_sync::{CreateSet, ForceMerge, MergeOutcome, SyncStorage, UpdateSet};
8use sos_vfs as vfs;
9use std::{collections::HashMap, sync::Arc};
10use tokio::sync::RwLock;
11
12/// Individual account.
13pub type ServerAccount = Arc<RwLock<ServerStorage>>;
14
15/// Collection of accounts by address.
16pub type Accounts = Arc<RwLock<HashMap<AccountId, ServerAccount>>>;
17
18fn into_device_verifying_key(
19    value: &DevicePublicKey,
20) -> Result<VerifyingKey> {
21    let bytes: [u8; 32] = value.as_ref().try_into()?;
22    Ok(VerifyingKey::from_bytes(&bytes)?)
23}
24
25/// Backend for a server.
26pub struct Backend {
27    paths: Paths,
28    accounts: Accounts,
29    target: BackendTarget,
30}
31
32impl Backend {
33    /// Create a new server backend.
34    pub fn new(paths: Paths, target: BackendTarget) -> Self {
35        Self {
36            paths,
37            accounts: Arc::new(RwLock::new(Default::default())),
38            target,
39        }
40    }
41
42    /// Storage paths.
43    pub fn paths(&self) -> &Paths {
44        &self.paths
45    }
46
47    /// Get the accounts.
48    pub fn accounts(&self) -> Accounts {
49        Arc::clone(&self.accounts)
50    }
51
52    /// Read accounts and event logs into memory.
53    pub(crate) async fn load_accounts(&mut self) -> Result<()> {
54        if !vfs::metadata(self.paths.documents_dir()).await?.is_dir() {
55            return Err(Error::NotDirectory(
56                self.paths.documents_dir().to_owned(),
57            ));
58        }
59
60        let target = self.target.clone();
61        match target {
62            BackendTarget::FileSystem(_) => self.load_fs_accounts().await,
63            BackendTarget::Database(client) => {
64                self.load_db_accounts(client).await
65            }
66        }
67    }
68
69    pub(crate) async fn load_fs_accounts(&mut self) -> Result<()> {
70        Paths::scaffold(Some(self.paths.documents_dir().to_owned())).await?;
71
72        tracing::debug!(
73            directory = %self.paths.documents_dir().display(),
74            "server_backend::load_fs_accounts");
75
76        if !vfs::try_exists(self.paths.local_dir()).await? {
77            vfs::create_dir(self.paths.local_dir()).await?;
78        }
79
80        let mut dir = vfs::read_dir(self.paths.local_dir()).await?;
81        while let Some(entry) = dir.next_entry().await? {
82            let path = entry.path();
83            if vfs::metadata(&path).await?.is_dir() {
84                if let Some(name) = path.file_stem() {
85                    if let Ok(account_id) =
86                        name.to_string_lossy().parse::<AccountId>()
87                    {
88                        tracing::debug!(
89                            account_id = %account_id,
90                            "server_backend::load_fs_accounts",
91                        );
92
93                        let account = ServerStorage::new(
94                            &self.paths,
95                            &account_id,
96                            self.target.clone(),
97                        )
98                        .await?;
99
100                        let mut accounts = self.accounts.write().await;
101                        accounts.insert(
102                            account_id,
103                            Arc::new(RwLock::new(account)),
104                        );
105                    }
106                }
107            }
108        }
109
110        Ok(())
111    }
112
113    pub(crate) async fn load_db_accounts(
114        &mut self,
115        client: Client,
116    ) -> Result<()> {
117        tracing::debug!(
118          directory = %self.paths.documents_dir().display(),
119          "server_backend::load_db_accounts");
120
121        let accounts = AccountEntity::list_all_accounts(&client).await?;
122
123        for account in accounts {
124            let account_id = *account.identity.account_id();
125            let account = ServerStorage::new(
126                &self.paths,
127                &account_id,
128                self.target.clone(),
129            )
130            .await?;
131
132            let mut accounts = self.accounts.write().await;
133            accounts.insert(account_id, Arc::new(RwLock::new(account)));
134        }
135
136        Ok(())
137    }
138
139    /// Create an account.
140    pub async fn create_account(
141        &mut self,
142        account_id: &AccountId,
143        account_data: CreateSet,
144    ) -> Result<()> {
145        {
146            let accounts = self.accounts.read().await;
147            let account = accounts.get(account_id);
148            if account.is_some() {
149                return Err(Error::AccountExists(*account_id));
150            }
151        }
152
153        tracing::debug!(
154            account_id = %account_id,
155            "server_backend::create_account",
156        );
157
158        let paths = self.paths.with_account_id(account_id);
159
160        let account = ServerStorage::create_account(
161            &paths,
162            account_id,
163            self.target.clone(),
164            &account_data,
165        )
166        .await?;
167
168        let mut accounts = self.accounts.write().await;
169        accounts
170            .entry(*account_id)
171            .or_insert(Arc::new(RwLock::new(account)));
172
173        Ok(())
174    }
175
176    /// Delete an account.
177    pub async fn delete_account(
178        &mut self,
179        account_id: &AccountId,
180    ) -> Result<()> {
181        tracing::debug!(address = %account_id, "server_backend::delete_account");
182
183        let mut accounts = self.accounts.write().await;
184        let account = accounts
185            .get_mut(account_id)
186            .ok_or(Error::NoAccount(*account_id))?;
187
188        let mut account = account.write().await;
189        account.delete_account().await?;
190
191        Ok(())
192    }
193
194    /// Update an account.
195    pub async fn update_account(
196        &mut self,
197        account_id: &AccountId,
198        account_data: UpdateSet,
199    ) -> Result<MergeOutcome> {
200        tracing::debug!(address = %account_id, "server_backend::update_account");
201
202        let mut outcome = MergeOutcome::default();
203
204        let mut accounts = self.accounts.write().await;
205        let account = accounts
206            .get_mut(account_id)
207            .ok_or(Error::NoAccount(*account_id))?;
208
209        let mut account = account.write().await;
210        account
211            .force_merge_update(account_data, &mut outcome)
212            .await?;
213        Ok(outcome)
214    }
215
216    /// Fetch an existing account.
217    pub async fn fetch_account(
218        &self,
219        account_id: &AccountId,
220    ) -> Result<CreateSet> {
221        tracing::debug!(
222            address = %account_id,
223            "server_backend::fetch_account",
224        );
225
226        let accounts = self.accounts.read().await;
227        let account = accounts
228            .get(account_id)
229            .ok_or(Error::NoAccount(*account_id))?;
230
231        let reader = account.read().await;
232        let change_set = reader.change_set().await?;
233
234        Ok(change_set)
235    }
236
237    /// Verify a device is allowed to access an account.
238    pub(crate) async fn verify_device(
239        &self,
240        account_id: &AccountId,
241        device_signature: &ed25519::Signature,
242        message_body: &[u8],
243    ) -> Result<()> {
244        let accounts = self.accounts.read().await;
245        if let Some(account) = accounts.get(account_id) {
246            let reader = account.read().await;
247            let account_devices = reader.list_device_keys();
248            for device_key in account_devices {
249                let verifying_key = into_device_verifying_key(device_key)?;
250                if verifying_key
251                    .verify(message_body, device_signature)
252                    .is_ok()
253                {
254                    return Ok(());
255                }
256            }
257            Err(Error::Forbidden)
258        } else {
259            Ok(())
260        }
261    }
262
263    /// Determine if an account exists.
264    pub async fn account_exists(
265        &self,
266        account_id: &AccountId,
267    ) -> Result<bool> {
268        let accounts = self.accounts.read().await;
269        Ok(accounts.get(account_id).is_some())
270    }
271}