#![allow(clippy::enum_variant_names, clippy::large_enum_variant)]
use std::{str::FromStr, vec};
use color_eyre::eyre::Context;
use inquire::{CustomType, Select};
use strum::{EnumDiscriminants, EnumIter, EnumMessage};
mod using_private_key;
mod using_seed_phrase;
mod using_web_wallet;
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(context = crate::GlobalContext)]
pub struct ImportAccountCommand {
#[interactive_clap(subcommand)]
import_account_actions: ImportAccountActions,
}
#[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(context = crate::GlobalContext)]
#[strum_discriminants(derive(EnumMessage, EnumIter))]
pub enum ImportAccountActions {
#[strum_discriminants(strum(
message = "using-web-wallet - Import existing account using unc Wallet (a.k.a. \"sign in\")"
))]
UsingWebWallet(self::using_web_wallet::LoginFromWebWallet),
#[strum_discriminants(strum(
message = "using-seed-phrase - Import existing account using a seed phrase"
))]
UsingSeedPhrase(self::using_seed_phrase::LoginFromSeedPhrase),
#[strum_discriminants(strum(
message = "using-private-key - Import existing account using a private key"
))]
UsingPrivateKey(self::using_private_key::LoginFromPrivateKey),
}
pub fn login(
network_config: crate::config::NetworkConfig,
credentials_home_dir: std::path::PathBuf,
key_pair_properties_buf: &str,
public_key_str: &str,
error_message: &str,
) -> crate::CliResult {
let public_key: unc_crypto::PublicKey = unc_crypto::PublicKey::from_str(public_key_str)?;
let account_id = loop {
let account_id_from_cli = input_account_id()?;
eprintln!();
if crate::common::verify_account_access_key(
account_id_from_cli.clone(),
public_key.clone(),
network_config.clone(),
)
.is_err()
{
eprintln!("{}", error_message);
#[derive(strum_macros::Display)]
enum ConfirmOptions {
#[strum(to_string = "Yes, I want to re-enter the account_id.")]
Yes,
#[strum(to_string = "No, I want to save the access key information.")]
No,
}
let select_choose_input = Select::new(
"Would you like to re-enter the account_id?",
vec![ConfirmOptions::Yes, ConfirmOptions::No],
)
.prompt()?;
if let ConfirmOptions::No = select_choose_input {
break account_id_from_cli;
}
} else {
break account_id_from_cli;
}
};
crate::common::update_used_account_list_as_signer(&credentials_home_dir, &account_id);
save_access_key(
account_id,
key_pair_properties_buf,
public_key_str,
network_config,
credentials_home_dir,
)?;
Ok(())
}
fn input_account_id() -> color_eyre::eyre::Result<unc_primitives::types::AccountId> {
Ok(CustomType::new("Enter account ID:").prompt()?)
}
fn save_access_key(
account_id: unc_primitives::types::AccountId,
key_pair_properties_buf: &str,
public_key_str: &str,
network_config: crate::config::NetworkConfig,
credentials_home_dir: std::path::PathBuf,
) -> crate::CliResult {
#[derive(strum_macros::Display)]
enum SelectStorage {
#[strum(to_string = "Store the access key in my keychain")]
SaveToKeychain,
#[strum(
to_string = "Store the access key in my legacy keychain (compatible with the old unc CLI)"
)]
SaveToLegacyKeychain,
}
let selection = Select::new(
"Select a keychain to save the access key to:",
vec![
SelectStorage::SaveToKeychain,
SelectStorage::SaveToLegacyKeychain,
],
)
.prompt()?;
if let SelectStorage::SaveToKeychain = selection {
let storage_message = crate::common::save_access_key_to_keychain(
network_config,
key_pair_properties_buf,
public_key_str,
account_id.as_ref(),
)
.wrap_err_with(|| {
format!(
"Failed to save the access key <{}> to the keychain",
public_key_str
)
})?;
eprintln!("{}", storage_message);
return Ok(());
}
let storage_message = crate::common::save_access_key_to_legacy_keychain(
network_config,
credentials_home_dir,
key_pair_properties_buf,
public_key_str,
account_id.as_ref(),
)
.wrap_err_with(|| format!("Failed to save a file with access key: {}", public_key_str))?;
eprintln!("{}", storage_message);
Ok(())
}