Skip to content
Snippets Groups Projects
Commit 503d4caa authored by Nicolas80's avatar Nicolas80
Browse files

Adapting `vault inspect`

* Added non-interactive support when providing the `password` or `no-password`
* Adapted to support default human-readable and optional json format
* using log::warn! to be able to get the info of why we don't have a secret seed value if we need to; while not impacting the "standard output" of the command that can still be piped to say `jq`
parent 63eed5bd
No related branches found
No related tags found
No related merge requests found
Pipeline #40555 passed
......@@ -119,6 +119,14 @@ pub enum Subcommand {
Inspect {
#[clap(flatten)]
address_or_vault_name: AddressOrVaultNameGroup,
/// Password to decrypt the <Base> account key (non-interactive mode)
#[clap(short = 'p', long, required = false, conflicts_with_all=["no_password"])]
password: Option<String>,
/// Use empty password to decrypt the <Base> account key (non-interactive mode)
#[clap(long, required = false)]
no_password: bool,
},
/// (deprecated) List available key files (needs to be migrated with command `vault migrate` in order to use them)
#[deprecated(
......@@ -179,6 +187,17 @@ pub struct AddressOrVaultNameGroup {
vault_name: Option<String>,
}
/// vault inspect for JSON serialization
#[derive(Serialize)]
struct VaultInspectData {
substrate_uri: String,
crypto_scheme: CryptoScheme,
secret_seed: Option<String>,
public_key_hex: String,
ss58_address: String,
g1v1_public_key: Option<String>,
}
pub struct VaultDataToImport {
secret_format: SecretFormat,
secret_suri: String,
......@@ -619,7 +638,11 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
}
Subcommand::Inspect {
address_or_vault_name,
password,
no_password,
} => {
let is_interactive = password.is_none() && !no_password;
let account_tree_node_to_inspect =
retrieve_account_tree_node(db, address_or_vault_name).await?;
......@@ -628,73 +651,51 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
let is_base_account =
Rc::ptr_eq(&account_tree_node_to_inspect, &base_account_tree_node);
if !is_base_account {
if is_interactive && !is_base_account {
let base_account = base_account_tree_node.borrow().account.clone();
println!("The linked <Base> account is {base_account}");
}
// Handle password from non-interactive mode or ask for it
let password = if no_password {
String::new()
} else if let Some(password) = password {
password
} else {
println!("Enter password to decrypt the <Base> account key");
let password = inputs::prompt_password()?;
inputs::prompt_password()?
};
let account_to_derive_secret_suri = vault_account::compute_suri_account_tree_node(
&account_tree_node_to_inspect,
password,
)?;
let vault_inspect_data =
compute_vault_inspect_data(&account_tree_node_to_inspect, password)?;
match data.args.output_format {
OutputFormat::Human => {
println!("Substrate URI: '{account_to_derive_secret_suri}'");
let crypto_scheme: CryptoScheme = base_account_tree_node
.borrow()
.account
.crypto_scheme
.ok_or(GcliError::Logic(
"Base account without crypto_scheme".to_string(),
))?
.into();
println!("Crypto scheme: {}", <&'static str>::from(crypto_scheme));
match compute_pair_and_mini_secret_seed_from_suri_and_crypto_scheme(
&account_to_derive_secret_suri,
crypto_scheme,
) {
Err(e) => {
println!("Secret seed/mini-secret: cannot be computed: {}", e)
}
Ok((_computed_pair, seed)) => {
println!("Secret seed/mini-secret: '0x{}'", hex::encode(seed));
println!("Substrate URI: '{}'", vault_inspect_data.substrate_uri);
println!(
"Crypto scheme: {}",
<&'static str>::from(vault_inspect_data.crypto_scheme)
);
match vault_inspect_data.secret_seed {
None => println!("Secret seed/mini-secret: N/A"),
Some(secret_seed) => {
println!("Secret seed/mini-secret: '0x{}'", secret_seed)
}
}
let account_address: AccountId = account_tree_node_to_inspect
.borrow()
.account
.address
.clone()
.into();
println!("Public key (hex): '0x{}'", hex::encode(account_address.0));
println!("SS58 Address: '{account_address}'");
if CryptoScheme::Ed25519 == crypto_scheme && is_base_account {
println!(
"(potential G1v1 public key: '{}')",
cesium::compute_g1v1_public_key_from_ed25519_account_id(
&account_address
)
"Public key (hex): '0x{}'",
vault_inspect_data.public_key_hex
);
println!("SS58 Address: '{}'", vault_inspect_data.ss58_address);
if let Some(g1v1_public_key) = vault_inspect_data.g1v1_public_key {
println!("(potential G1v1 public key: '{}')", g1v1_public_key);
}
}
OutputFormat::Json => {
//FIXME handle same data as interactive
let json_view = serde_json::json!({
"substrate_uri": account_to_derive_secret_suri
});
println!(
"{}",
serde_json::to_string(&json_view).map_err(|e| anyhow!(e))?
serde_json::to_string(&vault_inspect_data).map_err(|e| anyhow!(e))?
);
}
}
......@@ -788,6 +789,63 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
Ok(())
}
fn compute_vault_inspect_data(
account_tree_node_to_inspect: &Rc<RefCell<AccountTreeNode>>,
password: String,
) -> Result<VaultInspectData, GcliError> {
let base_account_tree_node =
vault_account::get_base_account_tree_node(account_tree_node_to_inspect);
let is_base_account = Rc::ptr_eq(account_tree_node_to_inspect, &base_account_tree_node);
let account_secret_suri =
vault_account::compute_suri_account_tree_node(account_tree_node_to_inspect, password)?;
let crypto_scheme: CryptoScheme = base_account_tree_node
.borrow()
.account
.crypto_scheme
.ok_or(GcliError::Logic(
"Base account without crypto_scheme".to_string(),
))?
.into();
let opt_seed = match compute_pair_and_mini_secret_seed_from_suri_and_crypto_scheme(
&account_secret_suri,
crypto_scheme,
) {
Err(e) => {
log::warn!("Secret seed/mini-secret cannot be computed: {}", e);
None
}
Ok((_computed_pair, seed)) => Some(hex::encode(seed)),
};
let account_address: AccountId = account_tree_node_to_inspect
.borrow()
.account
.address
.clone()
.into();
let opt_g1v1_pub_key = if CryptoScheme::Ed25519 == crypto_scheme && is_base_account {
let g1v1_public_key =
cesium::compute_g1v1_public_key_from_ed25519_account_id(&account_address);
Some(g1v1_public_key)
} else {
None
};
Ok(VaultInspectData {
substrate_uri: account_secret_suri,
crypto_scheme,
secret_seed: opt_seed,
public_key_hex: hex::encode(account_address.0),
ss58_address: account_address.to_string(),
g1v1_public_key: opt_g1v1_pub_key,
})
}
/// Method used to separate vault `name` part from optional `derivation` part in computed names that can be provided by users in the different `vault` commands using `AddressOrVaultNameGroup`
fn parse_vault_name_and_derivation_path_from_user_input(
user_input_name: String,
......
use crate::commands::vault;
use crate::*;
use serde::Serializer;
use sp_core::crypto::AddressUri;
use sp_core::crypto::Pair as PairTrait;
use sp_core::DeriveJunction;
......@@ -64,6 +65,16 @@ pub enum CryptoScheme {
Sr25519,
}
impl Serialize for CryptoScheme {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let as_str: &str = (*self).into(); // Use the `From<CryptoScheme>` implementation
serializer.serialize_str(as_str)
}
}
/// Setting a default to Ed25519
///
/// required when used in Args struct inside main.rs; even though we still have to give a clap "default_value"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment