Skip to content

Commit

Permalink
Provide password feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFeickert committed Jan 13, 2023
1 parent 3b21199 commit b419bfc
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 18 deletions.
130 changes: 122 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions applications/tari_console_wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ tracing = "0.1.26"
unicode-segmentation = "1.6.0"
unicode-width = "0.1"
zeroize = "1"
zxcvbn = "2"

[dependencies.tari_core]
path = "../../base_layer/core"
Expand Down
65 changes: 55 additions & 10 deletions applications/tari_console_wallet/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ use tari_wallet::{
WalletConfig,
WalletSqlite,
};
use zxcvbn::{feedback::Suggestion, zxcvbn};

use crate::{
cli::Cli,
Expand All @@ -77,6 +78,46 @@ pub enum WalletBoot {
Recovery,
}

/// Get feedback, if available, for a weak passphrase
fn get_password_feedback(passphrase: &SafePassword) -> Option<Vec<Suggestion>> {
if let Ok(passphrase_str) = std::str::from_utf8(passphrase.reveal()) {
match zxcvbn(passphrase_str, &[]) {
Ok(scoring) => scoring
.feedback()
.to_owned()
.map(|feedback| feedback.suggestions().to_owned()),
_ => None,
}
} else {
// Fail empty if we can't convert the passphrase back to a string, which shouldn't happen
None
}
}

// Display password feedback to the user
fn display_password_feedback(passphrase: &SafePassword) {
if passphrase.reveal().is_empty() {
// The passphrase is empty, which the scoring library doesn't handle
println!("However, an empty password puts your wallet at risk against an attacker with access to this device.");
println!("Use this only if you are sure that your device is safe from prying eyes!");
println!();
} else if let Some(feedback) = get_password_feedback(passphrase) {
// The scoring library provided feedback
println!(
"However, the password you chose is weak; a determined attacker with access to your device may be able to \
guess it."
);
println!("You may want to consider changing it to a stronger one.");
println!("Here are some suggestions:");
for suggestion in feedback {
println!("- {}", suggestion);
}
println!();
} else {
// There is no feedback to provide
}
}

/// Gets the password provided by command line argument or environment variable if available.
/// Otherwise prompts for the password to be typed in.
pub fn get_or_prompt_password(
Expand Down Expand Up @@ -105,15 +146,7 @@ pub fn get_or_prompt_password(
}

fn prompt_password(prompt: &str) -> Result<SafePassword, ExitError> {
let password = loop {
let pass = prompt_password_stdout(prompt).map_err(|e| ExitError::new(ExitCode::IOError, e))?;
if pass.is_empty() {
println!("Password cannot be empty!");
continue;
} else {
break pass;
}
};
let password = prompt_password_stdout(prompt).map_err(|e| ExitError::new(ExitCode::IOError, e))?;

Ok(SafePassword::from(password))
}
Expand Down Expand Up @@ -144,7 +177,14 @@ pub async fn change_password(
// .await
// .map_err(|e| ExitError::new(ExitCode::WalletError, e))?;

println!("Wallet password changed successfully.");
println!("Passwords match.");

// If the passphrase is weak, let the user know
display_password_feedback(&passphrase);

// TODO: remove this warning when this functionality is added
println!();
println!("WARNING: Password change functionality is not yet completed, so continue to use your existing password!");

Ok(())
}
Expand Down Expand Up @@ -625,6 +665,11 @@ pub(crate) fn boot_with_password(
return Err(ExitError::new(ExitCode::InputError, "Passwords don't match!"));
}

println!("Passwords match.");

// If the passphrase is weak, let the user know
display_password_feedback(&password);

password
},
WalletBoot::Existing | WalletBoot::Recovery => {
Expand Down

0 comments on commit b419bfc

Please sign in to comment.