diff --git a/src-tauri/src/http/mod.rs b/src-tauri/src/http/mod.rs index 0fe73d0..035c164 100644 --- a/src-tauri/src/http/mod.rs +++ b/src-tauri/src/http/mod.rs @@ -23,7 +23,7 @@ pub async fn serve(addr: SocketAddrV4, app_handle: AppHandle) -> io::Result<()> }); }, Err(e) => { - println!("Error accepting connection: {e}"); + eprintln!("Error accepting connection: {e}"); } } } @@ -73,27 +73,33 @@ use tokio::io::{stdin, stdout, BufReader, AsyncBufReadExt}; use crate::storage; use tokio::sync::oneshot; +use std::sync::Mutex; async fn get_creds(app_handle: &AppHandle) -> io::Result { - app_handle.emit_all("credentials-request", ()).unwrap(); - - // let mut out = stdout(); - // out.write_all(b"Enter passphrase: ").await?; - // out.flush().await?; + { + let state_guard = app_handle.state::>(); + let mut state = state_guard.lock().unwrap(); + state.num_requests += 1; + let req = crate::CredentialsRequest { + request_id: state.num_requests + }; + app_handle.emit_all("credentials-request", req).unwrap(); + // lock gets released here in case somebody else needs app state while we're waiting + } let (tx, rx) = oneshot::channel(); - app_handle.once_global("passphrase-entered", |event| { - match event.payload() { - Some(p) => {tx.send(p.to_string());} - None => {tx.send("".to_string());} // will fail decryption, we just need to unblock the outer function - } + app_handle.once_global("request-response", |event| { + let response = event.payload().unwrap_or("").to_string(); + tx.send(response).unwrap(); }); // Error is only returned if the rx is closed/dropped before receiving, which should never happen - let passphrase = rx.await.unwrap(); + // LOL who am I kidding this happens all the time + // fix it later + + // todo: handle "denied" response + let _response = rx.await.unwrap(); + let state_guard = app_handle.state::>(); + let state = state_guard.lock().unwrap(); - // let mut passphrase = String::new(); - // let mut reader = BufReader::new(stdin()); - // reader.read_line(&mut passphrase).await?; - - Ok(storage::load(&passphrase.trim())) + Ok(state.current_session.clone().unwrap()) } diff --git a/src-tauri/src/ipc.rs b/src-tauri/src/ipc.rs new file mode 100644 index 0000000..e353283 --- /dev/null +++ b/src-tauri/src/ipc.rs @@ -0,0 +1,10 @@ +pub enum RequestResponse { + Approved, + Denied, +} + + +pub struct Request { + pub id: u64, + pub response: RequestResponse, +} \ No newline at end of file diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e7cadf7..f61b328 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,15 +3,25 @@ windows_subsystem = "windows" )] +use std::collections::HashMap; use std::str::FromStr; +use std::sync::Mutex; // use tokio::runtime::Runtime; +use serde::{Serialize, Deserialize}; +use tauri::{Manager, State}; +use tokio::sync::oneshot; + mod storage; mod http; fn main() { tauri::Builder::default() + .manage(CurrentSession) + .manage(RequestCount) + .manage(OpenRequests) + .invoke_handler(tauri::generate_handler![unlock]) .setup(|app| { let addr = std::net::SocketAddrV4::from_str("127.0.0.1:12345").unwrap(); tauri::async_runtime::spawn(http::serve(addr, app.handle())); @@ -28,3 +38,35 @@ fn main() { // let creds = std::fs::read_to_string("credentials.json").unwrap(); // storage::save(&creds, "correct horse battery staple"); } + +#[derive(Serialize, Deserialize)] +pub enum Session { + Unlocked(String), + Locked, + Empty, +} + +type CurrentSession = Mutex; +type RequestCount = Mutex; +type OpenRequests = Mutex>; + +#[derive(Clone, Serialize, Deserialize)] +pub struct CredentialsRequest { + pub request_id: u64, +} + + +// struct Session { +// key_id: String, +// secret_key: String, +// token: String, +// expires: u64, +// } + + +#[tauri::command] +fn unlock(passphrase: String, current_session: State<'_, CurrentSession>) -> bool { + let credentials = storage::load(&passphrase); + *current_session.lock().unwrap() = CredentialStatus::Unlocked(credentials); + true +} diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs new file mode 100644 index 0000000..29e3506 --- /dev/null +++ b/src-tauri/src/state.rs @@ -0,0 +1,74 @@ +use std::sync::RwLock; + +use serde::{Serialize, Deserialize}; +use tokio::sync::oneshot::Sender; + +use crate::ipc; + + +#[derive(Serialize, Deserialize)] +pub enum Credentials { + LongLived { + key_id: String, + secret_key: String, + }, + ShortLived { + key_id: String, + secret_key: String, + session_token: String, + }, +} + + +#[derive(Serialize, Deserialize)] +pub enum CurrentSession { + Unlocked(String), + Locked, + Empty, +} + + +pub struct AppState { + current_session: RwLock, + request_count: RwLock, + open_requests: RwLock>, +} + +impl AppState { + pub fn new(current_session: CurrentSession) -> Self { + AppState { + current_session, + request_count: 0, + open_requests: HashMap::new(), + } + } + + pub fn register_request(&mut self, chan: Sender) -> u64 { + let count = { + let c = self.request_count.write().unwrap(); + *c += 1; + c + }; + + let open_requests = self.open_requests.write().unwrap(); + self.open_requests.insert(count, chan); + count + } + + pub fn send_response(&mut self, req_id: u64, response: ipc::RequestResponse) -> Result<(), SendResponseError> { + let mut open_requests = self.open_requests.write().unwrap(); + let chan = self.open_requests + .remove(&req_id) + .ok_or(SendResponseError::NotFound) + ?; + + chan.send(response) + .map_err(|_e| SendResponseError::Abandoned) + } +} + + +pub enum SendResponseError { + NotFound, // no request with the given id + Abandoned, // request has already been closed by client +} diff --git a/src/App.svelte b/src/App.svelte index 1b020af..da5875f 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -1,33 +1,36 @@ -{#if currentView === Home} - -{:else} - -{/if} + diff --git a/src/views/Approve.svelte b/src/views/Approve.svelte index 0e73f58..0587c67 100644 --- a/src/views/Approve.svelte +++ b/src/views/Approve.svelte @@ -1,10 +1,18 @@

Creddy

\ No newline at end of file diff --git a/src/views/ShowApproved.svelte b/src/views/ShowApproved.svelte index b87e2f1..d7d7e19 100644 --- a/src/views/ShowApproved.svelte +++ b/src/views/ShowApproved.svelte @@ -1,5 +1,14 @@ diff --git a/src/views/ShowDenied.svelte b/src/views/ShowDenied.svelte index 86d3d4a..310f261 100644 --- a/src/views/ShowDenied.svelte +++ b/src/views/ShowDenied.svelte @@ -1,5 +1,12 @@ diff --git a/src/views/Unlock.svelte b/src/views/Unlock.svelte new file mode 100644 index 0000000..0c1ad4c --- /dev/null +++ b/src/views/Unlock.svelte @@ -0,0 +1,29 @@ + + +
+
Enter your passphrase:
+ +