1use crate::{AccessPoint, BackendTarget, Error, FolderEventLog, Result};
3use sos_core::{
4 commit::{CommitHash, CommitState},
5 crypto::AccessKey,
6 encode,
7 events::{EventLog, EventLogType, EventRecord, ReadEvent, WriteEvent},
8 AccountId, VaultFlags, VaultId,
9};
10use sos_core::{constants::EVENT_LOG_EXT, decode, VaultCommit};
11use sos_database::{
12 entity::{FolderEntity, FolderRecord, SecretRecord},
13 VaultDatabaseWriter,
14};
15use sos_filesystem::VaultFileWriter;
16use sos_reducers::FolderReducer;
17use sos_vault::{
18 secret::{Secret, SecretId, SecretMeta, SecretRow},
19 AccessPoint as VaultAccessPoint, EncryptedEntry, SecretAccess, Vault,
20 VaultMeta,
21};
22use sos_vfs as vfs;
23use std::{path::Path, sync::Arc};
24use tokio::sync::{Mutex, RwLock};
25
26#[derive(Clone)]
28pub struct Folder {
29 access_point: Arc<Mutex<AccessPoint>>,
30 events: Arc<RwLock<FolderEventLog>>,
31}
32
33impl Folder {
34 pub async fn new(
38 target: BackendTarget,
39 account_id: &AccountId,
40 folder_id: &VaultId,
41 ) -> Result<Self> {
42 match target {
43 BackendTarget::FileSystem(paths) => {
44 Self::from_path(
45 paths.with_account_id(account_id).vault_path(folder_id),
46 account_id,
47 EventLogType::Folder(*folder_id),
48 )
49 .await
50 }
51 BackendTarget::Database(paths, client) => {
52 let folder_id = *folder_id;
53 let folder_row = client
54 .conn(move |conn| {
55 let folder = FolderEntity::new(&conn);
56 Ok(folder.find_one(&folder_id)?)
57 })
58 .await
59 .map_err(sos_database::Error::from)?;
60 let folder_record =
61 FolderRecord::from_row(folder_row).await?;
62 let mut vault = folder_record.into_vault()?;
63
64 let secrets = client
65 .conn_and_then(move |conn| {
66 let folder = FolderEntity::new(&conn);
67 let secrets =
68 folder.load_secrets(folder_record.row_id)?;
69 Ok::<_, sos_database::Error>(secrets)
70 })
71 .await?;
72
73 for secret in secrets {
74 let record = SecretRecord::from_row(secret).await?;
75 let VaultCommit(commit, entry) = record.commit;
76 vault
77 .insert_secret(record.secret_id, commit, entry)
78 .await?;
79 }
80
81 let mut event_log = FolderEventLog::new_folder(
82 BackendTarget::Database(paths, client.clone()),
83 &account_id,
84 &folder_id,
85 )
86 .await?;
87
88 event_log.load_tree().await?;
89
90 if event_log.tree().len() == 0 {
91 let buffer = encode(&vault).await?;
92 let event = WriteEvent::CreateVault(buffer);
93 event_log.apply(&[event]).await?;
94 }
95
96 let mirror =
97 VaultDatabaseWriter::<Error>::new(client, folder_id);
98 let access_point = VaultAccessPoint::<Error>::new_mirror(
99 vault,
100 Box::new(mirror),
101 );
102
103 Ok(Self::init(AccessPoint::wrap(access_point), event_log))
104 }
105 }
106 }
107
108 pub async fn from_vault_event_log(
110 target: &BackendTarget,
111 vault: Vault,
112 event_log: FolderEventLog,
113 ) -> Result<Self> {
114 let access_point = match target {
115 BackendTarget::FileSystem(paths) => {
116 let path = paths.vault_path(vault.id());
117 let mirror = VaultFileWriter::<Error>::new(path);
118 VaultAccessPoint::<Error>::new_mirror(vault, Box::new(mirror))
119 }
120 BackendTarget::Database(_, client) => {
121 let mirror = VaultDatabaseWriter::<Error>::new(
122 client.clone(),
123 *vault.id(),
124 );
125 VaultAccessPoint::<Error>::new_mirror(vault, Box::new(mirror))
126 }
127 };
128 Ok(Self::init(AccessPoint::wrap(access_point), event_log))
129 }
130
131 pub async fn from_path(
138 path: impl AsRef<Path>,
139 account_id: &AccountId,
140 log_type: EventLogType,
141 ) -> Result<Self> {
142 let mut events_path = path.as_ref().to_owned();
143 events_path.set_extension(EVENT_LOG_EXT);
144
145 let mut event_log =
146 sos_filesystem::FolderEventLog::<Error>::new_folder(
147 events_path,
148 *account_id,
149 log_type,
150 )
151 .await?;
152 event_log.load_tree().await?;
153 let needs_init = event_log.tree().root().is_none();
154
155 let vault = if needs_init {
156 let vault = if vfs::try_exists(path.as_ref()).await? {
157 let buffer = vfs::read(path.as_ref()).await?;
162 let vault: Vault = decode(&buffer).await?;
163 vault
164 } else {
165 Default::default()
167 };
168
169 let (_, events) =
170 FolderReducer::split::<Error>(vault.clone()).await?;
171 event_log.apply(events.as_slice()).await?;
172
173 vault
174 } else {
175 let buffer = vfs::read(path.as_ref()).await?;
176 let vault: Vault = decode(&buffer).await?;
177 vault
178 };
179
180 let mirror = VaultFileWriter::<Error>::new(path.as_ref());
181 let access_point =
182 VaultAccessPoint::<Error>::new_mirror(vault, Box::new(mirror));
183
184 Ok(Self::init(
185 AccessPoint::wrap(access_point),
186 FolderEventLog::FileSystem(event_log),
187 ))
188 }
189
190 fn init(access_point: AccessPoint, events: FolderEventLog) -> Self {
192 Self {
193 access_point: Arc::new(Mutex::new(access_point)),
194 events: Arc::new(RwLock::new(events)),
195 }
196 }
197
198 pub async fn id(&self) -> VaultId {
200 let access_point = self.access_point.lock().await;
201 *access_point.id()
202 }
203
204 pub fn access_point(&self) -> Arc<Mutex<AccessPoint>> {
206 self.access_point.clone()
207 }
208
209 pub fn event_log(&self) -> Arc<RwLock<FolderEventLog>> {
211 Arc::clone(&self.events)
212 }
213
214 pub async fn unlock(
216 &mut self,
217 key: &AccessKey,
218 ) -> crate::Result<VaultMeta> {
219 let mut access_point = self.access_point.lock().await;
220 Ok(access_point.unlock(key).await?)
221 }
222
223 pub async fn lock(&mut self) {
225 let mut access_point = self.access_point.lock().await;
226 access_point.lock();
227 }
228
229 pub async fn create_secret(
231 &mut self,
232 secret_data: &SecretRow,
233 ) -> crate::Result<WriteEvent> {
234 let mut access_point = self.access_point.lock().await;
235 let event = access_point.create_secret(secret_data).await?;
236 let mut events = self.events.write().await;
237 events.apply(&[event.clone()]).await?;
238 Ok(event)
239 }
240
241 pub async fn read_secret(
243 &self,
244 id: &SecretId,
245 ) -> crate::Result<Option<(SecretMeta, Secret, ReadEvent)>> {
246 let access_point = self.access_point.lock().await;
247 Ok(access_point.read_secret(id).await?)
248 }
249
250 pub async fn raw_secret(
252 &self,
253 id: &SecretId,
254 ) -> crate::Result<Option<(VaultCommit, ReadEvent)>> {
255 let access_point = self.access_point.lock().await;
256 Ok(access_point.raw_secret(id).await?)
257 }
258
259 pub async fn update_secret(
261 &mut self,
262 id: &SecretId,
263 secret_meta: SecretMeta,
264 secret: Secret,
265 ) -> crate::Result<Option<WriteEvent>> {
266 let mut access_point = self.access_point.lock().await;
267 if let Some(event) =
268 access_point.update_secret(id, secret_meta, secret).await?
269 {
270 let mut events = self.events.write().await;
271 events.apply(&[event.clone()]).await?;
272 Ok(Some(event))
273 } else {
274 Ok(None)
275 }
276 }
277
278 pub async fn delete_secret(
280 &mut self,
281 id: &SecretId,
282 ) -> Result<Option<WriteEvent>> {
283 let mut access_point = self.access_point.lock().await;
284 if let Some(event) = access_point.delete_secret(id).await? {
285 let mut events = self.events.write().await;
286 events.apply(&[event.clone()]).await?;
287 Ok(Some(event))
288 } else {
289 Ok(None)
290 }
291 }
292
293 pub async fn rename_folder(
295 &mut self,
296 name: impl AsRef<str>,
297 ) -> Result<WriteEvent> {
298 let mut access_point = self.access_point.lock().await;
299 access_point
300 .set_vault_name(name.as_ref().to_owned())
301 .await?;
302 let event = WriteEvent::SetVaultName(name.as_ref().to_owned());
303 let mut events = self.events.write().await;
304 events.apply(&[event.clone()]).await?;
305 Ok(event)
306 }
307
308 pub async fn update_folder_flags(
310 &mut self,
311 flags: VaultFlags,
312 ) -> Result<WriteEvent> {
313 let mut access_point = self.access_point.lock().await;
314 access_point.set_vault_flags(flags.clone()).await?;
315 let event = WriteEvent::SetVaultFlags(flags);
316 let mut events = self.events.write().await;
317 events.apply(&[event.clone()]).await?;
318 Ok(event)
319 }
320
321 pub async fn description(&self) -> Result<String> {
323 let access_point = self.access_point.lock().await;
324 let meta = access_point.vault_meta().await?;
325 Ok(meta.description().to_owned())
326 }
327
328 pub async fn set_description(
330 &mut self,
331 description: impl AsRef<str>,
332 ) -> Result<WriteEvent> {
333 let mut meta = {
334 let access_point = self.access_point.lock().await;
335 access_point.vault_meta().await?
336 };
337 meta.set_description(description.as_ref().to_owned());
338 self.set_meta(&meta).await
339 }
340
341 pub async fn set_meta(&mut self, meta: &VaultMeta) -> Result<WriteEvent> {
343 let mut access_point = self.access_point.lock().await;
344 let event = access_point.set_vault_meta(meta).await?;
345 let mut events = self.events.write().await;
346 events.apply(&[event.clone()]).await?;
347 Ok(event)
348 }
349
350 pub async fn commit_state(&self) -> Result<CommitState> {
352 let event_log = self.events.read().await;
353 Ok(event_log.tree().commit_state()?)
354 }
355
356 pub async fn root_hash(&self) -> Result<CommitHash> {
358 let event_log = self.events.read().await;
359 Ok(event_log
360 .tree()
361 .root()
362 .ok_or(sos_core::Error::NoRootCommit)?)
363 }
364
365 pub async fn apply(&mut self, events: &[WriteEvent]) -> Result<()> {
367 let mut event_log = self.events.write().await;
368 event_log.apply(events).await?;
369 Ok(())
370 }
371
372 pub async fn apply_records(
374 &mut self,
375 records: Vec<EventRecord>,
376 ) -> Result<()> {
377 let mut event_log = self.events.write().await;
378 event_log.apply_records(records).await?;
379 Ok(())
380 }
381
382 pub async fn clear(&mut self) -> Result<()> {
384 let mut event_log = self.events.write().await;
385 event_log.clear().await?;
386 Ok(())
387 }
388}
389
390impl From<Folder> for Vault {
391 fn from(value: Folder) -> Self {
392 let mutex = Arc::into_inner(value.access_point).unwrap();
393 let access_point = mutex.into_inner();
394 access_point.into()
395 }
396}