@@ -147,6 +147,30 @@ pub struct NodeConfig {
147
147
pub unused : HashMap < String , Value > ,
148
148
}
149
149
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
+
150
174
fn app ( ) -> App < ' static , ' static > {
151
175
App :: new ( crate_name ! ( ) )
152
176
. version ( crate_version ! ( ) )
@@ -160,6 +184,13 @@ fn app() -> App<'static, 'static> {
160
184
. help ( "Load settings from saved config file. \
161
185
Config file format is YAML")
162
186
. 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 ( ) )
163
194
. arg ( Arg :: with_name ( "udp-address" )
164
195
. short ( "u" )
165
196
. long ( "udp-address" )
@@ -182,24 +213,6 @@ fn app() -> App<'static, 'static> {
182
213
. requires ( "tcp-address" )
183
214
. takes_value ( true )
184
215
. 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" ) )
203
216
. arg ( Arg :: with_name ( "bootstrap-node" )
204
217
. short ( "b" )
205
218
. long ( "bootstrap-node" )
@@ -251,6 +264,7 @@ pub fn cli_parse() -> NodeConfig {
251
264
let matches = app ( ) . get_matches ( ) ;
252
265
253
266
match matches. subcommand ( ) {
267
+ ( "derive-pk" , Some ( m) ) => run_derive_pk ( m) ,
254
268
( "config" , Some ( m) ) => run_config ( m) ,
255
269
_ => run_args ( & matches) ,
256
270
}
@@ -283,6 +297,39 @@ fn parse_config(config_path: &str) -> NodeConfig {
283
297
config
284
298
}
285
299
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
+
286
333
fn run_config ( matches : & ArgMatches ) -> NodeConfig {
287
334
let config_path = value_t ! ( matches. value_of( "cfg-file" ) , String ) . unwrap_or_else ( |e| e. exit ( ) ) ;
288
335
@@ -607,4 +654,29 @@ mod tests {
607
654
let config = run_args ( & matches) ;
608
655
assert_eq ! ( config. threads, Threads :: N ( 42 ) ) ;
609
656
}
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
+ }
610
682
}
0 commit comments