finish basic Docker credential helper implementation
This commit is contained in:
@ -9,7 +9,11 @@ use crate::credentials::{
|
||||
DockerCredential,
|
||||
};
|
||||
use crate::errors::*;
|
||||
use crate::ipc::{Approval, RequestNotificationDetail};
|
||||
use crate::ipc::{
|
||||
Approval,
|
||||
RequestAction,
|
||||
RequestNotificationDetail
|
||||
};
|
||||
use crate::shortcuts::{self, ShortcutAction};
|
||||
use crate::state::AppState;
|
||||
use super::{
|
||||
@ -58,10 +62,10 @@ async fn handle(
|
||||
server_url, client, app_handle, waiter
|
||||
).await,
|
||||
CliRequest::StoreDockerCredential(docker_credential) => store_docker_credential(
|
||||
docker_credential, app_handle, waiter
|
||||
docker_credential, app_handle, client, waiter
|
||||
).await,
|
||||
CliRequest::EraseDockerCredential { server_url } => erase_docker_credential(
|
||||
server_url, app_handle, waiter
|
||||
server_url, app_handle, client, waiter
|
||||
).await,
|
||||
CliRequest::InvokeShortcut{ action } => invoke_shortcut(action).await,
|
||||
};
|
||||
@ -115,8 +119,8 @@ async fn get_docker_credential(
|
||||
waiter: CloseWaiter<'_>,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let state = app_handle.state::<AppState>();
|
||||
let credential_id = state.credential_id(&server_url).await.unwrap_or(None);
|
||||
if credential_id.is_none() {
|
||||
let meta = state.docker_credential_meta(&server_url).await.unwrap_or(None);
|
||||
if meta.is_none() {
|
||||
return Err(
|
||||
HandlerError::NoCredentials(
|
||||
GetCredentialsError::Load(
|
||||
@ -126,7 +130,11 @@ async fn get_docker_credential(
|
||||
);
|
||||
}
|
||||
|
||||
let detail = RequestNotificationDetail::new_docker(client, server_url.clone());
|
||||
let detail = RequestNotificationDetail::new_docker(
|
||||
RequestAction::Access,
|
||||
client,
|
||||
server_url.clone()
|
||||
);
|
||||
let response = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
match response.approval {
|
||||
Approval::Approved => {
|
||||
@ -142,22 +150,45 @@ async fn get_docker_credential(
|
||||
async fn store_docker_credential(
|
||||
docker_credential: DockerCredential,
|
||||
app_handle: AppHandle,
|
||||
_waiter: CloseWaiter<'_>,
|
||||
client: Client,
|
||||
waiter: CloseWaiter<'_>,
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let state = app_handle.state::<AppState>();
|
||||
|
||||
// eventually ask the frontend to confirm here
|
||||
// We want to do this before asking for confirmation from the user, because Docker has an annoying
|
||||
// habit of calling `get` and then immediately turning around and calling `store` with the same
|
||||
// data. In that case we want to avoid asking for confirmation at all.
|
||||
match state.get_docker_credential(&docker_credential.server_url).await {
|
||||
// if there is already a credential with this server_url, and it is unchanged, we're done
|
||||
Ok(c) if c == docker_credential => return Ok(CliResponse::Empty),
|
||||
// otherwise we are making an update, so proceed
|
||||
Ok(_) => (),
|
||||
// if the app is locked, then this isn't the situation described above, so proceed
|
||||
Err(GetCredentialsError::Locked) => (),
|
||||
// if the app is unlocked, and there is no matching credential, proceed
|
||||
Err(GetCredentialsError::Load(LoadCredentialsError::NoCredentials)) => (),
|
||||
// any other error is a failure
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
// for some reason Docker likes to call `store` immediately with whatever it gets
|
||||
// back from every `get` operation, so we have to check for an existing credential
|
||||
let id = state.credential_id(&docker_credential.server_url)
|
||||
let detail = RequestNotificationDetail::new_docker(
|
||||
RequestAction::Save,
|
||||
client,
|
||||
docker_credential.server_url.clone(),
|
||||
);
|
||||
let response = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
if matches!(response.approval, Approval::Denied) {
|
||||
return Err(HandlerError::Denied);
|
||||
}
|
||||
|
||||
let (id, name) = state.docker_credential_meta(&docker_credential.server_url)
|
||||
.await
|
||||
.map_err(|e| GetCredentialsError::Load(e))?
|
||||
.unwrap_or_else(|| credentials::random_uuid());
|
||||
.unwrap_or_else(|| (credentials::random_uuid(), docker_credential.server_url.clone()));
|
||||
|
||||
let record = CredentialRecord {
|
||||
id,
|
||||
name: docker_credential.server_url.clone(),
|
||||
name,
|
||||
is_default: false,
|
||||
credential: Credential::Docker(docker_credential)
|
||||
};
|
||||
@ -169,12 +200,24 @@ async fn store_docker_credential(
|
||||
async fn erase_docker_credential(
|
||||
server_url: String,
|
||||
app_handle: AppHandle,
|
||||
_waiter: CloseWaiter<'_>
|
||||
client: Client,
|
||||
waiter: CloseWaiter<'_>
|
||||
) -> Result<CliResponse, HandlerError> {
|
||||
let state = app_handle.state::<AppState>();
|
||||
|
||||
// eventually ask the frontend to confirm here
|
||||
|
||||
state.delete_credential_by_name(&server_url).await?;
|
||||
Ok(CliResponse::Empty)
|
||||
let detail = RequestNotificationDetail::new_docker(
|
||||
RequestAction::Delete,
|
||||
client,
|
||||
server_url.clone(),
|
||||
);
|
||||
let resp = super::send_credentials_request(detail, app_handle.clone(), waiter).await?;
|
||||
match resp.approval {
|
||||
Approval::Approved => {
|
||||
state.delete_credential_by_name(&server_url).await?;
|
||||
Ok(CliResponse::Empty)
|
||||
}
|
||||
Approval::Denied => {
|
||||
Err(HandlerError::Denied)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user