1#![deny(missing_docs)]
2#![forbid(unsafe_code)]
3#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
4mod account;
7pub mod commit;
8pub mod constants;
9pub mod crypto;
10mod date_time;
11pub mod device;
12pub mod encoding;
13mod error;
14pub mod events;
15mod file;
16pub mod file_identity;
17mod identity;
18mod origin;
19mod paths;
20
21pub use account::AccountId;
22pub use date_time::UtcDateTime;
24pub use encoding::{decode, encode};
26pub use error::{AuthenticationError, Error, ErrorExt, StorageError};
27pub use file::{ExternalFile, ExternalFileName};
28pub use identity::{AccountRef, PublicIdentity};
29pub use origin::{Origin, RemoteOrigins};
30pub use paths::Paths;
31pub use rs_merkle as merkle;
32
33pub(crate) type Result<T> = std::result::Result<T, Error>;
35
36use bitflags::bitflags;
37use rand::{rngs::OsRng, CryptoRng, Rng};
38use serde::{Deserialize, Serialize};
39use std::{fmt, path::Path, str::FromStr};
40use uuid::Uuid;
41
42pub fn csprng() -> impl CryptoRng + Rng {
44 OsRng
45}
46
47pub type VaultId = Uuid;
49
50pub type SecretId = Uuid;
52
53#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
55pub struct VaultEntry(pub crypto::AeadPack, pub crypto::AeadPack);
56
57#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)]
59pub struct VaultCommit(pub commit::CommitHash, pub VaultEntry);
60
61#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, PartialEq, Eq)]
63pub struct SecretPath(pub VaultId, pub SecretId);
64
65impl SecretPath {
66 pub fn folder_id(&self) -> &VaultId {
68 &self.0
69 }
70
71 pub fn secret_id(&self) -> &SecretId {
73 &self.1
74 }
75}
76
77pub fn basename(path: impl AsRef<Path>) -> String {
82 path.as_ref()
83 .file_name()
84 .unwrap_or_default()
85 .to_string_lossy()
86 .into_owned()
87}
88
89pub fn guess_mime(path: impl AsRef<Path>) -> Result<String> {
95 if let Some(extension) = path.as_ref().extension() {
96 let fixed = match extension.to_string_lossy().as_ref() {
97 "heic" => Some("image/heic".to_string()),
98 "heif" => Some("image/heif".to_string()),
99 "avif" => Some("image/avif".to_string()),
100 _ => None,
101 };
102
103 if let Some(fixed) = fixed {
104 return Ok(fixed);
105 }
106 }
107 let mime = mime_guess::from_path(&path)
108 .first_or(mime_guess::mime::APPLICATION_OCTET_STREAM)
109 .to_string();
110 Ok(mime)
111}
112
113bitflags! {
114 #[derive(Default, Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
116 #[serde(transparent)]
117 pub struct VaultFlags: u64 {
118 const DEFAULT = 0b0000000000000001;
121 const IDENTITY = 0b0000000000000010;
124 const ARCHIVE = 0b0000000000000100;
126 const AUTHENTICATOR = 0b0000000000001000;
129 const CONTACT = 0b0000000000010000;
131 const SYSTEM = 0b0000000000100000;
135 const DEVICE = 0b0000000001000000;
142 const NO_SYNC = 0b0000000010000000;
147 const LOCAL = 0b0000000100000000;
149 const SHARED = 0b0000001000000000;
152 }
153}
154
155impl VaultFlags {
156 pub fn is_default(&self) -> bool {
158 self.contains(VaultFlags::DEFAULT)
159 }
160
161 pub fn is_identity(&self) -> bool {
163 self.contains(VaultFlags::IDENTITY)
164 }
165
166 pub fn is_archive(&self) -> bool {
168 self.contains(VaultFlags::ARCHIVE)
169 }
170
171 pub fn is_authenticator(&self) -> bool {
173 self.contains(VaultFlags::AUTHENTICATOR)
174 }
175
176 pub fn is_contact(&self) -> bool {
178 self.contains(VaultFlags::CONTACT)
179 }
180
181 pub fn is_system(&self) -> bool {
183 self.contains(VaultFlags::SYSTEM)
184 }
185
186 pub fn is_device(&self) -> bool {
188 self.contains(VaultFlags::DEVICE)
189 }
190
191 pub fn is_sync_disabled(&self) -> bool {
194 self.contains(VaultFlags::NO_SYNC)
195 }
196
197 pub fn is_local(&self) -> bool {
199 self.contains(VaultFlags::LOCAL)
200 }
201
202 pub fn is_shared(&self) -> bool {
204 self.contains(VaultFlags::SHARED)
205 }
206}
207
208#[repr(u8)]
210#[derive(Debug, Copy, Clone, PartialEq, Eq)]
211pub enum ArchiveManifestVersion {
212 V1 = 1,
219
220 V2 = 2,
226
227 V3 = 3,
231}
232
233impl Default for ArchiveManifestVersion {
234 fn default() -> Self {
240 Self::V1
241 }
242}
243
244impl Serialize for ArchiveManifestVersion {
246 fn serialize<S>(
247 &self,
248 serializer: S,
249 ) -> std::result::Result<S::Ok, S::Error>
250 where
251 S: serde::Serializer,
252 {
253 serializer.serialize_u8(*self as u8)
254 }
255}
256
257impl<'de> Deserialize<'de> for ArchiveManifestVersion {
259 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
260 where
261 D: serde::Deserializer<'de>,
262 {
263 let value = u8::deserialize(deserializer)?;
264 match value {
265 1 => Ok(ArchiveManifestVersion::V1),
266 2 => Ok(ArchiveManifestVersion::V2),
267 3 => Ok(ArchiveManifestVersion::V3),
268 _ => Err(serde::de::Error::custom(
269 "invalid archive manifest version",
270 )),
271 }
272 }
273}
274
275#[derive(Debug, Clone)]
277pub enum FolderRef {
278 Id(VaultId),
280 Name(String),
282}
283
284impl fmt::Display for FolderRef {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 match self {
287 Self::Id(id) => write!(f, "{}", id),
288 Self::Name(name) => write!(f, "{}", name),
289 }
290 }
291}
292
293impl FromStr for FolderRef {
294 type Err = Error;
295 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
296 if let Ok(id) = Uuid::parse_str(s) {
297 Ok(Self::Id(id))
298 } else {
299 Ok(Self::Name(s.to_string()))
300 }
301 }
302}
303
304impl From<VaultId> for FolderRef {
305 fn from(value: VaultId) -> Self {
306 Self::Id(value)
307 }
308}