referrerpolicy=no-referrer-when-downgrade

sc_cli/params/
keystore_params.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use crate::{error, error::Result};
20use clap::Args;
21use sc_service::config::KeystoreConfig;
22use sp_core::crypto::SecretString;
23use std::{
24	fs,
25	path::{Path, PathBuf},
26};
27
28/// default sub directory for the key store
29const DEFAULT_KEYSTORE_CONFIG_PATH: &str = "keystore";
30
31/// Parameters of the keystore
32#[derive(Debug, Clone, Args)]
33pub struct KeystoreParams {
34	/// Specify custom keystore path.
35	#[arg(long, value_name = "PATH")]
36	pub keystore_path: Option<PathBuf>,
37
38	/// Use interactive shell for entering the password used by the keystore.
39	#[arg(long, conflicts_with_all = &["password", "password_filename"])]
40	pub password_interactive: bool,
41
42	/// Password used by the keystore.
43	///
44	/// This allows appending an extra user-defined secret to the seed.
45	#[arg(
46		long,
47		value_parser = secret_string_from_str,
48		conflicts_with_all = &["password_interactive", "password_filename"]
49	)]
50	pub password: Option<SecretString>,
51
52	/// File that contains the password used by the keystore.
53	#[arg(
54		long,
55		value_name = "PATH",
56		conflicts_with_all = &["password_interactive", "password"]
57	)]
58	pub password_filename: Option<PathBuf>,
59}
60
61/// Parse a secret string, returning a displayable error.
62pub fn secret_string_from_str(s: &str) -> std::result::Result<SecretString, String> {
63	std::str::FromStr::from_str(s).map_err(|_| "Could not get SecretString".to_string())
64}
65
66impl KeystoreParams {
67	/// Get the keystore configuration for the parameters
68	pub fn keystore_config(&self, config_dir: &Path) -> Result<KeystoreConfig> {
69		let password = if self.password_interactive {
70			Some(SecretString::new(input_keystore_password()?))
71		} else if let Some(ref file) = self.password_filename {
72			let password = fs::read_to_string(file).map_err(|e| format!("{}", e))?;
73			Some(SecretString::new(password))
74		} else {
75			self.password.clone()
76		};
77
78		let path = self
79			.keystore_path
80			.clone()
81			.unwrap_or_else(|| config_dir.join(DEFAULT_KEYSTORE_CONFIG_PATH));
82
83		Ok(KeystoreConfig::Path { path, password })
84	}
85
86	/// helper method to fetch password from `KeyParams` or read from stdin
87	pub fn read_password(&self) -> error::Result<Option<SecretString>> {
88		let (password_interactive, password) = (self.password_interactive, self.password.clone());
89
90		let pass = if password_interactive {
91			let password = rpassword::prompt_password("Key password: ")?;
92			Some(SecretString::new(password))
93		} else {
94			password
95		};
96
97		Ok(pass)
98	}
99}
100
101fn input_keystore_password() -> Result<String> {
102	rpassword::prompt_password("Keystore password: ").map_err(|e| format!("{:?}", e).into())
103}