working implementation of docker get
This commit is contained in:
@ -1,10 +1,16 @@
|
||||
use sqlx::types::uuid::Uuid;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::sync::oneshot;
|
||||
|
||||
use crate::clientinfo::{self, Client};
|
||||
use crate::credentials::{
|
||||
Credential,
|
||||
CredentialRecord,
|
||||
Crypto
|
||||
};
|
||||
use crate::errors::*;
|
||||
use crate::ipc::{Approval, RequestNotification};
|
||||
use crate::ipc::{Approval, AwsRequestNotification, RequestNotificationDetail, RequestResponse};
|
||||
use crate::shortcuts::{self, ShortcutAction};
|
||||
use crate::state::AppState;
|
||||
use super::{
|
||||
@ -46,9 +52,15 @@ async fn handle(
|
||||
|
||||
let req: CliRequest = serde_json::from_slice(&buf)?;
|
||||
let res = match req {
|
||||
CliRequest::GetCredential{ name, base } => get_aws_credentials(
|
||||
CliRequest::GetAwsCredential{ name, base } => get_aws_credentials(
|
||||
name, base, client, app_handle, waiter
|
||||
).await,
|
||||
CliRequest::GetDockerCredential{ server_url } => get_docker_credentials (
|
||||
server_url, client, app_handle, waiter
|
||||
).await,
|
||||
CliRequest::SaveCredential{ name, is_default, credential } => save_credential(
|
||||
name, is_default, credential, app_handle
|
||||
).await,
|
||||
CliRequest::InvokeShortcut(action) => invoke_shortcut(action).await,
|
||||
};
|
||||
|
||||
@ -74,59 +86,64 @@ async fn get_aws_credentials(
|
||||
base: bool,
|
||||
client: Client,
|
||||
app_handle: AppHandle,
|
||||
mut waiter: CloseWaiter<'_>,
|
||||
waiter: CloseWaiter<'_>,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let detail = RequestNotificationDetail::new_aws(client, name.clone(), base);
|
||||
let response = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
let state = app_handle.state::<AppState>();
|
||||
if response.base {
|
||||
let creds = state.get_aws_base(name).await?;
|
||||
Ok(CliResponse::Credential(CliCredential::AwsBase(creds)))
|
||||
}
|
||||
else {
|
||||
let creds = state.get_aws_session(name).await?.clone();
|
||||
Ok(CliResponse::Credential(CliCredential::AwsSession(creds)))
|
||||
}
|
||||
},
|
||||
Approval::Denied => Err(HandlerError::Denied),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_docker_credentials(
|
||||
server_url: String,
|
||||
client: Client,
|
||||
app_handle: AppHandle,
|
||||
waiter: CloseWaiter<'_>,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let detail = RequestNotificationDetail::new_docker(client, server_url.clone());
|
||||
let response = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
let state = app_handle.state::<AppState>();
|
||||
let creds = state.get_docker_credential(&server_url).await?;
|
||||
Ok(CliResponse::Credential(CliCredential::Docker(creds)))
|
||||
},
|
||||
Approval::Denied => {
|
||||
Err(HandlerError::Denied)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save_credential(
|
||||
name: String,
|
||||
is_default: bool,
|
||||
credential: Credential,
|
||||
app_handle: AppHandle,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let state = app_handle.state::<AppState>();
|
||||
let rehide_ms = {
|
||||
let config = state.config.read().await;
|
||||
config.rehide_ms
|
||||
|
||||
// eventually ask the frontend to unlock here
|
||||
|
||||
// a bit weird but convenient
|
||||
let random_bytes = Crypto::salt();
|
||||
let id = Uuid::from_slice(&random_bytes[..16]).unwrap();
|
||||
|
||||
let record = CredentialRecord {
|
||||
id, name, is_default, credential
|
||||
};
|
||||
let lease = state.acquire_visibility_lease(rehide_ms).await
|
||||
.map_err(|_e| HandlerError::NoMainWindow)?; // automate this conversion eventually?
|
||||
state.save_credential(record).await?;
|
||||
|
||||
let (chan_send, chan_recv) = oneshot::channel();
|
||||
let request_id = state.register_request(chan_send).await;
|
||||
|
||||
// if an error occurs in any of the following, we want to abort the operation
|
||||
// but ? returns immediately, and we want to unregister the request before returning
|
||||
// so we bundle it all up in an async block and return a Result so we can handle errors
|
||||
let proceed = async {
|
||||
let notification = RequestNotification::new_aws(
|
||||
request_id, client, name.clone(), base
|
||||
);
|
||||
app_handle.emit("credential-request", ¬ification)?;
|
||||
|
||||
let response = tokio::select! {
|
||||
r = chan_recv => r?,
|
||||
_ = waiter.wait_for_close() => {
|
||||
app_handle.emit("request-cancelled", request_id)?;
|
||||
return Err(HandlerError::Abandoned);
|
||||
},
|
||||
};
|
||||
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
if response.base {
|
||||
let creds = state.get_aws_base(name).await?;
|
||||
Ok(CliResponse::Credential(CliCredential::AwsBase(creds)))
|
||||
}
|
||||
else {
|
||||
let creds = state.get_aws_session(name).await?.clone();
|
||||
Ok(CliResponse::Credential(CliCredential::AwsSession(creds)))
|
||||
}
|
||||
},
|
||||
Approval::Denied => Err(HandlerError::Denied),
|
||||
}
|
||||
};
|
||||
|
||||
let result = match proceed.await {
|
||||
Ok(r) => Ok(r),
|
||||
Err(e) => {
|
||||
state.unregister_request(request_id).await;
|
||||
Err(e)
|
||||
},
|
||||
};
|
||||
|
||||
lease.release();
|
||||
result
|
||||
Ok(CliResponse::Empty)
|
||||
}
|
||||
|
Reference in New Issue
Block a user