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 Vault {
304 header: value.into(),
305 ..Default::default()
306 }
307 }
308}
309
310#[derive(Serialize, Deserialize, Clone, Default, Debug, Eq, PartialEq)]
312#[serde(rename_all = "camelCase")]
313pub struct Header {
314 pub(crate) summary: Summary,
316 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub(crate) meta: Option<AeadPack>,
319 pub(crate) auth: Auth,
322 #[serde(default, skip_serializing_if = "SharedAccess::is_empty")]
324 pub(crate) shared_access: SharedAccess,
325}
326
327impl Header {
328 pub fn new(
330 id: VaultId,
331 name: String,
332 cipher: Cipher,
333 kdf: KeyDerivation,
334 flags: VaultFlags,
335 ) -> Self {
336 Self {
337 summary: Summary::new(VERSION, id, name, cipher, kdf, flags),
338 meta: None,
339 auth: Default::default(),
340 shared_access: Default::default(),
341 }
342 }
343
344 pub fn id(&self) -> &VaultId {
346 self.summary.id()
347 }
348
349 pub fn id_mut(&mut self) -> &mut VaultId {
351 &mut self.summary.id
352 }
353
354 pub fn flags(&self) -> &VaultFlags {
356 self.summary.flags()
357 }
358
359 pub fn flags_mut(&mut self) -> &mut VaultFlags {
361 self.summary.flags_mut()
362 }
363
364 pub(crate) fn clear_salt(&mut self) {
369 self.auth.salt = None;
370 }
371
372 pub fn name(&self) -> &str {
374 &self.summary.name
375 }
376
377 pub fn set_name(&mut self, name: String) {
379 self.summary.set_name(name);
380 }
381
382 pub fn set_salt(&mut self, salt: Option<String>) {
384 self.auth.salt = salt;
385 }
386
387 pub fn meta(&self) -> Option<&AeadPack> {
389 self.meta.as_ref()
390 }
391
392 pub fn set_meta(&mut self, meta: Option<AeadPack>) {
394 self.meta = meta;
395 }
396
397 pub fn set_seed(&mut self, seed: Option<Seed>) {
399 self.auth.seed = seed;
400 }
401
402 pub fn set_shared_access(&mut self, shared_access: SharedAccess) {
404 self.shared_access = shared_access;
405 }
406
407 pub async fn read_content_offset<P: AsRef<Path>>(path: P) -> Result<u64> {
410 let mut stream = File::open(path.as_ref()).await?;
411 Header::read_content_offset_stream(&mut stream).await
412 }
413
414 pub async fn read_content_offset_slice(buffer: &[u8]) -> Result<u64> {
417 let mut stream = BufReader::new(Cursor::new(buffer));
418 Header::read_content_offset_stream(&mut stream).await
419 }
420
421 pub async fn read_content_offset_stream<
424 R: AsyncReadExt + AsyncSeek + Unpin + Send,
425 >(
426 stream: R,
427 ) -> Result<u64> {
428 let mut reader = BinaryReader::new(stream, encoding_options());
429 let identity = reader.read_bytes(VAULT_IDENTITY.len()).await?;
430 FileIdentity::read_slice(&identity, &VAULT_IDENTITY)?;
431 let header_len = reader.read_u32().await? as u64;
432 let content_offset = VAULT_IDENTITY.len() as u64 + 4 + header_len;
433 Ok(content_offset)
434 }
435
436 pub async fn read_summary_file<P: AsRef<Path>>(
438 file: P,
439 ) -> Result<Summary> {
440 let mut stream = File::open(file.as_ref()).await?;
441 Header::read_summary_stream(&mut stream).await
442 }
443
444 pub async fn read_summary_slice(buffer: &[u8]) -> Result<Summary> {
446 let mut stream = BufReader::new(Cursor::new(buffer));
447 Header::read_summary_stream(&mut stream).await
448 }
449
450 async fn read_summary_stream<
452 R: AsyncReadExt + AsyncSeek + Unpin + Send,
453 >(
454 stream: R,
455 ) -> Result<Summary> {
456 let mut reader = BinaryReader::new(stream, encoding_options());
457
458 FileIdentity::read_identity(&mut reader, &VAULT_IDENTITY).await?;
460
461 let _ = reader.read_u32().await?;
463
464 let mut summary: Summary = Default::default();
466 summary.decode(&mut reader).await?;
467
468 Ok(summary)
469 }
470
471 pub async fn read_header_file<P: AsRef<Path>>(file: P) -> Result<Header> {
473 let mut stream = File::open(file.as_ref()).await?;
474 Header::read_header_stream(&mut stream).await
475 }
476
477 pub(crate) async fn read_header_stream<
479 R: AsyncReadExt + AsyncSeek + Unpin + Send,
480 >(
481 stream: R,
482 ) -> Result<Header> {
483 let mut reader = BinaryReader::new(stream, encoding_options());
484 let mut header: Header = Default::default();
485 header.decode(&mut reader).await?;
486 Ok(header)
487 }
488}
489
490impl fmt::Display for Header {
491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492 write!(f, "{}", self.summary)
493 }
494}
495
496#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
498pub enum SharedAccess {
499 #[serde(rename = "write")]
503 WriteAccess(Vec<String>),
504 #[serde(rename = "read")]
509 ReadOnly(AeadPack),
510}
511
512impl Default for SharedAccess {
513 fn default() -> Self {
514 Self::WriteAccess(vec![])
515 }
516}
517
518impl SharedAccess {
519 pub fn is_empty(&self) -> bool {
521 match self {
522 Self::WriteAccess(recipients) => recipients.is_empty(),
523 Self::ReadOnly(_) => false,
524 }
525 }
526
527 pub fn parse_recipients(access: &Vec<String>) -> Result<Vec<Recipient>> {
529 let mut recipients = Vec::new();
530 for recipient in access {
531 let recipient = recipient.parse().map_err(|s: &str| {
532 Error::InvalidX25519Identity(s.to_owned())
533 })?;
534 recipients.push(recipient);
535 }
536 Ok(recipients)
537 }
538}
539
540#[doc(hidden)]
542#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
543pub struct Contents {
544 #[serde(flatten)]
545 pub(crate) data: IndexMap<SecretId, VaultCommit>,
546}
547
548#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq)]
550pub struct Vault {
551 pub(crate) header: Header,
552 pub(crate) contents: Contents,
553}
554
555impl Vault {
556 pub fn new(
558 id: VaultId,
559 name: String,
560 cipher: Cipher,
561 kdf: KeyDerivation,
562 flags: VaultFlags,
563 ) -> Self {
564 Self {
565 header: Header::new(id, name, cipher, kdf, flags),
566 contents: Default::default(),
567 }
568 }
569
570 pub fn shared_access(&self) -> &SharedAccess {
572 &self.header.shared_access
573 }
574
575 pub fn vault_urn(id: &VaultId) -> Result<Urn> {
577 let vault_urn = format!("urn:{}:{}{}", URN_NID, VAULT_NSS, id);
579 Ok(vault_urn.parse()?)
580 }
581
582 pub(crate) async fn symmetric(
585 &mut self,
586 password: SecretString,
587 seed: Option<Seed>,
588 ) -> Result<PrivateKey> {
589 if self.header.auth.salt.is_none() {
590 let salt = KeyDerivation::generate_salt();
591 let deriver = self.deriver();
592 let derived_private_key =
593 deriver.derive(&password, &salt, seed.as_ref())?;
594 let private_key = PrivateKey::Symmetric(derived_private_key);
595
596 self.header.auth.salt = Some(salt.to_string());
599 self.header.auth.seed = seed;
600
601 Ok(private_key)
602 } else {
603 Err(Error::VaultAlreadyInit)
604 }
605 }
606
607 pub(crate) async fn asymmetric(
609 &mut self,
610 owner: &Identity,
611 mut recipients: Vec<Recipient>,
612 read_only: bool,
613 ) -> Result<PrivateKey> {
614 if self.header.auth.salt.is_none() {
615 let owner_public = owner.to_public();
618 if !recipients
619 .iter()
620 .any(|r| r.to_string() == owner_public.to_string())
621 {
622 recipients.push(owner_public);
623 }
624
625 self.flags_mut().set(VaultFlags::SHARED, true);
626
627 let salt = KeyDerivation::generate_salt();
628 let private_key = PrivateKey::Asymmetric(owner.clone());
629 self.header.summary.cipher = Cipher::X25519;
630
631 let recipients: Vec<_> =
632 recipients.into_iter().map(|r| r.to_string()).collect();
633
634 self.header.shared_access = if read_only {
635 let access = SharedAccess::WriteAccess(recipients);
636 let buffer = encode(&access).await?;
637 let private_key = PrivateKey::Asymmetric(owner.clone());
638 let cipher = self.header.summary.cipher;
639 let owner_recipients = vec![owner.to_public()];
640 let aead = cipher
641 .encrypt_asymmetric(
642 &private_key,
643 &buffer,
644 owner_recipients,
645 )
646 .await?;
647 SharedAccess::ReadOnly(aead)
648 } else {
649 SharedAccess::WriteAccess(recipients)
650 };
651
652 self.header.auth.salt = Some(salt.to_string());
656
657 Ok(private_key)
658 } else {
659 Err(Error::VaultAlreadyInit)
660 }
661 }
662
663 pub fn deriver(&self) -> Box<dyn Deriver<Sha256> + Send + 'static> {
665 self.header.summary.kdf.deriver()
666 }
667
668 pub fn set_default_flag(&mut self, value: bool) {
670 self.flags_mut().set(VaultFlags::DEFAULT, value);
671 }
672
673 pub fn set_archive_flag(&mut self, value: bool) {
675 self.flags_mut().set(VaultFlags::ARCHIVE, value);
676 }
677
678 pub fn set_authenticator_flag(&mut self, value: bool) {
680 self.flags_mut().set(VaultFlags::AUTHENTICATOR, value);
681 }
682
683 pub fn set_contact_flag(&mut self, value: bool) {
685 self.flags_mut().set(VaultFlags::CONTACT, value);
686 }
687
688 pub fn set_system_flag(&mut self, value: bool) {
690 self.flags_mut().set(VaultFlags::SYSTEM, value);
691 }
692
693 pub fn set_device_flag(&mut self, value: bool) {
695 self.flags_mut().set(VaultFlags::DEVICE, value);
696 }
697
698 pub fn set_no_sync_flag(&mut self, value: bool) {
700 self.flags_mut().set(VaultFlags::NO_SYNC, value);
701 }
702
703 pub fn insert_entry(&mut self, id: SecretId, entry: VaultCommit) {
705 self.contents.data.insert(id, entry);
706 }
707
708 pub fn get(&self, id: &SecretId) -> Option<&VaultCommit> {
710 self.contents.data.get(id)
711 }
712
713 pub async fn encrypt(
715 &self,
716 key: &PrivateKey,
717 plaintext: &[u8],
718 ) -> Result<AeadPack> {
719 match self.cipher() {
720 Cipher::XChaCha20Poly1305 | Cipher::AesGcm256 => Ok(self
721 .cipher()
722 .encrypt_symmetric(key, plaintext, None)
723 .await?),
724 Cipher::X25519 => {
725 let recipients = match &self.header.shared_access {
726 SharedAccess::WriteAccess(access) => {
727 SharedAccess::parse_recipients(access)?
728 }
729 SharedAccess::ReadOnly(aead) => {
730 let buffer = self
731 .decrypt(key, aead)
732 .await
733 .map_err(|_| Error::PermissionDenied)?;
734 let shared_access: SharedAccess =
735 decode(&buffer).await?;
736 if let SharedAccess::WriteAccess(access) =
737 &shared_access
738 {
739 SharedAccess::parse_recipients(access)?
740 } else {
741 return Err(Error::PermissionDenied);
742 }
743 }
744 };
745
746 Ok(self
747 .cipher()
748 .encrypt_asymmetric(key, plaintext, recipients)
749 .await?)
750 }
751 }
752 }
753
754 pub async fn decrypt(
756 &self,
757 key: &PrivateKey,
758 aead: &AeadPack,
759 ) -> Result<Vec<u8>> {
760 match self.cipher() {
761 Cipher::XChaCha20Poly1305 | Cipher::AesGcm256 => {
762 Ok(self.cipher().decrypt_symmetric(key, aead).await?)
763 }
764 Cipher::X25519 => {
765 Ok(self.cipher().decrypt_asymmetric(key, aead).await?)
766 }
767 }
768 }
769
770 pub fn rotate_identifier(&mut self) {
777 self.header.summary.id = Uuid::new_v4();
778 }
779
780 pub async fn verify(&self, key: &AccessKey) -> Result<()> {
782 let salt = self.salt().ok_or(Error::VaultNotInit)?;
783 let meta_aead = self.header().meta().ok_or(Error::VaultNotInit)?;
784 let private_key = match key {
785 AccessKey::Password(password) => {
786 let salt = KeyDerivation::parse_salt(salt)?;
787 let deriver = self.deriver();
788 PrivateKey::Symmetric(deriver.derive(
789 password,
790 &salt,
791 self.seed(),
792 )?)
793 }
794 AccessKey::Identity(id) => PrivateKey::Asymmetric(id.clone()),
795 };
796
797 let _ = self
798 .decrypt(&private_key, meta_aead)
799 .await
800 .map_err(|_| AuthenticationError::PasswordVerification)?;
801
802 Ok(())
803 }
804
805 pub fn iter(&self) -> impl Iterator<Item = (&Uuid, &VaultCommit)> {
807 self.contents.data.iter()
808 }
809
810 pub fn keys(&self) -> impl Iterator<Item = &Uuid> {
812 self.contents.data.keys()
813 }
814
815 pub fn values(&self) -> impl Iterator<Item = &VaultCommit> {
817 self.contents.data.values()
818 }
819
820 pub fn len(&self) -> usize {
822 self.contents.data.len()
823 }
824
825 pub fn is_empty(&self) -> bool {
827 self.len() == 0
828 }
829
830 pub async fn into_event(&self) -> Result<WriteEvent> {
834 let buffer = if self.is_empty() {
835 encode(self).await?
836 } else {
837 let header = self.header.clone();
838 let vault: Vault = header.into();
839 encode(&vault).await?
840 };
841 Ok(WriteEvent::CreateVault(buffer))
842 }
843
844 pub fn commits(&self) -> impl Iterator<Item = (&Uuid, &CommitHash)> {
846 self.contents
847 .data
848 .keys()
849 .zip(self.contents.data.values().map(|v| &v.0))
850 }
851
852 pub fn salt(&self) -> Option<&String> {
854 self.header.auth.salt.as_ref()
855 }
856
857 pub fn seed(&self) -> Option<&Seed> {
859 self.header.auth.seed.as_ref()
860 }
861
862 pub fn summary(&self) -> &Summary {
864 &self.header.summary
865 }
866
867 pub fn flags(&self) -> &VaultFlags {
869 self.header.flags()
870 }
871
872 pub fn flags_mut(&mut self) -> &mut VaultFlags {
874 self.header.flags_mut()
875 }
876
877 pub fn id(&self) -> &VaultId {
879 &self.header.summary.id
880 }
881
882 pub fn name(&self) -> &str {
884 self.header.name()
885 }
886
887 pub fn set_name(&mut self, name: String) {
889 self.header.set_name(name);
890 }
891
892 pub fn cipher(&self) -> &Cipher {
894 &self.header.summary.cipher
895 }
896
897 pub fn kdf(&self) -> &KeyDerivation {
899 &self.header.summary.kdf
900 }
901
902 pub fn header(&self) -> &Header {
904 &self.header
905 }
906
907 pub fn header_mut(&mut self) -> &mut Header {
909 &mut self.header
910 }
911
912 pub fn data(&self) -> &IndexMap<SecretId, VaultCommit> {
914 &self.contents.data
915 }
916
917 pub fn data_mut(&mut self) -> &mut IndexMap<SecretId, VaultCommit> {
919 &mut self.contents.data
920 }
921
922 pub fn meta_data(&self) -> HashMap<&Uuid, &AeadPack> {
924 self.contents
925 .data
926 .iter()
927 .map(|(k, v)| (k, &v.1 .0))
928 .collect::<HashMap<_, _>>()
929 }
930
931 #[doc(hidden)]
934 pub async fn commit_hash(
935 meta_aead: &AeadPack,
936 secret_aead: &AeadPack,
937 ) -> Result<CommitHash> {
938 let encoded_meta = encode(meta_aead).await?;
940 let encoded_data = encode(secret_aead).await?;
941
942 let mut hasher = Sha256::new();
943 hasher.update(&encoded_meta);
944 hasher.update(&encoded_data);
945 let digest = hasher.finalize();
946 Ok(CommitHash(digest.as_slice().try_into()?))
947 }
948}
949
950impl From<Header> for Vault {
951 fn from(header: Header) -> Self {
952 Vault {
953 header,
954 contents: Default::default(),
955 }
956 }
957}
958
959impl From<Vault> for Header {
960 fn from(value: Vault) -> Self {
961 value.header
962 }
963}
964
965impl IntoIterator for Vault {
966 type Item = (SecretId, VaultCommit);
967 type IntoIter = indexmap::map::IntoIter<SecretId, VaultCommit>;
968
969 fn into_iter(self) -> Self::IntoIter {
970 self.contents.data.into_iter()
971 }
972}
973
974#[async_trait]
975impl EncryptedEntry for Vault {
976 type Error = Error;
977
978 async fn summary(&self) -> Result<Summary> {
979 Ok(self.header.summary.clone())
980 }
981
982 async fn vault_name(&self) -> Result<Cow<'_, str>> {
983 Ok(Cow::Borrowed(self.name()))
984 }
985
986 async fn set_vault_name(&mut self, name: String) -> Result<WriteEvent> {
987 self.set_name(name.clone());
988 Ok(WriteEvent::SetVaultName(name))
989 }
990
991 async fn set_vault_flags(
992 &mut self,
993 flags: VaultFlags,
994 ) -> Result<WriteEvent> {
995 *self.header.flags_mut() = flags.clone();
996 Ok(WriteEvent::SetVaultFlags(flags))
997 }
998
999 async fn set_vault_meta(
1000 &mut self,
1001 meta_data: AeadPack,
1002 ) -> Result<WriteEvent> {
1003 self.header.set_meta(Some(meta_data.clone()));
1004 Ok(WriteEvent::SetVaultMeta(meta_data))
1005 }
1006
1007 async fn create_secret(
1008 &mut self,
1009 commit: CommitHash,
1010 secret: VaultEntry,
1011 ) -> Result<WriteEvent> {
1012 let id = Uuid::new_v4();
1013 self.insert_secret(id, commit, secret).await
1014 }
1015
1016 async fn insert_secret(
1017 &mut self,
1018 id: SecretId,
1019 commit: CommitHash,
1020 secret: VaultEntry,
1021 ) -> Result<WriteEvent> {
1022 let value = self
1023 .contents
1024 .data
1025 .entry(id)
1026 .or_insert(VaultCommit(commit, secret));
1027 Ok(WriteEvent::CreateSecret(id, value.clone()))
1028 }
1029
1030 async fn read_secret<'a>(
1031 &'a self,
1032 id: &SecretId,
1033 ) -> Result<Option<(Cow<'a, VaultCommit>, ReadEvent)>> {
1034 let result = self
1035 .contents
1036 .data
1037 .get(id)
1038 .map(|c| (Cow::Borrowed(c), ReadEvent::ReadSecret(*id)));
1039 Ok(result)
1040 }
1041
1042 async fn update_secret(
1043 &mut self,
1044 id: &SecretId,
1045 commit: CommitHash,
1046 secret: VaultEntry,
1047 ) -> Result<Option<WriteEvent>> {
1048 let _vault_id = *self.id();
1049 if let Some(value) = self.contents.data.get_mut(id) {
1050 *value = VaultCommit(commit, secret);
1051 Ok(Some(WriteEvent::UpdateSecret(*id, value.clone())))
1052 } else {
1053 Ok(None)
1054 }
1055 }
1056
1057 async fn delete_secret(
1058 &mut self,
1059 id: &SecretId,
1060 ) -> Result<Option<WriteEvent>> {
1061 let entry = self.contents.data.shift_remove(id);
1062 Ok(entry.map(|_| WriteEvent::DeleteSecret(*id)))
1063 }
1064
1065 async fn replace_vault(&mut self, vault: &Vault) -> Result<()> {
1066 *self = vault.clone();
1067 Ok(())
1068 }
1069}