Skip to content
This repository was archived by the owner on Dec 10, 2022. It is now read-only.

Commit 6084e58

Browse files
authored
Merge pull request #51 from tox-rs/get_pk
Subcommand derive-pk
2 parents b8c44f8 + ff4ea52 commit 6084e58

File tree

1 file changed

+90
-18
lines changed

1 file changed

+90
-18
lines changed

src/node_config.rs

Lines changed: 90 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,30 @@ pub struct NodeConfig {
147147
pub unused: HashMap<String, Value>,
148148
}
149149

150+
fn create_sk_arg() -> Arg<'static, 'static> {
151+
Arg::with_name("secret-key")
152+
.short("s")
153+
.long("secret-key")
154+
.help("DHT secret key. Note that you should not pass the key via \
155+
arguments due to security reasons. Use this argument for \
156+
test purposes only. In the real world use the environment \
157+
variable instead")
158+
.takes_value(true)
159+
.conflicts_with("keys-file")
160+
.env("TOX_SECRET_KEY")
161+
.hidden(true)
162+
}
163+
164+
fn create_keys_file_arg() -> Arg<'static, 'static> {
165+
Arg::with_name("keys-file")
166+
.short("k")
167+
.long("keys-file")
168+
.help("Path to the file where DHT keys are stored")
169+
.takes_value(true)
170+
.required_unless("secret-key")
171+
.conflicts_with("secret-key")
172+
}
173+
150174
fn app() -> App<'static, 'static> {
151175
App::new(crate_name!())
152176
.version(crate_version!())
@@ -160,6 +184,13 @@ fn app() -> App<'static, 'static> {
160184
.help("Load settings from saved config file. \
161185
Config file format is YAML")
162186
.takes_value(true)))
187+
.subcommand(SubCommand::with_name("derive-pk")
188+
.about("Derive PK from either --keys-file or from env:TOX_SECRET_KEY")
189+
.arg(create_sk_arg())
190+
.arg(create_keys_file_arg()))
191+
// here go args without subcommands
192+
.arg(create_sk_arg())
193+
.arg(create_keys_file_arg())
163194
.arg(Arg::with_name("udp-address")
164195
.short("u")
165196
.long("udp-address")
@@ -182,24 +213,6 @@ fn app() -> App<'static, 'static> {
182213
.requires("tcp-address")
183214
.takes_value(true)
184215
.default_value_if("tcp-address", None, "512"))
185-
.arg(Arg::with_name("secret-key")
186-
.short("s")
187-
.long("secret-key")
188-
.help("DHT secret key. Note that you should not pass the key via \
189-
arguments due to security reasons. Use this argument for \
190-
test purposes only. In the real world use the environment \
191-
variable instead")
192-
.takes_value(true)
193-
.conflicts_with("keys-file")
194-
.env("TOX_SECRET_KEY")
195-
.hidden(true))
196-
.arg(Arg::with_name("keys-file")
197-
.short("k")
198-
.long("keys-file")
199-
.help("Path to the file where DHT keys are stored")
200-
.takes_value(true)
201-
.required_unless("secret-key")
202-
.conflicts_with("secret-key"))
203216
.arg(Arg::with_name("bootstrap-node")
204217
.short("b")
205218
.long("bootstrap-node")
@@ -251,6 +264,7 @@ pub fn cli_parse() -> NodeConfig {
251264
let matches = app().get_matches();
252265

253266
match matches.subcommand() {
267+
("derive-pk", Some(m)) => run_derive_pk(m),
254268
("config", Some(m)) => run_config(m),
255269
_ => run_args(&matches),
256270
}
@@ -283,6 +297,39 @@ fn parse_config(config_path: &str) -> NodeConfig {
283297
config
284298
}
285299

300+
fn run_derive_pk(matches: &ArgMatches) -> ! {
301+
let sk_passed_as_arg = matches.occurrences_of("secret-key") > 0;
302+
if sk_passed_as_arg {
303+
panic!("You should not pass the secret key via arguments due to \
304+
security reasons. Use the environment variable instead");
305+
}
306+
307+
let pk_from_arg = matches.value_of("secret-key").map(|s| {
308+
let sk_bytes: [u8; 32] = FromHex::from_hex(s).expect("Invalid DHT secret key");
309+
let sk = SecretKey::from_slice(&sk_bytes).expect("Invalid DHT secret key");
310+
sk.public_key()
311+
});
312+
let pk_from_file = matches.value_of("keys-file").map(|keys_file| {
313+
let mut file = std::fs::File::open(keys_file).expect("Failed to read the keys file");
314+
315+
let mut buf = [0; PUBLICKEYBYTES + SECRETKEYBYTES];
316+
use std::io::Read;
317+
file.read_exact(&mut buf).expect("Failed to read keys from the keys file");
318+
let pk = PublicKey::from_slice(&buf[..PUBLICKEYBYTES]).expect("Failed to read public key from the keys file");
319+
let sk = SecretKey::from_slice(&buf[PUBLICKEYBYTES..]).expect("Failed to read secret key from the keys file");
320+
assert!(pk == sk.public_key(), "The loaded public key does not correspond to the loaded secret key");
321+
pk
322+
});
323+
324+
let pk = pk_from_arg.or(pk_from_file).unwrap();
325+
326+
println!("{}", hex::encode(&pk).to_uppercase());
327+
328+
// FIXME: use ExitCode::SUCCESS when stabilized
329+
// https://doc.rust-lang.org/std/process/struct.ExitCode.html
330+
std::process::exit(0)
331+
}
332+
286333
fn run_config(matches: &ArgMatches) -> NodeConfig {
287334
let config_path = value_t!(matches.value_of("cfg-file"), String).unwrap_or_else(|e| e.exit());
288335

@@ -607,4 +654,29 @@ mod tests {
607654
let config = run_args(&matches);
608655
assert_eq!(config.threads, Threads::N(42));
609656
}
657+
658+
#[test]
659+
fn args_derive_pk_keys_file() {
660+
let matches = app().get_matches_from(vec![
661+
"tox-node",
662+
"derive-pk",
663+
"--keys-file",
664+
"./keys",
665+
]);
666+
let matches = matches.subcommand_matches("derive-pk").unwrap();
667+
assert_eq!("./keys", matches.value_of("keys-file").unwrap());
668+
}
669+
670+
#[test]
671+
fn args_derive_pk_secret_key() {
672+
let sk_str = "d7f04a6db2c12f1eae0229c72e6bc429ca894541acc5f292da0e4d9a47827774";
673+
let matches = app().get_matches_from(vec![
674+
"tox-node",
675+
"derive-pk",
676+
"--secret-key",
677+
sk_str
678+
]);
679+
let matches = matches.subcommand_matches("derive-pk").unwrap();
680+
assert_eq!(sk_str, matches.value_of("secret-key").unwrap());
681+
}
610682
}

0 commit comments

Comments
 (0)