From e71d79dc38665e83cd5e8b8e86bbe72d04b21533 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Fri, 31 Jan 2020 09:18:11 +0000 Subject: [PATCH] Rework directory checks/setups at launch (#318) * rework setup code to ensure --top_level_dir flag works and all files are only output into the desired directory * check for existence of wallet configuration file in target directory before asking recovery phrase and password * test fixes and add test_mode flag to parse_init_args --- config/src/config.rs | 73 +++++++++++++++++++++++++++++++----------- config/src/lib.rs | 4 ++- config/src/types.rs | 4 +++ src/bin/grin-wallet.rs | 32 ++++++++++++++++-- src/cmd/wallet_args.rs | 12 +++++-- tests/common/mod.rs | 2 +- 6 files changed, 101 insertions(+), 26 deletions(-) diff --git a/config/src/config.rs b/config/src/config.rs index 6349680..731ba7c 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -42,7 +42,10 @@ pub const API_SECRET_FILE_NAME: &'static str = ".api_secret"; /// Owner API secret pub const OWNER_API_SECRET_FILE_NAME: &'static str = ".owner_api_secret"; -fn get_grin_path(chain_type: &global::ChainTypes) -> Result { +fn get_grin_path( + chain_type: &global::ChainTypes, + create_path: bool, +) -> Result { // Check if grin dir exists let mut grin_path = match dirs::home_dir() { Some(p) => p, @@ -51,10 +54,17 @@ fn get_grin_path(chain_type: &global::ChainTypes) -> Result Option { @@ -72,6 +82,13 @@ fn check_config_current_dir(path: &str) -> Option { None } +/// Whether a config file exists at the given directory +pub fn config_file_exists(path: &str) -> bool { + let mut path = PathBuf::from(path); + path.push(WALLET_CONFIG_FILE_NAME); + path.exists() +} + /// Create file with api secret pub fn init_api_secret(api_secret_path: &PathBuf) -> Result<(), ConfigError> { let mut api_secret_file = File::create(api_secret_path)?; @@ -104,7 +121,7 @@ fn check_api_secret_file( ) -> Result<(), ConfigError> { let grin_path = match data_path { Some(p) => p, - None => get_grin_path(chain_type)?, + None => get_grin_path(chain_type, false)?, }; let mut api_secret_path = grin_path.clone(); api_secret_path.push(file_name); @@ -119,17 +136,23 @@ fn check_api_secret_file( pub fn initial_setup_wallet( chain_type: &global::ChainTypes, data_path: Option, + create_path: bool, ) -> Result { - check_api_secret_file(chain_type, data_path.clone(), OWNER_API_SECRET_FILE_NAME)?; - check_api_secret_file(chain_type, data_path.clone(), API_SECRET_FILE_NAME)?; + if create_path { + if let Some(p) = data_path.clone() { + fs::create_dir_all(p)?; + } + } // Use config file if current directory if it exists, .grin home otherwise - if let Some(p) = check_config_current_dir(WALLET_CONFIG_FILE_NAME) { - GlobalWalletConfig::new(p.to_str().unwrap()) + let (path, config) = if let Some(p) = check_config_current_dir(WALLET_CONFIG_FILE_NAME) { + let mut path = p.clone(); + path.pop(); + (path, GlobalWalletConfig::new(p.to_str().unwrap())?) } else { // Check if grin dir exists - let grin_path = match data_path { + let grin_path = match data_path.clone() { Some(p) => p, - None => get_grin_path(chain_type)?, + None => get_grin_path(chain_type, create_path)?, }; // Get path to default config file @@ -137,16 +160,28 @@ pub fn initial_setup_wallet( config_path.push(WALLET_CONFIG_FILE_NAME); // Return defaults if file doesn't exist - if !config_path.exists() { - let mut default_config = GlobalWalletConfig::for_chain(chain_type); - default_config.config_file_path = Some(config_path); - // update paths relative to current dir - default_config.update_paths(&grin_path); - Ok(default_config) - } else { - GlobalWalletConfig::new(config_path.to_str().unwrap()) + match config_path.clone().exists() { + false => { + let mut default_config = GlobalWalletConfig::for_chain(chain_type); + default_config.config_file_path = Some(config_path); + // update paths relative to current dir + default_config.update_paths(&grin_path); + (grin_path, default_config) + } + true => { + let mut path = config_path.clone(); + path.pop(); + ( + path, + GlobalWalletConfig::new(config_path.to_str().unwrap())?, + ) + } } - } + }; + + check_api_secret_file(chain_type, Some(path.clone()), OWNER_API_SECRET_FILE_NAME)?; + check_api_secret_file(chain_type, Some(path), API_SECRET_FILE_NAME)?; + Ok(config) } impl Default for GlobalWalletConfigMembers { diff --git a/config/src/lib.rs b/config/src/lib.rs index 313e0b5..e64ee56 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -30,7 +30,9 @@ mod comments; pub mod config; pub mod types; -pub use crate::config::{initial_setup_wallet, GRIN_WALLET_DIR, WALLET_CONFIG_FILE_NAME}; +pub use crate::config::{ + config_file_exists, initial_setup_wallet, GRIN_WALLET_DIR, WALLET_CONFIG_FILE_NAME, +}; pub use crate::types::{ ConfigError, GlobalWalletConfig, GlobalWalletConfigMembers, TorConfig, WalletConfig, }; diff --git a/config/src/types.rs b/config/src/types.rs index 57b6ca7..911a585 100644 --- a/config/src/types.rs +++ b/config/src/types.rs @@ -115,6 +115,9 @@ pub enum ConfigError { /// Error serializing config values SerializationError(String), + + /// Path doesn't exist + PathNotFoundError(String), } impl fmt::Display for ConfigError { @@ -134,6 +137,7 @@ impl fmt::Display for ConfigError { ConfigError::SerializationError(ref message) => { write!(f, "Error serializing configuration: {}", message) } + ConfigError::PathNotFoundError(ref message) => write!(f, "Path not found: {}", message), } } } diff --git a/src/bin/grin-wallet.rs b/src/bin/grin-wallet.rs index 31070de..e7c4305 100644 --- a/src/bin/grin-wallet.rs +++ b/src/bin/grin-wallet.rs @@ -19,6 +19,7 @@ extern crate clap; #[macro_use] extern crate log; +use crate::config::ConfigError; use crate::core::global; use crate::util::init_logger; use clap::App; @@ -27,6 +28,7 @@ use grin_wallet_impls::HTTPNodeClient; use grin_wallet_util::grin_core as core; use grin_wallet_util::grin_util as util; use std::env; +use std::path::PathBuf; use grin_wallet::cmd; @@ -80,6 +82,19 @@ fn real_main() -> i32 { }; let mut current_dir = None; + let mut create_path = false; + + if args.is_present("top_level_dir") { + let res = args.value_of("top_level_dir"); + match res { + Some(d) => { + current_dir = Some(PathBuf::from(d)); + } + None => { + warn!("Argument --top_level_dir needs a value. Defaulting to current directory") + } + } + } // special cases for certain lifecycle commands match args.subcommand() { @@ -89,15 +104,26 @@ fn real_main() -> i32 { panic!("Error creating config file: {}", e); })); } + create_path = true; } _ => {} } // Load relevant config, try and load a wallet config file // Use defaults for configuration if config file not found anywhere - let mut config = config::initial_setup_wallet(&chain_type, current_dir).unwrap_or_else(|e| { - panic!("Error loading wallet configuration: {}", e); - }); + let mut config = match config::initial_setup_wallet(&chain_type, current_dir, create_path) { + Ok(c) => c, + Err(e) => match e { + ConfigError::PathNotFoundError(m) => { + println!("Wallet configuration not found at {}. (Run `grin-wallet init` to create a new wallet)", m); + return 0; + } + m => { + println!("Unable to load wallet configuration: {} (Run `grin-wallet init` to create a new wallet)", m); + return 0; + } + }, + }; //config.members.as_mut().unwrap().wallet.chain_type = Some(chain_type); diff --git a/src/cmd/wallet_args.rs b/src/cmd/wallet_args.rs index 7cf948f..2a173d1 100644 --- a/src/cmd/wallet_args.rs +++ b/src/cmd/wallet_args.rs @@ -19,7 +19,7 @@ use crate::util::{Mutex, ZeroingString}; /// Argument parsing and error handling for wallet commands use clap::ArgMatches; use failure::Fail; -use grin_wallet_config::{TorConfig, WalletConfig}; +use grin_wallet_config::{config_file_exists, TorConfig, WalletConfig}; use grin_wallet_controller::command; use grin_wallet_controller::{Error, ErrorKind}; use grin_wallet_impls::tor::config::is_tor_address; @@ -58,6 +58,8 @@ pub enum ParseError { ArgumentError(String), #[fail(display = "Parsing IO error: {}", _0)] IOError(String), + #[fail(display = "Wallet configuration already exists: {}", _0)] + WalletExists(String), #[fail(display = "User Cancelled")] CancelledError, } @@ -298,6 +300,7 @@ pub fn parse_init_args( config: &WalletConfig, g_args: &command::GlobalArgs, args: &ArgMatches, + test_mode: bool, ) -> Result where DefaultWalletImpl<'static, C>: WalletInst<'static, L, C, K>, @@ -305,6 +308,10 @@ where C: NodeClient + 'static, K: keychain::Keychain + 'static, { + if config_file_exists(&config.data_file_dir) && !test_mode { + return Err(ParseError::WalletExists(config.data_file_dir.clone())); + } + let list_length = match args.is_present("short_wordlist") { false => 32, true => 16, @@ -951,7 +958,8 @@ where wallet.clone(), &wallet_config, &global_wallet_args, - &args + &args, + test_mode, )); command::init(wallet, &global_wallet_args, a) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 6497de6..1f55bda 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -308,7 +308,7 @@ where { let args = app.clone().get_matches_from(arg_vec); let _ = get_wallet_subcommand(test_dir, wallet_name, args.clone()); - let config = config::initial_setup_wallet(&ChainTypes::AutomatedTesting, None).unwrap(); + let config = config::initial_setup_wallet(&ChainTypes::AutomatedTesting, None, true).unwrap(); let mut wallet_config = config.clone().members.unwrap().wallet; wallet_config.chain_type = None; wallet_config.api_secret_path = None;