sos_core/
file.rs

1use crate::{Error, Result, SecretId, SecretPath, VaultId};
2use serde::{Deserialize, Serialize};
3use std::{fmt, str::FromStr};
4
5/// External file name is an SHA2-256 checksum of
6/// the encrypted file contents.
7#[derive(
8    Default, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize,
9)]
10pub struct ExternalFileName(#[serde(with = "hex::serde")] [u8; 32]);
11
12impl fmt::Debug for ExternalFileName {
13    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14        f.debug_tuple("ExternalFileName")
15            .field(&hex::encode(self.0))
16            .finish()
17    }
18}
19
20impl From<ExternalFileName> for [u8; 32] {
21    fn from(value: ExternalFileName) -> Self {
22        value.0
23    }
24}
25
26impl AsRef<[u8]> for ExternalFileName {
27    fn as_ref(&self) -> &[u8] {
28        &self.0
29    }
30}
31
32impl From<[u8; 32]> for ExternalFileName {
33    fn from(value: [u8; 32]) -> Self {
34        Self(value)
35    }
36}
37
38impl TryFrom<&[u8]> for ExternalFileName {
39    type Error = Error;
40
41    fn try_from(value: &[u8]) -> Result<Self> {
42        let value: [u8; 32] = value.try_into()?;
43        Ok(value.into())
44    }
45}
46
47impl fmt::Display for ExternalFileName {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        write!(f, "{}", hex::encode(self.0))
50    }
51}
52
53impl FromStr for ExternalFileName {
54    type Err = Error;
55
56    fn from_str(s: &str) -> Result<Self> {
57        let buf: [u8; 32] = hex::decode(s)?.as_slice().try_into()?;
58        Ok(Self(buf))
59    }
60}
61
62/// Pointer to an external file.
63#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
64pub struct ExternalFile(SecretPath, ExternalFileName);
65
66impl From<ExternalFile> for (SecretPath, ExternalFileName) {
67    fn from(value: ExternalFile) -> Self {
68        (value.0, value.1)
69    }
70}
71
72impl ExternalFile {
73    /// Create a new external file reference.
74    pub fn new(path: SecretPath, file_name: ExternalFileName) -> Self {
75        Self(path, file_name)
76    }
77
78    /// Vault identifier.
79    pub fn vault_id(&self) -> &VaultId {
80        &self.0 .0
81    }
82
83    /// Secret identifier.
84    pub fn secret_id(&self) -> &SecretId {
85        &self.0 .1
86    }
87
88    /// File name.
89    pub fn file_name(&self) -> &ExternalFileName {
90        &self.1
91    }
92}
93
94impl fmt::Display for ExternalFile {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        write!(
97            f,
98            "{}/{}/{}",
99            self.vault_id(),
100            self.secret_id(),
101            self.file_name()
102        )
103    }
104}
105
106impl FromStr for ExternalFile {
107    type Err = Error;
108
109    fn from_str(s: &str) -> Result<Self> {
110        let mut parts = s.splitn(3, '/');
111        let vault_id = parts
112            .next()
113            .ok_or(Error::InvalidExternalFile(s.to_owned()))?;
114        let secret_id = parts
115            .next()
116            .ok_or(Error::InvalidExternalFile(s.to_owned()))?;
117        let file_name = parts
118            .next()
119            .ok_or(Error::InvalidExternalFile(s.to_owned()))?;
120        let vault_id: VaultId = vault_id.parse()?;
121        let secret_id: SecretId = secret_id.parse()?;
122        let file_name: ExternalFileName = file_name.parse()?;
123        Ok(Self(SecretPath(vault_id, secret_id), file_name))
124    }
125}