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 backend accounts.
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!(
182            account_id = %account_id,
183            "server_backend::delete_account");
184
185        let mut accounts = self.accounts.write().await;
186        // Remove from storage
187        {
188            let account = accounts
189                .get_mut(account_id)
190                .ok_or(Error::NoAccount(*account_id))?;
191
192            let mut account = account.write().await;
193            account.delete_account().await?;
194        }
195
196        // Clean in-memory reference
197        accounts.remove(account_id);
198
199        Ok(())
200    }
201
202    /// Update an account.
203    pub async fn update_account(
204        &mut self,
205        account_id: &AccountId,
206        account_data: UpdateSet,
207    ) -> Result<MergeOutcome> {
208        tracing::debug!(
209            account_id = %account_id, 
210            "server_backend::update_account");
211
212        let mut outcome = MergeOutcome::default();
213
214        let mut accounts = self.accounts.write().await;
215        let account = accounts
216            .get_mut(account_id)
217            .ok_or(Error::NoAccount(*account_id))?;
218
219        let mut account = account.write().await;
220        account
221            .force_merge_update(account_data, &mut outcome)
222            .await?;
223        Ok(outcome)
224    }
225
226    /// Fetch an existing account.
227    pub async fn fetch_account(
228        &self,
229        account_id: &AccountId,
230    ) -> Result<CreateSet> {
231        tracing::debug!(
232            account_id = %account_id,
233            "server_backend::fetch_account",
234        );
235
236        let accounts = self.accounts.read().await;
237        let account = accounts
238            .get(account_id)
239            .ok_or(Error::NoAccount(*account_id))?;
240
241        let reader = account.read().await;
242        let change_set = reader.change_set().await?;
243
244        Ok(change_set)
245    }
246
247    /// Verify a device is allowed to access an account.
248    pub(crate) async fn verify_device(
249        &self,
250        account_id: &AccountId,
251        device_signature: &ed25519::Signature,
252        message_body: &[u8],
253    ) -> Result<()> {
254        let accounts = self.accounts.read().await;
255        if let Some(account) = accounts.get(account_id) {
256            let reader = account.read().await;
257            let account_devices = reader.list_device_keys();
258            for device_key in account_devices {
259                let verifying_key = into_device_verifying_key(device_key)?;
260                if verifying_key
261                    .verify(message_body, device_signature)
262                    .is_ok()
263                {
264                    return Ok(());
265                }
266            }
267            Err(Error::Forbidden)
268        } else {
269            Ok(())
270        }
271    }
272
273    /// Determine if an account exists.
274    pub async fn account_exists(
275        &self,
276        account_id: &AccountId,
277    ) -> Result<bool> {
278        let accounts = self.accounts.read().await;
279        Ok(accounts.get(account_id).is_some())
280    }
281}