Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using existing key file on login #688

Merged
merged 3 commits into from
Feb 10, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
86 changes: 53 additions & 33 deletions src/command/client/sync/login.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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 },
Expand All @@ -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(())
Expand Down