Add support for json output in subkey (#4882)

* Add support for json output in subkey

* Updates as per code review

* Apply suggestions from code review

Co-Authored-By: Nikolay Volf <nikvolf@gmail.com>

* Apply suggestions from code review

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Clean up error handler as per code review

* Apply suggestions from code review

Co-Authored-By: Marcio Diaz <marcio@parity.io>

* Fix compilation error

* Remove accidental file commit

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Marcio Diaz <marcio@parity.io>
This commit is contained in:
Hayden Bakkum
2020-02-11 22:35:58 +13:00
committed by GitHub
parent da42d7408c
commit 0d45d12e3f
3 changed files with 112 additions and 36 deletions
+110 -36
View File
@@ -25,6 +25,7 @@ use hex_literal::hex;
use itertools::Itertools;
use node_primitives::{Balance, Hash, Index, AccountId, Signature};
use node_runtime::{BalancesCall, Call, Runtime, SignedPayload, UncheckedExtrinsic, VERSION};
use serde_json::json;
use sp_core::{
crypto::{set_default_ss58_version, Ss58AddressFormat, Ss58Codec},
ed25519, sr25519, ecdsa, Pair, Public, H256, hexdisplay::HexDisplay,
@@ -37,6 +38,24 @@ use std::{
mod rpc;
mod vanity;
enum OutputType {
Json,
Text,
}
impl<'a> TryFrom<&'a str> for OutputType {
type Error = ();
fn try_from(s: &'a str) -> Result<OutputType, ()> {
match s {
"json" => Ok(OutputType::Json),
"text" => Ok(OutputType::Text),
_ => Err(()),
}
}
}
trait Crypto: Sized {
type Pair: Pair<Public = Self::Public>;
type Public: Public + Ss58Codec + AsRef<[u8]> + std::hash::Hash;
@@ -55,50 +74,97 @@ trait Crypto: Sized {
uri: &str,
password: Option<&str>,
network_override: Option<Ss58AddressFormat>,
output: OutputType,
) where
<Self::Pair as Pair>::Public: PublicT,
{
if let Ok((pair, seed)) = Self::Pair::from_phrase(uri, password) {
let public_key = Self::public_from_pair(&pair);
println!("Secret phrase `{}` is account:\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
format_seed::<Self>(seed),
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key),
Self::ss58_from_pair(&pair)
);
match output {
OutputType::Json => {
let json = json!({
"secretPhrase": uri,
"secretSeed": format_seed::<Self>(seed),
"publicKey": format_public_key::<Self>(public_key.clone()),
"accountId": format_account_id::<Self>(public_key),
"ss58Address": Self::ss58_from_pair(&pair),
});
println!("{}", serde_json::to_string_pretty(&json).expect("Json pretty print failed"));
},
OutputType::Text => {
println!("Secret phrase `{}` is account:\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
format_seed::<Self>(seed),
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key),
Self::ss58_from_pair(&pair),
);
},
}
} else if let Ok((pair, seed)) = Self::Pair::from_string_with_seed(uri, password) {
let public_key = Self::public_from_pair(&pair);
println!("Secret Key URI `{}` is account:\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
if let Some(seed) = seed { format_seed::<Self>(seed) } else { "n/a".into() },
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key),
Self::ss58_from_pair(&pair)
);
match output {
OutputType::Json => {
let json = json!({
"secretKeyUri": uri,
"secretSeed": if let Some(seed) = seed { format_seed::<Self>(seed) } else { "n/a".into() },
"publicKey": format_public_key::<Self>(public_key.clone()),
"accountId": format_account_id::<Self>(public_key),
"ss58Address": Self::ss58_from_pair(&pair),
});
println!("{}", serde_json::to_string_pretty(&json).expect("Json pretty print failed"));
},
OutputType::Text => {
println!("Secret Key URI `{}` is account:\n \
Secret seed: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
if let Some(seed) = seed { format_seed::<Self>(seed) } else { "n/a".into() },
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key),
Self::ss58_from_pair(&pair),
);
},
}
} else if let Ok((public_key, v)) =
<Self::Pair as Pair>::Public::from_string_with_version(uri)
{
let v = network_override.unwrap_or(v);
println!("Public Key URI `{}` is account:\n \
Network ID/version: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
String::from(v),
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key.clone()),
public_key.to_ss58check_with_version(v)
);
match output {
OutputType::Json => {
let json = json!({
"publicKeyUri": uri,
"networkId": String::from(v),
"publicKey": format_public_key::<Self>(public_key.clone()),
"accountId": format_account_id::<Self>(public_key.clone()),
"ss58Address": public_key.to_ss58check_with_version(v),
});
println!("{}", serde_json::to_string_pretty(&json).expect("Json pretty print failed"));
},
OutputType::Text => {
println!("Public Key URI `{}` is account:\n \
Network ID/version: {}\n \
Public key (hex): {}\n \
Account ID: {}\n \
SS58 Address: {}",
uri,
String::from(v),
format_public_key::<Self>(public_key.clone()),
format_account_id::<Self>(public_key.clone()),
public_key.to_ss58check_with_version(v),
);
},
}
} else {
println!("Invalid phrase/URI given");
}
@@ -165,6 +231,7 @@ fn get_usage() -> String {
[network] -n, --network <network> 'Specify a network. One of {}. Default is {}'
[password] -p, --password <password> 'The password for the key'
--password-interactive 'You will be prompted for the password for the key.'
[output] -o, --output <output> 'Specify an output format. One of text, json. Default is text.'
", networks, default_network)
}
@@ -329,13 +396,20 @@ where
if let Some(network) = maybe_network {
set_default_ss58_version(network);
}
let output: OutputType = match matches.value_of("output").map(TryInto::try_into) {
Some(Err(_)) => return Err(Error::Static("Invalid output name. See --help for available outputs.")),
Some(Ok(v)) => v,
None => OutputType::Text,
};
match matches.subcommand() {
("generate", Some(matches)) => {
let mnemonic = generate_mnemonic(matches)?;
C::print_from_uri(mnemonic.phrase(), password, maybe_network);
C::print_from_uri(mnemonic.phrase(), password, maybe_network, output);
}
("inspect", Some(matches)) => {
C::print_from_uri(&get_uri("uri", &matches)?, password, maybe_network);
C::print_from_uri(&get_uri("uri", &matches)?, password, maybe_network, output);
}
("sign", Some(matches)) => {
let suri = get_uri("suri", &matches)?;
@@ -364,7 +438,7 @@ where
.unwrap_or_default();
let result = vanity::generate_key::<C>(&desired)?;
let formated_seed = format_seed::<C>(result.seed);
C::print_from_uri(&formated_seed, None, maybe_network);
C::print_from_uri(&formated_seed, None, maybe_network, output);
}
("transfer", Some(matches)) => {
let signer = read_pair::<C>(matches.value_of("from"), password)?;