Newer
Older
pub const SUBSTRATE_MNEMONIC: &str =
"bottom drive obey lake curtain smoke basket hold race lonely fit walk";
/// Raw 32B seed
Seed,
/// Substrate secret key or BIP39 mnemonic (optionally followed by derivation path)
/// Predefined (Alice, Bob, ...)
Predefined,
}
impl FromStr for SecretFormat {
fn from_str(s: &str) -> std::io::Result<Self> {
match s {
"seed" => Ok(SecretFormat::Seed),
"substrate" => Ok(SecretFormat::Substrate),
"predefined" => Ok(SecretFormat::Predefined),
_ => Err(std::io::Error::from(std::io::ErrorKind::InvalidInput)),
}
}
}
impl From<SecretFormat> for &'static str {
fn from(val: SecretFormat) -> &'static str {
match val {
SecretFormat::Seed => "seed",
SecretFormat::Substrate => "substrate",
SecretFormat::Predefined => "predefined",
}
impl From<SecretFormat> for OsStr {
fn from(val: SecretFormat) -> OsStr {
OsStr::from(Into::<&str>::into(val))
}
/// wrapper type for keys + signature
pub enum KeyPair {
Sr25519(Sr25519Pair),
Nacl(nacl::sign::Keypair),
}
impl KeyPair {
pub fn address(&self) -> AccountId {
match self {
KeyPair::Sr25519(keypair) => keypair.public().into(),
KeyPair::Nacl(keypair) => keypair.pkey.into(),
}
}
// can not derive clone because nacl does not implement it
impl Clone for KeyPair {
fn clone(&self) -> Self {
match self {
KeyPair::Sr25519(keypair) => KeyPair::Sr25519(keypair.clone()),
KeyPair::Nacl(keypair) => KeyPair::Nacl(nacl::sign::Keypair {
skey: keypair.skey,
pkey: keypair.pkey,
}),
impl From<Sr25519Pair> for KeyPair {
fn from(pair: Sr25519Pair) -> KeyPair {
KeyPair::Sr25519(pair)
}
}
impl From<nacl::sign::Keypair> for KeyPair {
fn from(pair: nacl::sign::Keypair) -> KeyPair {
KeyPair::Nacl(pair)
}
}
pub enum Signature {
Sr25519(sr25519::Signature),
Nacl(Vec<u8>),
}
/// get keypair in any possible way
/// at this point, if secret is predefined, it's not replaced yet
pub fn get_keypair(
secret_format: SecretFormat,
secret: Option<&str>,
) -> Result<KeyPair, GcliError> {
match (secret_format, secret) {
(SecretFormat::Cesium, None) => Ok(prompt_secret(SecretFormat::Cesium)),
(SecretFormat::Predefined, Some(deriv)) => pair_from_predefined(deriv).map(|v| v.into()),
(_, Some(secret)) => Ok(pair_from_secret(secret_format, secret)?.into()),
_ => Err(GcliError::Logic(
"can not get keypair from available options".to_string(),
)),
}
}
/// get keypair from given secret
/// if secret is predefined, secret should contain the predefined value
pub fn pair_from_secret(
secret_format: SecretFormat,
secret: &str,
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
) -> Result<Sr25519Pair, GcliError> {
match secret_format {
SecretFormat::Substrate => pair_from_str(secret),
SecretFormat::Predefined => pair_from_str(secret), /* if predefined, secret arg is replaced in config */
SecretFormat::Seed => pair_from_seed(secret),
SecretFormat::Cesium => Err(GcliError::Logic(
"cesium format incompatible with single secret".to_string(),
)),
}
}
/// get keypair from given string secret
pub fn pair_from_str(secret: &str) -> Result<Sr25519Pair, GcliError> {
Sr25519Pair::from_string(secret, None)
.map_err(|_| GcliError::Input("Invalid secret".to_string()))
}
/// get keypair from given seed
pub fn pair_from_seed(secret: &str) -> Result<Sr25519Pair, GcliError> {
let mut seed = [0; 32];
hex::decode_to_slice(secret, &mut seed)
.map_err(|_| GcliError::Input("Invalid secret".to_string()))?;
let pair = Sr25519Pair::from_seed(&seed);
Ok(pair)
}
/// get mnemonic from predefined derivation path
pub fn predefined_mnemonic(deriv: &str) -> String {
format!("{SUBSTRATE_MNEMONIC}//{deriv}")
}
/// get keypair from predefined secret
pub fn pair_from_predefined(deriv: &str) -> Result<Sr25519Pair, GcliError> {
pair_from_str(&predefined_mnemonic(deriv))
}
/// get keypair from Cesium id/pwd
pub fn pair_from_cesium(id: String, pwd: String) -> nacl::sign::Keypair {
let params = scrypt::Params::new(12u8, 16u32, 1u32, 32).unwrap();
let seed = &mut [0u8; 32];
scrypt::scrypt(&pwd.into_bytes(), &id.into_bytes(), ¶ms, seed).unwrap();
nacl::sign::generate_keypair(seed)
}
/// ask user to input a secret
pub fn prompt_secret_substrate() -> Sr25519Pair {
let mnemonic = &rpassword::prompt_password("Mnemonic: ").unwrap();
match pair_from_str(mnemonic) {
Ok(pair) => return pair,
Err(_) => println!("Invalid secret"),
}
}
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/// ask user pass (Cesium format)
pub fn prompt_secret_cesium() -> nacl::sign::Keypair {
let id = rpassword::prompt_password("Cesium id: ").unwrap();
let pwd = rpassword::prompt_password("Cesium password: ").unwrap();
pair_from_cesium(id, pwd)
}
/// ask user to input a seed
pub fn prompt_seed() -> Sr25519Pair {
loop {
let seed = &rpassword::prompt_password("Seed: ").unwrap();
match pair_from_seed(seed) {
Ok(pair) => return pair,
Err(_) => println!("Invalid seed"),
}
}
}
/// ask user pass (Cesium format)
pub fn prompt_predefined() -> Sr25519Pair {
let deriv = rpassword::prompt_password("Enter derivation path: ").unwrap();
pair_from_predefined(&deriv).expect("invalid secret")
}
/// ask user secret in relevant format
pub fn prompt_secret(secret_format: SecretFormat) -> KeyPair {
match secret_format {
SecretFormat::Substrate => prompt_secret_substrate().into(),
SecretFormat::Cesium => prompt_secret_cesium().into(),
SecretFormat::Seed => prompt_seed().into(),
SecretFormat::Predefined => prompt_predefined().into(),
}
}