add alternate entry mode for ssh keys
This commit is contained in:
parent
ae93a57aab
commit
10231df860
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "creddy",
|
"name": "creddy",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
2
src-tauri/Cargo.lock
generated
2
src-tauri/Cargo.lock
generated
@ -1196,7 +1196,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "creddy"
|
name = "creddy"
|
||||||
version = "0.4.9"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"argon2",
|
"argon2",
|
||||||
"auto-launch",
|
"auto-launch",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "creddy"
|
name = "creddy"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
description = "A friendly AWS credentials manager"
|
description = "A friendly AWS credentials manager"
|
||||||
authors = ["Joseph Montanaro"]
|
authors = ["Joseph Montanaro"]
|
||||||
license = ""
|
license = ""
|
||||||
|
@ -53,6 +53,7 @@ pub fn run() -> tauri::Result<()> {
|
|||||||
ipc::delete_credential,
|
ipc::delete_credential,
|
||||||
ipc::list_credentials,
|
ipc::list_credentials,
|
||||||
ipc::sshkey_from_file,
|
ipc::sshkey_from_file,
|
||||||
|
ipc::sshkey_from_private_key,
|
||||||
ipc::get_config,
|
ipc::get_config,
|
||||||
ipc::save_config,
|
ipc::save_config,
|
||||||
ipc::launch_terminal,
|
ipc::launch_terminal,
|
||||||
|
@ -74,6 +74,21 @@ impl SshKey {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_private_key(private_key: &str, passphrase: &str) -> Result<SshKey, LoadSshKeyError> {
|
||||||
|
let mut privkey = PrivateKey::from_openssh(private_key)?;
|
||||||
|
if privkey.is_encrypted() {
|
||||||
|
privkey = privkey.decrypt(passphrase)
|
||||||
|
.map_err(|_| LoadSshKeyError::InvalidPassphrase)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SshKey {
|
||||||
|
algorithm: privkey.algorithm(),
|
||||||
|
comment: privkey.comment().into(),
|
||||||
|
public_key: privkey.public_key().clone(),
|
||||||
|
private_key: privkey,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn name_from_pubkey(pubkey: &[u8], pool: &SqlitePool) -> Result<String, LoadCredentialsError> {
|
pub async fn name_from_pubkey(pubkey: &[u8], pool: &SqlitePool) -> Result<String, LoadCredentialsError> {
|
||||||
let row = sqlx::query!(
|
let row = sqlx::query!(
|
||||||
"SELECT c.name
|
"SELECT c.name
|
||||||
|
@ -142,6 +142,12 @@ pub async fn sshkey_from_file(path: &str, passphrase: &str) -> Result<SshKey, Lo
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn sshkey_from_private_key(private_key: &str, passphrase: &str) -> Result<SshKey, LoadSshKeyError> {
|
||||||
|
SshKey::from_private_key(private_key, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_config(app_state: State<'_, AppState>) -> Result<AppConfig, ()> {
|
pub async fn get_config(app_state: State<'_, AppState>) -> Result<AppConfig, ()> {
|
||||||
let config = app_state.config.read().await;
|
let config = app_state.config.read().await;
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"productName": "creddy",
|
"productName": "creddy",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"identifier": "creddy",
|
"identifier": "creddy",
|
||||||
"plugins": {},
|
"plugins": {},
|
||||||
"app": {
|
"app": {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
|
|
||||||
// Extra 50ms so the window can finish disappearing before the redraw
|
// Extra 50ms so the window can finish disappearing before the redraw
|
||||||
const rehideDelay = Math.min(5000, $appState.config.rehide_ms + 50);
|
const rehideDelay = Math.min(5000, $appState.config.rehide_ms + 100);
|
||||||
|
|
||||||
let alert;
|
let alert;
|
||||||
let success = false;
|
let success = false;
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
async function saveCredential() {
|
async function saveCredential() {
|
||||||
await invoke('save_credential', {record: local});
|
await invoke('save_credential', {record: local});
|
||||||
dispatch('save', local);
|
dispatch('save', local);
|
||||||
showDetails = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function copyText(evt) {
|
async function copyText(evt) {
|
||||||
|
@ -13,20 +13,23 @@
|
|||||||
|
|
||||||
let name;
|
let name;
|
||||||
let file;
|
let file;
|
||||||
|
let privateKey = '';
|
||||||
let passphrase = '';
|
let passphrase = '';
|
||||||
let showDetails = true;
|
let showDetails = true;
|
||||||
|
let mode = 'file';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
let defaultPath = null;
|
let defaultPath = null;
|
||||||
homeDir().then(d => defaultPath = `${d}/.ssh`);
|
homeDir().then(d => defaultPath = `${d}/.ssh`);
|
||||||
|
|
||||||
|
|
||||||
let alert;
|
let alert;
|
||||||
let saving = false;
|
let saving = false;
|
||||||
async function saveCredential() {
|
async function saveCredential() {
|
||||||
saving = true;
|
saving = true;
|
||||||
try {
|
try {
|
||||||
let key = await invoke('sshkey_from_file', {path: file.path, passphrase});
|
let key = await getKey();
|
||||||
const payload = {
|
const payload = {
|
||||||
id: record.id,
|
id: record.id,
|
||||||
name,
|
name,
|
||||||
@ -41,9 +44,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getKey() {
|
||||||
|
if (mode === 'file') {
|
||||||
|
return await invoke('sshkey_from_file', {path: file.path, passphrase});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return await invoke('sshkey_from_private_key', {privateKey, passphrase});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div role="tablist" class="join max-w-sm mx-auto flex justify-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
class="join-item flex-1 btn border border-primary"
|
||||||
|
class:btn-primary={mode === 'file'}
|
||||||
|
on:click={() => mode = 'file'}
|
||||||
|
>
|
||||||
|
From file
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
class="join-item flex-1 btn border border-primary"
|
||||||
|
class:btn-primary={mode === 'direct'}
|
||||||
|
on:click={() => mode = 'direct'}
|
||||||
|
>
|
||||||
|
From private key
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<form class="space-y-4" on:submit|preventDefault={alert.run(saveCredential)}>
|
<form class="space-y-4" on:submit|preventDefault={alert.run(saveCredential)}>
|
||||||
<ErrorAlert bind:this={alert} />
|
<ErrorAlert bind:this={alert} />
|
||||||
|
|
||||||
@ -55,15 +89,20 @@
|
|||||||
bind:value={name}
|
bind:value={name}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
{#if mode === 'file'}
|
||||||
<span class="justify-self-end">File</span>
|
<span class="justify-self-end">File</span>
|
||||||
<FileInput params={{defaultPath}} bind:value={file} on:update={() => name = file.name} />
|
<FileInput params={{defaultPath}} bind:value={file} on:update={() => name = file.name} />
|
||||||
|
{:else}
|
||||||
|
<span class="justify-self-end">Private key</span>
|
||||||
|
<textarea bind:value={privateKey} rows="5" class="textarea textarea-bordered bg-transparent font-mono whitespace-pre overflow-x-auto"></textarea>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<span class="justify-self-end">Passphrase</span>
|
<span class="justify-self-end">Passphrase</span>
|
||||||
<PassphraseInput class="bg-transparent" bind:value={passphrase} />
|
<PassphraseInput class="bg-transparent" bind:value={passphrase} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-end">
|
||||||
{#if file?.path}
|
{#if file?.path || privateKey !== ''}
|
||||||
<button
|
<button
|
||||||
transition:fade={{duration: 100}}
|
transition:fade={{duration: 100}}
|
||||||
type="submit"
|
type="submit"
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
{#if record.isNew}
|
{#if record.isNew}
|
||||||
<NewSshKey {record} on:save on:save={handleSave} />
|
<NewSshKey {record} on:save on:save={handleSave} />
|
||||||
{:else}
|
{:else}
|
||||||
<EditSshKey bind:local={local} {isModified} on:save />
|
<EditSshKey bind:local={local} {isModified} on:save={handleSave} on:save />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user