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: Paths,
28 accounts: Accounts,
29 target: BackendTarget,
30}
31
32impl Backend {
33 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 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(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 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 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 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 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 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 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}