ngd config local core public private dynamic save-config key save-key base

pull/19/head
Niko 1 year ago
parent 684cd58962
commit 83d691d591
  1. 13
      Cargo.lock
  2. 3
      ngd/Cargo.toml
  3. 55
      ngd/src/cli.rs
  4. 507
      ngd/src/main.rs
  5. 4
      ngd/src/types.rs
  6. 61
      p2p-broker/src/types.rs

13
Cargo.lock generated

@ -2757,13 +2757,16 @@ dependencies = [
"clap", "clap",
"default-net", "default-net",
"env_logger", "env_logger",
"lazy_static",
"log", "log",
"p2p-broker", "p2p-broker",
"p2p-net", "p2p-net",
"p2p-repo", "p2p-repo",
"regex",
"serde", "serde",
"serde_bare", "serde_bare",
"serde_bytes", "serde_bytes",
"serde_json",
"slice_as_array", "slice_as_array",
] ]
@ -3618,13 +3621,13 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.8.1" version = "1.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-syntax 0.7.1", "regex-syntax 0.7.2",
] ]
[[package]] [[package]]
@ -3644,9 +3647,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.1" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]] [[package]]
name = "reqwest" name = "reqwest"

@ -21,3 +21,6 @@ env_logger = "0.10"
clap = { version = "4.3.4", features = ["derive","env"] } clap = { version = "4.3.4", features = ["derive","env"] }
base64-url = "2.0.0" base64-url = "2.0.0"
slice_as_array = "1.1.0" slice_as_array = "1.1.0"
serde_json = "1.0"
regex = "1.8.4"
lazy_static = "1.4.0"

@ -9,6 +9,8 @@
use clap::Parser; use clap::Parser;
use p2p_net::WS_PORT;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
pub(crate) struct Cli { pub(crate) struct Cli {
@ -21,7 +23,7 @@ pub(crate) struct Cli {
pub verbose: u8, pub verbose: u8,
/// Base path for server home folder containing all persistent files /// Base path for server home folder containing all persistent files
#[arg(short, long, default_value = ".ng")] #[arg(short, long, default_value = ".ng", value_name("PATH"))]
pub base: String, pub base: String,
/// Master key of the server. Should be a base64-url encoded serde serialization of a [u8; 32]. if not provided, a new key will be generated for you /// Master key of the server. Should be a base64-url encoded serde serialization of a [u8; 32]. if not provided, a new key will be generated for you
@ -31,4 +33,55 @@ pub(crate) struct Cli {
/// Saves to disk the provided or automatically generated key. Only used if file storage is secure. Alternatives are passing the key at every start with --key or NG_SERVER_KEY env var. /// Saves to disk the provided or automatically generated key. Only used if file storage is secure. Alternatives are passing the key at every start with --key or NG_SERVER_KEY env var.
#[arg(long)] #[arg(long)]
pub save_key: bool, pub save_key: bool,
/// Quick config to listen for clients on localhost port PORT. Defaults to port 80
#[arg(short, long, value_name("PORT"), default_missing_value("80"), num_args(0..=1))]
pub local: Option<u16>,
/// Quick config to listen for core brokers on public INTERFACE (and optional :PORT). Defaults to first public interface on the host, port 80
#[arg(short, long, value_name("INTERFACE:PORT"), default_missing_value("default"), num_args(0..=1))]
pub core: Option<String>,
/// Quick config to forward all requests to another BROKER. format is "DOMAIN/IP[:PORT]@PEERID"
#[arg(
short,
long,
value_name("BROKER"),
conflicts_with("core"),
conflicts_with("public"),
conflicts_with("dynamic")
)]
pub forward: Option<String>,
/// Quick config to listen for clients on private INTERFACE (and optional :PORT). Defaults to first private interface on the host, port 80
#[arg(short, long, value_name("INTERFACE:PORT"), default_missing_value("default"), num_args(0..=1))]
pub private: Option<String>,
/// Quick config to listen for clients and core brokers on PRIVATE_INTERFACE, behind a DMZ or port forwarding of a public static IP. PORTs defaults to 80
#[arg(
short('g'),
long,
value_name("PRIVATE_INTERFACE:PORT,[PUBLIC_IPV6,]PUBLIC_IPV4:PORT")
)]
pub public: Option<String>,
/// Quick config to listen for clients and core brokers on PRIVATE_INTERFACE, behind a DMZ or port forwarding of a public dynamic IP. PORTs defaults to 80
#[arg(short('n'), long, value_name("PRIVATE_INTERFACE:PORT,PORT"), default_missing_value("default"), num_args(0..=1))]
pub dynamic: Option<String>,
/// Quick config to listen for clients on localhost port PORT, behind a reverse proxy that sends X-Forwarded-For for a TLS terminated DOMAIN name
#[arg(short, long, value_name("DOMAIN:PORT"))]
pub domain: Option<String>,
/// Option for --domain if this host is part of a pool of load-balanced servers behind a reverse proxy, and the same PeerId should be shared among them all
#[arg(short('e'), long, value_name("PEER_KEY"))]
pub domain_peer: Option<String>,
/// Option for quick config: does not listen on any IPv6 interfaces
#[arg(long)]
pub no_ipv6: bool,
/// Saves the quick config into a file on disk, that can then be modified for advanced configs
#[arg(long)]
pub save_config: bool,
} }

