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, 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(|_| Error::other("bad vault identity bytes"))?;
161
162        // Read in the header length
163        let _ = reader.read_u32().await?;
164
165        self.summary.decode(&mut *reader).await?;
166
167        let has_meta = reader.read_bool().await?;
168        if has_meta {
169            self.meta = Some(Default::default());
170            if let Some(meta) = self.meta.as_mut() {
171                meta.decode(&mut *reader).await?;
172            }
173        }
174
175        self.auth.decode(&mut *reader).await?;
176        self.shared_access.decode(&mut *reader).await?;
177
178        Ok(())
179    }
180}
181
182#[async_trait]
183impl Encodable for SharedAccess {
184    async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
185        &self,
186        writer: &mut BinaryWriter<W>,
187    ) -> Result<()> {
188        match self {
189            SharedAccess::WriteAccess(recipients) => {
190                writer.write_u8(1).await?;
191                writer.write_u16(recipients.len() as u16).await?;
192                for recipient in recipients {
193                    writer.write_string(recipient).await?;
194                }
195            }
196            SharedAccess::ReadOnly(aead) => {
197                writer.write_u8(2).await?;
198                aead.encode(writer).await?;
199            }
200        }
201
202        Ok(())
203    }
204}
205
206#[async_trait]
207impl Decodable for SharedAccess {
208    async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
209        &mut self,
210        reader: &mut BinaryReader<R>,
211    ) -> Result<()> {
212        let id = reader.read_u8().await?;
213
214        match id {
215            1 => {
216                let mut recipients = Vec::new();
217                let length = reader.read_u16().await?;
218                for _ in 0..length {
219                    let recipient = reader.read_string().await?;
220                    let _: age::x25519::Recipient =
221                        recipient.parse().map_err(|e: &str| {
222                            Error::other(crate::Error::InvalidX25519Identity(
223                                e.to_owned(),
224                            ))
225                        })?;
226                    recipients.push(recipient);
227                }
228                *self = SharedAccess::WriteAccess(recipients);
229            }
230            2 => {
231                let mut aead: AeadPack = Default::default();
232                aead.decode(reader).await?;
233                *self = SharedAccess::ReadOnly(aead);
234            }
235            _ => {
236                return Err(encoding_error(
237                    crate::Error::UnknownSharedAccessKind(id),
238                ));
239            }
240        }
241
242        Ok(())
243    }
244}
245
246impl Contents {
247    /// Encodable a single row into a serializer.
248    pub async fn encode_row<W: AsyncWrite + AsyncSeek + Unpin + Send>(
249        writer: &mut BinaryWriter<W>,
250        key: &SecretId,
251        row: &VaultCommit,
252    ) -> Result<()> {
253        let size_pos = writer.stream_position().await?;
254        writer.write_u32(0).await?;
255
256        writer.write_bytes(key.as_bytes()).await?;
257
258        row.encode(&mut *writer).await?;
259
260        // Backtrack to size_pos and write new length
261        let row_pos = writer.stream_position().await?;
262        let row_len = row_pos - (size_pos + 4);
263        writer.seek(SeekFrom::Start(size_pos)).await?;
264        writer.write_u32(row_len as u32).await?;
265        writer.seek(SeekFrom::Start(row_pos)).await?;
266
267        // Write out the row len at the end of the record too
268        // so we can support double ended iteration
269        writer.write_u32(row_len as u32).await?;
270
271        Ok(())
272    }
273
274    /// Decodable a single row from a deserializer.
275    pub async fn decode_row<R: AsyncRead + AsyncSeek + Unpin + Send>(
276        reader: &mut BinaryReader<R>,
277    ) -> Result<(SecretId, VaultCommit)> {
278        // Read in the row length
279        let _ = reader.read_u32().await?;
280
281        let uuid = decode_uuid(&mut *reader).await?;
282
283        let mut row: VaultCommit = Default::default();
284        row.decode(&mut *reader).await?;
285
286        // Read in the row length suffix
287        let _ = reader.read_u32().await?;
288
289        Ok((uuid, row))
290    }
291}
292
293#[async_trait]
294impl Encodable for Contents {
295    async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
296        &self,
297        writer: &mut BinaryWriter<W>,
298    ) -> Result<()> {
299        for (key, row) in &self.data {
300            Contents::encode_row(writer, key, row).await?;
301        }
302        Ok(())
303    }
304}
305
306#[async_trait]
307impl Decodable for Contents {
308    async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
309        &mut self,
310        reader: &mut BinaryReader<R>,
311    ) -> Result<()> {
312        let mut pos = reader.stream_position().await?;
313        let len = reader.len().await?;
314        while pos < len {
315            let (uuid, value) = Contents::decode_row(reader).await?;
316            self.data.insert(uuid, value);
317            pos = reader.stream_position().await?;
318        }
319
320        Ok(())
321    }
322}
323
324#[async_trait]
325impl Encodable for Vault {
326    async fn encode<W: AsyncWrite + AsyncSeek + Unpin + Send>(
327        &self,
328        writer: &mut BinaryWriter<W>,
329    ) -> Result<()> {
330        self.header.encode(writer).await?;
331        self.contents.encode(writer).await?;
332        Ok(())
333    }
334}
335
336#[async_trait]
337impl Decodable for Vault {
338    async fn decode<R: AsyncRead + AsyncSeek + Unpin + Send>(
339        &mut self,
340        reader: &mut BinaryReader<R>,
341    ) -> Result<()> {
342        self.header.decode(reader).await?;
343        self.contents.decode(reader).await?;
344        Ok(())
345    }
346}