diff --git a/src-tauri/src/credentials/record.rs b/src-tauri/src/credentials/record.rs index e7d1745..96b837c 100644 --- a/src-tauri/src/credentials/record.rs +++ b/src-tauri/src/credentials/record.rs @@ -21,6 +21,7 @@ use super::{ Credential, Crypto, PersistentCredential, + SshKey, }; @@ -48,6 +49,7 @@ impl CredentialRecord { pub async fn save(&self, crypto: &Crypto, pool: &SqlitePool) -> Result<(), SaveCredentialsError> { let type_name = match &self.credential { Credential::AwsBase(_) => AwsBaseCredential::type_name(), + Credential::Ssh(_) => SshKey::type_name(), _ => return Err(SaveCredentialsError::NotPersistent), }; @@ -82,6 +84,7 @@ impl CredentialRecord { // save credential details to child table match &self.credential { Credential::AwsBase(b) => b.save_details(&self.id, crypto, &mut txn).await, + Credential::Ssh(s) => s.save_details(&self.id, crypto, &mut txn).await, _ => Err(SaveCredentialsError::NotPersistent), }?; @@ -147,6 +150,11 @@ impl CredentialRecord { .ok_or(LoadCredentialsError::InvalidData)?; records.push(Self::from_parts(parent, credential)); } + for (id, credential) in SshKey::list(crypto, pool).await? { + let parent = parent_map.remove(&id) + .ok_or(LoadCredentialsError::InvalidData)?; + records.push(Self::from_parts(parent, credential)); + } Ok(records) } diff --git a/src/lib/errors.js b/src/lib/errors.js index 13eef7e..a42cb59 100644 --- a/src/lib/errors.js +++ b/src/lib/errors.js @@ -6,3 +6,12 @@ export function getRootCause(error) { return error; } } + + +export function fullMessage(error) { + let msg = error?.msg ? error.msg : error; + if (error.source) { + msg = `${msg}: ${fullMessage(error.source)}`; + } + return msg +} diff --git a/src/ui/ErrorAlert.svelte b/src/ui/ErrorAlert.svelte index aa09adb..6465f71 100644 --- a/src/ui/ErrorAlert.svelte +++ b/src/ui/ErrorAlert.svelte @@ -2,6 +2,9 @@ import { onMount } from 'svelte'; import { slide } from 'svelte/transition'; + import { fullMessage } from '../lib/errors.js'; + + let extraClasses = ""; export {extraClasses as class}; export let slideDuration = 150; @@ -78,7 +81,7 @@
- {error.msg || error} + {fullMessage(error)} {#if $$slots.buttons} diff --git a/src/ui/FileInput.svelte b/src/ui/FileInput.svelte index 8e5f659..49b2bed 100644 --- a/src/ui/FileInput.svelte +++ b/src/ui/FileInput.svelte @@ -1,20 +1,33 @@ @@ -59,7 +72,11 @@ {#if awsRecords.length > 0} {#each awsRecords as record (record.id)} - + {/each} {:else if records !== null}
You have no saved SSH keys.
@@ -101,3 +118,5 @@
+ + diff --git a/src/views/credentials/AwsCredential.svelte b/src/views/credentials/AwsCredential.svelte index c4aa001..a99f98b 100644 --- a/src/views/credentials/AwsCredential.svelte +++ b/src/views/credentials/AwsCredential.svelte @@ -31,36 +31,11 @@ showDetails = false; } - let deleteModal; - function conditionalDelete() { - if (!record.isNew) { - deleteModal.showModal(); - } - else { - deleteCredential(); - } - } - - async function deleteCredential() { - try { - if (!record.isNew) { - await invoke('delete_credential', {id: record.id}); - } - dispatch('update'); - } - catch (e) { - showDetails = true; - // wait for showDetails to take effect and the alert to be rendered - window.setTimeout(() => alert.setError(e), 0); - } - } + -
+

{#if !record?.isNew && showDetails} @@ -85,7 +60,7 @@ @@ -141,20 +116,4 @@

{/if} - - - -
diff --git a/src/views/credentials/ConfirmDelete.svelte b/src/views/credentials/ConfirmDelete.svelte new file mode 100644 index 0000000..4960626 --- /dev/null +++ b/src/views/credentials/ConfirmDelete.svelte @@ -0,0 +1,62 @@ + + + + + diff --git a/src/views/credentials/EditSshKey.svelte b/src/views/credentials/EditSshKey.svelte new file mode 100644 index 0000000..5f29307 --- /dev/null +++ b/src/views/credentials/EditSshKey.svelte @@ -0,0 +1,85 @@ + + + + + + +
alert.run(saveCredential)}> + + +
+ Comment + + + Public key +
+
+ {local.credential.public_key} +
+
+ + Private key +
+
+ {local.credential.private_key} +
+
+
+ +
+ {#if isModified} + + {/if} +
+ \ No newline at end of file diff --git a/src/views/credentials/NewSshKey.svelte b/src/views/credentials/NewSshKey.svelte index a337c43..8e19682 100644 --- a/src/views/credentials/NewSshKey.svelte +++ b/src/views/credentials/NewSshKey.svelte @@ -2,12 +2,12 @@ import { createEventDispatcher } from 'svelte'; import { invoke } from '@tauri-apps/api/core'; import { homeDir } from '@tauri-apps/api/path'; - import { fade, slide } from 'svelte/transition'; + import { fade } from 'svelte/transition'; import ErrorAlert from '../../ui/ErrorAlert.svelte'; import FileInput from '../../ui/FileInput.svelte'; - import Icon from '../../ui/Icon.svelte'; import PassphraseInput from '../../ui/PassphraseInput.svelte'; + import Spinner from '../../ui/Spinner.svelte'; export let record; @@ -22,71 +22,59 @@ homeDir().then(d => defaultPath = `${d}/.ssh`); let alert; + let saving = false; async function saveCredential() { - let key = await invoke('sshkey_from_file', {path: file.path, passphrase}); - dispatch('update', key); + saving = true; + try { + let key = await invoke('sshkey_from_file', {path: file.path, passphrase}); + const payload = { + id: record.id, + name, + is_default: false, // ssh keys don't care about defaults + credential: {type: 'Ssh', ...key}, + }; + await invoke('save_credential', {record: payload}); + dispatch('save', payload); + } + finally { + saving = false; + } } -
-
-
- - -
+
+ + +
+ Name + + + File + name = file.name} /> + + Passphrase +
- {#if showDetails} - alert.run(saveCredential)} - > - - -
- Name - - - File - - - Passphrase - -
- -
- {#if file?.path} - +
+ {#if file?.path} +
- - {/if} -
\ No newline at end of file + + {/if} +
+ \ No newline at end of file diff --git a/src/views/credentials/SshKey.svelte b/src/views/credentials/SshKey.svelte index e2febdf..ed474a9 100644 --- a/src/views/credentials/SshKey.svelte +++ b/src/views/credentials/SshKey.svelte @@ -1,46 +1,45 @@ -
+
-

{record.name || ''}

+ {#if !record.isNew} + {#if showDetails} + + {:else} +

+ {record.name} +

+ {/if} + {/if}
- {#if showDetails} -
alert.run(saveCredential)} - > - - -
- {#if record.isNew} - File - - - Passphrase - - {:else} - Algorithm - {record.credential.algorithm} - - Comment - {record.credential.comment} - - Public key - {record.credential.public_key} - - Private key - {record.credential.private_key} - {/if} -
- -
- {#if isModified} - - {/if} -
- + {#if record && showDetails} +
+ {#if record.isNew} + + {:else} + + {/if} +
{/if} -
\ No newline at end of file +