sos_vault/encoding/
vault.rs

1use 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        // Backtrack to size_pos and write new length
141        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        // Read in the header length
165        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    /// Encodable a single row into a serializer.
253    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        // Backtrack to size_pos and write new length
266        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        // Write out the row len at the end of the record too
273        // so we can support double ended iteration
274        writer.write_u32(row_len as u32).await?;
275
276        Ok(())
277    }
278
279    /// Decodable a single row from a deserializer.
280    pub async fn decode_row<R: AsyncRead + AsyncSeek + Unpin + Send>(
281        reader: &mut BinaryReader<R>,
282    ) -> Result<(SecretId, VaultCommit)> {
283        // Read in the row length
284        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        // Read in the row length suffix
292        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}