Allow reading suri && password override from file (#1059)

* allow reading suri && password override from file

* fix clippy

* Update relays/bin-substrate/src/cli/mod.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

* Update relays/bin-substrate/src/cli/mod.rs

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>

Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
Svyatoslav Nikolsky
2021-07-19 14:45:16 +03:00
committed by Bastian Köcher
parent 6103fbe40b
commit e18844d1f4
3 changed files with 128 additions and 20 deletions
+1
View File
@@ -63,3 +63,4 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master
hex-literal = "0.3"
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
tempdir = "0.3"
+122 -4
View File
@@ -374,24 +374,61 @@ macro_rules! declare_chain_options {
}
#[doc = $chain " signing params."]
#[derive(StructOpt, Debug, PartialEq, Eq)]
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
pub struct [<$chain SigningParams>] {
#[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."]
#[structopt(long)]
pub [<$chain_prefix _signer>]: String,
pub [<$chain_prefix _signer>]: Option<String>,
#[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."]
#[structopt(long)]
pub [<$chain_prefix _signer_password>]: Option<String>,
#[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."]
#[structopt(long)]
pub [<$chain_prefix _signer_file>]: Option<std::path::PathBuf>,
#[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."]
#[structopt(long)]
pub [<$chain_prefix _signer_password_file>]: Option<std::path::PathBuf>,
}
impl [<$chain SigningParams>] {
/// Parse signing params into chain-specific KeyPair.
pub fn to_keypair<Chain: CliChain>(&self) -> anyhow::Result<Chain::KeyPair> {
let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) {
(Some(suri), _) => suri.to_owned(),
(None, Some(suri_file)) => std::fs::read_to_string(suri_file)
.map_err(|err| anyhow::format_err!(
"Failed to read SURI from file {:?}: {}",
suri_file,
err,
))?,
(None, None) => return Err(anyhow::format_err!(
"One of options must be specified: '{}' or '{}'",
stringify!([<$chain_prefix _signer>]),
stringify!([<$chain_prefix _signer_file>]),
)),
};
let suri_password = match (
self.[<$chain_prefix _signer_password>].as_ref(),
self.[<$chain_prefix _signer_password_file>].as_ref(),
) {
(Some(suri_password), _) => Some(suri_password.to_owned()),
(None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file)
.map(Some)
.map_err(|err| anyhow::format_err!(
"Failed to read SURI password from file {:?}: {}",
suri_password_file,
err,
))?,
_ => None,
};
use sp_core::crypto::Pair;
Chain::KeyPair::from_string(
&self.[<$chain_prefix _signer>],
self.[<$chain_prefix _signer_password>].as_deref()
&suri,
suri_password.as_deref()
).map_err(|e| anyhow::format_err!("{:?}", e))
}
}
@@ -419,6 +456,7 @@ declare_chain_options!(Target, target);
#[cfg(test)]
mod tests {
use sp_core::Pair;
use std::str::FromStr;
use super::*;
@@ -456,4 +494,84 @@ mod tests {
// then
assert_eq!(hex.0, hex2.0);
}
#[test]
fn reads_suri_from_file() {
const ALICE: &str = "//Alice";
const BOB: &str = "//Bob";
const ALICE_PASSWORD: &str = "alice_password";
const BOB_PASSWORD: &str = "bob_password";
let alice = sp_core::sr25519::Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap();
let bob = sp_core::sr25519::Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap();
let bob_with_alice_password = sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap();
let temp_dir = tempdir::TempDir::new("reads_suri_from_file").unwrap();
let mut suri_file_path = temp_dir.path().to_path_buf();
let mut password_file_path = temp_dir.path().to_path_buf();
suri_file_path.push("suri");
password_file_path.push("password");
std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap();
std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap();
// when both seed and password are read from file
assert_eq!(
TargetSigningParams {
target_signer: Some(ALICE.into()),
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: None,
target_signer_password_file: None,
}
.to_keypair::<relay_rialto_client::Rialto>()
.map(|p| p.public())
.map_err(drop),
Ok(alice.public()),
);
// when both seed and password are read from file
assert_eq!(
TargetSigningParams {
target_signer: None,
target_signer_password: None,
target_signer_file: Some(suri_file_path.clone()),
target_signer_password_file: Some(password_file_path.clone()),
}
.to_keypair::<relay_rialto_client::Rialto>()
.map(|p| p.public())
.map_err(drop),
Ok(bob.public()),
);
// when password are is overriden by cli option
assert_eq!(
TargetSigningParams {
target_signer: None,
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: Some(suri_file_path.clone()),
target_signer_password_file: Some(password_file_path.clone()),
}
.to_keypair::<relay_rialto_client::Rialto>()
.map(|p| p.public())
.map_err(drop),
Ok(bob_with_alice_password.public()),
);
// when both seed and password are overriden by cli options
assert_eq!(
TargetSigningParams {
target_signer: Some(ALICE.into()),
target_signer_password: Some(ALICE_PASSWORD.into()),
target_signer_file: Some(suri_file_path),
target_signer_password_file: Some(password_file_path),
}
.to_keypair::<relay_rialto_client::Rialto>()
.map(|p| p.public())
.map_err(drop),
Ok(alice.public()),
);
}
}
@@ -60,12 +60,8 @@ pub struct SendMessage {
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
/// The SURI of secret key to use when transactions are submitted to the Target node.
#[structopt(long, required_if("origin", "Target"))]
target_signer: Option<String>,
/// The password for the SURI of secret key to use when transactions are submitted to the Target node.
#[structopt(long)]
target_signer_password: Option<String>,
#[structopt(flatten)]
target_sign: TargetSigningParams,
/// Hex-encoded lane id. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
@@ -99,8 +95,7 @@ impl SendMessage {
crate::select_full_bridge!(self.bridge, {
let SendMessage {
source_sign,
target_signer,
target_signer_password,
target_sign,
ref mut message,
dispatch_fee_payment,
dispatch_weight,
@@ -129,12 +124,6 @@ impl SendMessage {
match origin {
Origins::Source => CallOrigin::SourceAccount(source_account_id),
Origins::Target => {
let target_sign = TargetSigningParams {
target_signer: target_signer.clone().ok_or_else(|| {
anyhow::format_err!("The argument target_signer is not available")
})?,
target_signer_password: target_signer_password.clone(),
};
let target_sign = target_sign.to_keypair::<Target>()?;
let digest = account_ownership_digest(
&target_call,
@@ -361,7 +350,7 @@ mod tests {
}
#[test]
fn target_signer_must_exist_if_origin_is_target() {
fn accepts_send_message_command_without_target_sign_options() {
// given
let send_message = SendMessage::from_iter_safe(vec![
"send-message",
@@ -377,7 +366,7 @@ mod tests {
"1234",
]);
assert!(send_message.is_err());
assert!(send_message.is_ok());
}
#[test]