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