use crate::{
cli::{
commands::StorageLocationArgs,
scheme::{KeyGenerationResult, KeyInfo},
util::resolve_storage_location,
},
scheme::CryptoScheme,
};
use anyhow::Result;
use secrecy::ExposeSecret;
#[cfg(all(feature = "keyring", feature = "serde"))]
pub trait StorageScheme: CryptoScheme + crate::keyring::KeyringScheme {}
#[cfg(all(feature = "keyring", feature = "serde"))]
impl<T> StorageScheme for T where T: CryptoScheme + crate::keyring::KeyringScheme {}
#[cfg(not(all(feature = "keyring", feature = "serde")))]
pub trait StorageScheme: CryptoScheme {}
#[cfg(not(all(feature = "keyring", feature = "serde")))]
impl<T> StorageScheme for T where T: CryptoScheme {}
pub fn create_signer<S>(storage: &StorageLocationArgs) -> Result<crate::Signer<S>>
where
S: StorageScheme,
{
if let Some(path) = resolve_storage_location(storage) {
let path = crate::keyring::resolve_namespaced_path(path, S::namespace());
Ok(crate::Signer::fs(path)?)
} else {
Ok(crate::Signer::memory())
}
}
pub fn with_signer<S, F, R>(storage: &StorageLocationArgs, f: F) -> Result<R>
where
S: StorageScheme,
F: FnOnce(crate::Signer<S>) -> Result<R>,
{
f(create_signer::<S>(storage)?)
}
pub fn clear_keys_command<S>(
storage: &StorageLocationArgs,
) -> Result<crate::cli::scheme::ClearResult>
where
S: StorageScheme,
{
let signer: crate::Signer<S> = create_signer(storage)?;
let len = signer.list_keys()?.len();
signer.clear_keys()?;
Ok(crate::cli::scheme::ClearResult { removed: len })
}
pub fn generate_key_result<S>(
storage: &StorageLocationArgs,
show_secret: bool,
) -> Result<KeyGenerationResult>
where
S: StorageScheme,
{
with_signer::<S, _, _>(storage, |signer| {
let password = storage
.key_password
.as_ref()
.map(|p: &secrecy::SecretString| p.expose_secret().as_str());
let (private_key, public_key) = {
let (pk, _) = S::generate_keypair();
let public = if let Some(pwd) = password {
signer.import_encrypted(pk.clone(), pwd)?
} else {
signer.import(pk.clone())?
};
(pk, public)
};
let address = signer.address(public_key.clone());
Ok(KeyGenerationResult {
public_key: S::public_key_to_hex(&public_key),
address: S::address_to_string(&address),
scheme: S::NAME.to_string(),
secret: show_secret.then(|| hex::encode(S::private_key_to_seed(&private_key).as_ref())),
name: None,
})
})
}
pub fn key_info_from_public<S>(
signer: &crate::Signer<S>,
public_key: S::PublicKey,
show_secret: bool,
password: Option<&str>,
) -> Result<KeyInfo>
where
S: StorageScheme,
{
if !signer.has_key(public_key.clone())? {
anyhow::bail!("Key not found in storage");
}
let address = signer.address(public_key.clone());
let secret = if show_secret {
let private_key = if let Some(pwd) = password {
signer.private_key_encrypted(public_key.clone(), pwd)?
} else {
signer.private_key(public_key.clone())?
};
Some(hex::encode(S::private_key_to_seed(&private_key).as_ref()))
} else {
None
};
Ok(KeyInfo {
public_key: S::public_key_to_hex(&public_key),
address: S::address_to_string(&address),
scheme: S::NAME.to_string(),
secret,
name: None,
})
}
#[cfg(any(feature = "ed25519", feature = "sr25519"))]
pub fn show_key_for_public<S>(
storage: &StorageLocationArgs,
public_key: S::PublicKey,
show_secret: bool,
password: Option<&str>,
) -> Result<crate::cli::scheme::ListKeysResult>
where
S: StorageScheme,
{
with_signer::<S, _, _>(storage, |signer| {
let info = key_info_from_public(&signer, public_key, show_secret, password)?;
Ok(crate::cli::scheme::ListKeysResult { keys: vec![info] })
})
}
pub fn seed_from_hex<S>(hex_str: &str) -> Result<S::Seed>
where
S: StorageScheme,
{
let bytes = crate::cli::util::decode_hex_array::<32>(hex_str, "seed")?;
let mut seed = S::Seed::default();
let buffer = seed.as_mut();
if buffer.len() != bytes.len() {
anyhow::bail!(
"Invalid seed length: expected {} bytes, got {}",
buffer.len(),
bytes.len()
);
}
buffer.copy_from_slice(&bytes);
Ok(seed)
}