use crate::{
error, params::MessageParams, utils, with_crypto_scheme, CryptoSchemeFlag, KeystoreParams,
};
use array_bytes::bytes2hex;
use clap::Parser;
use sp_core::crypto::SecretString;
use std::io::{BufRead, Write};
#[derive(Debug, Clone, Parser)]
#[command(name = "sign", about = "Sign a message, with a given (secret) key")]
pub struct SignCmd {
#[arg(long)]
suri: Option<String>,
#[allow(missing_docs)]
#[clap(flatten)]
pub message_params: MessageParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub keystore_params: KeystoreParams,
#[allow(missing_docs)]
#[clap(flatten)]
pub crypto_scheme: CryptoSchemeFlag,
}
impl SignCmd {
pub fn run(&self) -> error::Result<()> {
let sig = self.sign(|| std::io::stdin().lock())?;
std::io::stdout().lock().write_all(sig.as_bytes())?;
Ok(())
}
pub(crate) fn sign<F, R>(&self, create_reader: F) -> error::Result<String>
where
R: BufRead,
F: FnOnce() -> R,
{
let message = self.message_params.message_from(create_reader)?;
let suri = utils::read_uri(self.suri.as_ref())?;
let password = self.keystore_params.read_password()?;
with_crypto_scheme!(self.crypto_scheme.scheme, sign(&suri, password, message))
}
}
fn sign<P: sp_core::Pair>(
suri: &str,
password: Option<SecretString>,
message: Vec<u8>,
) -> error::Result<String> {
let pair = utils::pair_from_suri::<P>(suri, password)?;
Ok(bytes2hex("0x", pair.sign(&message).as_ref()))
}
#[cfg(test)]
mod test {
use super::*;
const SEED: &str = "0xe5be9a5092b81bca64be81d212e7f2f9eba183bb7a90954f7b76361f6edb5c0a";
#[test]
fn sign_arg() {
let cmd = SignCmd::parse_from(&[
"sign",
"--suri",
&SEED,
"--message",
&SEED,
"--password",
"12345",
"--hex",
]);
let sig = cmd.sign(|| std::io::stdin().lock()).expect("Must sign");
assert!(sig.starts_with("0x"), "Signature must start with 0x");
assert!(array_bytes::hex2bytes(&sig).is_ok(), "Signature is valid hex");
}
#[test]
fn sign_stdin() {
let cmd = SignCmd::parse_from(&[
"sign",
"--suri",
SEED,
"--message",
&SEED,
"--password",
"12345",
]);
let sig = cmd.sign(|| SEED.as_bytes()).expect("Must sign");
assert!(sig.starts_with("0x"), "Signature must start with 0x");
assert!(array_bytes::hex2bytes(&sig).is_ok(), "Signature is valid hex");
}
}