sos_core/
file.rs

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