sos_vault/encoding/
vault.rs1use crate::{
2 Auth, Contents, Header, SharedAccess, Summary, Vault, VaultMeta,
3};
4use async_trait::async_trait;
5use binary_stream::futures::{
6 BinaryReader, BinaryWriter, Decodable, Encodable,
7};
8use sos_core::{
9 constants::VAULT_IDENTITY,
10 crypto::{AeadPack, Seed},
11 encoding::{decode_uuid, encoding_error},
12 file_identity::FileIdentity,
13 SecretId, UtcDateTime, VaultCommit, VaultFlags,
14};
15use std::io::{Error, ErrorKind, Result, SeekFrom};
16use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite};
17
18#[async_trait]
19impl Encodable for VaultMeta {
20 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
21 &self,
22 writer: &mut BinaryWriter<W>,
23 ) -> Result<()> {
24 self.date_created.encode(&mut *writer).await?;
25 writer.write_string(&self.description).await?;
26 Ok(())
27 }
28}
29
30#[async_trait]
31impl Decodable for VaultMeta {
32 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
33 &mut self,
34 reader: &mut BinaryReader<R>,
35 ) -> Result<()> {
36 let mut date_created: UtcDateTime = Default::default();
37 date_created.decode(&mut *reader).await?;
38 self.description = reader.read_string().await?;
39 Ok(())
40 }
41}
42
43#[async_trait]
44impl Encodable for Auth {
45 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
46 &self,
47 writer: &mut BinaryWriter<W>,
48 ) -> Result<()> {
49 writer.write_bool(self.salt.is_some()).await?;
50 if let Some(salt) = &self.salt {
51 writer.write_string(salt).await?;
52 }
53 writer.write_bool(self.seed.is_some()).await?;
54 if let Some(seed) = &self.seed {
55 writer.write_bytes(seed).await?;
56 }
57 Ok(())
58 }
59}
60
61#[async_trait]
62impl Decodable for Auth {
63 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
64 &mut self,
65 reader: &mut BinaryReader<R>,
66 ) -> Result<()> {
67 let has_salt = reader.read_bool().await?;
68 if has_salt {
69 self.salt = Some(reader.read_string().await?);
70 }
71 let has_seed = reader.read_bool().await?;
72 if has_seed {
73 let bytes: [u8; Seed::SIZE] = reader
74 .read_bytes(Seed::SIZE)
75 .await?
76 .as_slice()
77 .try_into()
78 .map_err(encoding_error)?;
79 self.seed = Some(Seed(bytes));
80 }
81 Ok(())
82 }
83}
84
85#[async_trait]
86impl Encodable for Summary {
87 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
88 &self,
89 writer: &mut BinaryWriter<W>,
90 ) -> Result<()> {
91 writer.write_u16(self.version).await?;
92 self.cipher.encode(&mut *writer).await?;
93 self.kdf.encode(&mut *writer).await?;
94 writer.write_bytes(self.id.as_bytes()).await?;
95 writer.write_string(&self.name).await?;
96 writer.write_u64(self.flags.bits()).await?;
97 Ok(())
98 }
99}
100
101#[async_trait]
102impl Decodable for Summary {
103 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
104 &mut self,
105 reader: &mut BinaryReader<R>,
106 ) -> Result<()> {
107 self.version = reader.read_u16().await?;
108 self.cipher.decode(&mut *reader).await?;
109 self.kdf.decode(&mut *reader).await?;
110 self.id = decode_uuid(&mut *reader).await?;
111 self.name = reader.read_string().await?;
112 self.flags = VaultFlags::from_bits(reader.read_u64().await?)
113 .ok_or(crate::Error::InvalidVaultFlags)
114 .map_err(encoding_error)?;
115 Ok(())
116 }
117}
118
119#[async_trait]
120impl Encodable for Header {
121 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
122 &self,
123 writer: &mut BinaryWriter<W>,
124 ) -> Result<()> {
125 writer.write_bytes(&VAULT_IDENTITY).await?;
126
127 let size_pos = writer.stream_position().await?;
128 writer.write_u32(0).await?;
129
130 self.summary.encode(&mut *writer).await?;
131
132 writer.write_bool(self.meta.is_some()).await?;
133 if let Some(meta) = &self.meta {
134 meta.encode(&mut *writer).await?;
135 }
136
137 self.auth.encode(&mut *writer).await?;
138 self.shared_access.encode(&mut *writer).await?;
139
140 let header_pos = writer.stream_position().await?;
142 let header_len = header_pos - (size_pos + 4);
143
144 writer.seek(SeekFrom::Start(size_pos)).await?;
145 writer.write_u32(header_len as u32).await?;
146 writer.seek(SeekFrom::Start(header_pos)).await?;
147
148 Ok(())
149 }
150}
151
152#[async_trait]
153impl Decodable for Header {
154 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
155 &mut self,
156 reader: &mut BinaryReader<R>,
157 ) -> Result<()> {
158 FileIdentity::read_identity(&mut *reader, &VAULT_IDENTITY)
159 .await
160 .map_err(|_| {
161 Error::new(ErrorKind::Other, "bad vault identity bytes")
162 })?;
163
164 let _ = reader.read_u32().await?;
166
167 self.summary.decode(&mut *reader).await?;
168
169 let has_meta = reader.read_bool().await?;
170 if has_meta {
171 self.meta = Some(Default::default());
172 if let Some(meta) = self.meta.as_mut() {
173 meta.decode(&mut *reader).await?;
174 }
175 }
176
177 self.auth.decode(&mut *reader).await?;
178 self.shared_access.decode(&mut *reader).await?;
179
180 Ok(())
181 }
182}
183
184#[async_trait]
185impl Encodable for SharedAccess {
186 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
187 &self,
188 writer: &mut BinaryWriter<W>,
189 ) -> Result<()> {
190 match self {
191 SharedAccess::WriteAccess(recipients) => {
192 writer.write_u8(1).await?;
193 writer.write_u16(recipients.len() as u16).await?;
194 for recipient in recipients {
195 writer.write_string(recipient).await?;
196 }
197 }
198 SharedAccess::ReadOnly(aead) => {
199 writer.write_u8(2).await?;
200 aead.encode(writer).await?;
201 }
202 }
203
204 Ok(())
205 }
206}
207
208#[async_trait]
209impl Decodable for SharedAccess {
210 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
211 &mut self,
212 reader: &mut BinaryReader<R>,
213 ) -> Result<()> {
214 let id = reader.read_u8().await?;
215
216 match id {
217 1 => {
218 let mut recipients = Vec::new();
219 let length = reader.read_u16().await?;
220 for _ in 0..length {
221 let recipient = reader.read_string().await?;
222 let _: age::x25519::Recipient =
223 recipient.parse().map_err(|e: &str| {
224 Error::new(
225 ErrorKind::Other,
226 crate::Error::InvalidX25519Identity(
227 e.to_owned(),
228 ),
229 )
230 })?;
231 recipients.push(recipient);
232 }
233 *self = SharedAccess::WriteAccess(recipients);
234 }
235 2 => {
236 let mut aead: AeadPack = Default::default();
237 aead.decode(reader).await?;
238 *self = SharedAccess::ReadOnly(aead);
239 }
240 _ => {
241 return Err(encoding_error(
242 crate::Error::UnknownSharedAccessKind(id),
243 ));
244 }
245 }
246
247 Ok(())
248 }
249}
250
251impl Contents {
252 pub async fn encode_row<W: AsyncWrite + AsyncSeek + Unpin + Send>(
254 writer: &mut BinaryWriter<W>,
255 key: &SecretId,
256 row: &VaultCommit,
257 ) -> Result<()> {
258 let size_pos = writer.stream_position().await?;
259 writer.write_u32(0).await?;
260
261 writer.write_bytes(key.as_bytes()).await?;
262
263 row.encode(&mut *writer).await?;
264
265 let row_pos = writer.stream_position().await?;
267 let row_len = row_pos - (size_pos + 4);
268 writer.seek(SeekFrom::Start(size_pos)).await?;
269 writer.write_u32(row_len as u32).await?;
270 writer.seek(SeekFrom::Start(row_pos)).await?;
271
272 writer.write_u32(row_len as u32).await?;
275
276 Ok(())
277 }
278
279 pub async fn decode_row<R: AsyncRead + AsyncSeek + Unpin + Send>(
281 reader: &mut BinaryReader<R>,
282 ) -> Result<(SecretId, VaultCommit)> {
283 let _ = reader.read_u32().await?;
285
286 let uuid = decode_uuid(&mut *reader).await?;
287
288 let mut row: VaultCommit = Default::default();
289 row.decode(&mut *reader).await?;
290
291 let _ = reader.read_u32().await?;
293
294 Ok((uuid, row))
295 }
296}
297
298#[async_trait]
299impl Encodable for Contents {
300 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
301 &self,
302 writer: &mut BinaryWriter<W>,
303 ) -> Result<()> {
304 for (key, row) in &self.data {
305 Contents::encode_row(writer, key, row).await?;
306 }
307 Ok(())
308 }
309}
310
311#[async_trait]
312impl Decodable for Contents {
313 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
314 &mut self,
315 reader: &mut BinaryReader<R>,
316 ) -> Result<()> {
317 let mut pos = reader.stream_position().await?;
318 let len = reader.len().await?;
319 while pos < len {
320 let (uuid, value) = Contents::decode_row(reader).await?;
321 self.data.insert(uuid, value);
322 pos = reader.stream_position().await?;
323 }
324
325 Ok(())
326 }
327}
328
329#[async_trait]
330impl Encodable for Vault {
331 async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
332 &self,
333 writer: &mut BinaryWriter<W>,
334 ) -> Result<()> {
335 self.header.encode(writer).await?;
336 self.contents.encode(writer).await?;
337 Ok(())
338 }
339}
340
341#[async_trait]
342impl Decodable for Vault {
343 async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
344 &mut self,
345 reader: &mut BinaryReader<R>,
346 ) -> Result<()> {
347 self.header.decode(reader).await?;
348 self.contents.decode(reader).await?;
349 Ok(())
350 }
351}