1#[cfg(feature = "unstable")]
21#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
22pub mod api;
23#[cfg(not(feature = "unstable"))]
24pub(crate) mod api;
25
26mod error;
27mod locked_item;
28mod locked_keyring;
29mod unlocked_item;
30mod unlocked_keyring;
31
32pub use error::{Error, InvalidItemError, WeakKeyError};
33pub use locked_item::LockedItem;
34pub use locked_keyring::LockedKeyring;
35pub use unlocked_item::UnlockedItem;
36pub use unlocked_keyring::{ItemDefinition, UnlockedKeyring};
37
38use crate::{AsAttributes, Key, Secret};
39
40#[derive(Debug)]
41pub enum Item {
42 Locked(LockedItem),
43 Unlocked(UnlockedItem),
44}
45
46impl From<UnlockedItem> for Item {
47 fn from(item: UnlockedItem) -> Self {
48 Self::Unlocked(item)
49 }
50}
51
52impl From<LockedItem> for Item {
53 fn from(item: LockedItem) -> Self {
54 Self::Locked(item)
55 }
56}
57
58impl Item {
59 pub const fn is_locked(&self) -> bool {
60 matches!(self, Self::Locked(_))
61 }
62
63 pub fn as_unlocked(&self) -> &UnlockedItem {
64 match self {
65 Self::Unlocked(item) => item,
66 _ => panic!("The item is locked"),
67 }
68 }
69
70 pub fn as_mut_unlocked(&mut self) -> &mut UnlockedItem {
71 match self {
72 Self::Unlocked(item) => item,
73 _ => panic!("The item is locked"),
74 }
75 }
76
77 pub fn as_locked(&self) -> &LockedItem {
78 match self {
79 Self::Locked(item) => item,
80 _ => panic!("The item is unlocked"),
81 }
82 }
83
84 pub fn matches_attributes(&self, attributes: &impl AsAttributes, key: Option<&Key>) -> bool {
86 match self {
87 Self::Unlocked(unlocked) => {
88 let item_attrs = unlocked.attributes();
89 attributes.search_attributes().iter().all(|(k, value)| {
90 item_attrs.get(k.as_str()).map(|v| v.as_ref()) == Some(value.as_str())
91 })
92 }
93 Self::Locked(locked) => locked.inner.matches(attributes, key),
94 }
95 }
96}
97
98#[derive(Debug)]
99pub enum Keyring {
100 Locked(LockedKeyring),
101 Unlocked(UnlockedKeyring),
102}
103
104impl From<LockedKeyring> for Keyring {
105 fn from(keyring: LockedKeyring) -> Self {
106 Self::Locked(keyring)
107 }
108}
109
110impl From<UnlockedKeyring> for Keyring {
111 fn from(keyring: UnlockedKeyring) -> Self {
112 Self::Unlocked(keyring)
113 }
114}
115
116impl Keyring {
117 #[cfg_attr(feature = "tracing", tracing::instrument(skip(self, secret)))]
119 pub async fn validate_secret(&self, secret: &Secret) -> Result<bool, Error> {
120 match self {
121 Self::Locked(keyring) => keyring.validate_secret(secret).await,
122 Self::Unlocked(keyring) => keyring.validate_secret(secret).await,
123 }
124 }
125
126 pub async fn validate_unencrypted(&self) -> Result<bool, Error> {
127 match self {
128 Self::Locked(keyring) => keyring.validate_unencrypted().await,
129 Self::Unlocked(keyring) => keyring.validate_unencrypted().await,
130 }
131 }
132
133 pub async fn modified_time(&self) -> std::time::Duration {
135 match self {
136 Self::Locked(keyring) => keyring.modified_time().await,
137 Self::Unlocked(keyring) => keyring.modified_time().await,
138 }
139 }
140
141 pub async fn created_time(&self) -> Option<std::time::Duration> {
144 let path = self.path()?;
145
146 #[cfg(feature = "tokio")]
147 let metadata = tokio::fs::metadata(path).await.ok()?;
148 #[cfg(feature = "async-std")]
149 let metadata = async_fs::metadata(path).await.ok()?;
150
151 metadata
152 .created()
153 .ok()
154 .and_then(|time| time.duration_since(std::time::SystemTime::UNIX_EPOCH).ok())
155 }
156
157 pub async fn items(&self) -> Result<Vec<Item>, Error> {
158 match self {
159 Self::Locked(keyring) => Ok(keyring
160 .items()
161 .await?
162 .into_iter()
163 .map(Item::Locked)
164 .collect()),
165 Self::Unlocked(keyring) => Ok(keyring
166 .items()
167 .await?
168 .into_iter()
169 .map(Item::Unlocked)
170 .collect()),
171 }
172 }
173
174 pub fn path(&self) -> Option<&std::path::Path> {
176 match self {
177 Self::Locked(keyring) => keyring.path(),
178 Self::Unlocked(keyring) => keyring.path(),
179 }
180 }
181
182 pub const fn is_locked(&self) -> bool {
183 matches!(self, Self::Locked(_))
184 }
185
186 pub fn as_unlocked(&self) -> &UnlockedKeyring {
187 match self {
188 Self::Unlocked(unlocked_keyring) => unlocked_keyring,
189 _ => panic!("The keyring is locked"),
190 }
191 }
192
193 pub fn as_locked(&self) -> &LockedKeyring {
194 match self {
195 Self::Locked(locked_keyring) => locked_keyring,
196 _ => panic!("The keyring is unlocked"),
197 }
198 }
199}