@ -14,9 +14,12 @@ pub mod types;
mod cli; mod cli;
use crate::cli::*; use crate::cli::*;
use crate::types::*;
use clap::Parser; use clap::Parser;
use p2p_broker::server_ws::run_server; use p2p_broker::server_ws::run_server;
use p2p_broker::types::*;
use p2p_broker::utils::*; use p2p_broker::utils::*;
use p2p_net::types::*;
use p2p_net::utils::{gen_keys, keys_from_bytes, Dual25519Keys, Sensitive, U8Array}; use p2p_net::utils::{gen_keys, keys_from_bytes, Dual25519Keys, Sensitive, U8Array};
use p2p_net::WS_PORT; use p2p_net::WS_PORT;
use p2p_repo::log::*; use p2p_repo::log::*;
@ -24,10 +27,12 @@ use p2p_repo::{
types::{PrivKey, PubKey}, types::{PrivKey, PubKey},
utils::{generate_keypair, keypair_from_ed, sign, verify}, utils::{generate_keypair, keypair_from_ed, sign, verify},
}; };
use serde_json::{from_str, json, to_string_pretty};
use std::fs::{read_to_string, write}; use std::fs::{read_to_string, write};
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::io::{BufReader, ErrorKind}; use std::io::{BufReader, ErrorKind};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -46,6 +51,7 @@ pub fn print_ipv6(ip: &default_net::ip::Ipv6Net) -> String {
format!("{}/{}", ip.addr, ip.prefix_len) format!("{}/{}", ip.addr, ip.prefix_len)
} }
#[derive(Clone, Debug)]
pub struct Interface { pub struct Interface {
pub if_type: InterfaceType, pub if_type: InterfaceType,
pub name: String, pub name: String,
@ -56,6 +62,28 @@ pub struct Interface {
pub ipv6: Vec<default_net::ip::Ipv6Net>, pub ipv6: Vec<default_net::ip::Ipv6Net>,
} }
fn find_first(list: &Vec<Interface>, iftype: InterfaceType) -> Option<Interface> {
for inf in list {
if inf.if_type == iftype {
return Some(inf.clone());
}
}
None
}
fn find_first_or_name(
list: &Vec<Interface>,
iftype: InterfaceType,
name: &String,
) -> Option<Interface> {
for inf in list {
if (name == "default" || *name == inf.name) && inf.if_type == iftype {
return Some(inf.clone());
}
}
None
}
pub fn get_interface() -> Vec<Interface> { pub fn get_interface() -> Vec<Interface> {
let mut res: Vec<Interface> = vec![]; let mut res: Vec<Interface> = vec![];
let interfaces = default_net::get_interfaces(); let interfaces = default_net::get_interfaces();
@ -127,6 +155,172 @@ fn decode_key(key_string: String) -> Result<[u8; 32], ()> {
.map_err(|_| log_err!("key has invalid content array"))?) .map_err(|_| log_err!("key has invalid content array"))?)
} }
use lazy_static::lazy_static;
use regex::Regex;
//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 = 80;
fn parse_interface_and_port_for(string: String, for_option: &str) -> 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::<u16>(chars.as_str()) {
Err(_) => DEFAULT_PORT,
Ok(p) => p,
}
}
};
Ok((interface.to_string(), port))
} else {
log_err!(
"The <INTERFACE:PORT> 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. Stopping here",
for_option
);
Err(())
}
}
fn parse_ipv6_for(string: String, for_option: &str) -> Result<Ipv6Addr, ()> {
string.parse::<Ipv6Addr>().map_err(|_| ())
}
fn parse_ipv4_and_port_for(string: String, for_option: &str) -> Result<(Ipv4Addr, u16), ()> {
let parts: Vec<&str> = string.split(":").collect();
let ipv4_res = parts[0].parse::<Ipv4Addr>();
if ipv4_res.is_err() {
log_err!(
"The <IPv4:PORT> value submitted for the {} option is invalid. Stopping here",
for_option
);
return Err(());
}
let port;
let ipv4 = ipv4_res.unwrap();
if parts.len() > 1 {
port = match from_str::<u16>(parts[1]) {
Err(_) => DEFAULT_PORT,
Ok(p) => 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::<u16>(chars.as_str()) {
Err(_) => DEFAULT_PORT,
Ok(p) => p,
}
}
};
let ipv6_res = ipv6_str.parse::<Ipv6Addr>();
if ipv6_res.is_err() {
log_err!(
"The <[IPv6]:PORT> value submitted for the {} option is invalid. Stopping here",
for_option
);
return Err(());
}
ipv6 = ipv6_res.unwrap();
return Ok((IpAddr::V6(ipv6), port));
} else {
// we try just an IPV6 without port
let ipv6_res = string.parse::<Ipv6Addr>();
if ipv6_res.is_err() {
// let's try IPv4
return parse_ipv4_and_port_for(string, for_option)
.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<Ipv6Addr>, (Ipv4Addr, u16))), ()> {
let parts: Vec<&str> = string.split(',').collect();
if parts.len() < 2 {
log_err!(
"The <PRIVATE_INTERFACE:PORT,[PUBLIC_IPV6,]PUBLIC_IPV4:PORT> value submitted for the {} option is invalid. It should be composed of at least 2 parts separated by a comma. Stopping here",
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),
);
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),
);
if last_part.is_err() {
return Err(());
}
Ok((first_part.unwrap(), (middle_part, last_part.unwrap())))
}
#[async_std::main] #[async_std::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
let args = Cli::parse(); let args = Cli::parse();
@ -188,10 +382,7 @@ async fn main() -> std::io::Result<()> {
); );
return Err(ErrorKind::InvalidInput.into()); return Err(ErrorKind::InvalidInput.into());
} }
key_from_file = match res { key_from_file = res.ok();
Err(_) => None,
Ok(k) => Some(k),
};
let keys: [[u8; 32]; 4] = match args.key { let keys: [[u8; 32]; 4] = match args.key {
Some(key_string) => { Some(key_string) => {
@ -228,7 +419,7 @@ async fn main() -> std::io::Result<()> {
} }
log_info!("The key has been saved to {}", key_path.to_str().unwrap()); log_info!("The key has been saved to {}", key_path.to_str().unwrap());
} else { } else {
// on purpose we don't log the key, just print it out stdout, as it should be saved in logger's files // 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); println!("YOUR GENERATED KEY IS: {}", master_key);
log_err!("At your request, the key wasn't saved."); 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"); log_err!("provide it again to the next start of ngd with --key option or NG_SERVER_KEY env variable");
@ -240,6 +431,312 @@ async fn main() -> std::io::Result<()> {
println!("{:?}", keys); println!("{:?}", keys);
// DEALING WITH CONFIG
// reading config from file, if any
let mut config_path = path.clone();
config_path.push("config.json");
let mut config: Option<DaemonConfig>;
let res = |config_path| -> Result<DaemonConfig, String> {
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. {}. aborting start",
res.unwrap_err()
);
return Err(ErrorKind::InvalidInput.into());
}
config = res.ok();
println!("CONFIG {:?}", config);
if config.is_some() && args.save_config {
log_err!("A config file is present. We cannot override it with Quick config options.");
return Err(ErrorKind::InvalidInput.into());
}
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() {
log_err!(
"A config file is present. You can use the Quick config options of the command-line. In order to use them, delete your config file first."
);
return Err(ErrorKind::InvalidInput.into());
}
if args.domain_peer.is_some() && args.domain.is_none() {
log_err!(
"The --domain-peer option can only be set when the --domain option is also present on the command line"
);
return Err(ErrorKind::InvalidInput.into());
}
let mut listeners: Vec<ListenerV0> = vec![];
let mut overlays_config: BrokerOverlayConfigV0 = BrokerOverlayConfigV0::new();
let interfaces = get_interface();
//// --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"
);
return Err(ErrorKind::InvalidInput.into());
}
Some(loopback) => {
overlays_config.server = BrokerOverlayPermission::AllRegisteredUser;
listeners.push(ListenerV0::new_direct(
loopback.name,
!args.no_ipv6,
args.local.unwrap(),
));
}
}
}
//// --core
if args.core.is_some() {
let arg_value = parse_interface_and_port_for(args.core.unwrap(), "--core");
if arg_value.is_err() {
return Err(ErrorKind::InvalidInput.into());
}
let if_name = &arg_value.as_ref().unwrap().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".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",
if_name
)
}
);
return Err(ErrorKind::InvalidInput.into());
}
Some(public) => {
overlays_config.core = BrokerOverlayPermission::AllRegisteredUser;
overlays_config.server = BrokerOverlayPermission::AllRegisteredUser;
listeners.push(ListenerV0::new_direct(
public.name,
!args.no_ipv6,
arg_value.unwrap().1,
));
}
}
}
//// --public
if args.public.is_some() {
let arg_value = parse_triple_interface_and_port_for(args.public.unwrap(), "--public");
if arg_value.is_err() {
return Err(ErrorKind::InvalidInput.into());
}
let public_part = &arg_value.as_ref().unwrap().1;
let private_part = &arg_value.as_ref().unwrap().0;
let private_interface;
let if_name = &private_part.0;
match find_first_or_name(&interfaces, InterfaceType::Private, &if_name) {
None => {
log_err!( "We could not find a private IP interface named {} on your host. use --list-interfaces to find the available interfaces on your host",
if_name
);
return Err(ErrorKind::InvalidInput.into());
}
Some(inter) => {
private_interface = inter;
}
}
if args.no_ipv6 && public_part.0.is_some() {
log_err!("The public IP is IPv6 but you selected the --no-ipv6 option");
return Err(ErrorKind::InvalidInput.into());
}
overlays_config.core = BrokerOverlayPermission::AllRegisteredUser;
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,
ipv6: public_part.0.is_some(),
interface_refresh: 0,
port: private_part.1,
discoverable: false,
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(),
)),
});
}
//// --private
if args.private.is_some() {
let arg_value = parse_interface_and_port_for(args.private.unwrap(), "--private");
if arg_value.is_err() {
return Err(ErrorKind::InvalidInput.into());
}
let if_name = &arg_value.as_ref().unwrap().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.".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",
if_name
)
}
);
return Err(ErrorKind::InvalidInput.into());
}
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.as_ref().unwrap().1
{
let r = listeners.last_mut().unwrap();
r.accept_direct = true;
r.ipv6 = !args.no_ipv6;
} else {
listeners.push(ListenerV0::new_direct(
inter.name,
!args.no_ipv6,
arg_value.unwrap().1,
));
}
}
}
}
//// --dynamic
if args.dynamic.is_some() {
let dynamic_string = args.dynamic.unwrap();
let parts: Vec<&str> = dynamic_string.split(',').collect();
let arg_value = parse_interface_and_port_for(parts[0].to_string(), "--dynamic");
if arg_value.is_err() {
return Err(ErrorKind::InvalidInput.into());
}
let public_port = if parts.len() == 2 {
match from_str::<u16>(parts[1]) {
Err(_) => DEFAULT_PORT,
Ok(p) => p,
}
} else {
DEFAULT_PORT
};
let if_name = &arg_value.as_ref().unwrap().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.".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",
if_name
)
}
);
return Err(ErrorKind::InvalidInput.into());
}
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.as_ref().unwrap().1
{
let r = listeners.last_mut().unwrap();
r.ipv6 = !args.no_ipv6;
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. Aborting");
return Err(ErrorKind::InvalidInput.into());
}
r.accept_forward_for =
AcceptForwardForV0::PublicDyn((public_port, 60, "".to_string()));
} else {
let mut listener =
ListenerV0::new_direct(inter.name, !args.no_ipv6, arg_value.unwrap().1);
listener.accept_direct = false;
listener.accept_forward_for =
AcceptForwardForV0::PublicDyn((public_port, 60, "".to_string()));
listeners.push(listener);
}
}
}
}
config = Some(DaemonConfig::V0(DaemonConfigV0 {
listeners,
overlays_config,
}));
if args.save_config {
// saves the config to file
let json_string = to_string_pretty(config.as_ref().unwrap()).unwrap();
if let Err(e) = write(config_path.clone(), json_string) {
log_err!("cannot save config to file. aborting start");
return Err(e);
}
log_info!(
"The config file has been saved to {}",
config_path.to_str().unwrap()
);
log_info!(
"You cannot use Quick config options anymore on the command line in your next 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(ErrorKind::InvalidInput.into());
}
}
// let keys = gen_keys(); // let keys = gen_keys();
// let pub_key = PubKey::Ed25519PubKey(keys.1); // let pub_key = PubKey::Ed25519PubKey(keys.1);
// let (ed_priv_key, ed_pub_key) = generate_keypair(); // let (ed_priv_key, ed_pub_key) = generate_keypair();

