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