diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2023-02-10 20:35:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-10 19:35:38 +0000 |
commit | 2cec7ba677f7b25a6e489a3545219b9965997fda (patch) | |
tree | e3b8ad726922568093aaae31f2ed9c4563e6a1ac | |
parent | 78b54662cdac3f8c3e2dfc8a8125c520d9c3f0ae (diff) |
Allow using existing key file on login (#688)
* Allow logging in without overwriting existing key file
If the given key on login in empty, keep the existing key file rather
than overwriting it with an empty file. This is useful if you log out
and want to log in again and still use the same key, or if you have
copied over the key file rather than providing it as input.
* Refuse logging in if key is empty
Before the previous commit, an empty key file would be created if key
wasn't specified, and after the previous commit, the key file would not
be created if the key wasn't specified and stay empty if it was empty.
Now the log command checks the key file if a key is not specified and
exits with an error message if either the key file couldn't be opened or
is empty. If a key is specified, the key file is just created with it as
before.
* Validate the key on login, create new if no exists
After reading the key either from an existing key file, or from the user
input, validate that the provided key is valid (rather than just
checking that it isn't empty). If no key file exists, create a new key
instead of erroring out.
-rw-r--r-- | src/command/client/sync/login.rs | 86 |
1 files changed, 53 insertions, 33 deletions
diff --git a/src/command/client/sync/login.rs b/src/command/client/sync/login.rs index bd3a8029..06e65196 100644 --- a/src/command/client/sync/login.rs +++ b/src/command/client/sync/login.rs @@ -1,12 +1,12 @@ -use std::io; +use std::{io, path::PathBuf}; use clap::Parser; -use eyre::{bail, ContextCompat, Result}; +use eyre::{bail, Context, ContextCompat, Result}; use tokio::{fs::File, io::AsyncWriteExt}; use atuin_client::{ api_client, - encryption::{encode_key, Key}, + encryption::{decode_key, encode_key, new_key, Key}, settings::Settings, }; use atuin_common::api::LoginRequest; @@ -44,8 +44,57 @@ impl Cmd { } let username = or_user_input(&self.username, "username"); - let key = or_user_input(&self.key, "encryption key"); + let key = or_user_input(&self.key, "encryption key [blank to use existing key file]"); let password = self.password.clone().unwrap_or_else(read_user_password); + + let key_path = settings.key_path.as_str(); + if key.is_empty() { + if PathBuf::from(key_path).exists() { + let bytes = fs_err::read_to_string(key_path) + .context("existing key file couldn't be read")?; + if decode_key(bytes).is_err() { + bail!("the key in existing key file was invalid"); + } + } else { + println!("No key file exists, creating a new"); + let _key = new_key(settings)?; + } + } else { + // try parse the key as a mnemonic... + let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { + Ok(mnemonic) => encode_key( + Key::from_slice(mnemonic.entropy()) + .context("key was not the correct length")?, + )?, + Err(err) => { + if let Some(err) = err.downcast_ref::<bip39::ErrorKind>() { + match err { + // assume they copied in the base64 key + bip39::ErrorKind::InvalidWord => key, + bip39::ErrorKind::InvalidChecksum => { + bail!("key mnemonic was not valid") + } + bip39::ErrorKind::InvalidKeysize(_) + | bip39::ErrorKind::InvalidWordLength(_) + | bip39::ErrorKind::InvalidEntropyLength(_, _) => { + bail!("key was not the correct length") + } + } + } else { + // unknown error. assume they copied the base64 key + key + } + } + }; + + if decode_key(key.clone()).is_err() { + bail!("the specified key was invalid"); + } + + let mut file = File::create(key_path).await?; + file.write_all(key.as_bytes()).await?; + } + let session = api_client::login( settings.sync_address.as_str(), LoginRequest { username, password }, @@ -56,35 +105,6 @@ impl Cmd { let mut file = File::create(session_path).await?; file.write_all(session.session.as_bytes()).await?; - let key_path = settings.key_path.as_str(); - let mut file = File::create(key_path).await?; - - // try parse the key as a mnemonic... - let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { - Ok(mnemonic) => encode_key( - Key::from_slice(mnemonic.entropy()).context("key was not the correct length")?, - )?, - Err(err) => { - if let Some(err) = err.downcast_ref::<bip39::ErrorKind>() { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord => key, - bip39::ErrorKind::InvalidChecksum => bail!("key mnemonic was not valid"), - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } - } else { - // unknown error. assume they copied the base64 key - key - } - } - }; - - file.write_all(key.as_bytes()).await?; - println!("Logged in!"); Ok(()) |