diff --git a/src/commands/vault.rs b/src/commands/vault.rs index 07b40fcf5244172a9444eed482b3f1fc825cdf62..8d7b814dbef71fc4b13efdf6d20dc8c5de6b94f8 100644 --- a/src/commands/vault.rs +++ b/src/commands/vault.rs @@ -3,12 +3,12 @@ mod display; use crate::commands::cesium::compute_g1v1_public_key; use crate::entities::vault_account; use crate::entities::vault_account::{AccountTreeNode, ActiveModel, DbAccountId}; -use crate::*; use crate::keys::seed_from_cesium; +use crate::*; use age::secrecy::Secret; use sea_orm::ActiveValue::Set; -use sea_orm::{ConnectionTrait, TransactionTrait}; use sea_orm::ModelTrait; +use sea_orm::{ConnectionTrait, TransactionTrait}; use sp_core::crypto::AddressUri; use std::cell::RefCell; use std::io::{Read, Write}; @@ -42,31 +42,31 @@ pub enum Subcommand { /// Secret key format (substrate, seed, g1v1) #[clap(short = 'S', long, required = false, default_value = SecretFormat::Substrate)] secret_format: SecretFormat, - + /// Crypto scheme to use (sr25519, ed25519) #[clap(short = 'c', long, required = false, default_value = CryptoScheme::Ed25519)] crypto_scheme: CryptoScheme, - + /// Substrate URI to import (non-interactive mode) #[clap(short = 'u', long, required = false)] uri: Option<String>, - + /// G1v1 ID (non-interactive mode for g1v1 format) #[clap(long, required = false)] g1v1_id: Option<String>, - + /// G1v1 password (non-interactive mode for g1v1 format) #[clap(long, required = false)] g1v1_password: Option<String>, - + /// Password for encrypting the key (non-interactive mode) #[clap(short = 'p', long, required = false)] password: Option<String>, - + /// Use empty password (non-interactive mode) #[clap(long, required = false)] no_password: bool, - + /// Name for the wallet entry (non-interactive mode) #[clap(short = 'n', long, required = false)] name: Option<String>, @@ -155,7 +155,10 @@ pub enum ListChoice { impl Default for ListChoice { fn default() -> Self { - ListChoice::All { show_g1v1: false, show_type: false } + ListChoice::All { + show_g1v1: false, + show_type: false, + } } } @@ -209,20 +212,34 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE // match subcommand match command { Subcommand::List(choice) => match choice { - ListChoice::All { show_g1v1, show_type } => { + ListChoice::All { + show_g1v1, + show_type, + } => { let all_account_tree_node_hierarchies = vault_account::fetch_all_base_account_tree_node_hierarchies(db).await?; - let table = display::compute_vault_accounts_table_with_g1v1(&all_account_tree_node_hierarchies, show_g1v1, show_type)?; + let table = display::compute_vault_accounts_table_with_g1v1( + &all_account_tree_node_hierarchies, + show_g1v1, + show_type, + )?; println!("available SS58 Addresses:"); println!("{table}"); } - ListChoice::Base { show_g1v1, show_type } => { + ListChoice::Base { + show_g1v1, + show_type, + } => { let base_account_tree_nodes = vault_account::fetch_only_base_account_tree_nodes(db).await?; - let table = display::compute_vault_accounts_table_with_g1v1(&base_account_tree_nodes, show_g1v1, show_type)?; + let table = display::compute_vault_accounts_table_with_g1v1( + &base_account_tree_nodes, + show_g1v1, + show_type, + )?; println!("available <Base> SS58 Addresses:"); println!("{table}"); @@ -238,7 +255,11 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE let base_account_tree_node = vault_account::get_base_account_tree_node(&account_tree_node); - let table = display::compute_vault_accounts_table_with_g1v1(&[base_account_tree_node], show_g1v1, show_type)?; + let table = display::compute_vault_accounts_table_with_g1v1( + &[base_account_tree_node], + show_g1v1, + show_type, + )?; println!( "available SS58 Addresses linked to {}:", @@ -275,19 +296,28 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE let mnemonic = bip39::Mnemonic::generate(12).unwrap(); println!("{mnemonic}"); } - Subcommand::Import { secret_format, crypto_scheme, uri, g1v1_id, g1v1_password, password, no_password, name } => { + Subcommand::Import { + secret_format, + crypto_scheme, + uri, + g1v1_id, + g1v1_password, + password, + no_password, + name, + } => { let vault_data_for_import = if let Some(uri_str) = uri { // Non-interactive mode with provided URI if secret_format != SecretFormat::Substrate { return Err(GcliError::Input(format!( - "URI can only be provided directly with secret_format=substrate, got: {:?}", + "URI can only be provided directly with secret_format=substrate, got: {:?}", secret_format ))); } - + // Create keypair from provided URI let key_pair = compute_keypair(crypto_scheme, &uri_str)?; - + VaultDataToImport { secret_format, secret_suri: uri_str, @@ -301,14 +331,14 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE secret_format ))); } - + // Create keypair from provided G1v1 ID and password let seed = seed_from_cesium(id, pwd); let secret_suri = format!("0x{}", hex::encode(seed)); - + // G1v1 always uses Ed25519 let key_pair = compute_keypair(CryptoScheme::Ed25519, &secret_suri)?; - + VaultDataToImport { secret_format, secret_suri, @@ -325,7 +355,7 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE "The G1v1 public key for the provided secret is: '{}'", compute_g1v1_public_key(&vault_data_for_import.key_pair)? ); - + // Skip confirmation in non-interactive mode let is_non_interactive_g1v1 = g1v1_id.is_some() && g1v1_password.is_some(); if !is_non_interactive_g1v1 { @@ -337,17 +367,22 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE } let txn = db.begin().await?; - + // Handle password in non-interactive mode let provided_password = if no_password { Some(String::new()) // Empty password } else { password }; - - let _account = - create_base_account_for_vault_data_to_import(&txn, &vault_data_for_import, provided_password.as_ref(), Some(crypto_scheme), name) - .await?; + + let _account = create_base_account_for_vault_data_to_import( + &txn, + &vault_data_for_import, + provided_password.as_ref(), + Some(crypto_scheme), + name, + ) + .await?; txn.commit().await?; @@ -399,12 +434,12 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE let derivation_secret_suri = format!("{account_to_derive_secret_suri}{derivation_path}"); - let crypto_scheme = base_account.crypto_scheme + let crypto_scheme = base_account + .crypto_scheme .map(CryptoScheme::from) .unwrap_or(CryptoScheme::Ed25519); // Fallback to Ed25519 if not defined (should never happen) - let derivation_keypair = - compute_keypair(crypto_scheme, &derivation_secret_suri)?; + let derivation_keypair = compute_keypair(crypto_scheme, &derivation_secret_suri)?; let derivation_address: String = derivation_keypair.address().to_string(); @@ -637,7 +672,10 @@ pub fn parse_prefix_and_derivation_path_from_suri( Ok((address_uri.phrase.map(|s| s.to_string()), full_path)) } -fn map_secret_format_to_crypto_scheme(secret_format: SecretFormat, override_crypto_scheme: Option<CryptoScheme>) -> CryptoScheme { +fn map_secret_format_to_crypto_scheme( + secret_format: SecretFormat, + override_crypto_scheme: Option<CryptoScheme>, +) -> CryptoScheme { // If a crypto_scheme is explicitly specified, use it except for G1v1 which must always use Ed25519 if let Some(scheme) = override_crypto_scheme { if secret_format == SecretFormat::G1v1 { @@ -806,19 +844,29 @@ fn prompt_secret_and_compute_vault_data_to_import( crypto_scheme: CryptoScheme, ) -> Result<VaultDataToImport, GcliError> { match secret_format { - SecretFormat::Substrate => { - create_vault_data_to_import(secret_format, crypto_scheme, prompt_secret_substrate_and_compute_keypair) - } - SecretFormat::Seed => { - create_vault_data_to_import(secret_format, crypto_scheme, prompt_seed_and_compute_keypair) - } + SecretFormat::Substrate => create_vault_data_to_import( + secret_format, + crypto_scheme, + prompt_secret_substrate_and_compute_keypair, + ), + SecretFormat::Seed => create_vault_data_to_import( + secret_format, + crypto_scheme, + prompt_seed_and_compute_keypair, + ), SecretFormat::G1v1 => { // G1v1 always uses Ed25519, ignore crypto_scheme - create_vault_data_to_import(secret_format, CryptoScheme::Ed25519, prompt_secret_cesium_and_compute_keypair) - } - SecretFormat::Predefined => { - create_vault_data_to_import(secret_format, crypto_scheme, prompt_predefined_and_compute_keypair) + create_vault_data_to_import( + secret_format, + CryptoScheme::Ed25519, + prompt_secret_cesium_and_compute_keypair, + ) } + SecretFormat::Predefined => create_vault_data_to_import( + secret_format, + crypto_scheme, + prompt_predefined_and_compute_keypair, + ), } } @@ -842,7 +890,8 @@ where let address = vault_data.key_pair.address().to_string(); // Check if the account already exists - let existing_vault_account = vault_account::find_by_id(db_tx, &DbAccountId(vault_data.key_pair.address())).await?; + let existing_vault_account = + vault_account::find_by_id(db_tx, &DbAccountId(vault_data.key_pair.address())).await?; let password = match password_opt { Some(password) => password.clone(), @@ -853,7 +902,7 @@ where if let Some(existing_vault_account) = existing_vault_account { // Existing account - match inputs::confirm_action(&format!( + match inputs::confirm_action(format!( "Account {} already exists. Do you want to update it?", existing_vault_account ))? { @@ -874,20 +923,19 @@ where vault_account.path = Set(None); vault_account.parent = Set(None); vault_account.crypto_scheme = Set(Some( - map_secret_format_to_crypto_scheme(vault_data.secret_format, crypto_scheme).into(), + map_secret_format_to_crypto_scheme(vault_data.secret_format, crypto_scheme) + .into(), )); vault_account.encrypted_suri = Set(Some(encrypted_suri)); vault_account.name = Set(name); vault_account.secret_format = Set(Some(vault_data.secret_format.into())); let updated_vault_account = vault_account::update_account(db_tx, vault_account).await?; - + println!("Updating vault account {updated_vault_account}"); Ok(updated_vault_account) } - _ => { - Err(GcliError::Input("import canceled".into())) - } + _ => Err(GcliError::Input("import canceled".into())), } } else { //New entry @@ -913,7 +961,7 @@ where secret_format, ) .await?; - + println!("Creating <Base> account {account}"); Ok(account) } @@ -1041,11 +1089,8 @@ where Ok(vault_account) } -/// Function will ask for password if not present and compute the encrypted suri -fn compute_encrypted_suri( - password: String, - secret_suri: String, -) -> Result<Vec<u8>, GcliError> { +/// Function will compute the encrypted suri +fn compute_encrypted_suri(password: String, secret_suri: String) -> Result<Vec<u8>, GcliError> { encrypt(secret_suri.as_bytes(), password).map_err(|e| GcliError::Input(e.to_string())) } diff --git a/src/commands/vault/display.rs b/src/commands/vault/display.rs index 5f024d6abaa64ebecf51841d14ecb8c5ea6cde4d..fe2997185f4f9b6f9fdc2722b9cf26a46de5bad8 100644 --- a/src/commands/vault/display.rs +++ b/src/commands/vault/display.rs @@ -37,26 +37,35 @@ pub fn compute_vault_accounts_table_with_g1v1( ) -> Result<Table, GcliError> { let mut table = Table::new(); table.load_preset(comfy_table::presets::UTF8_BORDERS_ONLY); - + // Prepare header based on options let mut header = vec![ - if show_g1v1 { "SS58 Address/G1v1 public key" } else { "SS58 Address" }, + if show_g1v1 { + "SS58 Address/G1v1 public key" + } else { + "SS58 Address" + }, "Crypto", ]; - + // Add Type column if show_type is true if show_type { header.push("Type"); } - + // Add remaining columns header.push("Path"); header.push("Name"); - + table.set_header(header); for account_tree_node in account_tree_nodes { - let _ = add_account_tree_node_to_table_with_g1v1(&mut table, account_tree_node, show_g1v1, show_type); + let _ = add_account_tree_node_to_table_with_g1v1( + &mut table, + account_tree_node, + show_g1v1, + show_type, + ); } Ok(table) @@ -118,7 +127,7 @@ pub fn compute_vault_accounts_row_with_g1v1( } else { let crypto_scheme = CryptoScheme::from(account_tree_node.account.crypto_scheme.unwrap()); let crypto_scheme_str: &str = crypto_scheme.into(); - + // Determine the wallet type based on the secret format let wallet_type = if let Some(secret_format) = &account_tree_node.account.secret_format { // If the secret format is available, use it to determine the type @@ -132,7 +141,7 @@ pub fn compute_vault_accounts_row_with_g1v1( // If the secret format is not available, display "Unknown" "Unknown".to_string() }; - + // Add a second line for the G1v1 public key only if show_g1v1 is true and it's an Ed25519 key let is_ed25519 = crypto_scheme == CryptoScheme::Ed25519; if show_g1v1 && is_ed25519 { @@ -142,7 +151,7 @@ pub fn compute_vault_accounts_row_with_g1v1( &account_tree_node.account.address.0 ) ))]; - + // Add empty cells to align with the main line g1v1_row.push(Cell::new("")); if show_type { @@ -150,7 +159,7 @@ pub fn compute_vault_accounts_row_with_g1v1( } g1v1_row.push(Cell::new("")); g1v1_row.push(Cell::new("")); - + rows.push(g1v1_row); } @@ -162,20 +171,17 @@ pub fn compute_vault_accounts_row_with_g1v1( }; // Add the first line - let mut main_row = vec![ - Cell::new(&address), - Cell::new(crypto), - ]; - + let mut main_row = vec![Cell::new(&address), Cell::new(crypto)]; + // Add the Type column if show_type is true if show_type { main_row.push(Cell::new(wallet_type)); } - + // Add the remaining columns main_row.push(Cell::new(&path)); main_row.push(Cell::new(&name)); - + rows.insert(0, main_row); Ok(rows) @@ -184,7 +190,9 @@ pub fn compute_vault_accounts_row_with_g1v1( #[cfg(test)] mod tests { mod vault_accounts_table_tests { - use crate::commands::vault::display::{compute_vault_accounts_table, compute_vault_accounts_table_with_g1v1}; + use crate::commands::vault::display::{ + compute_vault_accounts_table, compute_vault_accounts_table_with_g1v1, + }; use crate::entities::vault_account::tests::account_tree_node_tests::{ mother_account_tree_node, mother_g1v1_account_tree_node, }; @@ -254,26 +262,26 @@ mod tests { fn test_compute_vault_accounts_table_with_g1v1_empty() { // Test with show_g1v1 = true (default behavior) let table = compute_vault_accounts_table_with_g1v1(&[], true, false).unwrap(); - + let expected_table_with_g1v1 = indoc! {r#" ┌─────────────────────────────────────────────────────┠│ SS58 Address/G1v1 public key Crypto Path Name │ ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ └─────────────────────────────────────────────────────┘"# }; - + assert_eq!(table.to_string(), expected_table_with_g1v1); // Test with show_g1v1 = false let table = compute_vault_accounts_table_with_g1v1(&[], false, false).unwrap(); - + let expected_table_without_g1v1 = indoc! {r#" ┌─────────────────────────────────────┠│ SS58 Address Crypto Path Name │ ╞â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•¡ └─────────────────────────────────────┘"# }; - + assert_eq!(table.to_string(), expected_table_without_g1v1); } @@ -284,8 +292,9 @@ mod tests { let account_tree_nodes = vec![account_tree_node, g1v1_account_tree_node]; // Test with show_g1v1 = true (default behavior) - let table_with_g1v1 = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, false).unwrap(); - + let table_with_g1v1 = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, false).unwrap(); + let expected_table_with_g1v1 = indoc! {r#" ┌──────────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address/G1v1 public key Crypto Path Name │ @@ -299,12 +308,13 @@ mod tests { │ â”” G1v1: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 │ └──────────────────────────────────────────────────────────────────────────────────────────┘"# }; - + assert_eq!(table_with_g1v1.to_string(), expected_table_with_g1v1); // Test with show_g1v1 = false - let table_without_g1v1 = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, false).unwrap(); - + let table_without_g1v1 = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, false).unwrap(); + let expected_table_without_g1v1 = indoc! {r#" ┌──────────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address Crypto Path Name │ @@ -317,7 +327,7 @@ mod tests { │ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 <Base> MotherG1v1 │ └──────────────────────────────────────────────────────────────────────────────────────────┘"# }; - + assert_eq!(table_without_g1v1.to_string(), expected_table_without_g1v1); } @@ -328,8 +338,9 @@ mod tests { let account_tree_nodes = vec![child1]; // Test with show_g1v1 = true (default behavior) - let table_with_g1v1 = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, false).unwrap(); - + let table_with_g1v1 = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, false).unwrap(); + let expected_table_with_g1v1 = indoc! {r#" ┌─────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address/G1v1 public key Crypto Path Name │ @@ -338,12 +349,13 @@ mod tests { │ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ └─────────────────────────────────────────────────────────────────────────────────────┘"# }; - + assert_eq!(table_with_g1v1.to_string(), expected_table_with_g1v1); // Test with show_g1v1 = false - let table_without_g1v1 = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, false).unwrap(); - + let table_without_g1v1 = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, false).unwrap(); + let expected_table_without_g1v1 = indoc! {r#" ┌─────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address Crypto Path Name │ @@ -352,7 +364,7 @@ mod tests { │ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │ └─────────────────────────────────────────────────────────────────────────────────────┘"# }; - + assert_eq!(table_without_g1v1.to_string(), expected_table_without_g1v1); } @@ -363,8 +375,9 @@ mod tests { let account_tree_nodes = vec![account_tree_node, g1v1_account_tree_node]; // Test with show_type = true and show_g1v1 = true - let table_with_g1v1_and_type = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, true).unwrap(); - + let table_with_g1v1_and_type = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true, true).unwrap(); + let expected_table_with_g1v1_and_type = indoc! {r#" ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address/G1v1 public key Crypto Type Path Name │ @@ -378,12 +391,16 @@ mod tests { │ â”” G1v1: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘"# }; - - assert_eq!(table_with_g1v1_and_type.to_string(), expected_table_with_g1v1_and_type); - + + assert_eq!( + table_with_g1v1_and_type.to_string(), + expected_table_with_g1v1_and_type + ); + // Test with show_type = true and show_g1v1 = false - let table_with_type = compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, true).unwrap(); - + let table_with_type = + compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false, true).unwrap(); + let expected_table_with_type = indoc! {r#" ┌─────────────────────────────────────────────────────────────────────────────────────────────────────┠│ SS58 Address Crypto Type Path Name │ @@ -396,7 +413,7 @@ mod tests { │ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 G1v1 <Base> MotherG1v1 │ └─────────────────────────────────────────────────────────────────────────────────────────────────────┘"# }; - + assert_eq!(table_with_type.to_string(), expected_table_with_type); } } diff --git a/src/keys.rs b/src/keys.rs index 6097ca59d031422009c51b3051e0221141df03be..5ca4191c8d03a85751680a77c090b48bc74dadaf 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -141,17 +141,21 @@ pub fn get_keypair( match (secret_format, secret) { (SecretFormat::Predefined, Some(deriv)) => { match crypto_scheme { - Some(CryptoScheme::Ed25519) => pair_from_ed25519_str(&predefined_suri(deriv)).map(|v| v.into()), + Some(CryptoScheme::Ed25519) => { + pair_from_ed25519_str(&predefined_suri(deriv)).map(|v| v.into()) + } _ => pair_from_predefined(deriv).map(|v| v.into()), // Default to Sr25519 for backward compatibility } - }, + } (secret_format, None) => Ok(prompt_secret(secret_format, crypto_scheme)), (_, Some(secret)) => { match crypto_scheme { - Some(CryptoScheme::Ed25519) => pair_from_secret_with_scheme(secret_format, secret, CryptoScheme::Ed25519), + Some(CryptoScheme::Ed25519) => { + pair_from_secret_with_scheme(secret_format, secret, CryptoScheme::Ed25519) + } _ => Ok(pair_from_secret(secret_format, secret)?.into()), // Default to Sr25519 for backward compatibility } - }, + } } } @@ -174,7 +178,7 @@ pub fn pair_from_secret_with_scheme( hex::decode_to_slice(secret, &mut seed) .map_err(|_| GcliError::Input("Invalid secret".to_string()))?; Ok(ed25519::Pair::from_seed(&seed).into()) - }, + } SecretFormat::G1v1 => unreachable!(), // Already handled above }, (_, CryptoScheme::Sr25519) => pair_from_secret(secret_format, secret).map(|v| v.into()), @@ -249,100 +253,90 @@ pub fn seed_from_cesium(id: &str, pwd: &str) -> [u8; 32] { seed } -pub fn prompt_secret_substrate_and_compute_keypair(crypto_scheme: CryptoScheme) -> (String, KeyPair) { - loop { - println!("Substrate URI can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path"); - let substrate_suri = inputs::prompt_password_query("Substrate URI: ").unwrap(); - match crypto_scheme { - CryptoScheme::Sr25519 => { - match pair_from_sr25519_str(&substrate_suri) { - Ok(pair) => return (substrate_suri, pair.into()), - Err(_) => println!("Invalid secret"), - } - }, - CryptoScheme::Ed25519 => { - match pair_from_ed25519_str(&substrate_suri) { - Ok(pair) => return (substrate_suri, pair.into()), - Err(_) => println!("Invalid secret"), - } - } - } - } +pub fn prompt_secret_substrate_and_compute_keypair( + crypto_scheme: CryptoScheme, +) -> (String, KeyPair) { + loop { + println!("Substrate URI can be a mnemonic or a mini-secret ('0x' prefixed seed) together with optional derivation path"); + let substrate_suri = inputs::prompt_password_query("Substrate URI: ").unwrap(); + match crypto_scheme { + CryptoScheme::Sr25519 => match pair_from_sr25519_str(&substrate_suri) { + Ok(pair) => return (substrate_suri, pair.into()), + Err(_) => println!("Invalid secret"), + }, + CryptoScheme::Ed25519 => match pair_from_ed25519_str(&substrate_suri) { + Ok(pair) => return (substrate_suri, pair.into()), + Err(_) => println!("Invalid secret"), + }, + } + } } /// ask user pass (Cesium format) pub fn prompt_secret_cesium() -> ed25519::Pair { - // Only interested in the keypair which is the second element of the tuple - match prompt_secret_cesium_and_compute_keypair(CryptoScheme::Ed25519).1 { - KeyPair::Ed25519(pair) => pair, - _ => panic!("Expected Ed25519 keypair"), - } + // Only interested in the keypair which is the second element of the tuple + match prompt_secret_cesium_and_compute_keypair(CryptoScheme::Ed25519).1 { + KeyPair::Ed25519(pair) => pair, + _ => panic!("Expected Ed25519 keypair"), + } } pub fn prompt_secret_cesium_and_compute_keypair(_crypto_scheme: CryptoScheme) -> (String, KeyPair) { - let id = inputs::prompt_password_query("G1v1 id: ").unwrap(); - let pwd = inputs::prompt_password_query("G1v1 password: ").unwrap(); + let id = inputs::prompt_password_query("G1v1 id: ").unwrap(); + let pwd = inputs::prompt_password_query("G1v1 password: ").unwrap(); - let seed = seed_from_cesium(&id, &pwd); - let secret_suri = format!("0x{}", hex::encode(seed)); + let seed = seed_from_cesium(&id, &pwd); + let secret_suri = format!("0x{}", hex::encode(seed)); - // G1v1 always uses Ed25519, ignore crypto_scheme - match pair_from_ed25519_str(&secret_suri) { - Ok(pair) => (secret_suri, pair.into()), - Err(_) => panic!("Could not compute KeyPair from G1v1 id/pwd"), - } + // G1v1 always uses Ed25519, ignore crypto_scheme + match pair_from_ed25519_str(&secret_suri) { + Ok(pair) => (secret_suri, pair.into()), + Err(_) => panic!("Could not compute KeyPair from G1v1 id/pwd"), + } } pub fn prompt_seed_and_compute_keypair(crypto_scheme: CryptoScheme) -> (String, KeyPair) { - loop { - let seed_str = inputs::prompt_seed().unwrap(); - let secret_suri = format!("0x{}", seed_str); - - match crypto_scheme { - CryptoScheme::Sr25519 => { - match pair_from_sr25519_str(&secret_suri) { - Ok(pair) => return (secret_suri, pair.into()), - Err(_) => println!("Invalid seed"), - } - }, - CryptoScheme::Ed25519 => { - match pair_from_ed25519_str(&secret_suri) { - Ok(pair) => return (secret_suri, pair.into()), - Err(_) => println!("Invalid seed"), - } - } - } - } + loop { + let seed_str = inputs::prompt_seed().unwrap(); + let secret_suri = format!("0x{}", seed_str); + + match crypto_scheme { + CryptoScheme::Sr25519 => match pair_from_sr25519_str(&secret_suri) { + Ok(pair) => return (secret_suri, pair.into()), + Err(_) => println!("Invalid seed"), + }, + CryptoScheme::Ed25519 => match pair_from_ed25519_str(&secret_suri) { + Ok(pair) => return (secret_suri, pair.into()), + Err(_) => println!("Invalid seed"), + }, + } + } } pub fn prompt_predefined_and_compute_keypair(crypto_scheme: CryptoScheme) -> (String, KeyPair) { - let deriv = inputs::prompt_password_query("Enter derivation path: ").unwrap(); - let suri = predefined_suri(&deriv); - - match crypto_scheme { - CryptoScheme::Sr25519 => { - match pair_from_sr25519_str(&suri) { - Ok(pair) => (suri, pair.into()), - Err(e) => panic!("Invalid secret: {}", e), - } - }, - CryptoScheme::Ed25519 => { - match pair_from_ed25519_str(&suri) { - Ok(pair) => (suri, pair.into()), - Err(e) => panic!("Invalid secret: {}", e), - } - } - } + let deriv = inputs::prompt_password_query("Enter derivation path: ").unwrap(); + let suri = predefined_suri(&deriv); + + match crypto_scheme { + CryptoScheme::Sr25519 => match pair_from_sr25519_str(&suri) { + Ok(pair) => (suri, pair.into()), + Err(e) => panic!("Invalid secret: {}", e), + }, + CryptoScheme::Ed25519 => match pair_from_ed25519_str(&suri) { + Ok(pair) => (suri, pair.into()), + Err(e) => panic!("Invalid secret: {}", e), + }, + } } pub fn prompt_secret(secret_format: SecretFormat, crypto_scheme: Option<CryptoScheme>) -> KeyPair { let default_scheme = match secret_format { SecretFormat::G1v1 => CryptoScheme::Ed25519, // G1v1 always uses Ed25519 - _ => CryptoScheme::Ed25519, // All formats use Ed25519 by default + _ => CryptoScheme::Ed25519, // All formats use Ed25519 by default }; - + let scheme = crypto_scheme.unwrap_or(default_scheme); - + match secret_format { SecretFormat::Substrate => prompt_secret_substrate_and_compute_keypair(scheme).1, SecretFormat::G1v1 => prompt_secret_cesium_and_compute_keypair(CryptoScheme::Ed25519).1, // G1v1 always uses Ed25519 @@ -362,7 +356,9 @@ pub async fn fetch_or_get_keypair( // keypair is already known (useful for dev mode) if let Some(d) = catch_known(&address.to_string()) { match crypto_scheme { - Some(CryptoScheme::Ed25519) => return pair_from_ed25519_str(&predefined_suri(d)).map(|v| v.into()), + Some(CryptoScheme::Ed25519) => { + return pair_from_ed25519_str(&predefined_suri(d)).map(|v| v.into()) + } _ => return Ok(pair_from_predefined(d).unwrap().into()), // Default to Sr25519 for backward compatibility } };