Skip to content

Commit

Permalink
Rework directory checks/setups at launch (mimblewimble#318)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
yeastplume authored Jan 31, 2020
1 parent 14e126b commit e71d79d
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 26 deletions.
73 changes: 54 additions & 19 deletions config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PathBuf, ConfigError> {
fn get_grin_path(
chain_type: &global::ChainTypes,
create_path: bool,
) -> Result<PathBuf, ConfigError> {
// Check if grin dir exists
let mut grin_path = match dirs::home_dir() {
Some(p) => p,
Expand All @@ -51,10 +54,17 @@ fn get_grin_path(chain_type: &global::ChainTypes) -> Result<PathBuf, ConfigError
grin_path.push(GRIN_HOME);
grin_path.push(chain_type.shortname());
// Create if the default path doesn't exist
if !grin_path.exists() {
if !grin_path.exists() && create_path {
fs::create_dir_all(grin_path.clone())?;
}
Ok(grin_path)

if !grin_path.exists() {
return Err(ConfigError::PathNotFoundError(String::from(
grin_path.to_str().unwrap(),
)));
} else {
Ok(grin_path)
}
}

fn check_config_current_dir(path: &str) -> Option<PathBuf> {
Expand All @@ -72,6 +82,13 @@ fn check_config_current_dir(path: &str) -> Option<PathBuf> {
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)?;
Expand Down Expand Up @@ -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);
Expand All @@ -119,34 +136,52 @@ fn check_api_secret_file(
pub fn initial_setup_wallet(
chain_type: &global::ChainTypes,
data_path: Option<PathBuf>,
create_path: bool,
) -> Result<GlobalWalletConfig, ConfigError> {
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
let mut config_path = grin_path.clone();
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 {
Expand Down
4 changes: 3 additions & 1 deletion config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
4 changes: 4 additions & 0 deletions config/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ pub enum ConfigError {

/// Error serializing config values
SerializationError(String),

/// Path doesn't exist
PathNotFoundError(String),
}

impl fmt::Display for ConfigError {
Expand All @@ -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),
}
}
}
Expand Down
32 changes: 29 additions & 3 deletions src/bin/grin-wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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() {
Expand All @@ -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);

Expand Down
12 changes: 10 additions & 2 deletions src/cmd/wallet_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -298,13 +300,18 @@ pub fn parse_init_args<L, C, K>(
config: &WalletConfig,
g_args: &command::GlobalArgs,
args: &ArgMatches,
test_mode: bool,
) -> Result<command::InitArgs, ParseError>
where
DefaultWalletImpl<'static, C>: WalletInst<'static, L, C, K>,
L: WalletLCProvider<'static, C, K>,
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,
Expand Down Expand Up @@ -951,7 +958,8 @@ where
wallet.clone(),
&wallet_config,
&global_wallet_args,
&args
&args,
test_mode,
));
command::init(wallet, &global_wallet_args, a)
}
Expand Down
2 changes: 1 addition & 1 deletion tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit e71d79d

Please sign in to comment.