// Copyright (c) 2022-2023 Niko Bonnieure, Par le Peuple, NextGraph.org developers // All rights reserved. // Licensed under the Apache License, Version 2.0 // // or the MIT license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. #[macro_use] extern crate slice_as_array; pub mod types; mod cli; use crate::cli::*; use crate::types::*; use clap::Parser; use p2p_broker::interfaces::*; use p2p_broker::server_ws::run_server_v0; use p2p_broker::types::*; use p2p_broker::utils::*; use p2p_net::types::*; use p2p_net::utils::is_private_ip; use p2p_net::utils::is_public_ip; use p2p_net::utils::is_public_ipv4; use p2p_net::utils::is_public_ipv6; use p2p_net::utils::{ gen_keys, is_ipv4_global, is_ipv4_private, is_ipv6_global, is_ipv6_private, keys_from_bytes, Dual25519Keys, Sensitive, U8Array, }; use p2p_net::{WS_PORT, WS_PORT_REVERSE_PROXY}; use p2p_repo::log::*; use p2p_repo::{ types::{PrivKey, PubKey}, utils::{generate_keypair, keypair_from_ed, sign, verify}, }; use serde_json::{from_str, to_string_pretty}; use std::fs::{read_to_string, write}; use std::io::ErrorKind; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; use addr::parser::DnsName; use addr::psl::List; use lazy_static::lazy_static; use regex::Regex; fn decode_key(key_string: &String) -> Result<[u8; 32], ()> { let vec = base64_url::decode(key_string).map_err(|_| log_err!("key has invalid content"))?; Ok(*slice_as_array!(&vec, [u8; 32]) .ok_or(()) .map_err(|_| log_err!("key has invalid content array"))?) } //For windows: {846EE342-7039-11DE-9D20-806E6F6E6963} //For the other OSes: en0 lo ... #[cfg(not(target_os = "windows"))] lazy_static! { static ref RE_INTERFACE: Regex = Regex::new(r"^([0-9a-z]{2,16})(\:\d{1,5})?$").unwrap(); } #[cfg(target_os = "windows")] lazy_static! { static ref RE_INTERFACE: Regex = Regex::new( r"^(\{[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}\})(\:\d{1,5})?$" ) .unwrap(); } lazy_static! { static ref RE_IPV6_WITH_PORT: Regex = Regex::new(r"^\[([0-9a-fA-F:]{3,39})\](\:\d{1,5})?$").unwrap(); } pub static DEFAULT_PORT: u16 = WS_PORT; pub static DEFAULT_TLS_PORT: u16 = 443; fn parse_interface_and_port_for( string: &String, for_option: &str, default_port: u16, ) -> Result<(String, u16), ()> { let c = RE_INTERFACE.captures(string); if c.is_some() && c.as_ref().unwrap().get(1).is_some() { let cap = c.unwrap(); let interface = cap.get(1).unwrap().as_str(); let port = match cap.get(2) { None => default_port, Some(p) => { let mut chars = p.as_str().chars(); chars.next(); match from_str::(chars.as_str()) { Err(_) => default_port, Ok(p) => { if p == 0 { default_port } else { p } } } } }; Ok((interface.to_string(), port)) } else { log_err!( "The value submitted for the {} option is invalid. It should be the name of an interface found with --list-interfaces, with an optional port suffix of the form :123. cannot start", for_option ); Err(()) } } fn parse_ipv6_for(string: String, for_option: &str) -> Result { string.parse::().map_err(|_| { log_err!( "The value submitted for the {} option is invalid. cannot start", for_option ) }) } fn parse_ipv4_and_port_for( string: String, for_option: &str, default_port: u16, ) -> Result<(Ipv4Addr, u16), ()> { let parts: Vec<&str> = string.split(":").collect(); let ipv4 = parts[0].parse::().map_err(|_| { log_err!( "The value submitted for the {} option is invalid. cannot start", for_option ) })?; let port; if parts.len() > 1 { port = match from_str::(parts[1]) { Err(_) => default_port, Ok(p) => { if p == 0 { default_port } else { p } } }; } else { port = default_port; } return Ok((ipv4, port)); } fn parse_ip_and_port_for(string: String, for_option: &str) -> Result<(IpAddr, u16), ()> { let c = RE_IPV6_WITH_PORT.captures(&string); let ipv6; let port; if c.is_some() && c.as_ref().unwrap().get(1).is_some() { let cap = c.unwrap(); let ipv6_str = cap.get(1).unwrap().as_str(); port = match cap.get(2) { None => DEFAULT_PORT, Some(p) => { let mut chars = p.as_str().chars(); chars.next(); match from_str::(chars.as_str()) { Err(_) => DEFAULT_PORT, Ok(p) => { if p == 0 { DEFAULT_PORT } else { p } } } } }; let ipv6 = ipv6_str.parse::().map_err(|_| { log_err!( "The <[IPv6]:PORT> value submitted for the {} option is invalid. cannot start", for_option ) })?; return Ok((IpAddr::V6(ipv6), port)); } else { // we try just an IPV6 without port let ipv6_res = string.parse::(); if ipv6_res.is_err() { // let's try IPv4 return parse_ipv4_and_port_for(string, for_option, DEFAULT_PORT) .map(|ipv4| (IpAddr::V4(ipv4.0), ipv4.1)); } else { ipv6 = ipv6_res.unwrap(); port = DEFAULT_PORT; return Ok((IpAddr::V6(ipv6), port)); } } } fn parse_triple_interface_and_port_for( string: &String, for_option: &str, ) -> Result<((String, u16), (Option, (Ipv4Addr, u16))), ()> { let parts: Vec<&str> = string.split(',').collect(); if parts.len() < 2 { log_err!( "The value submitted for the {} option is invalid. It should be composed of at least 2 parts separated by a comma. cannot start", for_option ); return Err(()); } let first_part = parse_interface_and_port_for( &parts[0].to_string(), &format!("private interface+PORT (left) part of the {}", for_option), DEFAULT_PORT, ); if first_part.is_err() { return Err(()); } let mut middle_part = None; if parts.len() == 3 { let middle_part_res = parse_ipv6_for( parts[1].to_string(), &format!("public IPv6 (middle) part of the {}", for_option), ); if middle_part_res.is_err() { return Err(()); } middle_part = middle_part_res.ok(); } let last_part = parse_ipv4_and_port_for( parts[parts.len() - 1].to_string(), &format!("public IPv4+PORT (right) part of the {}", for_option), DEFAULT_PORT, ); if last_part.is_err() { return Err(()); } Ok((first_part.unwrap(), (middle_part, last_part.unwrap()))) } fn parse_domain_and_port( domain_string: &String, option: &str, default_port: u16, ) -> Result<(String, String, u16), ()> { let parts: Vec<&str> = domain_string.split(':').collect(); // check validity of domain name let valid_domain = List.parse_dns_name(parts[0]); match valid_domain { Err(e) => { log_err!( "The domain name provided for option {} is invalid. {}. cannot start", option, e.to_string() ); return Err(()); } Ok(name) => { if !name.has_known_suffix() { log_err!( "The domain name provided for option {} is invalid. Unknown suffix in public list. cannot start", option ); return Err(()); } } } let port = if parts.len() > 1 { match from_str::(parts[1]) { Err(_) => default_port, Ok(p) => { if p == 0 { default_port } else { p } } } } else { default_port }; let mut domain_with_port = parts[0].clone().to_string(); if port != default_port { domain_with_port.push_str(&format!(":{}", port)); } Ok((parts[0].to_string(), domain_with_port, port)) } fn prepare_accept_forward_for_domain(domain: String, args: &Cli) -> Result { if args.domain_peer.is_some() { let key_ser = base64_url::decode(args.domain_peer.as_ref().unwrap()).map_err(|_| ())?; let key = serde_bare::from_slice::(&key_ser); Ok(AcceptForwardForV0::PublicDomainPeer(( domain, key.unwrap(), "".to_string(), ))) } else { Ok(AcceptForwardForV0::PublicDomain((domain, "".to_string()))) } } #[async_std::main] async fn main() -> std::io::Result<()> { main_inner() .await .map_err(|_| ErrorKind::InvalidInput.into()) } async fn main_inner() -> Result<(), ()> { let args = Cli::parse(); if args.list_interfaces { println!("list of network interfaces"); print_interfaces(); return Ok(()); } if std::env::var("RUST_LOG").is_err() { if args.verbose == 0 { std::env::set_var("RUST_LOG", "warn"); } else if args.verbose == 1 { std::env::set_var("RUST_LOG", "info"); } else if args.verbose == 2 { std::env::set_var("RUST_LOG", "debug"); } else if args.verbose >= 3 { std::env::set_var("RUST_LOG", "trace"); } } env_logger::init(); log_info!("Starting NextGraph daemon (ngd)"); log_debug!("base {:?}", args.base); let mut path = PathBuf::from(&args.base); path.push("server"); if !path.is_absolute() { path = std::env::current_dir().unwrap().join(path); } log_debug!("cur {}", std::env::current_dir().unwrap().display()); log_debug!("home {}", path.to_str().unwrap()); std::fs::create_dir_all(path.clone()).unwrap(); // reading key from file, if any let mut key_path = path.clone(); key_path.push("key"); let key_from_file: Option<[u8; 32]>; let res = |key_path| -> Result<[u8; 32], &str> { let file = read_to_string(key_path).map_err(|_| "")?; decode_key( &file .lines() .nth(0) .ok_or("empty file")? .to_string() .trim() .to_string(), ) .map_err(|_| "invalid file") }(&key_path); if res.is_err() && res.unwrap_err().len() > 0 { log_err!( "provided key file is incorrect. {}. cannot start", res.unwrap_err() ); return Err(()); } key_from_file = res.ok(); let keys: [[u8; 32]; 4] = match &args.key { Some(key_string) => { if key_from_file.is_some() { log_err!("provided --key option will not be used as a key file is already present"); gen_broker_keys(Some(key_from_file.unwrap())) } else { let res = decode_key(key_string) .map_err(|_| log_err!("provided key is invalid. cannot start"))?; if args.save_key { let master_key = base64_url::encode(&res); write(key_path.clone(), master_key).map_err(|e| { log_err!("cannot save key to file. {}.cannot start", e.to_string()) })?; log_info!("The key has been saved to {}", key_path.to_str().unwrap()); } gen_broker_keys(Some(res)) } } None => { if key_from_file.is_some() { gen_broker_keys(Some(key_from_file.unwrap())) } else { let res = gen_broker_keys(None); let master_key = base64_url::encode(&res[0]); if args.save_key { write(key_path.clone(), master_key).map_err(|e| { log_err!("cannot save key to file. {}.cannot start", e.to_string()) })?; log_info!("The key has been saved to {}", key_path.to_str().unwrap()); } else { // on purpose we don't log the key, just print it out to stdout, as it should not be saved in logger's files println!("YOUR GENERATED KEY IS: {}", master_key); log_err!("At your request, the key wasn't saved."); log_err!("provide it again to the next start of ngd with --key option or NG_SERVER_KEY env variable"); } res } } }; // DEALING WITH CONFIG // reading config from file, if any let mut config_path = path.clone(); config_path.push("config.json"); let mut config: Option; let res = |config_path| -> Result { let file = read_to_string(config_path).map_err(|_| "".to_string())?; from_str(&file).map_err(|e| e.to_string()) }(&config_path); if res.is_err() && res.as_ref().unwrap_err().len() > 0 { log_err!( "provided config file is incorrect. {}. cannot start", res.unwrap_err() ); return Err(()); } config = res.ok(); if config.is_some() && args.save_config { log_err!("A config file is present. We cannot override it with Quick config options. cannot start"); return Err(()); } if args.local.is_some() || args.forward.is_some() || args.core.is_some() || args.private.is_some() || args.public.is_some() || args.dynamic.is_some() || args.domain.is_some() { // QUICK CONFIG if config.is_some() && !args.print_config { log_err!( "A config file is present. You can use the Quick config options on the command-line. In order to use them, delete your config file first. cannot start" ); return Err(()); } if args.domain_peer.is_some() && args.domain_private.is_none() && args.domain.is_none() { log_err!( "The --domain-peer option can only be set when the --domain or --domain-private option is also present on the command line. cannot start" ); return Err(()); } let mut listeners: Vec = vec![]; let mut overlays_config: BrokerOverlayConfigV0 = BrokerOverlayConfigV0::new(); let interfaces = get_interface(); //// --domain if args.domain.is_some() { let domain_string = args.domain.as_ref().unwrap(); let parts: Vec<&str> = domain_string.split(',').collect(); let local_port; let (_, domain, _) = if parts.len() == 1 { local_port = WS_PORT_REVERSE_PROXY; parse_domain_and_port(domain_string, "--domain", DEFAULT_TLS_PORT)? } else { local_port = match from_str::(parts[1]) { Err(_) => WS_PORT_REVERSE_PROXY, Ok(p) => { if p == 0 { WS_PORT_REVERSE_PROXY } else { p } } }; parse_domain_and_port(&parts[0].to_string(), "--domain", DEFAULT_TLS_PORT)? }; match find_first(&interfaces, InterfaceType::Loopback) { None => { log_err!( "That's pretty unusual, but no loopback interface could be found on your host. --domain option failed for that reason. cannot start" ); return Err(()); } Some(loopback) => { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; let mut listener = ListenerV0::new_direct(loopback, !args.no_ipv6, local_port); listener.accept_direct = false; let res = prepare_accept_forward_for_domain(domain, &args).map_err(|_| { log_err!("The --domain-peer option has an invalid key. it must be a base64_url encoded serialization of a PrivKey. cannot start") })?; listener.accept_forward_for = res; listeners.push(listener); } } } //// --local if args.local.is_some() { match find_first(&interfaces, InterfaceType::Loopback) { None => { log_err!( "That's pretty unusual, but no loopback interface could be found on your host. cannot start" ); return Err(()); } Some(loopback) => { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; if listeners.last().is_some() && listeners.last().unwrap().interface_name == loopback.name && listeners.last().unwrap().port == args.local.unwrap() { let r = listeners.last_mut().unwrap(); r.accept_direct = true; r.ipv6 = !args.no_ipv6; } else { listeners.push(ListenerV0::new_direct( loopback, !args.no_ipv6, args.local.unwrap(), )); } } } } //// --core if args.core.is_some() { let arg_value = parse_interface_and_port_for(args.core.as_ref().unwrap(), "--core", DEFAULT_PORT)?; let if_name = &arg_value.0; match find_first_or_name(&interfaces, InterfaceType::Public, &if_name) { None => { log_err!( "{}", if if_name == "default" { "We could not find a public IP interface on your host. If you are setting up a server behind a reverse proxy, enter the config manually in the config file. cannot start".to_string() } else { format!( "We could not find a public IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host. cannot start", if_name ) } ); return Err(()); } Some(public) => { overlays_config.core = BrokerOverlayPermission::AllRegisteredUser; let mut listener = ListenerV0::new_direct(public, !args.no_ipv6, arg_value.1); if args.core_with_clients { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; } else { listener.refuse_clients = true; } listeners.push(listener); } } } //// --public if args.public.is_some() { let arg_value = parse_triple_interface_and_port_for(args.public.as_ref().unwrap(), "--public")?; let public_part = &arg_value.1; let private_part = &arg_value.0; let private_interface; let if_name = &private_part.0; match find_first_or_name(&interfaces, InterfaceType::Private, &if_name) { None => { log_err!( "{}", if if_name == "default" { "We could not find a private IP interface on your host for --public option. cannot start" .to_string() } else { format!( "We could not find a private IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host. cannot start", if_name ) } ); return Err(()); } Some(inter) => { private_interface = inter; } } if !is_public_ipv4(&public_part.1 .0) || public_part.0.is_some() && !is_public_ipv6(public_part.0.as_ref().unwrap()) { log_err!("The provided IPs are not public. cannot start"); return Err(()); } if args.no_ipv6 && public_part.0.is_some() { log_err!( "The public IP is IPv6 but you selected the --no-ipv6 option. cannot start" ); return Err(()); } overlays_config.core = BrokerOverlayPermission::AllRegisteredUser; if !args.public_without_clients { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; } let ipv6 = public_part.0.map(|ipv6| BindAddress { port: public_part.1 .1, ip: (&IpAddr::V6(ipv6)).into(), }); listeners.push(ListenerV0 { interface_name: private_interface.name, if_type: private_interface.if_type, ipv6: public_part.0.is_some(), interface_refresh: 0, port: private_part.1, discoverable: false, refuse_clients: args.public_without_clients, serve_app: true, accept_direct: false, accept_forward_for: AcceptForwardForV0::PublicStatic(( BindAddress { port: public_part.1 .1, ip: (&IpAddr::V4(public_part.1 .0)).into(), }, ipv6, "".to_string(), )), }); } //// --dynamic if args.dynamic.is_some() { let dynamic_string = args.dynamic.as_ref().unwrap(); let parts: Vec<&str> = dynamic_string.split(',').collect(); let arg_value = parse_interface_and_port_for(&parts[0].to_string(), "--dynamic", DEFAULT_PORT)?; let public_port = if parts.len() == 2 { match from_str::(parts[1]) { Err(_) => DEFAULT_PORT, Ok(p) => { if p == 0 { DEFAULT_PORT } else { p } } } } else { DEFAULT_PORT }; let if_name = &arg_value.0; match find_first_or_name(&interfaces, InterfaceType::Private, if_name) { None => { log_err!( "{}", if if_name == "default" { "We could not find a private IP interface on your host for --dynamic option. cannot start" .to_string() } else { format!( "We could not find a private IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host. cannot start", if_name ) } ); return Err(()); } Some(inter) => { overlays_config.core = BrokerOverlayPermission::AllRegisteredUser; overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; if listeners.last().is_some() && listeners.last().unwrap().interface_name == inter.name && listeners.last().unwrap().port == arg_value.1 { let r = listeners.last_mut().unwrap(); if r.accept_forward_for != AcceptForwardForV0::No { log_err!("The same private interface is already forwarding with a different setting, probably because of a --public option conflicting with a --dynamic option. Changing the port on one of the interfaces can help. cannot start"); return Err(()); } panic!("this should never happen. --dynamic created after a --private"); //r.ipv6 = !args.no_ipv6; //r.accept_forward_for = AcceptForwardForV0::PublicDyn((public_port, 60, "".to_string())); } else { let mut listener = ListenerV0::new_direct(inter, !args.no_ipv6, arg_value.1); listener.accept_direct = false; listener.accept_forward_for = AcceptForwardForV0::PublicDyn((public_port, 60, "".to_string())); listeners.push(listener); } } } } //// --domain-private if args.domain_private.is_some() { let domain_string = args.domain_private.as_ref().unwrap(); let parts: Vec<&str> = domain_string.split(',').collect(); let (_, domain, _) = parse_domain_and_port(&parts[0].to_string(), "--domain-private", DEFAULT_TLS_PORT)?; let bind_string = if parts.len() > 1 { parts[1] } else { "default" }; let arg_value = parse_interface_and_port_for( &bind_string.to_string(), "--domain-private", WS_PORT_REVERSE_PROXY, )?; let if_name = &arg_value.0; match find_first_or_name(&interfaces, InterfaceType::Private, &if_name) { None => { log_err!( "{}", if if_name == "default" { "We could not find a private IP interface on your host for --domain-private option. cannot start" .to_string() } else { format!( "We could not find a private IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host. cannot start", if_name ) } ); return Err(()); } Some(inter) => { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; let res = prepare_accept_forward_for_domain(domain, &args).map_err(|_| { log_err!("The --domain-peer option has an invalid key. it must be a base64_url encoded serialization of a PrivKey. cannot start")})?; if listeners.last().is_some() && listeners.last().unwrap().interface_name == inter.name && listeners.last().unwrap().port == arg_value.1 { let r = listeners.last_mut().unwrap(); if r.accept_forward_for != AcceptForwardForV0::No { log_err!("The same private interface is already forwarding with a different setting, probably because of a --public or --dynamic option conflicting with the --domain-private option. Changing the port on one of the interfaces can help. cannot start"); return Err(()); } panic!( "this should never happen. --domain-private created after a --private" ); //r.ipv6 = !args.no_ipv6; //r.accept_forward_for = res; } else { let mut listener = ListenerV0::new_direct(inter, !args.no_ipv6, arg_value.1); listener.accept_direct = false; listener.accept_forward_for = res; listeners.push(listener); } } } } //// --private if args.private.is_some() { let arg_value = parse_interface_and_port_for( args.private.as_ref().unwrap(), "--private", DEFAULT_PORT, )?; let if_name = &arg_value.0; match find_first_or_name(&interfaces, InterfaceType::Private, &if_name) { None => { log_err!( "{}", if if_name == "default" { "We could not find a private IP interface on your host. cannot start" .to_string() } else { format!( "We could not find a private IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host. cannot start", if_name ) } ); return Err(()); } Some(inter) => { overlays_config.server = BrokerOverlayPermission::AllRegisteredUser; if listeners.last().is_some() && listeners.last().unwrap().interface_name == inter.name && listeners.last().unwrap().port == arg_value.1 { let r = listeners.last_mut().unwrap(); r.accept_direct = true; r.ipv6 = !args.no_ipv6; } else { listeners.push(ListenerV0::new_direct(inter, !args.no_ipv6, arg_value.1)); } } } } //// --forward if args.forward.is_some() { //"[DOMAIN/IP:PORT]@PEERID" let forward_string = args.forward.as_ref().unwrap(); let parts: Vec<&str> = forward_string.split('@').collect(); if parts.len() != 2 { log_err!( "The option --forward is invalid. It must contain two parts separated by a @ character. cannot start" ); return Err(()); } let vec = base64_url::decode(parts[1]) .map_err(|_| log_err!("The PEERID provided in the --forward option is invalid"))?; let pub_key_array = *slice_as_array!(vec.as_slice(), [u8; 32]) .ok_or(()) .map_err(|_| { log_err!("PEERID provided in the --forward option, has invalid array") })?; let peer_id = PubKey::Ed25519PubKey(pub_key_array); let server_type = if parts[0].len() > 0 { let first_char = parts[0].chars().next().unwrap(); if first_char == '[' || first_char.is_numeric() { // an IPv6 or IPv4 let bind = parse_ip_and_port_for(parts[0].to_string(), "--forward")?; let bind_addr = BindAddress { ip: (&bind.0).into(), port: bind.1, }; if is_private_ip(&bind.0) { BrokerServerTypeV0::BoxPrivate(vec![bind_addr]) } else if is_public_ip(&bind.0) { BrokerServerTypeV0::BoxPublic(vec![bind_addr]) } else { log_err!("Invalid IP address given for --forward option. cannot start"); return Err(()); } } else { // a domain name let (_, domain, _) = parse_domain_and_port( &parts[0].to_string(), "--forward", DEFAULT_TLS_PORT, )?; BrokerServerTypeV0::Domain(domain) } } else { BrokerServerTypeV0::BoxPublicDyn(vec![]) }; overlays_config.forward = vec![BrokerServerV0 { server_type, peer_id, }]; } config = Some(DaemonConfig::V0(DaemonConfigV0 { listeners, overlays_configs: vec![overlays_config], })); if args.print_config { let json_string = to_string_pretty(config.as_ref().unwrap()).unwrap(); println!("The Quick config would be:\n{}", json_string); return Ok(()); } if args.save_config { // saves the config to file let json_string = to_string_pretty(config.as_ref().unwrap()).unwrap(); write(config_path.clone(), json_string).map_err(|e| { log_err!( "cannot save config to file. {}. cannot start", e.to_string() ) })?; log_info!( "The config file has been saved to {}", config_path.to_str().unwrap() ); log_info!( "You not be able to use any Quick config options anymore on the command line at the next command-line start of the server. But you can go to modify the config file directly, or delete it.", ); } } else { if config.is_none() { log_err!( "No Quick config option passed, neither is a config file present. We cannot start the server. Choose at least one Quick config option. see --help for details" ); return Err(()); } if args.print_config { let json_string = to_string_pretty(config.as_ref().unwrap()).unwrap(); println!("The saved config is:\n{}", json_string); return Ok(()); } } // let keys = gen_keys(); // let pub_key = PubKey::Ed25519PubKey(keys.1); // let (ed_priv_key, ed_pub_key) = generate_keypair(); // let duals = Dual25519Keys::generate(); // let eds = keypair_from_ed(duals.ed25519_priv, duals.ed25519_pub); // let test_vector: Vec = vec![71, 51, 206, 126, 9, 84, 132]; // let sig = sign(eds.0, eds.1, &test_vector).unwrap(); // verify(&test_vector, sig, eds.1).unwrap(); // let privkey = duals.x25519_priv; // let pubkey = PubKey::Ed25519PubKey(duals.x25519_public); let (privkey, pubkey) = keys_from_bytes(keys[1]); let priv_key_array = *slice_as_array!(privkey.as_slice(), [u8; 32]) .ok_or(()) .map_err(|_| log_err!("Private key of peer has invalid array"))?; let priv_key = PrivKey::Ed25519PrivKey(priv_key_array); let priv_key_ser = serde_bare::to_vec(&priv_key).unwrap(); let prix_key_encoded = base64_url::encode(&priv_key_ser); log_info!("PeerId of node: {}", pubkey); debug_println!("Private key of peer: {}", prix_key_encoded); match config.unwrap() { DaemonConfig::V0(v0) => { run_server_v0( privkey, pubkey, Sensitive::<[u8; 32]>::from_slice(&keys[2]), v0, path, ) .await? } } Ok(()) }