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
12pub type ServerAccount = Arc<RwLock<ServerStorage>>;
14
15pub 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
25pub struct Backend {
27 paths: Arc<Paths>,
28 accounts: Accounts,
29 target: BackendTarget,
30}
31
32impl Backend {
33 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 pub fn paths(&self) -> &Paths {
44 &self.paths
45 }
46
47 pub fn accounts(&self) -> Accounts {
49 Arc::clone(&self.accounts)
50 }
51
52 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 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 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 {
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 accounts.remove(account_id);
195
196 Ok(())
197 }
198
199 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 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 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 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}