display client info and unlock errors to user

This commit is contained in:
Joseph Montanaro 2022-12-21 13:42:12 -08:00
parent 69475604c0
commit 50f0985f4f
8 changed files with 95 additions and 27 deletions

View File

@ -26,7 +26,7 @@ fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Err
}; };
if proto_info.local_port == local_port if proto_info.local_port == local_port
&& proto_info.remote_port == 12345 && proto_info.remote_port == 19_923
&& proto_info.local_addr == std::net::Ipv4Addr::LOCALHOST && proto_info.local_addr == std::net::Ipv4Addr::LOCALHOST
&& proto_info.remote_addr == std::net::Ipv4Addr::LOCALHOST && proto_info.remote_addr == std::net::Ipv4Addr::LOCALHOST
{ {

37
src-tauri/src/config.rs Normal file
View File

@ -0,0 +1,37 @@
use std::net::Ipv4Addr;
use std::path::PathBuf;
pub struct AppConfig {
pub db_path: PathBuf,
pub listen_addr: Ipv4Addr,
pub listen_port: u16,
}
impl Default for AppConfig {
fn default() -> Self {
AppConfig {
db_path: get_or_create_db_path(),
listen_addr: Ipv4Addr::LOCALHOST,
listen_port: 19_923
}
}
}
fn get_or_create_db_path() -> PathBuf {
if cfg!(debug_assertions) {
return PathBuf::from("./creddy.db");
}
let mut parent = std::env::var("HOME")
.map(|h| {
let mut p = PathBuf::from(h);
p.push(".config");
p
})
.unwrap_or(PathBuf::from("."));
parent.push("creddy.db");
parent
}

View File

@ -1,8 +1,5 @@
use std::fmt::{Display, Formatter};
use std::convert::From;
use std::str::Utf8Error;
use thiserror::Error; use thiserror::Error;
use aws_sdk_sts::{ use aws_sdk_sts::{
types::SdkError as AwsSdkError, types::SdkError as AwsSdkError,
error::GetSessionTokenError, error::GetSessionTokenError,

View File

@ -3,14 +3,17 @@
windows_subsystem = "windows" windows_subsystem = "windows"
)] )]
use std::str::FromStr; use tauri::Manager;
mod config;
mod errors; mod errors;
mod clientinfo; mod clientinfo;
mod ipc; mod ipc;
mod state; mod state;
mod server; mod server;
use state::AppState;
fn main() { fn main() {
let initial_state = match state::AppState::new() { let initial_state = match state::AppState::new() {
@ -27,7 +30,9 @@ fn main() {
ipc::save_credentials, ipc::save_credentials,
]) ])
.setup(|app| { .setup(|app| {
let addr = std::net::SocketAddrV4::from_str("127.0.0.1:12345").unwrap(); let state = app.state::<AppState>();
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())); tauri::async_runtime::spawn(server::serve(addr, app.handle()));
Ok(()) Ok(())
}) })

View File

@ -15,6 +15,7 @@ use sodiumoxide::crypto::{
use tauri::async_runtime as runtime; use tauri::async_runtime as runtime;
use tauri::Manager; use tauri::Manager;
use crate::config::AppConfig;
use crate::ipc; use crate::ipc;
use crate::clientinfo::Client; use crate::clientinfo::Client;
use crate::errors::*; use crate::errors::*;
@ -54,6 +55,7 @@ pub enum Session {
pub struct AppState { pub struct AppState {
pub config: RwLock<AppConfig>,
pub session: RwLock<Session>, pub session: RwLock<Session>,
pub request_count: RwLock<u64>, pub request_count: RwLock<u64>,
pub open_requests: RwLock<HashMap<u64, Sender<ipc::Approval>>>, pub open_requests: RwLock<HashMap<u64, Sender<ipc::Approval>>>,
@ -73,6 +75,7 @@ impl AppState {
let creds = runtime::block_on(Self::load_creds(&pool))?; let creds = runtime::block_on(Self::load_creds(&pool))?;
let state = AppState { let state = AppState {
config: RwLock::new(AppConfig::default()),
session: RwLock::new(creds), session: RwLock::new(creds),
request_count: RwLock::new(0), request_count: RwLock::new(0),
open_requests: RwLock::new(HashMap::new()), open_requests: RwLock::new(HashMap::new()),

View File

@ -34,14 +34,23 @@
<h2 class="text-3xl text-gray-200">An application would like to access your AWS credentials.</h2> <h2 class="text-3xl text-gray-200">An application would like to access your AWS credentials.</h2>
<button on:click={approve}> <div class="text-center">
<ul class="text-gray-200">
{#each appState.currentRequest.clients as client}
<li>PID: {client.pid}</li>
<li>Path: {client.exe}</li>
{/each}
</ul>
<button on:click={approve}>
<svg class="w-32 stroke-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1"> <svg class="w-32 stroke-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg> </svg>
</button> </button>
<button on:click={deny}> <button on:click={deny}>
<svg class="w-32 stroke-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1"> <svg class="w-32 stroke-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
<path stroke-linecap="round" stroke-linejoin="round" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> <path stroke-linecap="round" stroke-linejoin="round" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg> </svg>
</button> </button>
</div>

View File

@ -4,18 +4,31 @@
import { invoke } from '@tauri-apps/api/tauri'; import { invoke } from '@tauri-apps/api/tauri';
export let appState; export let appState;
let error = null;
onMount(async () => { const dispatch = createEventDispatcher();
async function respond() {
let response = { let response = {
id: appState.currentRequest.id, id: appState.currentRequest.id,
approval: 'Approved', approval: 'Approved',
} };
try {
await invoke('respond', {response}); await invoke('respond', {response});
appState.currentRequest = null; appState.currentRequest = null;
}); }
catch (e) {
error = e;
}
const dispatch = createEventDispatcher();
window.setTimeout(() => dispatch('navigate', {target: 'Home'}), 3000); window.setTimeout(() => dispatch('navigate', {target: 'Home'}), 3000);
}
onMount(respond);
</script> </script>
<h1 class="text-4xl text-gray-300">Approved!</h1> {#if error}
<div class="text-red-400">Error attempting to send approval: {error}</div>
{:else}
<h1 class="text-4xl text-gray-300">Approved!</h1>
{/if}

View File

@ -6,6 +6,7 @@
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let error = null;
let passphrase = ''; let passphrase = '';
async function unlock() { async function unlock() {
console.log('invoking unlock command.') console.log('invoking unlock command.')
@ -21,11 +22,14 @@
} }
} }
catch (e) { catch (e) {
console.log('Unlock error:', e); error = e;
} }
} }
</script> </script>
{#if error}
<div class="text-red-400">{error}</div>
{/if}
<form action="#" on:submit|preventDefault="{unlock}"> <form action="#" on:submit|preventDefault="{unlock}">
<div class="text-gray-200">Enter your passphrase:</div> <div class="text-gray-200">Enter your passphrase:</div>
<input autofocus class="text-gray-200 bg-zinc-800" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" /> <input autofocus class="text-gray-200 bg-zinc-800" type="password" placeholder="correct horse battery staple" bind:value="{passphrase}" />