fix permissions errors and terminal launching
This commit is contained in:
@ -43,6 +43,8 @@ pub fn run() -> tauri::Result<()> {
|
||||
.error_popup("Failed to show main window")
|
||||
}))
|
||||
.plugin(tauri_plugin_global_shortcut::Builder::default().build())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
ipc::unlock,
|
||||
ipc::lock,
|
||||
@ -60,17 +62,7 @@ pub fn run() -> tauri::Result<()> {
|
||||
ipc::get_setup_errors,
|
||||
ipc::exit,
|
||||
])
|
||||
.setup(|app| {
|
||||
let res = rt::block_on(setup(app));
|
||||
if let Err(ref e) = res {
|
||||
MessageDialog::new()
|
||||
.set_level(MessageLevel::Error)
|
||||
.set_title("Creddy failed to start")
|
||||
.set_description(format!("{e}"))
|
||||
.show();
|
||||
}
|
||||
res
|
||||
})
|
||||
.setup(|app| rt::block_on(setup(app)))
|
||||
.build(tauri::generate_context!())?
|
||||
.run(|app, run_event| {
|
||||
if let RunEvent::WindowEvent { event, .. } = run_event {
|
||||
|
@ -38,10 +38,10 @@ struct CredentialRow {
|
||||
pub struct CredentialRecord {
|
||||
#[serde(serialize_with = "serialize_uuid")]
|
||||
#[serde(deserialize_with = "deserialize_uuid")]
|
||||
id: Uuid, // UUID so it can be generated on the frontend
|
||||
name: String, // user-facing identifier so it can be changed
|
||||
is_default: bool,
|
||||
credential: Credential,
|
||||
pub id: Uuid, // UUID so it can be generated on the frontend
|
||||
pub name: String, // user-facing identifier so it can be changed
|
||||
pub is_default: bool,
|
||||
pub credential: Credential,
|
||||
}
|
||||
|
||||
impl CredentialRecord {
|
||||
|
@ -152,7 +152,8 @@ pub async fn save_config(config: AppConfig, app_state: State<'_, AppState>) -> R
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn launch_terminal(base: bool) -> Result<(), LaunchTerminalError> {
|
||||
terminal::launch(base).await
|
||||
let res = terminal::launch(base).await;
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
|
@ -145,11 +145,11 @@ async fn get_aws_credentials(
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
if response.base {
|
||||
let creds = state.get_aws_base("default").await?;
|
||||
let creds = state.get_aws_default().await?;
|
||||
Ok(Response::AwsBase(creds))
|
||||
}
|
||||
else {
|
||||
let creds = state.get_aws_session("default").await?;
|
||||
let creds = state.get_aws_default_session().await?;
|
||||
Ok(Response::AwsSession(creds.clone()))
|
||||
}
|
||||
},
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::time::Duration;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
@ -21,6 +22,7 @@ use crate::credentials::{
|
||||
use crate::{config, config::AppConfig};
|
||||
use crate::credentials::{
|
||||
AwsBaseCredential,
|
||||
Credential,
|
||||
CredentialRecord,
|
||||
PersistentCredential
|
||||
};
|
||||
@ -107,7 +109,8 @@ impl VisibilityLease {
|
||||
pub struct AppState {
|
||||
pub config: RwLock<AppConfig>,
|
||||
pub app_session: RwLock<AppSession>,
|
||||
pub aws_session: RwLock<Option<AwsSessionCredential>>,
|
||||
// session cache is keyed on id rather than name because names can change
|
||||
pub aws_sessions: RwLock<HashMap<Uuid, AwsSessionCredential>>,
|
||||
pub last_activity: RwLock<OffsetDateTime>,
|
||||
pub request_count: RwLock<u64>,
|
||||
pub waiting_requests: RwLock<HashMap<u64, Sender<RequestResponse>>>,
|
||||
@ -130,7 +133,7 @@ impl AppState {
|
||||
AppState {
|
||||
config: RwLock::new(config),
|
||||
app_session: RwLock::new(app_session),
|
||||
aws_session: RwLock::new(None),
|
||||
aws_sessions: RwLock::new(HashMap::new()),
|
||||
last_activity: RwLock::new(OffsetDateTime::now_utc()),
|
||||
request_count: RwLock::new(0),
|
||||
waiting_requests: RwLock::new(HashMap::new()),
|
||||
@ -261,26 +264,41 @@ impl AppState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_aws_base(&self, name: &str) -> Result<AwsBaseCredential, GetCredentialsError> {
|
||||
pub async fn get_aws_default(&self) -> Result<AwsBaseCredential, GetCredentialsError> {
|
||||
let app_session = self.app_session.read().await;
|
||||
let crypto = app_session.try_get_crypto()?;
|
||||
let creds = AwsBaseCredential::load_by_name(name, crypto, &self.pool).await?;
|
||||
let record = CredentialRecord::load_default("aws", crypto, &self.pool).await?;
|
||||
let creds = match record.credential {
|
||||
Credential::AwsBase(b) => Ok(b),
|
||||
_ => Err(LoadCredentialsError::NoCredentials)
|
||||
}?;
|
||||
Ok(creds)
|
||||
}
|
||||
|
||||
pub async fn get_aws_session(&self, name: &str) -> Result<RwLockReadGuard<'_, AwsSessionCredential>, GetCredentialsError> {
|
||||
// yes, this sometimes results in double-fetching base credentials from disk
|
||||
// I'm done trying to be optimal
|
||||
pub async fn get_aws_default_session(&self) -> Result<RwLockReadGuard<'_, AwsSessionCredential>, GetCredentialsError> {
|
||||
let app_session = self.app_session.read().await;
|
||||
let crypto = app_session.try_get_crypto()?;
|
||||
let record = CredentialRecord::load_default("aws", crypto, &self.pool).await?;
|
||||
let base = match &record.credential {
|
||||
Credential::AwsBase(b) => Ok(b),
|
||||
_ => Err(LoadCredentialsError::NoCredentials)
|
||||
}?;
|
||||
|
||||
{
|
||||
let mut aws_session = self.aws_session.write().await;
|
||||
if aws_session.is_none() || aws_session.as_ref().unwrap().is_expired() {
|
||||
let base_creds = self.get_aws_base(name).await?;
|
||||
*aws_session = Some(AwsSessionCredential::from_base(&base_creds).await?);
|
||||
let mut aws_sessions = self.aws_sessions.write().await;
|
||||
match aws_sessions.entry(record.id) {
|
||||
Entry::Vacant(e) => {
|
||||
e.insert(AwsSessionCredential::from_base(&base).await?);
|
||||
},
|
||||
Entry::Occupied(mut e) if e.get().is_expired() => {
|
||||
*(e.get_mut()) = AwsSessionCredential::from_base(&base).await?;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
// we know this is safe, because we juse made sure of it
|
||||
let s = RwLockReadGuard::map(self.aws_session.read().await, |opt| opt.as_ref().unwrap());
|
||||
// we know the unwrap is safe, because we just made sure of it
|
||||
let s = RwLockReadGuard::map(self.aws_sessions.read().await, |map| map.get(&record.id).unwrap());
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::process::Command;
|
||||
use std::time::Duration;
|
||||
|
||||
use tauri::Manager;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::app::APP;
|
||||
@ -18,6 +18,18 @@ pub async fn launch(use_base: bool) -> Result<(), LaunchTerminalError> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let res = do_launch(app, use_base).await;
|
||||
|
||||
state.unregister_terminal_request().await;
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
// this handles most of the work, the outer function is just to ensure we properly
|
||||
// unregister the request if there's an error
|
||||
async fn do_launch(app: &AppHandle, use_base: bool) -> Result<(), LaunchTerminalError> {
|
||||
let state = app.state::<AppState>();
|
||||
|
||||
let mut cmd = {
|
||||
let config = state.config.read().await;
|
||||
let mut cmd = Command::new(&config.terminal.exec);
|
||||
@ -41,7 +53,6 @@ pub async fn launch(use_base: bool) -> Result<(), LaunchTerminalError> {
|
||||
_ = rx => lease.release(),
|
||||
// otherwise, dump this request, but return Ok so we don't get an error popup
|
||||
_ = sleep(timeout) => {
|
||||
state.unregister_terminal_request().await;
|
||||
eprintln!("WARNING: Request to launch terminal timed out after 60 seconds.");
|
||||
return Ok(());
|
||||
},
|
||||
@ -52,27 +63,24 @@ pub async fn launch(use_base: bool) -> Result<(), LaunchTerminalError> {
|
||||
// (i.e. lies about unlocking) we could end up here with a locked session
|
||||
// this will result in an error popup to the user (see main hotkey handler)
|
||||
if use_base {
|
||||
let base_creds = state.get_aws_base("default").await?;
|
||||
let base_creds = state.get_aws_default().await?;
|
||||
cmd.env("AWS_ACCESS_KEY_ID", &base_creds.access_key_id);
|
||||
cmd.env("AWS_SECRET_ACCESS_KEY", &base_creds.secret_access_key);
|
||||
}
|
||||
else {
|
||||
let session_creds = state.get_aws_session("default").await?;
|
||||
let session_creds = state.get_aws_default_session().await?;
|
||||
cmd.env("AWS_ACCESS_KEY_ID", &session_creds.access_key_id);
|
||||
cmd.env("AWS_SECRET_ACCESS_KEY", &session_creds.secret_access_key);
|
||||
cmd.env("AWS_SESSION_TOKEN", &session_creds.session_token);
|
||||
}
|
||||
|
||||
let res = match cmd.spawn() {
|
||||
match cmd.spawn() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) if std::io::ErrorKind::NotFound == e.kind() => {
|
||||
Err(ExecError::NotFound(cmd.get_program().to_owned()))
|
||||
},
|
||||
Err(e) => Err(ExecError::ExecutionFailed(e)),
|
||||
};
|
||||
}?;
|
||||
|
||||
state.unregister_terminal_request().await;
|
||||
|
||||
res?; // ? auto-conversion is more liberal than .into()
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user