diff --git a/Cargo.lock b/Cargo.lock index 528c51a738..9a6a2b3c86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1505,6 +1505,7 @@ version = "0.10.0" dependencies = [ "bs58 0.4.0", "clap", + "colored", "config", "crypto", "dirs", diff --git a/clients/validator/package.json b/clients/validator/package.json index 8ef5351bfc..d1f61fdb31 100644 --- a/clients/validator/package.json +++ b/clients/validator/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nym-validator-client", - "version": "0.10.0-rc4", + "version": "0.10.0-rc5", "description": "A TypeScript client for interacting with smart contracts in Nym validators", "repository": "https://github.com/nymtech/nym", "main": "./dist/index.js", diff --git a/mixnode/Cargo.toml b/mixnode/Cargo.toml index 6fc8938dfa..fbc3cc3516 100644 --- a/mixnode/Cargo.toml +++ b/mixnode/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" [dependencies] bs58 = "0.4.0" clap = "2.33.0" +colored = "2" dirs = "3.0" dotenv = "0.15.0" futures = "0.3" diff --git a/mixnode/src/commands/mod.rs b/mixnode/src/commands/mod.rs index c3eb045732..fb4fed914a 100644 --- a/mixnode/src/commands/mod.rs +++ b/mixnode/src/commands/mod.rs @@ -7,6 +7,7 @@ use nymsphinx::params::DEFAULT_NUM_MIX_HOPS; pub(crate) mod init; pub(crate) mod run; +pub(crate) mod sign; pub(crate) mod upgrade; pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config { diff --git a/mixnode/src/commands/run.rs b/mixnode/src/commands/run.rs index e555bb4700..dadce82ab3 100644 --- a/mixnode/src/commands/run.rs +++ b/mixnode/src/commands/run.rs @@ -171,7 +171,7 @@ pub fn execute(matches: &ArgMatches) { ); println!( - "\nTo bond your mixnode you will need to provide the following: + "\nTo bond your mixnode, go to https://web-wallet-finney.nymtech.net/. You will need to provide the following: Identity key: {} Sphinx key: {} Host: {} diff --git a/mixnode/src/commands/sign.rs b/mixnode/src/commands/sign.rs new file mode 100644 index 0000000000..4ed3a4e033 --- /dev/null +++ b/mixnode/src/commands/sign.rs @@ -0,0 +1,73 @@ +use crate::config::{persistence::pathfinder::MixNodePathfinder, Config}; +use clap::{App, Arg, ArgMatches}; +use colored::*; +use config::NymConfig; +use crypto::asymmetric::identity; +use log::*; + +pub fn command_args<'a, 'b>() -> App<'a, 'b> { + App::new("sign") + .about("Sign text to prove ownership of this mixnode") + .arg( + Arg::with_name("id") + .long("id") + .help("The id of the mixnode you want to sign with") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("text") + .long("text") + .help("The text to sign") + .takes_value(true) + .required(true), + ) +} + +fn load_identity_keys(pathfinder: &MixNodePathfinder) -> identity::KeyPair { + let identity_keypair: identity::KeyPair = pemstore::load_keypair(&pemstore::KeyPairPath::new( + pathfinder.private_identity_key().to_owned(), + pathfinder.public_identity_key().to_owned(), + )) + .expect("Failed to read stored identity key files"); + identity_keypair +} + +pub fn execute(matches: &ArgMatches) { + let id = matches.value_of("id").unwrap(); + let text = matches.value_of("text").unwrap(); + + let config = match Config::load_from_file(id) { + Ok(cfg) => cfg, + Err(err) => { + error!("Failed to load config for {}. Are you sure you have run `init` before? (Error was: {})", id, err); + return; + } + }; + let pathfinder = MixNodePathfinder::new_from_config(&config); + let identity_keypair = load_identity_keys(&pathfinder); + let signature_bytes = identity_keypair + .private_key() + .sign(text.as_ref()) + .to_bytes(); + + let signature = bs58::encode(signature_bytes).into_string(); + let identity = identity_keypair.public_key().to_base58_string(); + + let channel_name = "@nymchan_help_chat".bright_cyan(); + + println!( + "Signing the text {:?} using your mixnode's Ed25519 identity key...", + text + ); + println!(); + println!("Signature is: {}", signature); + println!(); + println!("You can claim your mixnode in Telegram by talking to our bot. To do so:"); + println!(); + println!("* go to the '{}' channel", channel_name); + println!("* copy the following line of text, and paste it into the channel"); + println!(); + println!("/claim {} {}", identity, signature); + println!(); +} diff --git a/mixnode/src/main.rs b/mixnode/src/main.rs index e25210f9d2..3ae3ba5e81 100644 --- a/mixnode/src/main.rs +++ b/mixnode/src/main.rs @@ -19,6 +19,7 @@ fn main() { .subcommand(commands::init::command_args()) .subcommand(commands::run::command_args()) .subcommand(commands::upgrade::command_args()) + .subcommand(commands::sign::command_args()) .get_matches(); execute(arg_matches); @@ -28,6 +29,7 @@ fn execute(matches: ArgMatches) { match matches.subcommand() { ("init", Some(m)) => commands::init::execute(m), ("run", Some(m)) => commands::run::execute(m), + ("sign", Some(m)) => commands::sign::execute(m), ("upgrade", Some(m)) => commands::upgrade::execute(m), _ => println!("{}", usage()), }