finish extremely basic implementation of docker credentials
This commit is contained in:
parent
8bcdc5420a
commit
9bc9cb56c1
@ -13,11 +13,7 @@ use super::{
|
|||||||
pub fn docker_store(global_args: GlobalArgs) -> anyhow::Result<()> {
|
pub fn docker_store(global_args: GlobalArgs) -> anyhow::Result<()> {
|
||||||
let input: DockerCredential = serde_json::from_reader(io::stdin())?;
|
let input: DockerCredential = serde_json::from_reader(io::stdin())?;
|
||||||
|
|
||||||
let req = CliRequest::SaveCredential {
|
let req = CliRequest::StoreDockerCredential(input);
|
||||||
name: input.username.clone(),
|
|
||||||
is_default: false, // is_default doesn't really mean anything for Docker credentials
|
|
||||||
credential: CliCredential::Docker(input),
|
|
||||||
};
|
|
||||||
|
|
||||||
match super::make_request(global_args.server_addr, &req)?? {
|
match super::make_request(global_args.server_addr, &req)?? {
|
||||||
CliResponse::Empty => Ok(()),
|
CliResponse::Empty => Ok(()),
|
||||||
@ -41,3 +37,17 @@ pub fn docker_get(global_args: GlobalArgs) -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn docker_erase(global_args: GlobalArgs) -> anyhow::Result<()> {
|
||||||
|
let mut server_url = String::new();
|
||||||
|
io::stdin().read_to_string(&mut server_url)?;
|
||||||
|
let req = CliRequest::EraseDockerCredential {
|
||||||
|
server_url: server_url.trim().to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
match super::make_request(global_args.server_addr, &req)?? {
|
||||||
|
CliResponse::Empty => Ok(()),
|
||||||
|
r => bail!("Unexpected response from server: {r}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -193,7 +193,7 @@ pub fn exec(args: ExecArgs, global: GlobalArgs) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
|
|
||||||
pub fn invoke_shortcut(args: InvokeArgs, global: GlobalArgs) -> anyhow::Result<()> {
|
pub fn invoke_shortcut(args: InvokeArgs, global: GlobalArgs) -> anyhow::Result<()> {
|
||||||
let req = CliRequest::InvokeShortcut(args.shortcut_action);
|
let req = CliRequest::InvokeShortcut{action: args.shortcut_action};
|
||||||
match make_request(global.server_addr, &req)?? {
|
match make_request(global.server_addr, &req)?? {
|
||||||
CliResponse::Empty => Ok(()),
|
CliResponse::Empty => Ok(()),
|
||||||
r => bail!("Unexpected response from server: {r}"),
|
r => bail!("Unexpected response from server: {r}"),
|
||||||
@ -205,7 +205,7 @@ pub fn docker_credential_helper(cmd: DockerCmd, global_args: GlobalArgs) -> anyh
|
|||||||
match cmd {
|
match cmd {
|
||||||
DockerCmd::Get => docker::docker_get(global_args),
|
DockerCmd::Get => docker::docker_get(global_args),
|
||||||
DockerCmd::Store => docker::docker_store(global_args),
|
DockerCmd::Store => docker::docker_store(global_args),
|
||||||
DockerCmd::Erase => todo!(),
|
DockerCmd::Erase => docker::docker_erase(global_args),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,5 +7,6 @@ CREATE TABLE docker_credentials (
|
|||||||
server_url TEXT UNIQUE NOT NULL,
|
server_url TEXT UNIQUE NOT NULL,
|
||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
secret_enc BLOB NOT NULL,
|
secret_enc BLOB NOT NULL,
|
||||||
nonce BLOB NOT NULL
|
nonce BLOB NOT NULL,
|
||||||
|
FOREIGN KEY(id) REFERENCES credentials(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
@ -7,7 +7,8 @@ use crate::clientinfo::{self, Client};
|
|||||||
use crate::credentials::{
|
use crate::credentials::{
|
||||||
Credential,
|
Credential,
|
||||||
CredentialRecord,
|
CredentialRecord,
|
||||||
Crypto
|
Crypto,
|
||||||
|
DockerCredential
|
||||||
};
|
};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
use crate::ipc::{Approval, AwsRequestNotification, RequestNotificationDetail, RequestResponse};
|
use crate::ipc::{Approval, AwsRequestNotification, RequestNotificationDetail, RequestResponse};
|
||||||
@ -55,13 +56,16 @@ async fn handle(
|
|||||||
CliRequest::GetAwsCredential{ name, base } => get_aws_credentials(
|
CliRequest::GetAwsCredential{ name, base } => get_aws_credentials(
|
||||||
name, base, client, app_handle, waiter
|
name, base, client, app_handle, waiter
|
||||||
).await,
|
).await,
|
||||||
CliRequest::GetDockerCredential{ server_url } => get_docker_credentials (
|
CliRequest::GetDockerCredential{ server_url } => get_docker_credential (
|
||||||
server_url, client, app_handle, waiter
|
server_url, client, app_handle, waiter
|
||||||
).await,
|
).await,
|
||||||
CliRequest::SaveCredential{ name, is_default, credential } => save_credential(
|
CliRequest::StoreDockerCredential(docker_credential) => store_docker_credential(
|
||||||
name, is_default, credential, app_handle
|
docker_credential, app_handle, waiter
|
||||||
).await,
|
).await,
|
||||||
CliRequest::InvokeShortcut(action) => invoke_shortcut(action).await,
|
CliRequest::EraseDockerCredential { server_url } => erase_docker_credential(
|
||||||
|
server_url, app_handle, waiter
|
||||||
|
).await,
|
||||||
|
CliRequest::InvokeShortcut{ action } => invoke_shortcut(action).await,
|
||||||
};
|
};
|
||||||
|
|
||||||
// doesn't make sense to send the error to the client if the client has already left
|
// doesn't make sense to send the error to the client if the client has already left
|
||||||
@ -106,7 +110,7 @@ async fn get_aws_credentials(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_docker_credentials(
|
async fn get_docker_credential(
|
||||||
server_url: String,
|
server_url: String,
|
||||||
client: Client,
|
client: Client,
|
||||||
app_handle: AppHandle,
|
app_handle: AppHandle,
|
||||||
@ -126,24 +130,39 @@ async fn get_docker_credentials(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_credential(
|
async fn store_docker_credential(
|
||||||
name: String,
|
docker_credential: DockerCredential,
|
||||||
is_default: bool,
|
|
||||||
credential: Credential,
|
|
||||||
app_handle: AppHandle,
|
app_handle: AppHandle,
|
||||||
|
_waiter: CloseWaiter<'_>,
|
||||||
) -> Result<CliResponse, HandlerError> {
|
) -> Result<CliResponse, HandlerError> {
|
||||||
let state = app_handle.state::<AppState>();
|
let state = app_handle.state::<AppState>();
|
||||||
|
|
||||||
// eventually ask the frontend to unlock here
|
// eventually ask the frontend to confirm here
|
||||||
|
|
||||||
// a bit weird but convenient
|
// a bit weird but convenient
|
||||||
let random_bytes = Crypto::salt();
|
let random_bytes = Crypto::salt();
|
||||||
let id = Uuid::from_slice(&random_bytes[..16]).unwrap();
|
let id = Uuid::from_slice(&random_bytes[..16]).unwrap();
|
||||||
|
|
||||||
let record = CredentialRecord {
|
let record = CredentialRecord {
|
||||||
id, name, is_default, credential
|
id,
|
||||||
|
name: docker_credential.server_url.clone(),
|
||||||
|
is_default: false,
|
||||||
|
credential: Credential::Docker(docker_credential)
|
||||||
};
|
};
|
||||||
state.save_credential(record).await?;
|
state.save_credential(record).await?;
|
||||||
|
|
||||||
Ok(CliResponse::Empty)
|
Ok(CliResponse::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn erase_docker_credential(
|
||||||
|
server_url: String,
|
||||||
|
app_handle: AppHandle,
|
||||||
|
_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)
|
||||||
|
}
|
||||||
|
@ -13,7 +13,6 @@ use crate::clientinfo::Client;
|
|||||||
use crate::credentials::{
|
use crate::credentials::{
|
||||||
AwsBaseCredential,
|
AwsBaseCredential,
|
||||||
AwsSessionCredential,
|
AwsSessionCredential,
|
||||||
Credential,
|
|
||||||
DockerCredential,
|
DockerCredential,
|
||||||
};
|
};
|
||||||
use crate::errors::*;
|
use crate::errors::*;
|
||||||
@ -30,6 +29,7 @@ use platform::Stream;
|
|||||||
// so that we avoid polluting the standalone CLI with a bunch of dependencies
|
// so that we avoid polluting the standalone CLI with a bunch of dependencies
|
||||||
// that would make it impossible to build a completely static-linked version
|
// that would make it impossible to build a completely static-linked version
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
pub enum CliRequest {
|
pub enum CliRequest {
|
||||||
GetAwsCredential {
|
GetAwsCredential {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
@ -38,12 +38,13 @@ pub enum CliRequest {
|
|||||||
GetDockerCredential {
|
GetDockerCredential {
|
||||||
server_url: String,
|
server_url: String,
|
||||||
},
|
},
|
||||||
SaveCredential {
|
StoreDockerCredential(DockerCredential),
|
||||||
name: String,
|
EraseDockerCredential {
|
||||||
is_default: bool,
|
server_url: String,
|
||||||
credential: Credential,
|
},
|
||||||
|
InvokeShortcut{
|
||||||
|
action: ShortcutAction,
|
||||||
},
|
},
|
||||||
InvokeShortcut(ShortcutAction),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -161,6 +161,13 @@ impl AppState {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_credential_by_name(&self, name: &str) -> Result<(), SaveCredentialsError> {
|
||||||
|
sqlx::query!("DELETE FROM credentials WHERE name = ?", name)
|
||||||
|
.execute(&self.pool)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn list_credentials(&self) -> Result<Vec<CredentialRecord>, GetCredentialsError> {
|
pub async fn list_credentials(&self) -> Result<Vec<CredentialRecord>, GetCredentialsError> {
|
||||||
let session = self.app_session.read().await;
|
let session = self.app_session.read().await;
|
||||||
let crypto = session.try_get_crypto()?;
|
let crypto = session.try_get_crypto()?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user