diff --git a/src-tauri/creddy_cli/src/cli/docker.rs b/src-tauri/creddy_cli/src/cli/docker.rs index 7dbb010..c42b578 100644 --- a/src-tauri/creddy_cli/src/cli/docker.rs +++ b/src-tauri/creddy_cli/src/cli/docker.rs @@ -13,11 +13,7 @@ use super::{ pub fn docker_store(global_args: GlobalArgs) -> anyhow::Result<()> { let input: DockerCredential = serde_json::from_reader(io::stdin())?; - let req = CliRequest::SaveCredential { - name: input.username.clone(), - is_default: false, // is_default doesn't really mean anything for Docker credentials - credential: CliCredential::Docker(input), - }; + let req = CliRequest::StoreDockerCredential(input); match super::make_request(global_args.server_addr, &req)?? { CliResponse::Empty => Ok(()), @@ -41,3 +37,17 @@ pub fn docker_get(global_args: GlobalArgs) -> anyhow::Result<()> { } 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}"), + } +} diff --git a/src-tauri/creddy_cli/src/cli/mod.rs b/src-tauri/creddy_cli/src/cli/mod.rs index bd9faf6..dedf139 100644 --- a/src-tauri/creddy_cli/src/cli/mod.rs +++ b/src-tauri/creddy_cli/src/cli/mod.rs @@ -193,7 +193,7 @@ pub fn exec(args: ExecArgs, 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)?? { CliResponse::Empty => Ok(()), r => bail!("Unexpected response from server: {r}"), @@ -205,7 +205,7 @@ pub fn docker_credential_helper(cmd: DockerCmd, global_args: GlobalArgs) -> anyh match cmd { DockerCmd::Get => docker::docker_get(global_args), DockerCmd::Store => docker::docker_store(global_args), - DockerCmd::Erase => todo!(), + DockerCmd::Erase => docker::docker_erase(global_args), } } diff --git a/src-tauri/migrations/20240919135710_docker_creds.sql b/src-tauri/migrations/20240919135710_docker_creds.sql index ea45622..781a669 100644 --- a/src-tauri/migrations/20240919135710_docker_creds.sql +++ b/src-tauri/migrations/20240919135710_docker_creds.sql @@ -7,5 +7,6 @@ CREATE TABLE docker_credentials ( server_url TEXT UNIQUE NOT NULL, username TEXT NOT NULL, secret_enc BLOB NOT NULL, - nonce BLOB NOT NULL + nonce BLOB NOT NULL, + FOREIGN KEY(id) REFERENCES credentials(id) ON DELETE CASCADE ); diff --git a/src-tauri/src/srv/creddy_server.rs b/src-tauri/src/srv/creddy_server.rs index 6cb6817..5b7a9f0 100644 --- a/src-tauri/src/srv/creddy_server.rs +++ b/src-tauri/src/srv/creddy_server.rs @@ -7,7 +7,8 @@ use crate::clientinfo::{self, Client}; use crate::credentials::{ Credential, CredentialRecord, - Crypto + Crypto, + DockerCredential }; use crate::errors::*; use crate::ipc::{Approval, AwsRequestNotification, RequestNotificationDetail, RequestResponse}; @@ -55,13 +56,16 @@ async fn handle( CliRequest::GetAwsCredential{ name, base } => get_aws_credentials( name, base, client, app_handle, waiter ).await, - CliRequest::GetDockerCredential{ server_url } => get_docker_credentials ( + CliRequest::GetDockerCredential{ server_url } => get_docker_credential ( server_url, client, app_handle, waiter ).await, - CliRequest::SaveCredential{ name, is_default, credential } => save_credential( - name, is_default, credential, app_handle + CliRequest::StoreDockerCredential(docker_credential) => store_docker_credential( + docker_credential, app_handle, waiter ).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 @@ -106,7 +110,7 @@ async fn get_aws_credentials( } } -async fn get_docker_credentials( +async fn get_docker_credential( server_url: String, client: Client, app_handle: AppHandle, @@ -126,24 +130,39 @@ async fn get_docker_credentials( } } -pub async fn save_credential( - name: String, - is_default: bool, - credential: Credential, +async fn store_docker_credential( + docker_credential: DockerCredential, app_handle: AppHandle, + _waiter: CloseWaiter<'_>, ) -> Result { let state = app_handle.state::(); - // eventually ask the frontend to unlock here + // eventually ask the frontend to confirm 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 + id, + name: docker_credential.server_url.clone(), + is_default: false, + credential: Credential::Docker(docker_credential) }; state.save_credential(record).await?; Ok(CliResponse::Empty) } + +async fn erase_docker_credential( + server_url: String, + app_handle: AppHandle, + _waiter: CloseWaiter<'_> +) -> Result { + let state = app_handle.state::(); + + // eventually ask the frontend to confirm here + + state.delete_credential_by_name(&server_url).await?; + Ok(CliResponse::Empty) +} diff --git a/src-tauri/src/srv/mod.rs b/src-tauri/src/srv/mod.rs index 06e7cc0..a541e79 100644 --- a/src-tauri/src/srv/mod.rs +++ b/src-tauri/src/srv/mod.rs @@ -13,7 +13,6 @@ use crate::clientinfo::Client; use crate::credentials::{ AwsBaseCredential, AwsSessionCredential, - Credential, DockerCredential, }; use crate::errors::*; @@ -30,6 +29,7 @@ use platform::Stream; // 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 #[derive(Debug, Serialize, Deserialize)] +#[serde(tag = "type")] pub enum CliRequest { GetAwsCredential { name: Option, @@ -38,12 +38,13 @@ pub enum CliRequest { GetDockerCredential { server_url: String, }, - SaveCredential { - name: String, - is_default: bool, - credential: Credential, + StoreDockerCredential(DockerCredential), + EraseDockerCredential { + server_url: String, + }, + InvokeShortcut{ + action: ShortcutAction, }, - InvokeShortcut(ShortcutAction), } diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index de2bfb3..b3577f4 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -161,6 +161,13 @@ impl AppState { 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, GetCredentialsError> { let session = self.app_session.read().await; let crypto = session.try_get_crypto()?;