return structured errors from commands (wip)
This commit is contained in:
parent
2943634248
commit
df6b362a31
@ -9,40 +9,24 @@ use crate::errors::*;
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
pub db_path: PathBuf,
|
#[serde(default = "default_listen_addr")]
|
||||||
pub listen_addr: Ipv4Addr,
|
pub listen_addr: Ipv4Addr,
|
||||||
|
#[serde(default = "default_listen_port")]
|
||||||
pub listen_port: u16,
|
pub listen_port: u16,
|
||||||
|
#[serde(default = "default_rehide_ms")]
|
||||||
pub rehide_ms: u64,
|
pub rehide_ms: u64,
|
||||||
}
|
#[serde(default = "default_start_minimized")]
|
||||||
|
pub start_minimized: bool,
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DbAppConfig {
|
|
||||||
listen_addr: Option<Ipv4Addr>,
|
|
||||||
listen_port: Option<u16>,
|
|
||||||
rehide_ms: Option<u64>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Default for AppConfig {
|
impl Default for AppConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
AppConfig {
|
AppConfig {
|
||||||
db_path: get_or_create_db_path(),
|
listen_addr: default_listen_addr(),
|
||||||
listen_addr: Ipv4Addr::LOCALHOST,
|
listen_port: default_listen_port(),
|
||||||
listen_port: listen_port(),
|
rehide_ms: default_rehide_ms(),
|
||||||
rehide_ms: 1000,
|
start_minimized: default_start_minimized(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl From<DbAppConfig> for AppConfig {
|
|
||||||
fn from(db_config: DbAppConfig) -> Self {
|
|
||||||
AppConfig {
|
|
||||||
db_path: get_or_create_db_path(),
|
|
||||||
listen_addr: db_config.listen_addr.unwrap_or(Ipv4Addr::LOCALHOST),
|
|
||||||
listen_port: db_config.listen_port.unwrap_or_else(|| listen_port()),
|
|
||||||
rehide_ms: db_config.rehide_ms.unwrap_or(1000),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,18 +42,7 @@ pub async fn load(pool: &SqlitePool) -> Result<AppConfig, SetupError> {
|
|||||||
None => return Ok(AppConfig::default()),
|
None => return Ok(AppConfig::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let db_config: DbAppConfig = serde_json::from_str(&row.data)?;
|
Ok(serde_json::from_str(&row.data)?)
|
||||||
Ok(AppConfig::from(db_config))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn listen_port() -> u16 {
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
12_345
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
19_923
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -89,3 +62,19 @@ pub fn get_or_create_db_path() -> PathBuf {
|
|||||||
parent.push("creddy.db");
|
parent.push("creddy.db");
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn default_listen_port() -> u16 {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
12_345
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
19_923
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }
|
||||||
|
|
||||||
|
fn default_rehide_ms() -> u64 { 1000 }
|
||||||
|
|
||||||
|
fn default_start_minimized() -> bool { true }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error as ThisError;
|
||||||
|
|
||||||
use aws_sdk_sts::{
|
use aws_sdk_sts::{
|
||||||
types::SdkError as AwsSdkError,
|
types::SdkError as AwsSdkError,
|
||||||
@ -9,9 +9,34 @@ use sqlx::{
|
|||||||
migrate::MigrateError,
|
migrate::MigrateError,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer, ser::SerializeMap};
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SerializeError<E> {
|
||||||
|
pub err: E
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: std::error::Error> Serialize for SerializeError<E> {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
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<E: std::error::Error> From<E> for SerializeError<E> {
|
||||||
|
fn from(err: E) -> Self {
|
||||||
|
SerializeError { err }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// error during initial setup (primarily loading state from db)
|
// error during initial setup (primarily loading state from db)
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum SetupError {
|
pub enum SetupError {
|
||||||
#[error("Invalid database record")]
|
#[error("Invalid database record")]
|
||||||
InvalidRecord, // e.g. wrong size blob for nonce or salt
|
InvalidRecord, // e.g. wrong size blob for nonce or salt
|
||||||
@ -25,7 +50,7 @@ pub enum SetupError {
|
|||||||
|
|
||||||
|
|
||||||
// error when attempting to tell a request handler whether to release or deny credentials
|
// error when attempting to tell a request handler whether to release or deny credentials
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum SendResponseError {
|
pub enum SendResponseError {
|
||||||
#[error("The specified credentials request was not found")]
|
#[error("The specified credentials request was not found")]
|
||||||
NotFound, // no request with the given id
|
NotFound, // no request with the given id
|
||||||
@ -35,12 +60,12 @@ pub enum SendResponseError {
|
|||||||
|
|
||||||
|
|
||||||
// errors encountered while handling an HTTP request
|
// errors encountered while handling an HTTP request
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum RequestError {
|
pub enum RequestError {
|
||||||
#[error("Error writing to stream: {0}")]
|
#[error("Error writing to stream: {0}")]
|
||||||
StreamIOError(#[from] std::io::Error),
|
StreamIOError(#[from] std::io::Error),
|
||||||
#[error("Received invalid UTF-8 in request")]
|
// #[error("Received invalid UTF-8 in request")]
|
||||||
InvalidUtf8,
|
// InvalidUtf8,
|
||||||
// MalformedHttpRequest,
|
// MalformedHttpRequest,
|
||||||
#[error("HTTP request too large")]
|
#[error("HTTP request too large")]
|
||||||
RequestTooLarge,
|
RequestTooLarge,
|
||||||
@ -55,7 +80,7 @@ pub enum RequestError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum GetCredentialsError {
|
pub enum GetCredentialsError {
|
||||||
#[error("Credentials are currently locked")]
|
#[error("Credentials are currently locked")]
|
||||||
Locked,
|
Locked,
|
||||||
@ -64,7 +89,7 @@ pub enum GetCredentialsError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum GetSessionError {
|
pub enum GetSessionError {
|
||||||
#[error("Request completed successfully but no credentials were returned")]
|
#[error("Request completed successfully but no credentials were returned")]
|
||||||
NoCredentials, // SDK returned successfully but credentials are None
|
NoCredentials, // SDK returned successfully but credentials are None
|
||||||
@ -73,7 +98,7 @@ pub enum GetSessionError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum UnlockError {
|
pub enum UnlockError {
|
||||||
#[error("App is not locked")]
|
#[error("App is not locked")]
|
||||||
NotLocked,
|
NotLocked,
|
||||||
@ -91,7 +116,7 @@ pub enum UnlockError {
|
|||||||
|
|
||||||
|
|
||||||
// Errors encountered while trying to figure out who's on the other end of a request
|
// Errors encountered while trying to figure out who's on the other end of a request
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, ThisError)]
|
||||||
pub enum ClientInfoError {
|
pub enum ClientInfoError {
|
||||||
#[error("Found PID for client socket, but no corresponding process")]
|
#[error("Found PID for client socket, but no corresponding process")]
|
||||||
ProcessNotFound,
|
ProcessNotFound,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
use crate::clientinfo::Client;
|
use crate::clientinfo::Client;
|
||||||
use crate::state::{AppState, Session, Credentials};
|
use crate::state::{AppState, Session, Credentials};
|
||||||
@ -35,10 +36,10 @@ pub fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Res
|
|||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), String> {
|
pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), SerializeError<UnlockError>> {
|
||||||
app_state.decrypt(&passphrase)
|
app_state.decrypt(&passphrase)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| SerializeError::from(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -58,10 +59,10 @@ pub async fn save_credentials(
|
|||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
app_state: State<'_, AppState>
|
app_state: State<'_, AppState>
|
||||||
) -> Result<(), String> {
|
) -> Result<(), SerializeError<UnlockError>> {
|
||||||
app_state.save_creds(credentials, &passphrase)
|
app_state.save_creds(credentials, &passphrase)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {eprintln!("{e:?}"); e.to_string()})
|
.map_err(|e| SerializeError::from(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
use tauri::{AppHandle, Manager};
|
use tauri::{AppHandle, Manager, async_runtime as rt};
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
@ -14,13 +14,14 @@ mod state;
|
|||||||
mod server;
|
mod server;
|
||||||
mod tray;
|
mod tray;
|
||||||
|
|
||||||
|
use crate::errors::*;
|
||||||
use state::AppState;
|
use state::AppState;
|
||||||
|
|
||||||
|
|
||||||
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
pub static APP: OnceCell<AppHandle> = OnceCell::new();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let initial_state = match state::AppState::new() {
|
let initial_state = match rt::block_on(state::AppState::load()) {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(e) => {eprintln!("{}", e); return;}
|
Err(e) => {eprintln!("{}", e); return;}
|
||||||
};
|
};
|
||||||
@ -42,6 +43,12 @@ fn main() {
|
|||||||
let config = state.config.read().unwrap();
|
let config = state.config.read().unwrap();
|
||||||
let addr = std::net::SocketAddrV4::new(config.listen_addr, config.listen_port);
|
let addr = std::net::SocketAddrV4::new(config.listen_addr, config.listen_port);
|
||||||
tauri::async_runtime::spawn(server::serve(addr, app.handle()));
|
tauri::async_runtime::spawn(server::serve(addr, app.handle()));
|
||||||
|
|
||||||
|
if !config.start_minimized {
|
||||||
|
app.get_window("main")
|
||||||
|
.ok_or(RequestError::NoMainWindow)?
|
||||||
|
.show()?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.build(tauri::generate_context!())
|
.build(tauri::generate_context!())
|
||||||
|
@ -67,16 +67,16 @@ pub struct AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
pub fn new() -> Result<Self, SetupError> {
|
pub async fn load() -> Result<Self, SetupError> {
|
||||||
let conn_opts = SqliteConnectOptions::new()
|
let conn_opts = SqliteConnectOptions::new()
|
||||||
.filename(config::get_or_create_db_path())
|
.filename(config::get_or_create_db_path())
|
||||||
.create_if_missing(true);
|
.create_if_missing(true);
|
||||||
let pool_opts = SqlitePoolOptions::new();
|
let pool_opts = SqlitePoolOptions::new();
|
||||||
|
|
||||||
let pool: SqlitePool = runtime::block_on(pool_opts.connect_with(conn_opts))?;
|
let pool: SqlitePool = pool_opts.connect_with(conn_opts).await?;
|
||||||
runtime::block_on(sqlx::migrate!().run(&pool))?;
|
sqlx::migrate!().run(&pool).await?;
|
||||||
let creds = runtime::block_on(Self::load_creds(&pool))?;
|
let creds = Self::load_creds(&pool).await?;
|
||||||
let conf = runtime::block_on(config::load(&pool))?;
|
let conf = config::load(&pool).await?;
|
||||||
|
|
||||||
let state = AppState {
|
let state = AppState {
|
||||||
config: RwLock::new(conf),
|
config: RwLock::new(conf),
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
|
window.error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,6 @@
|
|||||||
onMount(async() => {
|
onMount(async() => {
|
||||||
status = await invoke('get_session_status');
|
status = await invoke('get_session_status');
|
||||||
})
|
})
|
||||||
|
|
||||||
function blah() {
|
|
||||||
console.log('blah');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1 class="text-4xl text-gray-300">Creddy</h1>
|
<h1 class="text-4xl text-gray-300">Creddy</h1>
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
|
window.error = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user