diff --git a/Cargo.lock b/Cargo.lock index 68f07a2..26bad73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -288,6 +288,7 @@ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", + "rand_core 0.6.4", "serde", "sha2", "subtle", @@ -822,16 +823,37 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.3", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -1243,7 +1265,7 @@ dependencies = [ "httparse", "log", "native-tls", - "rand", + "rand 0.9.2", "sha1", "thiserror", "utf-8", @@ -1341,6 +1363,9 @@ name = "wcli" version = "0.1.0" dependencies = [ "clap", + "ed25519-dalek", + "hex", + "rand 0.8.5", "serde", "serde_json", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 56887fb..5705317 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,12 @@ edition = "2024" [dependencies] clap = { version = "4.5.54", features = ["derive"] } +ed25519-dalek = { version = "2", features = ["rand_core"] } +hex = "0.4" +rand = "0.8" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" tokio = { version = "1.49.0", features = ["full"] } wampproto = { git = "https://github.com/xconnio/wampproto-rust.git", rev = "520130fa02343409578879959748b36f151bbc8d" } xconn = { git = "https://github.com/xconnio/xconn-rust.git", rev = "484b2deade287937d3c3a65b6ad9d8b2ae2dd2d1" } + diff --git a/src/cli.rs b/src/cli.rs index 6841d4d..9d4a4a9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -81,4 +81,10 @@ pub enum Commands { Subscribe, /// Publish to a topic Publish, + /// Generate a WAMP cryptosign ed25519 keypair + Keygen { + /// Write keypair to file. Uses 'key' and 'key.pub' by default, or specify a custom name + #[arg(short = 'O', long = "output-file", value_name = "NAME", num_args = 0..=1, default_missing_value = "key")] + output_file: Option, + }, } diff --git a/src/commands/keygen.rs b/src/commands/keygen.rs new file mode 100644 index 0000000..a1fcac9 --- /dev/null +++ b/src/commands/keygen.rs @@ -0,0 +1,31 @@ +use ed25519_dalek::SigningKey; +use hex::ToHex; +use rand::rngs::OsRng; +use std::fs::File; +use std::io::Write; + +pub fn handle(output_file: Option) -> Result<(), Box> { + let mut csprng = OsRng; + let signing_key = SigningKey::generate(&mut csprng); + + let private_key_hex: String = signing_key.to_bytes().encode_hex(); + let public_key_hex: String = signing_key.verifying_key().to_bytes().encode_hex(); + + println!("Public Key: {}", public_key_hex); + println!("Private Key: {}", private_key_hex); + + if let Some(name) = output_file { + let pub_path = format!("{}.pub", name); + let priv_path = name; + + let mut file = File::create(&pub_path)?; + writeln!(file, "{}", public_key_hex)?; + println!("Public key written to {}", pub_path); + + let mut file = File::create(&priv_path)?; + writeln!(file, "{}", private_key_hex)?; + println!("Private key written to {}", priv_path); + } + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 36a2c05..cf86660 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,4 +1,5 @@ pub mod call; +pub mod keygen; pub mod publish; pub mod register; pub mod subscribe; diff --git a/src/main.rs b/src/main.rs index e421c8c..b8dca46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,11 @@ use config::{CallConfig, ConnectionConfig}; async fn main() -> Result<(), Box> { let cli = Cli::parse(); + // Handle commands that don't require a connection first + if let Commands::Keygen { output_file } = cli.command { + return commands::keygen::handle(output_file); + } + println!("Connecting to {} in realm {}", cli.url, cli.realm); let conn_config = ConnectionConfig::from(&cli); @@ -51,6 +56,7 @@ async fn main() -> Result<(), Box> { commands::publish::handle(&session).await?; session.leave().await?; } + Commands::Keygen { .. } => unreachable!(), // Handled above } Ok(())