diff --git a/src-tauri/src/errors.rs b/src-tauri/src/errors.rs index 6f6c354..278bd12 100644 --- a/src-tauri/src/errors.rs +++ b/src-tauri/src/errors.rs @@ -1,3 +1,7 @@ +use std::error::Error; +use std::convert::AsRef; +use strum_macros::AsRefStr; + use thiserror::Error as ThisError; use aws_sdk_sts::{ @@ -10,35 +14,70 @@ use sqlx::{ }; use serde::{Serialize, Serializer, ser::SerializeMap}; -use strum_macros::IntoStaticStr; -pub struct SerializeError { - pub err: E -} +// pub struct SerializeError { +// pub err: E, +// } -impl Serialize for SerializeError +// impl Serialize for SerializeError +// { +// fn serialize(&self, serializer: S) -> Result { +// let mut map = serializer.serialize_map(None)?; +// map.serialize_entry("msg", &format!("{}", self.err))?; +// if let Some(src) = self.err.source() { +// let ser_src = SerializeError { err: src }; +// map.serialize_entry("source", &ser_src)?; +// } +// map.end() +// } +// } + +// impl From for SerializeError { +// fn from(err: E) -> Self { +// SerializeError { err } +// } +// } + + +fn serialize_basic_err(err: &E, serializer: S) -> Result +where + E: std::error::Error + AsRef, + S: Serializer, { - fn serialize(&self, serializer: S) -> Result { - let mut map = serializer.serialize_map(None)?; - map.serialize_entry("msg", &format!("{}", self.err))?; - if let Some(src) = self.err.source() { - let ser_src = SerializeError { err: src }; - map.serialize_entry("source", &ser_src)?; - } - map.end() + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("code", err.as_ref())?; + map.serialize_entry("msg", &format!("{err}"))?; + if let Some(src) = err.source() { + map.serialize_entry("source", &format!("{src}"))?; } + map.end() } -impl From for SerializeError { - fn from(err: E) -> Self { - SerializeError { err } + +fn serialize_upstream_err(err: &E, map: &mut M) -> Result<(), M::Error> +where + E: Error, + M: serde::ser::SerializeMap, +{ + let src = err.source().map(|s| format!("{s}")); + map.serialize_entry("source", &src) +} + + +macro_rules! impl_serialize_basic { + ($err_type:ident) => { + impl Serialize for $err_type { + fn serialize(&self, serializer: S) -> Result { + serialize_basic_err(self, serializer) + } + } } } // error during initial setup (primarily loading state from db) -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum SetupError { #[error("Invalid database record")] InvalidRecord, // e.g. wrong size blob for nonce or salt @@ -52,7 +91,7 @@ pub enum SetupError { // error when attempting to tell a request handler whether to release or deny credentials -#[derive(Debug, ThisError, IntoStaticStr)] +#[derive(Debug, ThisError, AsRefStr)] pub enum SendResponseError { #[error("The specified credentials request was not found")] NotFound, // no request with the given id @@ -62,7 +101,7 @@ pub enum SendResponseError { // errors encountered while handling an HTTP request -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum RequestError { #[error("Error writing to stream: {0}")] StreamIOError(#[from] std::io::Error), @@ -82,7 +121,7 @@ pub enum RequestError { } -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum GetCredentialsError { #[error("Credentials are currently locked")] Locked, @@ -91,7 +130,7 @@ pub enum GetCredentialsError { } -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum GetSessionError { #[error("Request completed successfully but no credentials were returned")] NoCredentials, // SDK returned successfully but credentials are None @@ -100,7 +139,7 @@ pub enum GetSessionError { } -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum UnlockError { #[error("App is not locked")] NotLocked, @@ -118,10 +157,87 @@ pub enum UnlockError { // Errors encountered while trying to figure out who's on the other end of a request -#[derive(Debug, ThisError)] +#[derive(Debug, ThisError, AsRefStr)] pub enum ClientInfoError { #[error("Found PID for client socket, but no corresponding process")] ProcessNotFound, #[error("Couldn't get client socket details: {0}")] NetstatError(#[from] netstat2::error::Error), } + + +// ========================= +// Serialize implementations +// ========================= + + +struct SerializeWrapper(pub E); + +impl Serialize for SerializeWrapper<&GetSessionTokenError> { + fn serialize(&self, serializer: S) -> Result { + let err = self.0; + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("code", &err.code())?; + map.serialize_entry("msg", &err.message())?; + map.serialize_entry("source", &None::<&str>)?; + map.end() + } +} + + + +impl_serialize_basic!(SetupError); +impl_serialize_basic!(SendResponseError); +impl_serialize_basic!(GetCredentialsError); +impl_serialize_basic!(ClientInfoError); + + +impl Serialize for RequestError { + fn serialize(&self, serializer: S) -> Result { + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("code", self.as_ref())?; + map.serialize_entry("msg", &format!("{self}"))?; + + match self { + RequestError::NoCredentials(src) => map.serialize_entry("source", &src)?, + RequestError::ClientInfo(src) => map.serialize_entry("source", &src)?, + _ => serialize_upstream_err(self, &mut map)?, + } + + map.end() + } +} + + +impl Serialize for GetSessionError { + fn serialize(&self, serializer: S) -> Result { + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("code", self.as_ref())?; + map.serialize_entry("msg", &format!("{self}"))?; + + match self { + GetSessionError::SdkError(AwsSdkError::ServiceError(se_wrapper)) => { + let err = se_wrapper.err(); + map.serialize_entry("source", &SerializeWrapper(err))? + } + _ => serialize_upstream_err(self, &mut map)?, + } + + map.end() + } +} + + +impl Serialize for UnlockError { + fn serialize(&self, serializer: S) -> Result { + let mut map = serializer.serialize_map(None)?; + map.serialize_entry("code", self.as_ref())?; + map.serialize_entry("msg", &format!("{self}"))?; + + match self { + UnlockError::GetSession(src) => map.serialize_entry("source", &src)?, + _ => serialize_upstream_err(self, &mut map)?, + } + map.end() + } +} diff --git a/src-tauri/src/ipc.rs b/src-tauri/src/ipc.rs index 0bff596..e06cfd2 100644 --- a/src-tauri/src/ipc.rs +++ b/src-tauri/src/ipc.rs @@ -36,10 +36,8 @@ pub fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Res #[tauri::command] -pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), SerializeError> { - app_state.decrypt(&passphrase) - .await - .map_err(|e| SerializeError::from(e)) +pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), UnlockError> { + app_state.decrypt(&passphrase).await } @@ -59,10 +57,8 @@ pub async fn save_credentials( credentials: Credentials, passphrase: String, app_state: State<'_, AppState> -) -> Result<(), SerializeError> { - app_state.save_creds(credentials, &passphrase) - .await - .map_err(|e| SerializeError::from(e)) +) -> Result<(), UnlockError> { + app_state.save_creds(credentials, &passphrase).await } diff --git a/src/views/EnterCredentials.svelte b/src/views/EnterCredentials.svelte index f3f2fe0..817e378 100644 --- a/src/views/EnterCredentials.svelte +++ b/src/views/EnterCredentials.svelte @@ -1,41 +1,42 @@ -{#if error} -
{error}
+{#if errorMsg} +
{errorMsg}
{/if}
diff --git a/src/views/Unlock.svelte b/src/views/Unlock.svelte index 5171d46..87de5aa 100644 --- a/src/views/Unlock.svelte +++ b/src/views/Unlock.svelte @@ -1,13 +1,14 @@ -{#if error} -
{error}
+{#if errorMsg} +
{errorMsg}
{/if}