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: Arc<Paths>,
28    accounts: Accounts,
29    target: BackendTarget,
30}
31
32impl Backend {
33    /// Create a new server backend.
34    pub fn new(paths: Arc<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(self.paths.documents_dir()).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.target.clone(),
95                            &account_id,
96                        )
97                        .await?;
98
99                        let mut accounts = self.accounts.write().await;
100                        accounts.insert(
101                            account_id,
102                            Arc::new(RwLock::new(account)),
103                        );
104                    }
105                }
106            }
107        }
108
109        Ok(())
110    }
111
112    pub(crate) async fn load_db_accounts(
113        &mut self,
114        client: Client,
115    ) -> Result<()> {
116        tracing::debug!(
117          directory = %self.paths.documents_dir().display(),
118          "server_backend::load_db_accounts");
119
120        let accounts = AccountEntity::list_all_accounts(&client).await?;
121
122        for account in accounts {
123            let account_id = *account.identity.account_id();
124            let account = ServerStorage::new(
125                self.target.clone(),
126                &account_id,
127            )
128            .await?;
129
130            let mut accounts = self.accounts.write().await;
131            accounts.insert(account_id, Arc::new(RwLock::new(account)));
132        }
133
134        Ok(())
135    }
136
137    /// Create an account.
138    pub async fn create_account(
139        &mut self,
140        account_id: &AccountId,
141        account_data: CreateSet,
142    ) -> Result<()> {
143        {
144            let accounts = self.accounts.read().await;
145            let account = accounts.get(account_id);
146            if account.is_some() {
147                return Err(Error::AccountExists(*account_id));
148            }
149        }
150
151        tracing::debug!(
152            account_id = %account_id,
153            "server_backend::create_account",
154        );
155
156        let target = self.target.clone().with_account_id(account_id);
157
158        let account = ServerStorage::create_account(
159            target,
160            account_id,
161            &account_data,
162        )
163        .await?;
164
165        let mut accounts = self.accounts.write().await;
166        accounts
167            .entry(*account_id)
168            .or_insert(Arc::new(RwLock::new(account)));
169
170        Ok(())
171    }
172
173    /// Delete an account.
174    pub async fn delete_account(
175        &mut self,
176        account_id: &AccountId,
177    ) -> Result<()> {
178        tracing::debug!(
179            account_id = %account_id,
180            "server_backend::delete_account");
181
182        let mut accounts = self.accounts.write().await;
183        // Remove from storage
184        {
185            let account = accounts
186                .get_mut(account_id)
187                .ok_or(Error::NoAccount(*account_id))?;
188
189            let mut account = account.write().await;
190            account.delete_account().await?;
191        }
192
193        // Clean in-memory reference
194        accounts.remove(account_id);
195
196        Ok(())
197    }
198
199    /// Update an account.
200    pub async fn update_account(
201        &mut self,
202        account_id: &AccountId,
203        account_data: UpdateSet,
204    ) -> Result<MergeOutcome> {
205        tracing::debug!(
206            account_id = %account_id, 
207            "server_backend::update_account");
208
209        let mut outcome = MergeOutcome::default();
210
211        let mut accounts = self.accounts.write().await;
212        let account = accounts
213            .get_mut(account_id)
214            .ok_or(Error::NoAccount(*account_id))?;
215
216        let mut account = account.write().await;
217        account
218            .force_merge_update(account_data, &mut outcome)
219            .await?;
220        Ok(outcome)
221    }
222
223    /// Fetch an existing account.
224    pub async fn fetch_account(
225        &self,
226        account_id: &AccountId,
227    ) -> Result<CreateSet> {
228        tracing::debug!(
229            account_id = %account_id,
230            "server_backend::fetch_account",
231        );
232
233        let accounts = self.accounts.read().await;
234        let account = accounts
235            .get(account_id)
236            .ok_or(Error::NoAccount(*account_id))?;
237
238        let reader = account.read().await;
239        Ok(reader.create_set().await?)
240    }
241
242    /// Verify a device is allowed to access an account.
243    pub(crate) async fn verify_device(
244        &self,
245        account_id: &AccountId,
246        device_signature: &ed25519::Signature,
247        message_body: &[u8],
248    ) -> Result<()> {
249        let accounts = self.accounts.read().await;
250        if let Some(account) = accounts.get(account_id) {
251            let reader = account.read().await;
252            let account_devices = reader.list_device_keys();
253            for device_key in account_devices {
254                let verifying_key = into_device_verifying_key(device_key)?;
255                if verifying_key
256                    .verify(message_body, device_signature)
257                    .is_ok()
258                {
259                    return Ok(());
260                }
261            }
262            Err(Error::Forbidden)
263        } else {
264            Ok(())
265        }
266    }
267
268    /// Determine if an account exists.
269    pub async fn account_exists(
270        &self,
271        account_id: &AccountId,
272    ) -> Result<bool> {
273        let accounts = self.accounts.read().await;
274        Ok(accounts.get(account_id).is_some())
275    }
276}