veilid_core/protected_store/
native.rs1use super::*;
2use data_encoding::BASE64URL_NOPAD;
3use keyring_manager::*;
4use std::path::Path;
5
6impl_veilid_log_facility!("pstore");
7
8pub struct ProtectedStoreInner {
10 keyring_manager: Option<KeyringManager>,
11}
12impl fmt::Debug for ProtectedStoreInner {
13 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14 f.debug_struct("ProtectedStoreInner").finish()
15 }
16}
17
18#[derive(Debug)]
21#[must_use]
22pub struct ProtectedStore {
23 registry: VeilidComponentRegistry,
24 inner: Mutex<ProtectedStoreInner>,
25}
26
27impl_veilid_component!(ProtectedStore);
28
29impl ProtectedStore {
30 fn new_inner() -> ProtectedStoreInner {
31 ProtectedStoreInner {
32 keyring_manager: None,
33 }
34 }
35
36 pub(crate) fn new(registry: VeilidComponentRegistry) -> Self {
37 Self {
38 registry,
39 inner: Mutex::new(Self::new_inner()),
40 }
41 }
42
43 #[cfg_attr(feature = "instrument", instrument(level = "trace", skip(self), fields(__VEILID_LOG_KEY = self.log_key())))]
44 pub fn delete_all(&self) {
48 for kpsk in &KNOWN_PROTECTED_STORE_KEYS {
49 if let Err(e) = self.remove_user_secret(kpsk) {
50 veilid_log!(self error "failed to delete '{}': {}", kpsk, e);
51 } else {
52 veilid_log!(self debug "deleted protected store key '{}'", kpsk);
53 }
54 }
55 }
56
57 fn log_facilities_impl(&self) -> VeilidComponentLogFacilities {
58 VeilidComponentLogFacilities::new().with_facility(
59 VeilidComponentLogFacility::try_new_with_tags("pstore", ["#common"]).unwrap(),
60 )
61 }
62
63 #[cfg_attr(feature = "instrument", instrument(level = "debug", skip(self), err, fields(__VEILID_LOG_KEY = self.log_key())))]
64 #[allow(clippy::unused_async)]
65 async fn init_async(&self) -> EyreResult<()> {
66 let delete = {
67 let config = self.config();
68 let mut inner = self.inner.lock();
69 if !config.protected_store.always_use_insecure_storage {
70 cfg_if! {
72 if #[cfg(target_os = "android")] {
73 let maybe_km = KeyringManager::new_secure(&config.program_name, crate::veilid_api::android::get_android_globals());
74 } else {
75 let maybe_km = KeyringManager::new_secure(&config.program_name);
76 }
77 }
78
79 inner.keyring_manager = match maybe_km {
80 Ok(v) => Some(v),
81 Err(e) => {
82 veilid_log!(self info "Secure key storage service unavailable, falling back to direct disk-based storage: {}", e);
83 None
84 }
85 };
86 }
87 if (config.protected_store.always_use_insecure_storage
88 || config.protected_store.allow_insecure_fallback)
89 && inner.keyring_manager.is_none()
90 {
91 let directory = Path::new(&config.protected_store.directory);
92 let insecure_keyring_file = directory.to_owned().join(format!(
93 "insecure_keyring{}",
94 if config.namespace.is_empty() {
95 "".to_owned()
96 } else {
97 format!("_{}", config.namespace)
98 }
99 ));
100
101 ensure_file_private_owner(&insecure_keyring_file).map_err(|e| eyre!("{}", e))?;
103
104 inner.keyring_manager = Some(
106 KeyringManager::new_insecure(&config.program_name, &insecure_keyring_file)
107 .wrap_err("failed to create insecure keyring")?,
108 );
109 }
110 if inner.keyring_manager.is_none() {
111 bail!("Could not initialize the protected store.");
112 }
113 config.protected_store.delete
114 };
115
116 if delete {
117 self.delete_all();
118 }
119
120 Ok(())
121 }
122
123 #[cfg_attr(feature = "instrument", instrument(level = "debug", skip(self), err, fields(__VEILID_LOG_KEY = self.log_key())))]
124 #[allow(clippy::unused_async)]
125 async fn post_init_async(&self) -> EyreResult<()> {
126 Ok(())
127 }
128
129 #[cfg_attr(feature = "instrument", instrument(level = "debug", skip(self), fields(__VEILID_LOG_KEY = self.log_key())))]
130 #[allow(clippy::unused_async)]
131 async fn pre_terminate_async(&self) {}
132
133 #[cfg_attr(feature = "instrument", instrument(level = "debug", skip(self), fields(__VEILID_LOG_KEY = self.log_key())))]
134 #[allow(clippy::unused_async)]
135 async fn terminate_async(&self) {
136 *self.inner.lock() = Self::new_inner();
137 }
138
139 fn service_name(&self) -> String {
140 let config = self.config();
141 if config.namespace.is_empty() {
142 "veilid_protected_store".to_owned()
143 } else {
144 format!("veilid_protected_store_{}", config.namespace)
145 }
146 }
147
148 #[cfg_attr(
149 feature = "instrument",
150 instrument(level = "trace", skip(self, value), ret, err, fields(__VEILID_LOG_KEY = self.log_key()))
151 )]
152 pub fn save_user_secret_string<K: AsRef<str> + fmt::Debug, V: AsRef<str> + fmt::Debug>(
158 &self,
159 key: K,
160 value: V,
161 ) -> VeilidAPIResult<bool> {
162 let inner = self.inner.lock();
163 inner
164 .keyring_manager
165 .as_ref()
166 .ok_or_else(VeilidAPIError::not_initialized)?
167 .with_keyring(&self.service_name(), key.as_ref(), |kr| {
168 let existed = kr.get_value().is_ok();
169 kr.set_value(value.as_ref())?;
170 Ok(existed)
171 })
172 .map_err(|e| VeilidAPIError::generic(format!("failed to save user secret: {}", e)))
173 }
174
175 #[cfg_attr(feature = "instrument", instrument(level = "trace", skip(self), err, fields(__VEILID_LOG_KEY = self.log_key())))]
176 pub fn load_user_secret_string<K: AsRef<str> + fmt::Debug>(
182 &self,
183 key: K,
184 ) -> VeilidAPIResult<Option<String>> {
185 let inner = self.inner.lock();
186 match inner
187 .keyring_manager
188 .as_ref()
189 .ok_or_else(VeilidAPIError::not_initialized)?
190 .with_keyring(&self.service_name(), key.as_ref(), |kr| kr.get_value())
191 {
192 Ok(v) => Ok(Some(v)),
193 Err(KeyringError::NoPasswordFound) => Ok(None),
194 Err(e) => Err(VeilidAPIError::generic(format!(
195 "Failed to load user secret: {}",
196 e
197 ))),
198 }
199 }
200
201 #[cfg_attr(feature = "instrument", instrument(level = "trace", skip(self, value), fields(__VEILID_LOG_KEY = self.log_key())))]
202 pub fn save_user_secret_json<K, T>(&self, key: K, value: &T) -> VeilidAPIResult<bool>
208 where
209 K: AsRef<str> + fmt::Debug,
210 T: serde::Serialize,
211 {
212 let v = serde_json::to_vec(value).map_err(VeilidAPIError::generic)?;
213 self.save_user_secret(&key, &v)
214 }
215
216 #[cfg_attr(feature = "instrument", instrument(level = "trace", skip(self), fields(__VEILID_LOG_KEY = self.log_key())))]
217 pub fn load_user_secret_json<K, T>(&self, key: K) -> VeilidAPIResult<Option<T>>
223 where
224 K: AsRef<str> + fmt::Debug,
225 T: for<'de> serde::de::Deserialize<'de>,
226 {
227 let out = self.load_user_secret(key)?;
228 let b = match out {
229 Some(v) => v,
230 None => {
231 return Ok(None);
232 }
233 };
234
235 let obj = serde_json::from_slice(&b).map_err(VeilidAPIError::generic)?;
236 Ok(Some(obj))
237 }
238
239 #[cfg_attr(
240 feature = "instrument",
241 instrument(level = "trace", skip(self, value), ret, err, fields(__VEILID_LOG_KEY = self.log_key()))
242 )]
243 pub fn save_user_secret<K: AsRef<str> + fmt::Debug>(
249 &self,
250 key: K,
251 value: &[u8],
252 ) -> VeilidAPIResult<bool> {
253 let mut s = BASE64URL_NOPAD.encode(value);
254 s.push('!');
255
256 self.save_user_secret_string(key, s.as_str())
257 }
258
259 #[cfg_attr(feature = "instrument", instrument(level = "trace", skip(self), err, fields(__VEILID_LOG_KEY = self.log_key())))]
260 pub fn load_user_secret<K: AsRef<str> + fmt::Debug>(
266 &self,
267 key: K,
268 ) -> VeilidAPIResult<Option<Vec<u8>>> {
269 let mut s = match self.load_user_secret_string(key)? {
270 Some(s) => s,
271 None => {
272 return Ok(None);
273 }
274 };
275
276 if s.pop() != Some('!') {
277 apibail_generic!("User secret is not a buffer");
278 }
279
280 let mut bytes = Vec::<u8>::new();
281 let res = BASE64URL_NOPAD.decode_len(s.len());
282 match res {
283 Ok(l) => {
284 bytes.resize(l, 0u8);
285 }
286 Err(_) => {
287 apibail_generic!("Failed to decode");
288 }
289 }
290
291 let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes);
292 match res {
293 Ok(_) => Ok(Some(bytes)),
294 Err(_) => apibail_generic!("Failed to decode"),
295 }
296 }
297
298 #[cfg_attr(
299 feature = "instrument",
300 instrument(level = "trace", skip(self), ret, err, fields(__VEILID_LOG_KEY = self.log_key()))
301 )]
302 pub fn remove_user_secret<K: AsRef<str> + fmt::Debug>(&self, key: K) -> VeilidAPIResult<bool> {
308 let inner = self.inner.lock();
309 match inner
310 .keyring_manager
311 .as_ref()
312 .ok_or_else(VeilidAPIError::not_initialized)?
313 .with_keyring(&self.service_name(), key.as_ref(), |kr| kr.delete_value())
314 {
315 Ok(_) => Ok(true),
316 Err(KeyringError::NoPasswordFound) => Ok(false),
317 Err(e) => Err(VeilidAPIError::generic(format!(
318 "Failed to remove user secret: {}",
319 e
320 ))),
321 }
322 }
323}