From 856b6f1e1b33ea1d710c1689c0f306284da91ef8 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Wed, 21 Dec 2022 11:01:34 -0800 Subject: [PATCH] use thiserror for errors --- src-tauri/Cargo.lock | 9 +- src-tauri/Cargo.toml | 1 + src-tauri/src/clientinfo.rs | 2 +- src-tauri/src/errors.rs | 177 ++++++++++-------------------------- 4 files changed, 56 insertions(+), 133 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2fc5bc5..0696848 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -80,6 +80,7 @@ dependencies = [ "sysinfo", "tauri", "tauri-build", + "thiserror", "tokio", ] @@ -3874,18 +3875,18 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 7a7fdd7..cb6be0d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,6 +27,7 @@ aws-types = "0.52.0" aws-sdk-sts = "0.22.0" aws-smithy-types = "0.52.0" aws-config = "0.52.0" +thiserror = "1.0.38" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/clientinfo.rs b/src-tauri/src/clientinfo.rs index c0ae19f..d164105 100644 --- a/src-tauri/src/clientinfo.rs +++ b/src-tauri/src/clientinfo.rs @@ -45,7 +45,7 @@ pub fn get_clients(local_port: u16) -> Result>, ClientInfoErr let pid = Pid::from_u32(p); sys.refresh_process(pid); let proc = sys.process(pid) - .ok_or(ClientInfoError::PidNotFound)?; + .ok_or(ClientInfoError::ProcessNotFound)?; let client = Client { pid: p, diff --git a/src-tauri/src/errors.rs b/src-tauri/src/errors.rs index 5abd6e4..d00625a 100644 --- a/src-tauri/src/errors.rs +++ b/src-tauri/src/errors.rs @@ -2,6 +2,11 @@ use std::fmt::{Display, Formatter}; use std::convert::From; use std::str::Utf8Error; +use thiserror::Error; +use aws_sdk_sts::{ + types::SdkError as AwsSdkError, + error::GetSessionTokenError, +}; use sqlx::{ error::Error as SqlxError, migrate::MigrateError, @@ -9,172 +14,88 @@ use sqlx::{ // error during initial setup (primarily loading state from db) +#[derive(Debug, Error)] pub enum SetupError { + #[error("Invalid database record")] InvalidRecord, // e.g. wrong size blob for nonce or salt - DbError(SqlxError), -} -impl From for SetupError { - fn from(e: SqlxError) -> SetupError { - SetupError::DbError(e) - } -} -impl From for SetupError { - fn from (e: MigrateError) -> SetupError { - SetupError::DbError(SqlxError::from(e)) - } -} -impl Display for SetupError { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - match self { - SetupError::InvalidRecord => write!(f, "Malformed database record"), - SetupError::DbError(e) => write!(f, "Error from database: {e}"), - } - } + #[error("Error from database: {0}")] + DbError(#[from] SqlxError), + #[error("Error running migrations: {0}")] + MigrationError(#[from] MigrateError) } -// error when attempting to tell a request handler whether to release or deny crednetials +// error when attempting to tell a request handler whether to release or deny credentials +#[derive(Debug, Error)] pub enum SendResponseError { + #[error("The specified credentials request was not found")] NotFound, // no request with the given id + #[error("The specified request was already closed by the client")] Abandoned, // request has already been closed by client } -impl Display for SendResponseError { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - use SendResponseError::*; - match self { - NotFound => write!(f, "The specified command was not found."), - Abandoned => write!(f, "The specified request was closed by the client."), - } - } -} - // errors encountered while handling an HTTP request +#[derive(Debug, Error)] pub enum RequestError { - StreamIOError(std::io::Error), + #[error("Error writing to stream: {0}")] + StreamIOError(#[from] std::io::Error), + #[error("Received invalid UTF-8 in request")] InvalidUtf8, - MalformedHttpRequest, + // MalformedHttpRequest, + #[error("HTTP request too large")] RequestTooLarge, - NoCredentials(GetCredentialsError), - ClientInfo(ClientInfoError), - Tauri(tauri::Error), + #[error("Error accessing credentials: {0}")] + NoCredentials(#[from] GetCredentialsError), + #[error("Error getting client details: {0}")] + ClientInfo(#[from] ClientInfoError), + #[error("Error from Tauri: {0}")] + Tauri(#[from] tauri::Error), + #[error("No main application window found")] NoMainWindow, } -impl From for RequestError { - fn from(e: std::io::Error) -> RequestError { - RequestError::StreamIOError(e) - } -} -impl From for RequestError { - fn from(_e: Utf8Error) -> RequestError { - RequestError::InvalidUtf8 - } -} -impl From for RequestError { - fn from (e: GetCredentialsError) -> RequestError { - RequestError::NoCredentials(e) - } -} -impl From for RequestError { - fn from(e: ClientInfoError) -> RequestError { - RequestError::ClientInfo(e) - } -} -impl From for RequestError { - fn from(e: tauri::Error) -> RequestError { - RequestError::Tauri(e) - } -} - -impl Display for RequestError { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - use RequestError::*; - match self { - StreamIOError(e) => write!(f, "Stream IO error: {e}"), - InvalidUtf8 => write!(f, "Could not decode UTF-8 from bytestream"), - MalformedHttpRequest => write!(f, "Maformed HTTP request"), - RequestTooLarge => write!(f, "HTTP request too large"), - NoCredentials(GetCredentialsError::Locked) => write!(f, "Recieved go-ahead but app is locked"), - NoCredentials(GetCredentialsError::Empty) => write!(f, "Received go-ahead but no credentials are known"), - ClientInfo(ClientInfoError::PidNotFound) => write!(f, "Could not resolve PID of client process."), - ClientInfo(ClientInfoError::NetstatError(e)) => write!(f, "Error getting client socket details: {e}"), - Tauri(e) => write!(f, "Tauri error: {e}"), - NoMainWindow => write!(f, "No main application window found"), - } - } -} +#[derive(Debug, Error)] pub enum GetCredentialsError { + #[error("Credentials are currently locked")] Locked, + #[error("No credentials are known")] Empty, } -pub type AwsTokenError = aws_sdk_sts::types::SdkError; +#[derive(Debug, Error)] pub enum GetSessionError { + #[error("Request completed successfully but no credentials were returned")] NoCredentials, // SDK returned successfully but credentials are None - SdkError(AwsTokenError), -} -impl From for GetSessionError { - fn from(e: AwsTokenError) -> GetSessionError { - GetSessionError::SdkError(e) - } -} -impl Display for GetSessionError { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - match self { - GetSessionError::NoCredentials => write!(f, "Request completed successfully but no credentials were returned"), - GetSessionError::SdkError(e) => write!(f, "Error response from AWS: {e}") - } - } + #[error("Error response from AWS SDK: {0}")] + SdkError(#[from] AwsSdkError), } +#[derive(Debug, Error)] pub enum UnlockError { + #[error("App is not locked")] NotLocked, + #[error("No saved credentials were found")] NoCredentials, + #[error("Invalid passphrase")] BadPassphrase, + #[error("Data was found to be corrupt after decryption")] InvalidUtf8, // Somehow we got invalid utf-8 even though decryption succeeded - DbError(SqlxError), - GetSession(GetSessionError), -} -impl From for UnlockError { - fn from (e: SqlxError) -> UnlockError { - match e { - SqlxError::RowNotFound => UnlockError::NoCredentials, - _ => UnlockError::DbError(e), - } - } -} -impl From for UnlockError { - fn from(e: GetSessionError) -> UnlockError { - UnlockError::GetSession(e) - } -} -impl Display for UnlockError { - fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> { - use UnlockError::*; - match self { - NotLocked => write!(f, "App is not locked"), - NoCredentials => write!(f, "No saved credentials were found"), - BadPassphrase => write!(f, "Invalid passphrase"), - InvalidUtf8 => write!(f, "Decrypted data was corrupted"), - DbError(e) => write!(f, "Database error: {e}"), - GetSession(e) => write!(f, "Failed to create AWS session: {e}") - } - } + #[error("Database error: {0}")] + DbError(#[from] SqlxError), + #[error("Failed to create AWS session: {0}")] + GetSession(#[from] GetSessionError), } // Errors encountered while trying to figure out who's on the other end of a request +#[derive(Debug, Error)] pub enum ClientInfoError { - PidNotFound, - NetstatError(netstat2::error::Error), -} -impl From for ClientInfoError { - fn from(e: netstat2::error::Error) -> ClientInfoError { - ClientInfoError::NetstatError(e) - } + #[error("Found PID for client socket, but no corresponding process")] + ProcessNotFound, + #[error("Couldn't get client socket details: {0}")] + NetstatError(#[from] netstat2::error::Error), }