@ -6,7 +6,7 @@
// at your option. All files in the project carrying such // at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except // notice may not be copied, modified, or distributed except
// according to those terms. // according to those terms.
use p2p_broker::types::BrokerOverlayConfig; use p2p_broker::types::BrokerOverlayConfigV0;
use p2p_broker::types::ListenerV0; use p2p_broker::types::ListenerV0;
use p2p_repo::types::PrivKey; use p2p_repo::types::PrivKey;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -17,7 +17,7 @@ pub struct DaemonConfigV0 {
/// List of listeners for TCP (HTTP) incoming connections /// List of listeners for TCP (HTTP) incoming connections
pub listeners: Vec<ListenerV0>, pub listeners: Vec<ListenerV0>,
pub overlays_config: BrokerOverlayConfig, pub overlays_config: BrokerOverlayConfigV0,
} }
/// Daemon config /// Daemon config

@ -18,18 +18,28 @@ use serde::{Deserialize, Serialize};
pub enum AcceptForwardForV0 { pub enum AcceptForwardForV0 {
/// X-Forwarded-For not allowed /// X-Forwarded-For not allowed
No, No,
/// X-Forwarded-For accepted only for clients with private LAN addresses. First param is the bind address of the proxy server
Private((BindAddress, String)), /// X-Forwarded-For accepted only for clients with private LAN addresses. First param is the domain of the proxy server
Private((String, String)),
/// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server /// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
/// domain can take an option port with a trailing `:port` /// domain can take an option port (trailing `:port`)
PublicDomain((String, String)), PublicDomain((String, String)),
/// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server /// X-Forwarded-For accepted only for clients with public addresses. First param is the domain of the proxy server
/// domain can take an option port with a trailing `:port` /// domain can take an option port (trailing `:port`)
/// second param is the privKey of the PeerId of the proxy server, useful when the proxy server is load balancing to several daemons /// second param is the privKey of the PeerId of the proxy server, useful when the proxy server is load balancing to several daemons
/// that should all use the same PeerId to answer requests /// that should all use the same PeerId to answer requests
PublicDomainPeer((String, PrivKey, String)), PublicDomainPeer((String, PrivKey, String)),
PublicDyn((u16, u32, String)), // first param is the port, second param in tuple is the interval for periodic probe of the external IP
PublicStatic((BindAddress, String)), /// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
/// first param is the port, second param in tuple is the interval for periodic probe of the external IP
PublicDyn((u16, u32, String)),
/// accepts only clients with public addresses that arrive on a LAN address binding. This is used for DMZ and port forwarding configs
/// First param is the IPv4 bind address of the reverse NAT server (DMZ, port forwarding)
/// Second param is ab optional IPv6 bind address of the reverse NAT server (DMZ, port forwarding)
PublicStatic((BindAddress, Option<BindAddress>, String)),
} }
/// DaemonConfig Listener Version 0 /// DaemonConfig Listener Version 0
@ -37,10 +47,12 @@ pub enum AcceptForwardForV0 {
pub struct ListenerV0 { pub struct ListenerV0 {
/// local interface name to bind to /// local interface name to bind to
/// names of interfaces can be retrieved with the --list-interfaces option /// names of interfaces can be retrieved with the --list-interfaces option
/// the string can take an optional trailing option of the form `:3600` for number of seconds
/// for an interval periodic refresh of the actual IP(s) of the interface. Used for dynamic IP interfaces.
pub interface_name: String, pub interface_name: String,
/// optional number of seconds for an interval of periodic refresh
/// of the actual IP(s) of the interface. Used for dynamic IP interfaces (DHCP)
pub interface_refresh: u32,
// if to bind to the ipv6 address of the interface // if to bind to the ipv6 address of the interface
pub ipv6: bool, pub ipv6: bool,
@ -63,6 +75,20 @@ pub struct ListenerV0 {
// an interface with no accept_forward_for and no accept_direct, is de facto, disabled // an interface with no accept_forward_for and no accept_direct, is de facto, disabled
} }
impl ListenerV0 {
pub fn new_direct(name: String, ipv6: bool, port: u16) -> Self {
Self {
interface_name: name,
interface_refresh: 0,
ipv6,
port,
discoverable: false,
accept_direct: true,
accept_forward_for: AcceptForwardForV0::No,
}
}
}
/// Broker Overlay Permission /// Broker Overlay Permission
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub enum BrokerOverlayPermission { pub enum BrokerOverlayPermission {
@ -74,10 +100,10 @@ pub enum BrokerOverlayPermission {
/// Broker Overlay Config /// Broker Overlay Config
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct BrokerOverlayConfig { pub struct BrokerOverlayConfigV0 {
// list of overlays this config applies to. empty array means applying to all // list of overlays this config applies to. empty array means applying to all
pub overlays: Vec<OverlayId>, pub overlays: Vec<OverlayId>,
// Who can ask to join an overlay on the core protocol // Who can ask to join an overlay on the core
pub core: BrokerOverlayPermission, pub core: BrokerOverlayPermission,
// Who can connect as a client to this server // Who can connect as a client to this server
pub server: BrokerOverlayPermission, pub server: BrokerOverlayPermission,
@ -87,6 +113,19 @@ pub struct BrokerOverlayConfig {
pub allow_read: bool, pub allow_read: bool,
/// an empty list means to forward to the peer known for each overlay. /// an empty list means to forward to the peer known for each overlay.
/// forward becomes the default when core is disabled /// forward and core are mutually exclusive. forward becomes the default when core is disabled (set to Nobody).
/// core always takes precedence.
pub forward: Vec<BrokerServerV0>, pub forward: Vec<BrokerServerV0>,
} }
impl BrokerOverlayConfigV0 {
pub fn new() -> Self {
BrokerOverlayConfigV0 {
overlays: vec![],
core: BrokerOverlayPermission::Nobody,
server: BrokerOverlayPermission::Nobody,
allow_read: false,
forward: vec![],
}
}
}

Loading…
Cancel
Save