diff --git a/src-tauri/src/ipc.rs b/src-tauri/src/ipc.rs index dbbb613..1b72d6b 100644 --- a/src-tauri/src/ipc.rs +++ b/src-tauri/src/ipc.rs @@ -4,7 +4,7 @@ use tauri::State; use crate::errors::*; use crate::config::AppConfig; use crate::clientinfo::Client; -use crate::state::{AppState, Session, Credentials}; +use crate::state::{AppState, Session, BaseCredentials}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -37,7 +37,7 @@ pub fn respond(response: RequestResponse, app_state: State<'_, AppState>) -> Res #[tauri::command] pub async fn unlock(passphrase: String, app_state: State<'_, AppState>) -> Result<(), UnlockError> { - app_state.decrypt(&passphrase).await + app_state.unlock(&passphrase).await } @@ -46,7 +46,7 @@ pub fn get_session_status(app_state: State<'_, AppState>) -> String { let session = app_state.session.read().unwrap(); match *session { Session::Locked(_) => "locked".into(), - Session::Unlocked(_) => "unlocked".into(), + Session::Unlocked{..} => "unlocked".into(), Session::Empty => "empty".into() } } @@ -54,7 +54,7 @@ pub fn get_session_status(app_state: State<'_, AppState>) -> String { #[tauri::command] pub async fn save_credentials( - credentials: Credentials, + credentials: BaseCredentials, passphrase: String, app_state: State<'_, AppState> ) -> Result<(), UnlockError> { diff --git a/src-tauri/src/server.rs b/src-tauri/src/server.rs index 1e10e22..ffca72a 100644 --- a/src-tauri/src/server.rs +++ b/src-tauri/src/server.rs @@ -157,7 +157,7 @@ impl Handler { async fn send_credentials(&mut self) -> Result<(), RequestError> { let state = self.app.state::(); - let creds = state.get_creds_serialized()?; + let creds = state.serialize_session_creds()?; self.stream.write(b"\r\nContent-Length: ").await?; self.stream.write(creds.as_bytes().len().to_string().as_bytes()).await?; diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index a53a958..e36f7af 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -23,20 +23,19 @@ use crate::server::Server; #[derive(Debug, Serialize, Deserialize)] -#[serde(untagged)] -pub enum Credentials { - #[serde(rename_all = "PascalCase")] - LongLived { - access_key_id: String, - secret_access_key: String, - }, - #[serde(rename_all = "PascalCase")] - ShortLived { - access_key_id: String, - secret_access_key: String, - token: String, - expiration: String, - }, +#[serde(rename_all = "PascalCase")] +pub struct BaseCredentials { + access_key_id: String, + secret_access_key: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct SessionCredentials { + access_key_id: String, + secret_access_key: String, + token: String, + expiration: String, } @@ -51,7 +50,10 @@ pub struct LockedCredentials { #[derive(Debug)] pub enum Session { - Unlocked(Credentials), + Unlocked{ + base: BaseCredentials, + session: SessionCredentials, + }, Locked(LockedCredentials), Empty, } @@ -106,16 +108,11 @@ impl AppState { Ok(Session::Locked(creds)) } - pub async fn save_creds(&self, creds: Credentials, passphrase: &str) -> Result<(), UnlockError> { - let (key_id, secret_key) = match creds { - Credentials::LongLived {access_key_id, secret_access_key} => { - (access_key_id, secret_access_key) - }, - _ => unreachable!(), - }; + pub async fn save_creds(&self, creds: BaseCredentials, passphrase: &str) -> Result<(), UnlockError> { + let BaseCredentials {access_key_id, secret_access_key} = creds; // do this first so that if it fails we don't save bad credentials - self.new_session(&key_id, &secret_key).await?; + self.new_session(&access_key_id, &secret_access_key).await?; let salt = pwhash::gen_salt(); let mut key_buf = [0; secretbox::KEYBYTES]; @@ -124,14 +121,14 @@ impl AppState { // not sure we need both salt AND nonce given that we generate a // fresh salt every time we encrypt, but better safe than sorry let nonce = secretbox::gen_nonce(); - let secret_key_enc = secretbox::seal(secret_key.as_bytes(), &nonce, &key); + let secret_key_enc = secretbox::seal(secret_access_key.as_bytes(), &nonce, &key); sqlx::query( "INSERT INTO credentials (access_key_id, secret_key_enc, salt, nonce, created_at) VALUES (?, ?, ?, ?, strftime('%s'))" ) - .bind(&key_id) + .bind(&access_key_id) .bind(&secret_key_enc) .bind(&salt.0[0..]) .bind(&nonce.0[0..]) @@ -210,13 +207,13 @@ impl AppState { self.bans.read().unwrap().contains(&client) } - pub async fn decrypt(&self, passphrase: &str) -> Result<(), UnlockError> { - let (key_id, secret) = { + pub async fn unlock(&self, passphrase: &str) -> Result<(), UnlockError> { + let (access_key_id, secret_access_key) = { // do this all in a block so that we aren't holding a lock across an await let session = self.session.read().unwrap(); let locked = match *session { Session::Empty => {return Err(UnlockError::NoCredentials);}, - Session::Unlocked(_) => {return Err(UnlockError::NotLocked);}, + Session::Unlocked{..} => {return Err(UnlockError::NotLocked);}, Session::Locked(ref c) => c, }; @@ -230,21 +227,35 @@ impl AppState { (locked.access_key_id.clone(), secret_str) }; - self.new_session(&key_id, &secret).await?; + let session_creds = self.new_session(&access_key_id, &secret_access_key).await?; + let mut app_session = self.session.write().unwrap(); + *app_session = Session::Unlocked { + base: BaseCredentials {access_key_id, secret_access_key}, + session: session_creds + }; Ok(()) } - pub fn get_creds_serialized(&self) -> Result { + // pub fn serialize_base_creds(&self) -> Result { + // let session = self.session.read().unwrap(); + // match *session { + // Session::Unlocked{ref base, ..} => Ok(serde_json::to_string(base).unwrap()), + // Session::Locked(_) => Err(GetCredentialsError::Locked), + // Session::Empty => Err(GetCredentialsError::Empty), + // } + // } + + pub fn serialize_session_creds(&self) -> Result { let session = self.session.read().unwrap(); match *session { - Session::Unlocked(ref creds) => Ok(serde_json::to_string(creds).unwrap()), + Session::Unlocked{ref session, ..} => Ok(serde_json::to_string(session).unwrap()), Session::Locked(_) => Err(GetCredentialsError::Locked), Session::Empty => Err(GetCredentialsError::Empty), } } - async fn new_session(&self, key_id: &str, secret_key: &str) -> Result<(), GetSessionError> { + async fn new_session(&self, key_id: &str, secret_key: &str) -> Result { let creds = aws_sdk_sts::Credentials::new( key_id, secret_key, @@ -279,8 +290,7 @@ impl AppState { .fmt(aws_smithy_types::date_time::Format::DateTime) .unwrap(); // only fails if the d/t is out of range, which it can't be for this format - let mut app_session = self.session.write().unwrap(); - let session_creds = Credentials::ShortLived { + let session_creds = SessionCredentials { access_key_id, secret_access_key, token, @@ -290,8 +300,6 @@ impl AppState { #[cfg(debug_assertions)] println!("Got new session:\n{}", serde_json::to_string(&session_creds).unwrap()); - *app_session = Session::Unlocked(session_creds); - - Ok(()) + Ok(session_creds) } } diff --git a/src/App.svelte b/src/App.svelte index f0d2db5..4f0d979 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -7,7 +7,6 @@ import { appState, acceptRequest } from './lib/state.js'; import { views, currentView, navigate } from './lib/routing.js'; - $views = import.meta.glob('./views/*.svelte', {eager: true}); navigate('Home'); @@ -17,11 +16,6 @@ listen('credentials-request', (tauriEvent) => { $appState.pendingRequests.put(tauriEvent.payload); }); - -// $appState.pendingRequests.get().then(req => { -// $appState.currentRequest = req; -// }) -appState.subscribe($s => window.state = $s); acceptRequest();