Use VeilidAPIError type for ProtectedStore functions

This commit is contained in:
Christien Rioux 2025-09-08 14:54:02 -04:00 committed by GitLab
parent f7575467a6
commit 45dffe0d9f
No known key found for this signature in database
3 changed files with 61 additions and 60 deletions

View file

@ -19,6 +19,7 @@
- Eliminated 'best' CryptoKind concept, crypto kinds must now be explicitly stated, otherwise upgrades of veilid-core that change the 'best' CryptoKind could break functionality silently. - Eliminated 'best' CryptoKind concept, crypto kinds must now be explicitly stated, otherwise upgrades of veilid-core that change the 'best' CryptoKind could break functionality silently.
- Encryption is enabled by default for all DHT operations, closes [#300](https://gitlab.com/veilid/veilid/-/issues/300) (@neequ57) - Encryption is enabled by default for all DHT operations, closes [#300](https://gitlab.com/veilid/veilid/-/issues/300) (@neequ57)
- Deprecation of WSS config and removal of Application config - Deprecation of WSS config and removal of Application config
- Use VeilidAPIError type for ProtectedStore functions [#480](https://gitlab.com/veilid/veilid/-/issues/480)
- veilid-core: - veilid-core:
- Hop counts removed from private routes [#466](https://gitlab.com/veilid/veilid/-/issues/466) - Hop counts removed from private routes [#466](https://gitlab.com/veilid/veilid/-/issues/466)

View file

@ -37,8 +37,8 @@ impl ProtectedStore {
} }
} }
#[instrument(level = "trace", skip(self), err)] #[instrument(level = "trace", skip(self))]
pub fn delete_all(&self) -> EyreResult<()> { pub fn delete_all(&self) {
for kpsk in &KNOWN_PROTECTED_STORE_KEYS { for kpsk in &KNOWN_PROTECTED_STORE_KEYS {
if let Err(e) = self.remove_user_secret(kpsk) { if let Err(e) = self.remove_user_secret(kpsk) {
veilid_log!(self error "failed to delete '{}': {}", kpsk, e); veilid_log!(self error "failed to delete '{}': {}", kpsk, e);
@ -46,7 +46,6 @@ impl ProtectedStore {
veilid_log!(self debug "deleted protected store key '{}'", kpsk); veilid_log!(self debug "deleted protected store key '{}'", kpsk);
} }
} }
Ok(())
} }
#[instrument(level = "debug", skip(self), err)] #[instrument(level = "debug", skip(self), err)]
@ -103,7 +102,7 @@ impl ProtectedStore {
}; };
if delete { if delete {
self.delete_all()?; self.delete_all();
} }
Ok(()) Ok(())
@ -137,50 +136,53 @@ impl ProtectedStore {
&self, &self,
key: K, key: K,
value: V, value: V,
) -> EyreResult<bool> { ) -> VeilidAPIResult<bool> {
let inner = self.inner.lock(); let inner = self.inner.lock();
inner inner
.keyring_manager .keyring_manager
.as_ref() .as_ref()
.ok_or_else(|| eyre!("Protected store not initialized"))? .ok_or_else(VeilidAPIError::not_initialized)?
.with_keyring(&self.service_name(), key.as_ref(), |kr| { .with_keyring(&self.service_name(), key.as_ref(), |kr| {
let existed = kr.get_value().is_ok(); let existed = kr.get_value().is_ok();
kr.set_value(value.as_ref())?; kr.set_value(value.as_ref())?;
Ok(existed) Ok(existed)
}) })
.wrap_err("failed to save user secret") .map_err(VeilidAPIError::generic)
} }
#[instrument(level = "trace", skip(self), err)] #[instrument(level = "trace", skip(self), err)]
pub fn load_user_secret_string<K: AsRef<str> + fmt::Debug>( pub fn load_user_secret_string<K: AsRef<str> + fmt::Debug>(
&self, &self,
key: K, key: K,
) -> EyreResult<Option<String>> { ) -> VeilidAPIResult<Option<String>> {
let inner = self.inner.lock(); let inner = self.inner.lock();
match inner match inner
.keyring_manager .keyring_manager
.as_ref() .as_ref()
.ok_or_else(|| eyre!("Protected store not initialized"))? .ok_or_else(VeilidAPIError::not_initialized)?
.with_keyring(&self.service_name(), key.as_ref(), |kr| kr.get_value()) .with_keyring(&self.service_name(), key.as_ref(), |kr| kr.get_value())
{ {
Ok(v) => Ok(Some(v)), Ok(v) => Ok(Some(v)),
Err(KeyringError::NoPasswordFound) => Ok(None), Err(KeyringError::NoPasswordFound) => Ok(None),
Err(e) => Err(eyre!("Failed to load user secret: {}", e)), Err(e) => Err(VeilidAPIError::generic(format!(
"Failed to load user secret: {}",
e
))),
} }
} }
#[instrument(level = "trace", skip(self, value))] #[instrument(level = "trace", skip(self, value))]
pub fn save_user_secret_json<K, T>(&self, key: K, value: &T) -> EyreResult<bool> pub fn save_user_secret_json<K, T>(&self, key: K, value: &T) -> VeilidAPIResult<bool>
where where
K: AsRef<str> + fmt::Debug, K: AsRef<str> + fmt::Debug,
T: serde::Serialize, T: serde::Serialize,
{ {
let v = serde_json::to_vec(value)?; let v = serde_json::to_vec(value).map_err(VeilidAPIError::generic)?;
self.save_user_secret(&key, &v) self.save_user_secret(&key, &v)
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub fn load_user_secret_json<K, T>(&self, key: K) -> EyreResult<Option<T>> pub fn load_user_secret_json<K, T>(&self, key: K) -> VeilidAPIResult<Option<T>>
where where
K: AsRef<str> + fmt::Debug, K: AsRef<str> + fmt::Debug,
T: for<'de> serde::de::Deserialize<'de>, T: for<'de> serde::de::Deserialize<'de>,
@ -193,7 +195,7 @@ impl ProtectedStore {
} }
}; };
let obj = serde_json::from_slice(&b)?; let obj = serde_json::from_slice(&b).map_err(VeilidAPIError::generic)?;
Ok(Some(obj)) Ok(Some(obj))
} }
@ -202,7 +204,7 @@ impl ProtectedStore {
&self, &self,
key: K, key: K,
value: &[u8], value: &[u8],
) -> EyreResult<bool> { ) -> VeilidAPIResult<bool> {
let mut s = BASE64URL_NOPAD.encode(value); let mut s = BASE64URL_NOPAD.encode(value);
s.push('!'); s.push('!');
@ -213,7 +215,7 @@ impl ProtectedStore {
pub fn load_user_secret<K: AsRef<str> + fmt::Debug>( pub fn load_user_secret<K: AsRef<str> + fmt::Debug>(
&self, &self,
key: K, key: K,
) -> EyreResult<Option<Vec<u8>>> { ) -> VeilidAPIResult<Option<Vec<u8>>> {
let mut s = match self.load_user_secret_string(key)? { let mut s = match self.load_user_secret_string(key)? {
Some(s) => s, Some(s) => s,
None => { None => {
@ -222,7 +224,7 @@ impl ProtectedStore {
}; };
if s.pop() != Some('!') { if s.pop() != Some('!') {
bail!("User secret is not a buffer"); apibail_generic!("User secret is not a buffer");
} }
let mut bytes = Vec::<u8>::new(); let mut bytes = Vec::<u8>::new();
@ -232,29 +234,32 @@ impl ProtectedStore {
bytes.resize(l, 0u8); bytes.resize(l, 0u8);
} }
Err(_) => { Err(_) => {
bail!("Failed to decode"); apibail_generic!("Failed to decode");
} }
} }
let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes); let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes);
match res { match res {
Ok(_) => Ok(Some(bytes)), Ok(_) => Ok(Some(bytes)),
Err(_) => bail!("Failed to decode"), Err(_) => apibail_generic!("Failed to decode"),
} }
} }
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub fn remove_user_secret<K: AsRef<str> + fmt::Debug>(&self, key: K) -> EyreResult<bool> { pub fn remove_user_secret<K: AsRef<str> + fmt::Debug>(&self, key: K) -> VeilidAPIResult<bool> {
let inner = self.inner.lock(); let inner = self.inner.lock();
match inner match inner
.keyring_manager .keyring_manager
.as_ref() .as_ref()
.ok_or_else(|| eyre!("Protected store not initialized"))? .ok_or_else(VeilidAPIError::not_initialized)?
.with_keyring(&self.service_name(), key.as_ref(), |kr| kr.delete_value()) .with_keyring(&self.service_name(), key.as_ref(), |kr| kr.delete_value())
{ {
Ok(_) => Ok(true), Ok(_) => Ok(true),
Err(KeyringError::NoPasswordFound) => Ok(false), Err(KeyringError::NoPasswordFound) => Ok(false),
Err(e) => Err(eyre!("Failed to remove user secret: {}", e)), Err(e) => Err(VeilidAPIError::generic(format!(
"Failed to remove user secret: {}",
e
))),
} }
} }
} }

