refactor passkey/password prompts so they are always SecretString (#281)
This commit is contained in:
parent
d9261d0ac8
commit
df47ff1823
5 changed files with 42 additions and 30 deletions
|
@ -45,8 +45,7 @@ fn load_accounts_with_prompts(manager: &mut AccountManager) -> anyhow::Result<()
|
||||||
if manager.has_passkey() {
|
if manager.has_passkey() {
|
||||||
error!("Incorrect passkey");
|
error!("Incorrect passkey");
|
||||||
}
|
}
|
||||||
let passkey = rpassword::prompt_password_stdout("Enter encryption passkey: ").ok();
|
let passkey = Some(crate::tui::prompt_passkey()?);
|
||||||
let passkey = passkey.map(SecretString::new);
|
|
||||||
manager.submit_passkey(passkey);
|
manager.submit_passkey(passkey);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use secrecy::ExposeSecret;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
encryption::{EncryptionScheme, EntryEncryptor},
|
encryption::{EncryptionScheme, EntryEncryptor},
|
||||||
|
@ -17,23 +18,22 @@ where
|
||||||
{
|
{
|
||||||
fn execute(&self, _transport: T, manager: &mut AccountManager) -> anyhow::Result<()> {
|
fn execute(&self, _transport: T, manager: &mut AccountManager) -> anyhow::Result<()> {
|
||||||
if !manager.has_passkey() {
|
if !manager.has_passkey() {
|
||||||
let mut passkey;
|
let passkey: Option<SecretString>;
|
||||||
loop {
|
loop {
|
||||||
passkey = rpassword::prompt_password_stdout("Enter encryption passkey: ").ok();
|
let passkey1 = tui::prompt_passkey()?;
|
||||||
if let Some(p) = passkey.as_ref() {
|
if passkey1.expose_secret().is_empty() {
|
||||||
if p.is_empty() {
|
error!("Passkey cannot be empty, try again.");
|
||||||
error!("Passkey cannot be empty, try again.");
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let passkey_confirm =
|
let passkey_confirm =
|
||||||
rpassword::prompt_password_stdout("Confirm encryption passkey: ").ok();
|
rpassword::prompt_password_stdout("Confirm encryption passkey: ")
|
||||||
if passkey == passkey_confirm {
|
.map(SecretString::new)?;
|
||||||
|
if passkey1.expose_secret() == passkey_confirm.expose_secret() {
|
||||||
|
passkey = Some(passkey1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
error!("Passkeys do not match, try again.");
|
error!("Passkeys do not match, try again.");
|
||||||
}
|
}
|
||||||
let passkey = passkey.map(SecretString::new);
|
|
||||||
|
|
||||||
#[cfg(feature = "keyring")]
|
#[cfg(feature = "keyring")]
|
||||||
{
|
{
|
||||||
|
|
20
src/login.rs
20
src/login.rs
|
@ -1,6 +1,7 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use secrecy::{ExposeSecret, SecretString};
|
||||||
use steamguard::{
|
use steamguard::{
|
||||||
protobufs::steammessages_auth_steamclient::{EAuthSessionGuardType, EAuthTokenPlatformType},
|
protobufs::steammessages_auth_steamclient::{EAuthSessionGuardType, EAuthTokenPlatformType},
|
||||||
refresher::TokenRefresher,
|
refresher::TokenRefresher,
|
||||||
|
@ -42,8 +43,8 @@ pub fn do_login<T: Transport + Clone>(
|
||||||
account.account_name = tui::prompt();
|
account.account_name = tui::prompt();
|
||||||
}
|
}
|
||||||
let _ = std::io::stdout().flush();
|
let _ = std::io::stdout().flush();
|
||||||
let password = rpassword::prompt_password_stdout("Password: ").unwrap();
|
let password = tui::prompt_password()?;
|
||||||
if !password.is_empty() {
|
if !password.expose_secret().is_empty() {
|
||||||
debug!("password is present");
|
debug!("password is present");
|
||||||
} else {
|
} else {
|
||||||
debug!("password is empty");
|
debug!("password is empty");
|
||||||
|
@ -65,8 +66,8 @@ pub fn do_login_raw<T: Transport + Clone>(
|
||||||
username: String,
|
username: String,
|
||||||
) -> anyhow::Result<Tokens> {
|
) -> anyhow::Result<Tokens> {
|
||||||
let _ = std::io::stdout().flush();
|
let _ = std::io::stdout().flush();
|
||||||
let password = rpassword::prompt_password_stdout("Password: ").unwrap();
|
let password = tui::prompt_password()?;
|
||||||
if !password.is_empty() {
|
if !password.expose_secret().is_empty() {
|
||||||
debug!("password is present");
|
debug!("password is present");
|
||||||
} else {
|
} else {
|
||||||
debug!("password is empty");
|
debug!("password is empty");
|
||||||
|
@ -77,7 +78,7 @@ pub fn do_login_raw<T: Transport + Clone>(
|
||||||
fn do_login_impl<T: Transport + Clone>(
|
fn do_login_impl<T: Transport + Clone>(
|
||||||
transport: T,
|
transport: T,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: SecretString,
|
||||||
account: Option<&SteamGuardAccount>,
|
account: Option<&SteamGuardAccount>,
|
||||||
) -> anyhow::Result<Tokens> {
|
) -> anyhow::Result<Tokens> {
|
||||||
let mut login = UserLogin::new(transport.clone(), build_device_details());
|
let mut login = UserLogin::new(transport.clone(), build_device_details());
|
||||||
|
@ -85,7 +86,7 @@ fn do_login_impl<T: Transport + Clone>(
|
||||||
let mut password = password;
|
let mut password = password;
|
||||||
let confirmation_methods;
|
let confirmation_methods;
|
||||||
loop {
|
loop {
|
||||||
match login.begin_auth_via_credentials(&username, &password) {
|
match login.begin_auth_via_credentials(&username, password.expose_secret()) {
|
||||||
Ok(methods) => {
|
Ok(methods) => {
|
||||||
confirmation_methods = methods;
|
confirmation_methods = methods;
|
||||||
break;
|
break;
|
||||||
|
@ -95,11 +96,8 @@ fn do_login_impl<T: Transport + Clone>(
|
||||||
return Err(LoginError::TooManyAttempts.into());
|
return Err(LoginError::TooManyAttempts.into());
|
||||||
}
|
}
|
||||||
Err(LoginError::BadCredentials) => {
|
Err(LoginError::BadCredentials) => {
|
||||||
error!("Incorrect password.");
|
error!("Incorrect password for {username}");
|
||||||
password = rpassword::prompt_password_stdout("Password: ")
|
password = tui::prompt_password()?;
|
||||||
.unwrap()
|
|
||||||
.trim()
|
|
||||||
.to_owned();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -152,9 +152,7 @@ fn run(args: commands::Args) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw =
|
passkey = Some(tui::prompt_passkey()?);
|
||||||
rpassword::prompt_password_stdout("Enter encryption passkey: ")?;
|
|
||||||
passkey = Some(SecretString::new(raw));
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to migrate manifest: {}", e);
|
error!("Failed to migrate manifest: {}", e);
|
||||||
|
@ -208,8 +206,7 @@ fn run(args: commands::Args) -> anyhow::Result<()> {
|
||||||
if manager.has_passkey() {
|
if manager.has_passkey() {
|
||||||
error!("Incorrect passkey");
|
error!("Incorrect passkey");
|
||||||
}
|
}
|
||||||
let raw = rpassword::prompt_password_stdout("Enter encryption passkey: ")?;
|
passkey = Some(tui::prompt_passkey()?);
|
||||||
passkey = Some(SecretString::new(raw));
|
|
||||||
manager.submit_passkey(passkey);
|
manager.submit_passkey(passkey);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -253,8 +250,7 @@ fn run(args: commands::Args) -> anyhow::Result<()> {
|
||||||
if manager.has_passkey() {
|
if manager.has_passkey() {
|
||||||
error!("Incorrect passkey");
|
error!("Incorrect passkey");
|
||||||
}
|
}
|
||||||
let raw = rpassword::prompt_password_stdout("Enter encryption passkey: ")?;
|
passkey = Some(tui::prompt_passkey()?);
|
||||||
passkey = Some(SecretString::new(raw));
|
|
||||||
manager.submit_passkey(passkey);
|
manager.submit_passkey(passkey);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
19
src/tui.rs
19
src/tui.rs
|
@ -6,6 +6,7 @@ use crossterm::{
|
||||||
terminal::{Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
QueueableCommand,
|
QueueableCommand,
|
||||||
};
|
};
|
||||||
|
use secrecy::SecretString;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::{stderr, stdout, Write};
|
use std::io::{stderr, stdout, Write};
|
||||||
use steamguard::Confirmation;
|
use steamguard::Confirmation;
|
||||||
|
@ -244,6 +245,24 @@ pub(crate) fn pause() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn prompt_passkey() -> std::io::Result<SecretString> {
|
||||||
|
loop {
|
||||||
|
let raw = rpassword::prompt_password_stdout("Enter encryption passkey: ")?;
|
||||||
|
if !raw.is_empty() {
|
||||||
|
return Ok(SecretString::new(raw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn prompt_password() -> std::io::Result<SecretString> {
|
||||||
|
loop {
|
||||||
|
let raw = rpassword::prompt_password_stdout("Password: ")?;
|
||||||
|
if !raw.is_empty() {
|
||||||
|
return Ok(SecretString::new(raw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod prompt_char_tests {
|
mod prompt_char_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
Loading…
Reference in a new issue