1use crate::{Error, Result};
2use age::x25519::{Identity, Recipient};
3use async_trait::async_trait;
4use binary_stream::futures::{BinaryReader, Decodable};
5use indexmap::IndexMap;
6use secrecy::SecretString;
7use serde::{Deserialize, Serialize};
8use sha2::{Digest, Sha256};
9use sos_core::{
10 commit::CommitHash,
11 constants::{DEFAULT_VAULT_NAME, URN_NID, VAULT_IDENTITY, VAULT_NSS},
12 crypto::{
13 AccessKey, AeadPack, Cipher, Deriver, KeyDerivation, PrivateKey, Seed,
14 },
15 decode, encode,
16 encoding::{encoding_options, VERSION},
17 events::{ReadEvent, WriteEvent},
18 file_identity::FileIdentity,
19 AuthenticationError, SecretId, UtcDateTime, VaultCommit, VaultEntry,
20 VaultFlags, VaultId,
21};
22use sos_vfs::File;
23use std::io::Cursor;
24use std::{
25 borrow::Cow, cmp::Ordering, collections::HashMap, fmt, path::Path,
26};
27use tokio::io::{AsyncReadExt, AsyncSeek, BufReader};
28use typeshare::typeshare;
29use urn::Urn;
30use uuid::Uuid;
31
32#[derive(Default, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub struct VaultMeta {
36 pub(crate) date_created: UtcDateTime,
38 #[serde(skip_serializing_if = "String::is_empty")]
40 pub(crate) description: String,
41}
42
43impl VaultMeta {
44 pub fn description(&self) -> &str {
46 &self.description
47 }
48
49 pub fn set_description(&mut self, description: String) {
51 self.description = description;
52 }
53
54 pub fn date_created(&self) -> &UtcDateTime {
56 &self.date_created
57 }
58}
59
60#[async_trait]
69pub trait EncryptedEntry {
70 type Error: std::error::Error
72 + std::fmt::Debug
73 + From<crate::Error>
74 + From<sos_core::Error>
75 + Send
76 + Sync
77 + 'static;
78
79 async fn summary(&self) -> std::result::Result<Summary, Self::Error>;
81
82 async fn vault_name(
84 &self,
85 ) -> std::result::Result<Cow<'_, str>, Self::Error>;
86
87 async fn set_vault_name(
89 &mut self,
90 name: String,
91 ) -> std::result::Result<WriteEvent, Self::Error>;
92
93 async fn set_vault_flags(
95 &mut self,
96 flags: VaultFlags,
97 ) -> std::result::Result<WriteEvent, Self::Error>;
98
99 async fn set_vault_meta(
101 &mut self,
102 meta_data: AeadPack,
103 ) -> std::result::Result<WriteEvent, Self::Error>;
104
105 async fn create_secret(
107 &mut self,
108 commit: CommitHash,
109 secret: VaultEntry,
110 ) -> std::result::Result<WriteEvent, Self::Error>;
111
112 #[doc(hidden)]
117 async fn insert_secret(
118 &mut self,
119 id: SecretId,
120 commit: CommitHash,
121 secret: VaultEntry,
122 ) -> std::result::Result<WriteEvent, Self::Error>;
123
124 async fn read_secret<'a>(
126 &'a self,
127 id: &SecretId,
128 ) -> std::result::Result<
129 Option<(Cow<'a, VaultCommit>, ReadEvent)>,
130 Self::Error,
131 >;
132
133 async fn update_secret(
135 &mut self,
136 id: &SecretId,
137 commit: CommitHash,
138 secret: VaultEntry,
139 ) -> std::result::Result<Option<WriteEvent>, Self::Error>;
140
141 async fn delete_secret(
143 &mut self,
144 id: &SecretId,
145 ) -> std::result::Result<Option<WriteEvent>, Self::Error>;
146
147 async fn replace_vault(
149 &mut self,
150 vault: &Vault,
151 ) -> std::result::Result<(), Self::Error>;
152}
153
154#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
156#[serde(rename_all = "camelCase")]
157pub struct Auth {
158 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub(crate) salt: Option<String>,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
164 pub(crate) seed: Option<Seed>,
165}
166
167#[typeshare]
170#[derive(Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Clone)]
171#[serde(rename_all = "camelCase")]
172pub struct Summary {
173 pub(crate) version: u16,
175 pub(crate) id: VaultId,
177 pub(crate) name: String,
179 pub(crate) cipher: Cipher,
181 pub(crate) kdf: KeyDerivation,
183 pub(crate) flags: VaultFlags,
185}
186
187impl Ord for Summary {
188 fn cmp(&self, other: &Self) -> Ordering {
189 self.name.cmp(&other.name)
190 }
191}
192
193impl PartialOrd for Summary {
194 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
195 Some(self.cmp(other))
196 }
197}
198
199impl fmt::Display for Summary {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 write!(
202 f,
203 "Version {} using {} with {}\n{} {}",
204 self.version, self.cipher, self.kdf, self.name, self.id
205 )
206 }
207}
208
209impl Default for Summary {
210 fn default() -> Self {
211 Self {
212 version: VERSION,
213 cipher: Default::default(),
214 kdf: Default::default(),
215 id: Uuid::new_v4(),
216 name: DEFAULT_VAULT_NAME.to_string(),
217 flags: Default::default(),
218 }
219 }
220}
221
222impl Summary {
223 pub fn new(
225 version: u16,
226 id: VaultId,
227 name: String,
228 cipher: Cipher,
229 kdf: KeyDerivation,
230 flags: VaultFlags,
231 ) -> Self {
232 Self {
233 version,
234 cipher,
235 kdf,
236 id,
237 name,
238 flags,
239 }
240 }
241
242 pub fn version(&self) -> &u16 {
244 &self.version
245 }
246
247 pub fn cipher(&self) -> &Cipher {
249 &self.cipher
250 }
251
252 pub fn kdf(&self) -> &KeyDerivation {
254 &self.kdf
255 }
256
257 pub fn id(&self) -> &VaultId {
259 &self.id
260 }
261
262 pub fn name(&self) -> &str {
264 &self.name
265 }
266
267 pub fn set_name(&mut self, name: String) {
269 self.name = name;
270 }
271
272 pub fn flags(&self) -> &VaultFlags {
274 &self.flags
275 }
276
277 pub fn flags_mut(&mut self) -> &mut VaultFlags {
279 &mut self.flags
280 }
281}
282
283impl From<Summary> for VaultId {
284 fn from(value: Summary) -> Self {
285 value.id
286 }
287}
288
289impl From<Summary> for Header {
290 fn from(value: Summary) -> Self {
291 Header::new(
292 value.id,
293 value.name,
294 value.cipher,
295 value.kdf,
296 value.flags,
297 )
298 }
299}
300
301impl From<Summary> for Vault {
302 fn from(value: Summary) -> Self {
303 let mut vault: Vault = Default::default();
304 vault.header = value.into();
305 vault
306 }
307}
308
309#[derive(Serialize, Deserialize, Clone, Default, Debug, Eq, PartialEq)]
311#[serde(rename_all = "camelCase")]
312pub struct Header {
313 pub(crate) summary: Summary,
315 #[serde(default, skip_serializing_if = "Option::is_none")]
317 pub(crate) meta: Option<AeadPack>,
318 pub(crate) auth: Auth,
321 #[serde(default, skip_serializing_if = "SharedAccess::is_empty")]
323 pub(crate) shared_access: SharedAccess,
324}
325
326impl Header {
327 pub fn new(
329 id: VaultId,
330 name: String,
331 cipher: Cipher,
332 kdf: KeyDerivation,
333 flags: VaultFlags,
334 ) -> Self {
335 Self {
336 summary: Summary::new(VERSION, id, name, cipher, kdf, flags),
337 meta: None,
338 auth: Default::default(),
339 shared_access: Default::default(),
340 }
341 }
342
343 pub fn id(&self) -> &VaultId {
345 self.summary.id()
346 }
347
348 pub fn id_mut(&mut self) -> &mut VaultId {
350 &mut self.summary.id
351 }
352
353 pub fn flags(&self) -> &VaultFlags {
355 self.summary.flags()
356 }
357
358 pub fn flags_mut(&mut self) -> &mut VaultFlags {
360 self.summary.flags_mut()
361 }
362
363 pub(crate) fn clear_salt(&mut self) {
368 self.auth.salt = None;
369 }
370
371 pub fn name(&self) -> &str {
373 &self.summary.name
374 }
375
376 pub fn set_name(&mut self, name: String) {
378 self.summary.set_name(name);
379 }
380
381 pub fn set_salt(&mut self, salt: Option<String>) {
383 self.auth.salt = salt;
384 }
385
386 pub fn meta(&self) -> Option<&AeadPack> {
388 self.meta.as_ref()
389 }
390
391 pub fn set_meta(&mut self, meta: Option<AeadPack>) {
393 self.meta = meta;
394 }
395
396 pub fn set_seed(&mut self, seed: Option<Seed>) {
398 self.auth.seed = seed;
399 }
400
401 pub async fn read_content_offset<P: AsRef<Path>>(path: P) -> Result<u64> {
404 let mut stream = File::open(path.as_ref()).await?;
405 Header::read_content_offset_stream(&mut stream).await
406 }
407
408 pub async fn read_content_offset_slice(buffer: &[u8]) -> Result<u64> {
411 let mut stream = BufReader::new(Cursor::new(buffer));
412 Header::read_content_offset_stream(&mut stream).await
413 }
414
415 pub async fn read_content_offset_stream<
418 R: AsyncReadExt + AsyncSeek + Unpin + Send,
419 >(
420 stream: R,
421 ) -> Result<u64> {
422 let mut reader = BinaryReader::new(stream, encoding_options());
423 let identity = reader.read_bytes(VAULT_IDENTITY.len()).await?;
424 FileIdentity::read_slice(&identity, &VAULT_IDENTITY)?;
425 let header_len = reader.read_u32().await? as u64;
426 let content_offset = VAULT_IDENTITY.len() as u64 + 4 + header_len;
427 Ok(content_offset)
428 }
429
430 pub async fn read_summary_file<P: AsRef<Path>>(
432 file: P,
433 ) -> Result<Summary> {
434 let mut stream = File::open(file.as_ref()).await?;
435 Header::read_summary_stream(&mut stream).await
436 }
437
438 pub async fn read_summary_slice(buffer: &[u8]) -> Result<Summary> {
440 let mut stream = BufReader::new(Cursor::new(buffer));
441 Header::read_summary_stream(&mut stream).await
442 }
443
444 async fn read_summary_stream<
446 R: AsyncReadExt + AsyncSeek + Unpin + Send,
447 >(
448 stream: R,
449 ) -> Result<Summary> {
450 let mut reader = BinaryReader::new(stream, encoding_options());
451
452 FileIdentity::read_identity(&mut reader, &VAULT_IDENTITY).await?;
454
455 let _ = reader.read_u32().await?;
457
458 let mut summary: Summary = Default::default();
460 summary.decode(&mut reader).await?;
461
462 Ok(summary)
463 }
464
465 pub async fn read_header_file<P: AsRef<Path>>(file: P) -> Result<Header> {
467 let mut stream = File::open(file.as_ref()).await?;
468 Header::read_header_stream(&mut stream).await
469 }
470
471 pub(crate) async fn read_header_stream<
473 R: AsyncReadExt + AsyncSeek + Unpin + Send,
474 >(
475 stream: R,
476 ) -> Result<Header> {
477 let mut reader = BinaryReader::new(stream, encoding_options());
478 let mut header: Header = Default::default();
479 header.decode(&mut reader).await?;
480 Ok(header)
481 }
482}
483
484impl fmt::Display for Header {
485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 write!(f, "{}", self.summary)
487 }
488}
489
490#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
492pub enum SharedAccess {
493 #[serde(rename = "write")]
497 WriteAccess(Vec<String>),
498 #[serde(rename = "read")]
503 ReadOnly(AeadPack),
504}
505
506impl Default for SharedAccess {
507 fn default() -> Self {
508 Self::WriteAccess(vec![])
509 }
510}
511
512impl SharedAccess {
513 pub fn is_empty(&self) -> bool {
515 match self {
516 Self::WriteAccess(recipients) => recipients.is_empty(),
517 Self::ReadOnly(_) => false,
518 }
519 }
520
521 fn parse_recipients(access: &Vec<String>) -> Result<Vec<Recipient>> {
522 let mut recipients = Vec::new();
523 for recipient in access {
524 let recipient = recipient.parse().map_err(|s: &str| {
525 Error::InvalidX25519Identity(s.to_owned())
526 })?;
527 recipients.push(recipient);
528 }
529 Ok(recipients)
530 }
531}
532
533#[doc(hidden)]
535#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
536pub struct Contents {
537 #[serde(flatten)]
538 pub(crate) data: IndexMap<SecretId, VaultCommit>,
539}
540
541#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
543pub struct Vault {
544 pub(crate) header: Header,
545 pub(crate) contents: Contents,
546}
547
548impl Vault {
549 pub fn new(
551 id: VaultId,
552 name: String,
553 cipher: Cipher,
554 kdf: KeyDerivation,
555 flags: VaultFlags,
556 ) -> Self {
557 Self {
558 header: Header::new(id, name, cipher, kdf, flags),
559 contents: Default::default(),
560 }
561 }
562
563 pub fn shared_access(&self) -> &SharedAccess {
565 &self.header.shared_access
566 }
567
568 pub fn vault_urn(id: &VaultId) -> Result<Urn> {
570 let vault_urn = format!("urn:{}:{}{}", URN_NID, VAULT_NSS, id);
572 Ok(vault_urn.parse()?)
573 }
574
575 pub(crate) async fn symmetric(
578 &mut self,
579 password: SecretString,
580 seed: Option<Seed>,
581 ) -> Result<PrivateKey> {
582 if self.header.auth.salt.is_none() {
583 let salt = KeyDerivation::generate_salt();
584 let deriver = self.deriver();
585 let derived_private_key =
586 deriver.derive(&password, &salt, seed.as_ref())?;
587 let private_key = PrivateKey::Symmetric(derived_private_key);
588
589 self.header.auth.salt = Some(salt.to_string());
592 self.header.auth.seed = seed;
593
594 Ok(private_key)
595 } else {
596 Err(Error::VaultAlreadyInit)
597 }
598 }
599
600 pub(crate) async fn asymmetric(
602 &mut self,
603 owner: &Identity,
604 mut recipients: Vec<Recipient>,
605 read_only: bool,
606 ) -> Result<PrivateKey> {
607 if self.header.auth.salt.is_none() {
608 let owner_public = owner.to_public();
611 if !recipients
612 .iter()
613 .any(|r| r.to_string() == owner_public.to_string())
614 {
615 recipients.push(owner_public);
616 }
617
618 self.flags_mut().set(VaultFlags::SHARED, true);
619
620 let salt = KeyDerivation::generate_salt();
621 let private_key = PrivateKey::Asymmetric(owner.clone());
622 self.header.summary.cipher = Cipher::X25519;
623
624 let recipients: Vec<_> =
625 recipients.into_iter().map(|r| r.to_string()).collect();
626
627 self.header.shared_access = if read_only {
628 let access = SharedAccess::WriteAccess(recipients);
629 let buffer = encode(&access).await?;
630 let private_key = PrivateKey::Asymmetric(owner.clone());
631 let cipher = self.header.summary.cipher.clone();
632 let owner_recipients = vec![owner.to_public()];
633 let aead = cipher
634 .encrypt_asymmetric(
635 &private_key,
636 &buffer,
637 owner_recipients,
638 )
639 .await?;
640 SharedAccess::ReadOnly(aead)
641 } else {
642 SharedAccess::WriteAccess(recipients)
643 };
644
645 self.header.auth.salt = Some(salt.to_string());
649
650 Ok(private_key)
651 } else {
652 Err(Error::VaultAlreadyInit)
653 }
654 }
655
656 pub fn deriver(&self) -> Box<dyn Deriver<Sha256> + Send + 'static> {
658 self.header.summary.kdf.deriver()
659 }
660
661 pub fn set_default_flag(&mut self, value: bool) {
663 self.flags_mut().set(VaultFlags::DEFAULT, value);
664 }
665
666 pub fn set_archive_flag(&mut self, value: bool) {
668 self.flags_mut().set(VaultFlags::ARCHIVE, value);
669 }
670
671 pub fn set_authenticator_flag(&mut self, value: bool) {
673 self.flags_mut().set(VaultFlags::AUTHENTICATOR, value);
674 }
675
676 pub fn set_contact_flag(&mut self, value: bool) {
678 self.flags_mut().set(VaultFlags::CONTACT, value);
679 }
680
681 pub fn set_system_flag(&mut self, value: bool) {
683 self.flags_mut().set(VaultFlags::SYSTEM, value);
684 }
685
686 pub fn set_device_flag(&mut self, value: bool) {
688 self.flags_mut().set(VaultFlags::DEVICE, value);
689 }
690
691 pub fn set_no_sync_flag(&mut self, value: bool) {
693 self.flags_mut().set(VaultFlags::NO_SYNC, value);
694 }
695
696 pub fn insert_entry(&mut self, id: SecretId, entry: VaultCommit) {
698 self.contents.data.insert(id, entry);
699 }
700
701 pub fn get(&self, id: &SecretId) -> Option<&VaultCommit> {
703 self.contents.data.get(id)
704 }
705
706 pub async fn encrypt(
708 &self,
709 key: &PrivateKey,
710 plaintext: &[u8],
711 ) -> Result<AeadPack> {
712 match self.cipher() {
713 Cipher::XChaCha20Poly1305 | Cipher::AesGcm256 => Ok(self
714 .cipher()
715 .encrypt_symmetric(key, plaintext, None)
716 .await?),
717 Cipher::X25519 => {
718 let recipients = match &self.header.shared_access {
719 SharedAccess::WriteAccess(access) => {
720 SharedAccess::parse_recipients(access)?
721 }
722 SharedAccess::ReadOnly(aead) => {
723 let buffer = self
724 .decrypt(key, aead)
725 .await
726 .map_err(|_| Error::PermissionDenied)?;
727 let shared_access: SharedAccess =
728 decode(&buffer).await?;
729 if let SharedAccess::WriteAccess(access) =
730 &shared_access
731 {
732 SharedAccess::parse_recipients(access)?
733 } else {
734 return Err(Error::PermissionDenied);
735 }
736 }
737 };
738
739 Ok(self
740 .cipher()
741 .encrypt_asymmetric(key, plaintext, recipients)
742 .await?)
743 }
744 }
745 }
746
747 pub async fn decrypt(
749 &self,
750 key: &PrivateKey,
751 aead: &AeadPack,
752 ) -> Result<Vec<u8>> {
753 match self.cipher() {
754 Cipher::XChaCha20Poly1305 | Cipher::AesGcm256 => {
755 Ok(self.cipher().decrypt_symmetric(key, aead).await?)
756 }
757 Cipher::X25519 => {
758 Ok(self.cipher().decrypt_asymmetric(key, aead).await?)
759 }
760 }
761 }
762
763 pub fn rotate_identifier(&mut self) {
770 self.header.summary.id = Uuid::new_v4();
771 }
772
773 pub async fn verify(&self, key: &AccessKey) -> Result<()> {
775 let salt = self.salt().ok_or(Error::VaultNotInit)?;
776 let meta_aead = self.header().meta().ok_or(Error::VaultNotInit)?;
777 let private_key = match key {
778 AccessKey::Password(password) => {
779 let salt = KeyDerivation::parse_salt(salt)?;
780 let deriver = self.deriver();
781 PrivateKey::Symmetric(deriver.derive(
782 password,
783 &salt,
784 self.seed(),
785 )?)
786 }
787 AccessKey::Identity(id) => PrivateKey::Asymmetric(id.clone()),
788 };
789
790 let _ = self
791 .decrypt(&private_key, meta_aead)
792 .await
793 .map_err(|_| AuthenticationError::PasswordVerification)?;
794
795 Ok(())
796 }
797
798 pub fn iter(&self) -> impl Iterator<Item = (&Uuid, &VaultCommit)> {
800 self.contents.data.iter()
801 }
802
803 pub fn keys(&self) -> impl Iterator<Item = &Uuid> {
805 self.contents.data.keys()
806 }
807
808 pub fn values(&self) -> impl Iterator<Item = &VaultCommit> {
810 self.contents.data.values()
811 }
812
813 pub fn len(&self) -> usize {
815 self.contents.data.len()
816 }
817
818 pub fn is_empty(&self) -> bool {
820 self.len() == 0
821 }
822
823 pub async fn into_event(&self) -> Result<WriteEvent> {
827 let buffer = if self.is_empty() {
828 encode(self).await?
829 } else {
830 let header = self.header.clone();
831 let vault: Vault = header.into();
832 encode(&vault).await?
833 };
834 Ok(WriteEvent::CreateVault(buffer))
835 }
836
837 pub fn commits(&self) -> impl Iterator<Item = (&Uuid, &CommitHash)> {
839 self.contents
840 .data
841 .keys()
842 .zip(self.contents.data.values().map(|v| &v.0))
843 }
844
845 pub fn salt(&self) -> Option<&String> {
847 self.header.auth.salt.as_ref()
848 }
849
850 pub fn seed(&self) -> Option<&Seed> {
852 self.header.auth.seed.as_ref()
853 }
854
855 pub fn summary(&self) -> &Summary {
857 &self.header.summary
858 }
859
860 pub fn flags(&self) -> &VaultFlags {
862 self.header.flags()
863 }
864
865 pub fn flags_mut(&mut self) -> &mut VaultFlags {
867 self.header.flags_mut()
868 }
869
870 pub fn id(&self) -> &VaultId {
872 &self.header.summary.id
873 }
874
875 pub fn name(&self) -> &str {
877 self.header.name()
878 }
879
880 pub fn set_name(&mut self, name: String) {
882 self.header.set_name(name);
883 }
884
885 pub fn cipher(&self) -> &Cipher {
887 &self.header.summary.cipher
888 }
889
890 pub fn kdf(&self) -> &KeyDerivation {
892 &self.header.summary.kdf
893 }
894
895 pub fn header(&self) -> &Header {
897 &self.header
898 }
899
900 pub fn header_mut(&mut self) -> &mut Header {
902 &mut self.header
903 }
904
905 pub fn data(&self) -> &IndexMap<SecretId, VaultCommit> {
907 &self.contents.data
908 }
909
910 pub fn data_mut(&mut self) -> &mut IndexMap<SecretId, VaultCommit> {
912 &mut self.contents.data
913 }
914
915 pub fn meta_data(&self) -> HashMap<&Uuid, &AeadPack> {
917 self.contents
918 .data
919 .iter()
920 .map(|(k, v)| (k, &v.1 .0))
921 .collect::<HashMap<_, _>>()
922 }
923
924 #[doc(hidden)]
927 pub async fn commit_hash(
928 meta_aead: &AeadPack,
929 secret_aead: &AeadPack,
930 ) -> Result<CommitHash> {
931 let encoded_meta = encode(meta_aead).await?;
933 let encoded_data = encode(secret_aead).await?;
934
935 let mut hasher = Sha256::new();
936 hasher.update(&encoded_meta);
937 hasher.update(&encoded_data);
938 let digest = hasher.finalize();
939 Ok(CommitHash(digest.as_slice().try_into()?))
940 }
941}
942
943impl From<Header> for Vault {
944 fn from(header: Header) -> Self {
945 Vault {
946 header,
947 contents: Default::default(),
948 }
949 }
950}
951
952impl From<Vault> for Header {
953 fn from(value: Vault) -> Self {
954 value.header
955 }
956}
957
958impl IntoIterator for Vault {
959 type Item = (SecretId, VaultCommit);
960 type IntoIter = indexmap::map::IntoIter<SecretId, VaultCommit>;
961
962 fn into_iter(self) -> Self::IntoIter {
963 self.contents.data.into_iter()
964 }
965}
966
967#[async_trait]
968impl EncryptedEntry for Vault {
969 type Error = Error;
970
971 async fn summary(&self) -> Result<Summary> {
972 Ok(self.header.summary.clone())
973 }
974
975 async fn vault_name(&self) -> Result<Cow<'_, str>> {
976 Ok(Cow::Borrowed(self.name()))
977 }
978
979 async fn set_vault_name(&mut self, name: String) -> Result<WriteEvent> {
980 self.set_name(name.clone());
981 Ok(WriteEvent::SetVaultName(name))
982 }
983
984 async fn set_vault_flags(
985 &mut self,
986 flags: VaultFlags,
987 ) -> Result<WriteEvent> {
988 *self.header.flags_mut() = flags.clone();
989 Ok(WriteEvent::SetVaultFlags(flags))
990 }
991
992 async fn set_vault_meta(
993 &mut self,
994 meta_data: AeadPack,
995 ) -> Result<WriteEvent> {
996 self.header.set_meta(Some(meta_data.clone()));
997 Ok(WriteEvent::SetVaultMeta(meta_data))
998 }
999
1000 async fn create_secret(
1001 &mut self,
1002 commit: CommitHash,
1003 secret: VaultEntry,
1004 ) -> Result<WriteEvent> {
1005 let id = Uuid::new_v4();
1006 self.insert_secret(id, commit, secret).await
1007 }
1008
1009 async fn insert_secret(
1010 &mut self,
1011 id: SecretId,
1012 commit: CommitHash,
1013 secret: VaultEntry,
1014 ) -> Result<WriteEvent> {
1015 let value = self
1016 .contents
1017 .data
1018 .entry(id)
1019 .or_insert(VaultCommit(commit, secret));
1020 Ok(WriteEvent::CreateSecret(id, value.clone()))
1021 }
1022
1023 async fn read_secret<'a>(
1024 &'a self,
1025 id: &SecretId,
1026 ) -> Result<Option<(Cow<'a, VaultCommit>, ReadEvent)>> {
1027 let result = self
1028 .contents
1029 .data
1030 .get(id)
1031 .map(|c| (Cow::Borrowed(c), ReadEvent::ReadSecret(*id)));
1032 Ok(result)
1033 }
1034
1035 async fn update_secret(
1036 &mut self,
1037 id: &SecretId,
1038 commit: CommitHash,
1039 secret: VaultEntry,
1040 ) -> Result<Option<WriteEvent>> {
1041 let _vault_id = *self.id();
1042 if let Some(value) = self.contents.data.get_mut(id) {
1043 *value = VaultCommit(commit, secret);
1044 Ok(Some(WriteEvent::UpdateSecret(*id, value.clone())))
1045 } else {
1046 Ok(None)
1047 }
1048 }
1049
1050 async fn delete_secret(
1051 &mut self,
1052 id: &SecretId,
1053 ) -> Result<Option<WriteEvent>> {
1054 let entry = self.contents.data.shift_remove(id);
1055 Ok(entry.map(|_| WriteEvent::DeleteSecret(*id)))
1056 }
1057
1058 async fn replace_vault(&mut self, vault: &Vault) -> Result<()> {
1059 *self = vault.clone();
1060 Ok(())
1061 }
1062}