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

Revert "Added support for the different SecretFormat within the Vault"

This reverts commit fd92df0c.
parent 2b8dac2d
No related branches found
No related tags found
No related merge requests found
use crate::*;
use age::secrecy::Secret;
use std::io::{Read, Write};
use std::path::PathBuf;
/// define universal dividends subcommands
#[derive(Clone, Default, Debug, clap::Parser)]
......@@ -13,18 +12,8 @@ pub enum Subcommand {
Where,
/// Generate a mnemonic
Generate,
/// Import key from (substrate)mnemonic or other format with interactive prompt
Import {
/// Secret key format (substrate, seed, cesium)
#[clap(short = 'S', long, required = false, default_value = SecretFormat::Substrate)]
secret_format: SecretFormat,
},
}
struct VaultItem {
secret_format: SecretFormat,
secret: keys::Secret,
keypair: KeyPair,
/// Import mnemonic with interactive prompt
Import,
}
// encrypt input with passphrase
......@@ -73,14 +62,11 @@ pub fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError>
let mnemonic = bip39::Mnemonic::generate(12).unwrap();
println!("{mnemonic}");
}
Subcommand::Import {
secret_format,
} => {
let vault_item = prompt_secret_and_compute_vault_item(secret_format)?;
Subcommand::Import => {
let mnemonic = rpassword::prompt_password("Mnemonic: ")?;
println!("Enter password to protect the key");
let password = rpassword::prompt_password("Password: ")?;
let address = store_vault_item(&data, vault_item, password)?;
let address = store_mnemonic(&data, &mnemonic, password)?;
println!("Stored secret for {address}");
}
};
......@@ -88,120 +74,34 @@ pub fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError>
Ok(())
}
fn create_vault_item<F, P>(secret_format: SecretFormat, prompt_fn: F) -> Result<VaultItem, GcliError>
where
F: Fn() -> (keys::Secret, P),
P: Into<KeyPair>,
{
let (secret, pair) = prompt_fn();
Ok(VaultItem {
secret_format,
secret,
keypair: pair.into(),
})
}
fn prompt_secret_and_compute_vault_item(secret_format: SecretFormat) -> Result<VaultItem, GcliError> {
match secret_format {
SecretFormat::Substrate =>
create_vault_item(secret_format, prompt_secret_substrate_and_compute_keypair),
SecretFormat::Seed =>
create_vault_item(secret_format, prompt_seed_and_compute_keypair),
SecretFormat::Cesium =>
create_vault_item(secret_format, prompt_secret_cesium_and_compute_keypair),
SecretFormat::Predefined =>
create_vault_item(secret_format, prompt_predefined_and_compute_keypair),
}
}
/// store VaultItem protected with password
fn store_vault_item(
/// store mnemonic protected with password
pub fn store_mnemonic(
data: &Data,
vault_item: VaultItem,
mnemonic: &str,
password: String,
) -> Result<AccountId, GcliError> {
let keypair = vault_item.keypair;
let address = keypair.address();
// write encrypted secret in file identified by address pubkey and secret_format
let path = get_vault_key_path(data, vault_item.secret_format, address.to_string());
// check validity by deriving keypair
let keypair = pair_from_str(mnemonic)?;
let address = keypair.public();
// write encrypted mnemonic in file identified by pubkey
let path = data.project_dir.data_dir().join(address.to_string());
let mut file = std::fs::File::create(path)?;
match vault_item.secret {
keys::Secret::SimpleSecret(secret) => {
file.write_all(&encrypt(secret.as_bytes(), password).map_err(|e| anyhow!(e))?[..])?;
}
keys::Secret::DualSecret(id, pwd) => {
//Making a simple separation of the 2 parts with a newline character
let secret = format!("{id}\n{pwd}");
file.write_all(&encrypt(secret.as_bytes(), password).map_err(|e| anyhow!(e))?[..])?;
}
}
Ok(address)
}
fn get_vault_key_path(data: &Data, secret_format: SecretFormat, address: String) -> PathBuf {
let format_str: &'static str = From::from(secret_format);
data.project_dir.data_dir().join(format!("{}-{}", address, format_str))
file.write_all(&encrypt(mnemonic.as_bytes(), password).map_err(|e| anyhow!(e))?[..])?;
Ok(keypair.public().into())
}
/// look for different possible paths for vault keys and return both format and path
fn find_vault_key(data: &Data, address: String) -> Result<Option<(SecretFormat, PathBuf)>, GcliError> {
let mut secret_format = SecretFormat::Substrate;
let mut path = get_vault_key_path(data, secret_format, address.to_string());
//Also checking for old file name without secret_format which would be for (default) substrate key
if !path.exists() {
path = data.project_dir.data_dir().join(address.to_string());
}
if !path.exists() {
secret_format = SecretFormat::Seed;
path = get_vault_key_path(data, secret_format, address.to_string());
}
if !path.exists() {
secret_format = SecretFormat::Cesium;
path = get_vault_key_path(data, secret_format, address.to_string());
}
if !path.exists() {
secret_format = SecretFormat::Predefined;
path = get_vault_key_path(data, secret_format, address.to_string());
}
/// try get secret in keystore
pub fn try_fetch_secret(data: &Data, address: AccountId) -> Result<Option<String>, GcliError> {
let path = data.project_dir.data_dir().join(address.to_string());
if path.exists() {
Ok(Some((secret_format, path)))
} else {
Ok(None)
}
}
/// try to get secret in keystore, prompt for the password and compute the keypair
pub fn try_fetch_key_pair(data: &Data, address: AccountId) -> Result<Option<KeyPair>, GcliError> {
if let Some((secret_format, path)) = find_vault_key(data, address.to_string())? {
println!("Enter password to unlock account {address}");
let password = rpassword::prompt_password("Password: ")?;
let mut file = std::fs::OpenOptions::new().read(true).open(path)?;
let mut cypher = vec![];
file.read_to_end(&mut cypher)?;
let secret_vec = decrypt(&cypher, password).map_err(|e| GcliError::Input(e.to_string()))?;
let secret = String::from_utf8(secret_vec).map_err(|e| anyhow!(e))?;
//Still need to handle different secret formats
match secret_format {
SecretFormat::Substrate => {
Ok(Some(pair_from_str(&secret)?.into()))
}
SecretFormat::Seed => {
Ok(Some(pair_from_seed(&secret)?.into()))
}
SecretFormat::Cesium => {
let mut lines = secret.lines();
//Un-wrapping the 2 secrets from each line
let id = lines.next().unwrap();
let pwd = lines.next().unwrap();
Ok(Some(pair_from_cesium(id.to_string(), pwd.to_string()).into()))
}
SecretFormat::Predefined => {
Ok(Some(pair_from_predefined(&secret)?.into()))
}
}
let secret = decrypt(&cypher, password).map_err(|e| GcliError::Input(e.to_string()))?;
let secretstr = String::from_utf8(secret).map_err(|e| anyhow!(e))?;
Ok(Some(secretstr))
} else {
Ok(None)
}
......
use sp_core::sr25519::Pair;
use crate::*;
use sr25519::Pair as Sr25519Pair;
......@@ -18,12 +17,6 @@ pub enum SecretFormat {
/// Cesium (scrypt + nacl)
Cesium,
}
pub enum Secret {
SimpleSecret(String),
DualSecret(String, String),
}
impl FromStr for SecretFormat {
type Err = std::io::Error;
......@@ -159,15 +152,10 @@ pub fn pair_from_cesium(id: String, pwd: String) -> nacl::sign::Keypair {
/// ask user to input a secret
pub fn prompt_secret_substrate() -> Sr25519Pair {
// Only interested in the keypair which is the second element of the tuple
prompt_secret_substrate_and_compute_keypair().1
}
pub fn prompt_secret_substrate_and_compute_keypair() -> (Secret, Sr25519Pair) {
loop {
let mnemonic = rpassword::prompt_password("Mnemonic: ").unwrap();
match pair_from_str(&mnemonic) {
Ok(pair) => return (Secret::SimpleSecret(mnemonic), pair),
let mnemonic = &rpassword::prompt_password("Mnemonic: ").unwrap();
match pair_from_str(mnemonic) {
Ok(pair) => return pair,
Err(_) => println!("Invalid secret"),
}
}
......@@ -175,27 +163,17 @@ pub fn prompt_secret_substrate_and_compute_keypair() -> (Secret, Sr25519Pair) {
/// ask user pass (Cesium format)
pub fn prompt_secret_cesium() -> nacl::sign::Keypair {
// Only interested in the keypair which is the second element of the tuple
prompt_secret_cesium_and_compute_keypair().1
}
pub fn prompt_secret_cesium_and_compute_keypair() -> (Secret, nacl::sign::Keypair) {
let id = rpassword::prompt_password("Cesium id: ").unwrap();
let pwd = rpassword::prompt_password("Cesium password: ").unwrap();
(Secret::DualSecret(id.clone(),pwd.clone()), pair_from_cesium(id, pwd))
pair_from_cesium(id, pwd)
}
/// ask user to input a seed
pub fn prompt_seed() -> Sr25519Pair {
// Only interested in the keypair which is the second element of the tuple
prompt_seed_and_compute_keypair().1
}
pub fn prompt_seed_and_compute_keypair() -> (Secret,Pair) {
loop {
let seed = rpassword::prompt_password("Seed: ").unwrap();
match pair_from_seed(&seed) {
Ok(pair) => return (Secret::SimpleSecret(seed), pair),
let seed = &rpassword::prompt_password("Seed: ").unwrap();
match pair_from_seed(seed) {
Ok(pair) => return pair,
Err(_) => println!("Invalid seed"),
}
}
......@@ -203,13 +181,8 @@ pub fn prompt_seed_and_compute_keypair() -> (Secret,Pair) {
/// ask user pass (Cesium format)
pub fn prompt_predefined() -> Sr25519Pair {
// Only interested in the keypair which is the second element of the tuple
prompt_predefined_and_compute_keypair().1
}
pub fn prompt_predefined_and_compute_keypair() -> (Secret, Sr25519Pair) {
let deriv = rpassword::prompt_password("Enter derivation path: ").unwrap();
(Secret::SimpleSecret(deriv.clone()), pair_from_predefined(&deriv).expect("invalid secret"))
pair_from_predefined(&deriv).expect("invalid secret")
}
/// ask user secret in relevant format
......@@ -231,9 +204,9 @@ pub fn fetch_or_get_keypair(data: &Data, address: Option<AccountId>) -> Result<K
return Ok(pair_from_predefined(d).unwrap().into());
};
// look for corresponding KeyPair in keystore
if let Some(key_pair) = commands::vault::try_fetch_key_pair(data, address)? {
return Ok(key_pair);
// look for corresponding secret in keystore
if let Some(secret) = commands::vault::try_fetch_secret(data, address)? {
return get_keypair(SecretFormat::Substrate, Some(&secret));
};
}
// at the moment, there is no way to confg gcli to use an other kind of secret
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment