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