store base credentials as well as session credentials
This commit is contained in:
parent
760987f09b
commit
161148d1f6
@ -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> {
|
||||
|
@ -157,7 +157,7 @@ impl Handler {
|
||||
|
||||
async fn send_credentials(&mut self) -> Result<(), RequestError> {
|
||||
let state = self.app.state::<AppState>();
|
||||
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?;
|
||||
|
@ -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<String, GetCredentialsError> {
|
||||
// pub fn serialize_base_creds(&self) -> Result<String, GetCredentialsError> {
|
||||
// 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<String, GetCredentialsError> {
|
||||
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<SessionCredentials, GetSessionError> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
</script>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user