View file

@ -13,13 +13,17 @@ pub struct ProtectedStore {
impl_veilid_component!(ProtectedStore); impl_veilid_component!(ProtectedStore);
fn map_js_error_generic<M: ToString>(message: M) -> impl FnOnce(JsValue) -> VeilidAPIError {
move |x| VeilidAPIError::generic(format!("{}: {}", message.to_string(), map_jsvalue_error(x)))
}
impl ProtectedStore { impl ProtectedStore {
pub(crate) fn new(registry: VeilidComponentRegistry) -> Self { pub(crate) fn new(registry: VeilidComponentRegistry) -> Self {
Self { registry } Self { registry }
} }
#[instrument(level = "trace", skip(self), err)] #[instrument(level = "trace", skip(self))]
pub fn delete_all(&self) -> EyreResult<()> { pub fn delete_all(&self) {
for kpsk in &KNOWN_PROTECTED_STORE_KEYS { for kpsk in &KNOWN_PROTECTED_STORE_KEYS {
if let Err(e) = self.remove_user_secret(kpsk) { if let Err(e) = self.remove_user_secret(kpsk) {
veilid_log!(self error "failed to delete protected store key '{}': {}", kpsk, e); veilid_log!(self error "failed to delete protected store key '{}': {}", kpsk, e);
@ -27,13 +31,12 @@ impl ProtectedStore {
veilid_log!(self debug "deleted protected store key '{}'", kpsk); veilid_log!(self debug "deleted protected store key '{}'", kpsk);
} }
} }
Ok(())
} }
#[instrument(level = "debug", skip(self), err)] #[instrument(level = "debug", skip(self), err)]
async fn init_async(&self) -> EyreResult<()> { async fn init_async(&self) -> EyreResult<()> {
if self.config().with(|c| c.protected_store.delete) { if self.config().with(|c| c.protected_store.delete) {
self.delete_all()?; self.delete_all();
} }
Ok(()) Ok(())
@ -65,23 +68,22 @@ impl ProtectedStore {
&self, &self,
key: K, key: K,
value: V, value: V,
) -> EyreResult<bool> { ) -> VeilidAPIResult<bool> {
if is_browser() { if is_browser() {
let win = match window() { let win = match window() {
Some(w) => w, Some(w) => w,
None => { None => {
bail!("failed to get window"); apibail_generic!("failed to get window");
} }
}; };
let ls = match win let ls = match win
.local_storage() .local_storage()
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception getting local storage"))?
.wrap_err("exception getting local storage")?
{ {
Some(l) => l, Some(l) => l,
None => { None => {
bail!("failed to get local storage"); apibail_generic!("failed to get local storage");
} }
}; };
@ -89,13 +91,11 @@ impl ProtectedStore {
let prev = ls let prev = ls
.get_item(&vkey) .get_item(&vkey)
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception thrown"))?
.wrap_err("exception_thrown")?
.is_some(); .is_some();
ls.set_item(&vkey, value.as_ref()) ls.set_item(&vkey, value.as_ref())
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception thrown"))?;
.wrap_err("exception_thrown")?;
Ok(prev) Ok(prev)
} else { } else {
@ -107,47 +107,45 @@ impl ProtectedStore {
pub fn load_user_secret_string<K: AsRef<str> + fmt::Debug>( pub fn load_user_secret_string<K: AsRef<str> + fmt::Debug>(
&self, &self,
key: K, key: K,
) -> EyreResult<Option<String>> { ) -> VeilidAPIResult<Option<String>> {
if is_browser() { if is_browser() {
let win = match window() { let win = match window() {
Some(w) => w, Some(w) => w,
None => { None => {
bail!("failed to get window"); apibail_generic!("failed to get window");
} }
}; };
let ls = match win let ls = match win
.local_storage() .local_storage()
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception getting local storage"))?
.wrap_err("exception getting local storage")?
{ {
Some(l) => l, Some(l) => l,
None => { None => {
bail!("failed to get local storage"); apibail_generic!("failed to get local storage");
} }
}; };
let vkey = self.browser_key_name(key.as_ref()); let vkey = self.browser_key_name(key.as_ref());
ls.get_item(&vkey) ls.get_item(&vkey)
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception thrown"))
.wrap_err("exception_thrown")
} else { } else {
unimplemented!(); unimplemented!();
} }
} }
#[instrument(level = "trace", skip(self, value))] #[instrument(level = "trace", skip(self, value))]
pub fn save_user_secret_json<K, T>(&self, key: K, value: &T) -> EyreResult<bool> pub fn save_user_secret_json<K, T>(&self, key: K, value: &T) -> VeilidAPIResult<bool>
where where
K: AsRef<str> + fmt::Debug, K: AsRef<str> + fmt::Debug,
T: serde::Serialize, T: serde::Serialize,
{ {
let v = serde_json::to_vec(value)?; let v = serde_json::to_vec(value).map_err(VeilidAPIError::generic)?;
self.save_user_secret(key, &v) self.save_user_secret(key, &v)
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub fn load_user_secret_json<K, T>(&self, key: K) -> EyreResult<Option<T>> pub fn load_user_secret_json<K, T>(&self, key: K) -> VeilidAPIResult<Option<T>>
where where
K: AsRef<str> + fmt::Debug, K: AsRef<str> + fmt::Debug,
T: for<'de> serde::de::Deserialize<'de>, T: for<'de> serde::de::Deserialize<'de>,
@ -160,7 +158,7 @@ impl ProtectedStore {
} }
}; };
let obj = serde_json::from_slice(&b)?; let obj = serde_json::from_slice(&b).map_err(VeilidAPIError::generic)?;
Ok(Some(obj)) Ok(Some(obj))
} }
@ -169,7 +167,7 @@ impl ProtectedStore {
&self, &self,
key: K, key: K,
value: &[u8], value: &[u8],
) -> EyreResult<bool> { ) -> VeilidAPIResult<bool> {
let mut s = BASE64URL_NOPAD.encode(value); let mut s = BASE64URL_NOPAD.encode(value);
s.push('!'); s.push('!');
@ -180,7 +178,7 @@ impl ProtectedStore {
pub fn load_user_secret<K: AsRef<str> + fmt::Debug>( pub fn load_user_secret<K: AsRef<str> + fmt::Debug>(
&self, &self,
key: K, key: K,
) -> EyreResult<Option<Vec<u8>>> { ) -> VeilidAPIResult<Option<Vec<u8>>> {
let mut s = match self.load_user_secret_string(key)? { let mut s = match self.load_user_secret_string(key)? {
Some(s) => s, Some(s) => s,
None => { None => {
@ -189,7 +187,7 @@ impl ProtectedStore {
}; };
if s.pop() != Some('!') { if s.pop() != Some('!') {
bail!("User secret is not a buffer"); apibail_generic!("User secret is not a buffer");
} }
let mut bytes = Vec::<u8>::new(); let mut bytes = Vec::<u8>::new();
@ -199,35 +197,34 @@ impl ProtectedStore {
bytes.resize(l, 0u8); bytes.resize(l, 0u8);
} }
Err(_) => { Err(_) => {
bail!("Failed to decode"); apibail_generic!("Failed to decode");
} }
} }
let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes); let res = BASE64URL_NOPAD.decode_mut(s.as_bytes(), &mut bytes);
match res { match res {
Ok(_) => Ok(Some(bytes)), Ok(_) => Ok(Some(bytes)),
Err(_) => bail!("Failed to decode"), Err(_) => apibail_generic!("Failed to decode"),
} }
} }
#[instrument(level = "trace", skip(self), ret, err)] #[instrument(level = "trace", skip(self), ret, err)]
pub fn remove_user_secret<K: AsRef<str> + fmt::Debug>(&self, key: K) -> EyreResult<bool> { pub fn remove_user_secret<K: AsRef<str> + fmt::Debug>(&self, key: K) -> VeilidAPIResult<bool> {
if is_browser() { if is_browser() {
let win = match window() { let win = match window() {
Some(w) => w, Some(w) => w,
None => { None => {
bail!("failed to get window"); apibail_generic!("failed to get window");
} }
}; };
let ls = match win let ls = match win
.local_storage() .local_storage()
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception getting local storage"))?
.wrap_err("exception getting local storage")?
{ {
Some(l) => l, Some(l) => l,
None => { None => {
bail!("failed to get local storage"); apibail_generic!("failed to get local storage");
} }
}; };
@ -235,13 +232,11 @@ impl ProtectedStore {
match ls match ls
.get_item(&vkey) .get_item(&vkey)
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception thrown"))?
.wrap_err("exception_thrown")?
{ {
Some(_) => { Some(_) => {
ls.delete(&vkey) ls.delete(&vkey)
.map_err(map_jsvalue_error) .map_err(map_js_error_generic("exception thrown"))?;
.wrap_err("exception_thrown")?;
Ok(true) Ok(true)
} }
None => Ok(false), None => Ok(false),