1use crate::{
3 entity::{FolderEntity, FolderRecord, SecretRecord, SecretRow},
4 Error,
5};
6use async_sqlite::Client;
7use async_trait::async_trait;
8use sos_core::{
9 commit::CommitHash,
10 crypto::AeadPack,
11 encode,
12 events::{ReadEvent, WriteEvent},
13 SecretId, VaultCommit, VaultEntry, VaultFlags, VaultId,
14};
15use sos_vault::{EncryptedEntry, Summary, Vault};
16use std::borrow::Cow;
17
18pub struct VaultDatabaseWriter<E>
20where
21 E: std::error::Error
22 + std::fmt::Debug
23 + From<sos_core::Error>
24 + From<sos_vault::Error>
25 + From<Error>
26 + Send
27 + Sync
28 + 'static,
29{
30 client: Client,
31 folder_id: VaultId,
32 marker: std::marker::PhantomData<E>,
33}
34
35impl<E> VaultDatabaseWriter<E>
36where
37 E: std::error::Error
38 + std::fmt::Debug
39 + From<sos_core::Error>
40 + From<sos_vault::Error>
41 + From<Error>
42 + Send
43 + Sync
44 + 'static,
45{
46 pub fn new(client: Client, folder_id: VaultId) -> Self {
48 Self {
49 client,
50 folder_id,
51 marker: std::marker::PhantomData,
52 }
53 }
54}
55
56#[async_trait]
57impl<E> EncryptedEntry for VaultDatabaseWriter<E>
58where
59 E: std::error::Error
60 + std::fmt::Debug
61 + From<sos_core::Error>
62 + From<sos_vault::Error>
63 + From<Error>
64 + Send
65 + Sync
66 + 'static,
67{
68 type Error = E;
69
70 async fn summary(&self) -> Result<Summary, Self::Error> {
71 let folder_id = self.folder_id;
72 let row = self
73 .client
74 .conn(move |conn| {
75 let folder = FolderEntity::new(&conn);
76 let row = folder.find_optional(&folder_id)?;
77 Ok(row)
78 })
79 .await
80 .map_err(Error::from)?;
81 let row = row.ok_or(Error::DatabaseFolderNotFound(folder_id))?;
82 let record = FolderRecord::from_row(row).await?;
83 Ok(record.summary)
84 }
85
86 async fn vault_name(&self) -> Result<Cow<'_, str>, Self::Error> {
87 let summary = self.summary().await?;
88 Ok(Cow::Owned(summary.name().to_string()))
89 }
90
91 async fn set_vault_name(
92 &mut self,
93 name: String,
94 ) -> Result<WriteEvent, Self::Error> {
95 let folder_id = self.folder_id;
96 let folder_name = name.clone();
97 self.client
98 .conn_and_then(move |conn| {
99 let folder = FolderEntity::new(&conn);
100 folder.update_name(&folder_id, &folder_name)
101 })
102 .await?;
103 Ok(WriteEvent::SetVaultName(name))
104 }
105
106 async fn set_vault_flags(
107 &mut self,
108 flags: VaultFlags,
109 ) -> Result<WriteEvent, Self::Error> {
110 let folder_id = self.folder_id;
111 let folder_flags = flags.clone();
112 self.client
113 .conn_and_then(move |conn| {
114 let folder = FolderEntity::new(&conn);
115 folder.update_flags(&folder_id, &folder_flags)
116 })
117 .await?;
118 Ok(WriteEvent::SetVaultFlags(flags))
119 }
120
121 async fn set_vault_meta(
122 &mut self,
123 meta_data: AeadPack,
124 ) -> Result<WriteEvent, Self::Error> {
125 let folder_id = self.folder_id;
126 let folder_meta = encode(&meta_data).await?;
127 self.client
128 .conn_and_then(move |conn| {
129 let folder = FolderEntity::new(&conn);
130 folder.update_meta(&folder_id, folder_meta.as_slice())
131 })
132 .await?;
133 Ok(WriteEvent::SetVaultMeta(meta_data))
134 }
135
136 async fn create_secret(
137 &mut self,
138 commit: CommitHash,
139 secret: VaultEntry,
140 ) -> Result<WriteEvent, Self::Error> {
141 self.insert_secret(SecretId::new_v4(), commit, secret).await
142 }
143
144 async fn insert_secret(
145 &mut self,
146 secret_id: SecretId,
147 commit: CommitHash,
148 secret: VaultEntry,
149 ) -> Result<WriteEvent, Self::Error> {
150 let folder_id = self.folder_id;
151 let secret_row = SecretRow::new(&secret_id, &commit, &secret).await?;
152 self.client
153 .conn(move |conn| {
154 let folder = FolderEntity::new(&conn);
155 folder.insert_secret(&folder_id, &secret_row)?;
156 Ok(())
157 })
158 .await
159 .map_err(Error::from)?;
160 Ok(WriteEvent::CreateSecret(
161 secret_id,
162 VaultCommit(commit, secret),
163 ))
164 }
165
166 async fn read_secret<'a>(
167 &'a self,
168 secret_id: &SecretId,
169 ) -> Result<Option<(Cow<'a, VaultCommit>, ReadEvent)>, Self::Error> {
170 let folder_id = self.folder_id;
171 let folder_secret_id = *secret_id;
172 let secret_row = self
173 .client
174 .conn(move |conn| {
175 let folder = FolderEntity::new(&conn);
176 folder.find_secret(&folder_id, &folder_secret_id)
177 })
178 .await
179 .map_err(Error::from)?;
180
181 let event = ReadEvent::ReadSecret(*secret_id);
182 if let Some(row) = secret_row {
183 let record = SecretRecord::from_row(row).await?;
184 Ok(Some((Cow::Owned(record.commit), event)))
185 } else {
186 Ok(None)
187 }
188 }
189
190 async fn update_secret(
191 &mut self,
192 secret_id: &SecretId,
193 commit: CommitHash,
194 secret: VaultEntry,
195 ) -> Result<Option<WriteEvent>, Self::Error> {
196 let folder_id = self.folder_id;
197 let secret_row = SecretRow::new(secret_id, &commit, &secret).await?;
198 let updated = self
199 .client
200 .conn_and_then(move |conn| {
201 let folder = FolderEntity::new(&conn);
202 folder.update_secret(&folder_id, &secret_row)
203 })
204 .await?;
205 Ok(updated.then_some(WriteEvent::UpdateSecret(
206 *secret_id,
207 VaultCommit(commit, secret),
208 )))
209 }
210
211 async fn delete_secret(
212 &mut self,
213 secret_id: &SecretId,
214 ) -> Result<Option<WriteEvent>, Self::Error> {
215 let folder_id = self.folder_id;
216 let folder_secret_id = *secret_id;
217 let deleted = self
218 .client
219 .conn(move |conn| {
220 let folder = FolderEntity::new(&conn);
221 folder.delete_secret(&folder_id, &folder_secret_id)
222 })
223 .await
224 .map_err(Error::from)?;
225 Ok(deleted.then_some(WriteEvent::DeleteSecret(*secret_id)))
226 }
227
228 async fn replace_vault(
229 &mut self,
230 vault: &Vault,
231 ) -> Result<(), Self::Error> {
232 Ok(FolderEntity::replace_all_secrets(
233 self.client.clone(),
234 &self.folder_id,
235 vault,
236 )
237 .await?)
238 }
239}