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

fix: remove optionals from wallet set up #4984

Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

119 changes: 49 additions & 70 deletions applications/tari_console_wallet/src/init/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,26 @@ pub enum WalletBoot {
pub fn get_or_prompt_password(
arg_password: Option<SafePassword>,
config_password: Option<SafePassword>,
) -> Result<Option<SafePassword>, ExitError> {
if arg_password.is_some() {
return Ok(arg_password);
) -> Result<SafePassword, ExitError> {
if let Some(passphrase) = arg_password {
return Ok(passphrase);
}

let env = std::env::var_os(TARI_WALLET_PASSWORD);
if let Some(p) = env {
let env_password = p
.into_string()
.map_err(|_| ExitError::new(ExitCode::IOError, "Failed to convert OsString into String"))?;
return Ok(Some(env_password.into()));
return Ok(env_password.into());
}

if config_password.is_some() {
return Ok(config_password);
if let Some(passphrase) = config_password {
return Ok(passphrase);
}

let password = prompt_password("Wallet password: ")?;

Ok(Some(password))
Ok(password)
}

fn prompt_password(prompt: &str) -> Result<SafePassword, ExitError> {
Expand All @@ -121,7 +121,7 @@ fn prompt_password(prompt: &str) -> Result<SafePassword, ExitError> {
/// Allows the user to change the password of the wallet.
pub async fn change_password(
config: &ApplicationConfig,
arg_password: Option<SafePassword>,
arg_password: SafePassword,
shutdown_signal: ShutdownSignal,
non_interactive_mode: bool,
) -> Result<(), ExitError> {
Expand Down Expand Up @@ -250,7 +250,7 @@ pub(crate) fn wallet_mode(cli: &Cli, boot_mode: WalletBoot) -> WalletMode {
#[allow(clippy::too_many_lines)]
pub async fn init_wallet(
config: &ApplicationConfig,
arg_password: Option<SafePassword>,
arg_password: SafePassword,
seed_words_file_name: Option<PathBuf>,
recovery_seed: Option<CipherSeed>,
shutdown_signal: ShutdownSignal,
Expand All @@ -269,34 +269,16 @@ pub async fn init_wallet(

debug!(target: LOG_TARGET, "Running Wallet database migrations");

// test encryption by initializing with no passphrase...
let db_path = &config.wallet.db_file;

let result = initialize_sqlite_database_backends(db_path, None, config.wallet.db_connection_pool_size);
let (backends, wallet_encrypted) = match result {
Ok(backends) => {
// wallet is not encrypted
(backends, false)
},
Err(WalletStorageError::NoPasswordError) => {
// get supplied or prompt password
let passphrase = get_or_prompt_password(arg_password.clone(), config.wallet.password.clone())?;
let backends =
initialize_sqlite_database_backends(db_path, passphrase, config.wallet.db_connection_pool_size)?;
(backends, true)
},
Err(e) => {
return Err(e.into());
},
};
let (wallet_backend, transaction_backend, output_manager_backend, contacts_backend, key_manager_backend) = backends;
// wallet should be encrypted from the beginning, so we must require a password to be provided by the user
let (wallet_backend, transaction_backend, output_manager_backend, contacts_backend, key_manager_backend) =
initialize_sqlite_database_backends(db_path, arg_password, config.wallet.db_connection_pool_size)?;

let wallet_db = WalletDatabase::new(wallet_backend);
let output_db = OutputManagerDatabase::new(output_manager_backend.clone());

debug!(
target: LOG_TARGET,
"Databases Initialized. Wallet encrypted? {}.", wallet_encrypted
);
debug!(target: LOG_TARGET, "Databases Initialized. Wallet is encrypted.",);

let node_address = match config.wallet.p2p.public_address.clone() {
Some(addr) => addr,
Expand Down Expand Up @@ -362,43 +344,6 @@ pub async fn init_wallet(
.map_err(|e| ExitError::new(ExitCode::WalletError, format!("Problem writing tor identity. {}", e)))?;
}

if !wallet_encrypted {
debug!(target: LOG_TARGET, "Wallet is not encrypted.");

// create using --password arg if supplied and skip seed words confirmation
let passphrase = match arg_password {
Some(password) => {
debug!(target: LOG_TARGET, "Setting password from command line argument.");
password
},
None => {
debug!(target: LOG_TARGET, "Prompting for password.");
let password = prompt_password("Create wallet password: ")?;
let confirmed = prompt_password("Confirm wallet password: ")?;

if password.reveal() != confirmed.reveal() {
return Err(ExitError::new(ExitCode::InputError, "Passwords don't match!"));
}

password
},
};

wallet.apply_encryption(passphrase).await?;

debug!(target: LOG_TARGET, "Wallet encrypted.");

if !non_interactive_mode && recovery_seed.is_none() {
match confirm_seed_words(&mut wallet) {
Ok(()) => {
print!("\x1Bc"); // Clear the screen
},
Err(error) => {
return Err(error);
},
};
}
}
if let Some(file_name) = seed_words_file_name {
let seed_words = wallet.get_seed_words(&MnemonicLanguage::English)?.join(" ");
let _result = fs::write(file_name, seed_words.reveal()).map_err(|e| {
Expand Down Expand Up @@ -590,7 +535,7 @@ pub fn tari_splash_screen(heading: &str) {

/// Prompts the user for a new wallet or to recover an existing wallet.
/// Returns the wallet bootmode indicating if it's a new or existing wallet, or if recovery is required.
pub(crate) fn boot(cli: &Cli, wallet_config: &WalletConfig) -> Result<WalletBoot, ExitError> {
fn boot(cli: &Cli, wallet_config: &WalletConfig) -> Result<WalletBoot, ExitError> {
let wallet_exists = wallet_config.db_file.exists();

// forced recovery
Expand Down Expand Up @@ -652,3 +597,37 @@ pub(crate) fn boot(cli: &Cli, wallet_config: &WalletConfig) -> Result<WalletBoot
}
}
}

pub(crate) fn boot_with_password(
cli: &Cli,
wallet_config: &WalletConfig,
) -> Result<(WalletBoot, SafePassword), ExitError> {
let boot_mode = boot(cli, wallet_config)?;

if cli.password.is_some() {
return Ok((boot_mode, cli.password.clone().unwrap()));
}
if wallet_config.password.is_some() {
return Ok((boot_mode, wallet_config.password.clone().unwrap()));
}

let password = match boot_mode {
WalletBoot::New => {
debug!(target: LOG_TARGET, "Prompting for password.");
let password = prompt_password("Create wallet password: ")?;
let confirmed = prompt_password("Confirm wallet password: ")?;

if password.reveal() != confirmed.reveal() {
return Err(ExitError::new(ExitCode::InputError, "Passwords don't match!"));
}

password
},
WalletBoot::Existing | WalletBoot::Recovery => {
debug!(target: LOG_TARGET, "Prompting for password.");
prompt_password("Prompt wallet password: ")?
},
};

Ok((boot_mode, password))
}
14 changes: 3 additions & 11 deletions applications/tari_console_wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,7 @@ mod utils;
mod wallet_modes;

pub use cli::Cli;
use init::{
boot,
change_password,
get_base_node_peer_config,
init_wallet,
start_wallet,
tari_splash_screen,
WalletBoot,
};
use init::{change_password, get_base_node_peer_config, init_wallet, start_wallet, tari_splash_screen, WalletBoot};
use log::*;
use recovery::{get_seed_from_seed_words, prompt_private_key_from_seed_words};
use tari_app_utilities::{common_cli_args::CommonCliArgs, consts};
Expand All @@ -57,7 +49,7 @@ use tokio::runtime::Runtime;
use wallet_modes::{command_mode, grpc_mode, recovery_mode, script_mode, tui_mode, WalletMode};

pub use crate::config::ApplicationConfig;
use crate::init::wallet_mode;
use crate::init::{boot_with_password, wallet_mode};

pub const LOG_TARGET: &str = "wallet::console_wallet::main";

Expand Down Expand Up @@ -110,7 +102,7 @@ pub fn run_wallet_with_cli(runtime: Runtime, config: &mut ApplicationConfig, cli
}

// check for recovery based on existence of wallet file
let mut boot_mode = boot(&cli, &config.wallet)?;
let (mut boot_mode, password) = boot_with_password(&cli, &config.wallet)?;

let recovery_seed = get_recovery_seed(boot_mode, &cli)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const LOG_TARGET: &str = "wallet::key_manager_service::database::wallet";
#[derive(Clone)]
pub struct KeyManagerSqliteDatabase {
database_connection: WalletDbConnection,
cipher: Arc<RwLock<Option<XChaCha20Poly1305>>>,
cipher: Arc<RwLock<XChaCha20Poly1305>>,
}

impl KeyManagerSqliteDatabase {
Expand All @@ -56,7 +56,7 @@ impl KeyManagerSqliteDatabase {
/// not encrypt sensitive fields
pub fn new(
database_connection: WalletDbConnection,
cipher: Option<XChaCha20Poly1305>,
cipher: XChaCha20Poly1305,
) -> Result<Self, KeyManagerStorageError> {
let db = Self {
database_connection,
Expand All @@ -67,19 +67,19 @@ impl KeyManagerSqliteDatabase {

fn decrypt_if_necessary<T: Encryptable<XChaCha20Poly1305>>(&self, o: &mut T) -> Result<(), KeyManagerStorageError> {
let cipher = acquire_read_lock!(self.cipher);
if let Some(cipher) = cipher.as_ref() {
o.decrypt(cipher)
.map_err(|_| KeyManagerStorageError::AeadError("Decryption Error".to_string()))?;
}

jorgeantonio21 marked this conversation as resolved.
Show resolved Hide resolved
o.decrypt(&cipher)
.map_err(|_| KeyManagerStorageError::AeadError("Decryption Error".to_string()))?;

Ok(())
}

fn encrypt_if_necessary<T: Encryptable<XChaCha20Poly1305>>(&self, o: &mut T) -> Result<(), KeyManagerStorageError> {
let cipher = acquire_read_lock!(self.cipher);
if let Some(cipher) = cipher.as_ref() {
o.encrypt(cipher)
.map_err(|_| KeyManagerStorageError::AeadError("Encryption Error".to_string()))?;
}

o.encrypt(&cipher)
.map_err(|_| KeyManagerStorageError::AeadError("Encryption Error".to_string()))?;

Ok(())
}
}
Expand Down Expand Up @@ -181,10 +181,6 @@ impl KeyManagerBackend for KeyManagerSqliteDatabase {
fn apply_encryption(&self, cipher: XChaCha20Poly1305) -> Result<(), KeyManagerStorageError> {
let mut current_cipher = acquire_write_lock!(self.cipher);

if (*current_cipher).is_some() {
return Err(KeyManagerStorageError::AlreadyEncrypted);
}

let start = Instant::now();
let conn = self.database_connection.get_pooled_connection()?;
let acquire_lock = start.elapsed();
Expand All @@ -197,7 +193,7 @@ impl KeyManagerBackend for KeyManagerSqliteDatabase {
key_manager_state.set_state(&conn)?;
}

(*current_cipher) = Some(cipher);
(*current_cipher) = cipher;
if start.elapsed().as_millis() > 0 {
trace!(
target: LOG_TARGET,
Expand All @@ -212,12 +208,9 @@ impl KeyManagerBackend for KeyManagerSqliteDatabase {
}

fn remove_encryption(&self) -> Result<(), KeyManagerStorageError> {
let mut current_cipher = acquire_write_lock!(self.cipher);
let cipher = if let Some(cipher) = (*current_cipher).clone().take() {
cipher
} else {
return Ok(());
};
let current_cipher = acquire_write_lock!(self.cipher);
let cipher = (*current_cipher).clone();

let start = Instant::now();
let conn = self.database_connection.get_pooled_connection()?;
let acquire_lock = start.elapsed();
Expand All @@ -229,8 +222,6 @@ impl KeyManagerBackend for KeyManagerSqliteDatabase {
.map_err(|_| KeyManagerStorageError::AeadError("Encryption Error".to_string()))?;
key_manager_state.set_state(&conn)?;
}
// Now that all the decryption has been completed we can safely remove the cipher fully
std::mem::drop((*current_cipher).take());
if start.elapsed().as_millis() > 0 {
trace!(
target: LOG_TARGET,
Expand Down
Loading