refactor ngclie and ngd error handling, and refactor server_broker and its storage

master
Niko PLP 2 weeks ago
parent dcc9bbcf52
commit a4d96aa92c
  1. 13
      ng-broker/src/broker_storage/mod.rs
  2. 10
      ng-broker/src/lib.rs
  3. 44
      ng-broker/src/rocksdb_server_storage.rs
  4. 171
      ng-broker/src/server_broker.rs
  5. 12
      ng-broker/src/server_storage/admin/account.rs
  6. 12
      ng-broker/src/server_storage/admin/invitation.rs
  7. 5
      ng-broker/src/server_storage/admin/mod.rs
  8. 0
      ng-broker/src/server_storage/admin/wallet.rs
  9. 0
      ng-broker/src/server_storage/config.rs
  10. 5
      ng-broker/src/server_storage/core/mod.rs
  11. 0
      ng-broker/src/server_storage/core/overlay.rs
  12. 0
      ng-broker/src/server_storage/core/peer.rs
  13. 0
      ng-broker/src/server_storage/core/topic.rs
  14. 5
      ng-broker/src/server_storage/mod.rs
  15. 50
      ng-broker/src/server_ws.rs
  16. 2
      ng-net/src/actors/add_invitation.rs
  17. 2
      ng-net/src/actors/add_user.rs
  18. 2
      ng-net/src/actors/client/commit_get.rs
  19. 2
      ng-net/src/actors/client/pin_repo.rs
  20. 2
      ng-net/src/actors/client/repo_pin_status.rs
  21. 2
      ng-net/src/actors/client/topic_sub.rs
  22. 2
      ng-net/src/actors/del_user.rs
  23. 2
      ng-net/src/actors/list_invitations.rs
  24. 2
      ng-net/src/actors/list_users.rs
  25. 28
      ng-net/src/broker.rs
  26. 2
      ng-net/src/lib.rs
  27. 4
      ng-net/src/server_broker.rs
  28. 46
      ng-repo/src/errors.rs
  29. 4
      ng-repo/src/types.rs
  30. 8
      ng-repo/src/utils.rs
  31. 3
      ng-storage-rocksdb/src/block_storage.rs
  32. 2
      ng-storage-rocksdb/src/kcv_storage.rs
  33. 6
      ng-verifier/src/rocksdb_user_storage.rs
  34. 2
      ng-verifier/src/types.rs
  35. 99
      ng-verifier/src/user_storage/storage.rs
  36. 4
      ng-verifier/src/verifier.rs
  37. 264
      ngcli/src/main.rs
  38. 483
      ngd/src/main.rs

@ -1,13 +0,0 @@
pub mod account;
pub mod config;
pub mod overlay;
pub mod peer;
pub mod topic;
pub mod invitation;
pub mod wallet;

@ -1,11 +1,13 @@
pub mod broker_storage;
pub mod server_ws;
pub mod types;
pub mod utils;
pub mod interfaces;
pub mod server_broker;
pub mod server_storage;
pub mod rocksdb_server_storage;
pub mod server_ws;

@ -15,11 +15,11 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use crate::broker_storage::account::Account;
use crate::broker_storage::invitation::Invitation;
use crate::broker_storage::wallet::Wallet;
use crate::server_storage::admin::account::Account;
use crate::server_storage::admin::invitation::Invitation;
use crate::server_storage::admin::wallet::Wallet;
use crate::types::*;
use ng_net::server_storage::*;
use ng_net::server_broker::*;
use ng_net::types::*;
use ng_repo::errors::{ProtocolError, ServerError, StorageError};
use ng_repo::kcv_storage::KCVStorage;
@ -28,7 +28,7 @@ use ng_repo::types::*;
use ng_storage_rocksdb::block_storage::RocksDbBlockStorage;
use ng_storage_rocksdb::kcv_storage::RocksDbKCVStorage;
pub struct RocksDbServerStorage {
pub(crate) struct RocksDbServerStorage {
wallet_storage: RocksDbKCVStorage,
accounts_storage: RocksDbKCVStorage,
//peers_storage: RocksDbKCVStorage,
@ -39,7 +39,7 @@ pub struct RocksDbServerStorage {
}
impl RocksDbServerStorage {
pub fn open(
pub(crate) fn open(
path: &mut PathBuf,
master_key: SymKey,
admin_invite: Option<BootstrapContentV0>,
@ -132,10 +132,8 @@ impl RocksDbServerStorage {
core_storage,
})
}
}
impl ServerStorage for RocksDbServerStorage {
fn next_seq_for_peer(&self, peer: &PeerId, seq: u64) -> Result<(), ServerError> {
pub(crate) fn next_seq_for_peer(&self, peer: &PeerId, seq: u64) -> Result<(), ServerError> {
// for now we don't use the hashmap.
// TODO: let's see if the lock is even needed
let _ = self.peers_last_seq.lock();
@ -165,26 +163,26 @@ impl ServerStorage for RocksDbServerStorage {
Ok(())
}
fn get_user(&self, user_id: PubKey) -> Result<bool, ProtocolError> {
pub(crate) fn get_user(&self, user_id: PubKey) -> Result<bool, ProtocolError> {
log_debug!("get_user {user_id}");
Ok(Account::open(&user_id, &self.accounts_storage)?.is_admin()?)
}
fn add_user(&self, user_id: PubKey, is_admin: bool) -> Result<(), ProtocolError> {
pub(crate) fn add_user(&self, user_id: PubKey, is_admin: bool) -> Result<(), ProtocolError> {
log_debug!("add_user {user_id} is admin {is_admin}");
Account::create(&user_id, is_admin, &self.accounts_storage)?;
Ok(())
}
fn del_user(&self, user_id: PubKey) -> Result<(), ProtocolError> {
pub(crate) fn del_user(&self, user_id: PubKey) -> Result<(), ProtocolError> {
log_debug!("del_user {user_id}");
let acc = Account::open(&user_id, &self.accounts_storage)?;
acc.del()?;
Ok(())
}
fn list_users(&self, admins: bool) -> Result<Vec<PubKey>, ProtocolError> {
pub(crate) fn list_users(&self, admins: bool) -> Result<Vec<PubKey>, ProtocolError> {
log_debug!("list_users that are admin == {admins}");
Ok(Account::get_all_users(admins, &self.accounts_storage)?)
}
fn list_invitations(
pub(crate) fn list_invitations(
&self,
admin: bool,
unique: bool,
@ -198,7 +196,7 @@ impl ServerStorage for RocksDbServerStorage {
multi,
)?)
}
fn add_invitation(
pub(crate) fn add_invitation(
&self,
invite_code: &InvitationCode,
expiry: u32,
@ -208,18 +206,18 @@ impl ServerStorage for RocksDbServerStorage {
Invitation::create(invite_code, expiry, memo, &self.accounts_storage)?;
Ok(())
}
fn get_invitation_type(&self, invite_code: [u8; 32]) -> Result<u8, ProtocolError> {
pub(crate) fn get_invitation_type(&self, invite_code: [u8; 32]) -> Result<u8, ProtocolError> {
log_debug!("get_invitation_type {:?}", invite_code);
let inv = Invitation::open(&invite_code, &self.accounts_storage)?;
inv.get_type()
}
fn remove_invitation(&self, invite_code: [u8; 32]) -> Result<(), ProtocolError> {
pub(crate) fn remove_invitation(&self, invite_code: [u8; 32]) -> Result<(), ProtocolError> {
log_debug!("remove_invitation {:?}", invite_code);
let inv = Invitation::open(&invite_code, &self.accounts_storage)?;
inv.del()?;
Ok(())
}
fn get_repo_pin_status(
pub(crate) fn get_repo_pin_status(
&self,
overlay: &OverlayId,
repo: &RepoHash,
@ -237,7 +235,7 @@ impl ServerStorage for RocksDbServerStorage {
// }))
}
fn pin_repo(
pub(crate) fn pin_repo(
&self,
overlay: &OverlayId,
repo: &RepoHash,
@ -255,7 +253,7 @@ impl ServerStorage for RocksDbServerStorage {
Ok(opened)
}
fn topic_sub(
pub(crate) fn topic_sub(
&self,
overlay: &OverlayId,
repo: &RepoHash,
@ -270,7 +268,11 @@ impl ServerStorage for RocksDbServerStorage {
}))
}
fn get_commit(&self, overlay: &OverlayId, id: &ObjectId) -> Result<Vec<Block>, ServerError> {
pub(crate) fn get_commit(
&self,
overlay: &OverlayId,
id: &ObjectId,
) -> Result<Vec<Block>, ServerError> {
//TODO: implement correctly !
Ok(vec![Block::dummy()])
}

@ -0,0 +1,171 @@
/*
* Copyright (c) 2022-2024 Niko Bonnieure, Par le Peuple, NextGraph.org developers
* All rights reserved.
* Licensed under the Apache License, Version 2.0
* <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
* or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
* at your option. All files in the project carrying such
* notice may not be copied, modified, or distributed except
* according to those terms.
*/
//! Implementation of the Server Broker
use std::collections::{HashMap, HashSet};
use ng_net::{server_broker::IServerBroker, types::*};
use ng_repo::{
errors::{NgError, ProtocolError, ServerError},
types::*,
};
use crate::rocksdb_server_storage::RocksDbServerStorage;
struct TopicInfo {
/// can be None if the Broker is not currently serving this topic for its clients.
repo: Option<RepoHash>,
publisher_advert: Option<PublisherAdvert>,
current_heads: Vec<ObjectId>,
expose_outer: bool,
/// indicates which users have subscribed to topic (boolean says if as publisher or not)
users: HashMap<UserId, bool>,
}
struct RepoInfo {
/// set of users that requested the repo to be exposed on the outer overlay
/// only possible if the user is a publisher
expose_outer: HashSet<UserId>,
/// set of topics of this repo
topics: HashSet<TopicId>,
}
struct OverlayInfo {
inner: Option<OverlayId>,
topics: HashMap<TopicId, TopicInfo>,
repos: HashMap<RepoHash, RepoInfo>,
}
pub struct ServerBroker {
storage: RocksDbServerStorage,
overlays: HashMap<OverlayId, OverlayInfo>,
inner_overlays: HashMap<OverlayId, Option<OverlayId>>,
}
impl ServerBroker {
pub fn new(storage: RocksDbServerStorage) -> Self {
ServerBroker {
storage: storage,
overlays: HashMap::new(),
inner_overlays: HashMap::new(),
}
}
pub fn load(&mut self) -> Result<(), NgError> {
Ok(())
}
}
impl IServerBroker for ServerBroker {
fn next_seq_for_peer(&self, peer: &PeerId, seq: u64) -> Result<(), ServerError> {
self.storage.next_seq_for_peer(peer, seq)
}
fn get_user(&self, user_id: PubKey) -> Result<bool, ProtocolError> {
self.storage.get_user(user_id)
}
fn add_user(&self, user_id: PubKey, is_admin: bool) -> Result<(), ProtocolError> {
self.storage.add_user(user_id, is_admin)
}
fn del_user(&self, user_id: PubKey) -> Result<(), ProtocolError> {
self.storage.del_user(user_id)
}
fn list_users(&self, admins: bool) -> Result<Vec<PubKey>, ProtocolError> {
self.storage.list_users(admins)
}
fn list_invitations(
&self,
admin: bool,
unique: bool,
multi: bool,
) -> Result<Vec<(InvitationCode, u32, Option<String>)>, ProtocolError> {
self.storage.list_invitations(admin, unique, multi)
}
fn add_invitation(
&self,
invite_code: &InvitationCode,
expiry: u32,
memo: &Option<String>,
) -> Result<(), ProtocolError> {
self.storage.add_invitation(invite_code, expiry, memo)
}
fn get_invitation_type(&self, invite_code: [u8; 32]) -> Result<u8, ProtocolError> {
self.storage.get_invitation_type(invite_code)
}
fn remove_invitation(&self, invite_code: [u8; 32]) -> Result<(), ProtocolError> {
self.storage.remove_invitation(invite_code)
}
fn get_repo_pin_status(
&self,
overlay: &OverlayId,
repo: &RepoHash,
) -> Result<RepoPinStatus, ServerError> {
Err(ServerError::False)
//TODO: implement correctly !
// Ok(RepoPinStatus::V0(RepoPinStatusV0 {
// hash: repo.clone(),
// // only possible for RW overlays
// expose_outer: false,
// // list of topics that are subscribed to
// topics: vec![],
// }))
}
fn pin_repo(
&self,
overlay: &OverlayId,
repo: &RepoHash,
ro_topics: &Vec<TopicId>,
rw_topics: &Vec<PublisherAdvert>,
) -> Result<RepoOpened, ServerError> {
//TODO: implement correctly !
let mut opened = Vec::with_capacity(ro_topics.len() + rw_topics.len());
for topic in ro_topics {
opened.push((*topic).into());
}
for topic in rw_topics {
opened.push((*topic).into());
}
Ok(opened)
}
fn topic_sub(
&self,
overlay: &OverlayId,
repo: &RepoHash,
topic: &TopicId,
publisher: Option<&PublisherAdvert>,
) -> Result<TopicSubRes, ServerError> {
//TODO: implement correctly !
Ok(TopicSubRes::V0(TopicSubResV0 {
topic: topic.clone(),
known_heads: vec![],
publisher: publisher.is_some(),
}))
}
fn get_commit(&self, overlay: &OverlayId, id: &ObjectId) -> Result<Vec<Block>, ServerError> {
//TODO: implement correctly !
Ok(vec![Block::dummy()])
}
}

@ -28,13 +28,13 @@ pub struct Account<'a> {
}
impl<'a> Account<'a> {
const PREFIX_ACCOUNT: u8 = b"a"[0];
const PREFIX_CLIENT: u8 = b"c"[0];
const PREFIX_CLIENT_PROPERTY: u8 = b"d"[0];
const PREFIX_ACCOUNT: u8 = b'a';
const PREFIX_CLIENT: u8 = b'c';
const PREFIX_CLIENT_PROPERTY: u8 = b'd';
// propertie's client suffixes
const INFO: u8 = b"i"[0];
const LAST_SEEN: u8 = b"l"[0];
const INFO: u8 = b'i';
const LAST_SEEN: u8 = b'l';
const ALL_CLIENT_PROPERTIES: [u8; 2] = [Self::INFO, Self::LAST_SEEN];
@ -252,7 +252,7 @@ mod test {
use std::fs;
use tempfile::Builder;
use crate::broker_storage::account::Account;
use crate::server_storage::admin::account::Account;
#[test]
pub fn test_account() {

@ -31,15 +31,15 @@ pub struct Invitation<'a> {
}
impl<'a> Invitation<'a> {
const PREFIX: u8 = b"i"[0];
const PREFIX: u8 = b'i';
// propertie's invitation suffixes
const TYPE: u8 = b"t"[0];
//const EXPIRE: u8 = b"e"[0];
const TYPE: u8 = b't';
//const EXPIRE: u8 = b'e';
const PREFIX_EXPIRE: u8 = b"e"[0];
const PREFIX_EXPIRE: u8 = b'e';
// propertie's expiry suffixes
const INVITATION: u8 = b"i"[0];
const INVITATION: u8 = b'i';
const ALL_PROPERTIES: [u8; 1] = [Self::TYPE];
@ -196,7 +196,7 @@ mod test {
use std::fs;
use tempfile::Builder;
use crate::broker_storage::account::Account;
use crate::server_storage::admin::account::Account;
#[test]
pub fn test_invitation() {}

@ -0,0 +1,5 @@
pub mod invitation;
pub mod wallet;
pub mod account;

@ -0,0 +1,5 @@
pub mod overlay;
pub mod peer;
pub mod topic;

@ -0,0 +1,5 @@
pub mod admin;
pub mod core;
//pub mod config;

@ -12,7 +12,8 @@
//! WebSocket implementation of the Broker
use crate::interfaces::*;
use crate::server_storage::RocksDbServerStorage;
use crate::rocksdb_server_storage::RocksDbServerStorage;
use crate::server_broker::ServerBroker;
use crate::types::*;
use async_std::io::ReadExt;
use async_std::net::{TcpListener, TcpStream};
@ -38,6 +39,7 @@ use ng_net::utils::get_domain_without_port;
use ng_net::utils::is_private_ip;
use ng_net::utils::is_public_ip;
use ng_net::NG_BOOTSTRAP_LOCAL_PATH;
use ng_repo::errors::NgError;
use ng_repo::log::*;
use ng_repo::types::SymKey;
use ng_repo::types::{PrivKey, PubKey};
@ -610,7 +612,7 @@ pub async fn run_server_v0(
config: DaemonConfigV0,
mut path: PathBuf,
admin_invite: bool,
) -> Result<(), ()> {
) -> Result<(), NgError> {
// check config
let mut run_core = false;
@ -624,8 +626,9 @@ pub async fn run_server_v0(
}
}
if !run_core && !run_server {
log_err!("There isn't any overlay_config that should run as core or server. Check your config. cannot start");
return Err(());
return Err(NgError::BrokerConfigErrorStr(
"There isn't any overlay_config that should run as core or server. Check your config.",
));
}
if run_core && !run_server {
@ -636,11 +639,10 @@ pub async fn run_server_v0(
for listener in &config.listeners {
let id: String = listener.to_string();
if !listeners.insert(id.clone()) {
log_err!(
"The listener {} is defined twice. Check your config file. cannot start",
return Err(NgError::BrokerConfigError(format!(
"The listener {} is defined twice. Check your config file.",
id
);
return Err(());
)));
}
}
@ -670,11 +672,10 @@ pub async fn run_server_v0(
match find_name(&interfaces, &listener.interface_name) {
None => {
log_err!(
"The interface {} does not exist on your host. Check your config file. cannot start",
return Err(NgError::BrokerConfigError(format!(
"The interface {} does not exist on your host. Check your config file.",
listener.interface_name
);
return Err(());
)));
}
Some(interface) => {
let mut addrs: Vec<SocketAddr> = interface
@ -689,11 +690,10 @@ pub async fn run_server_v0(
})
.collect();
if addrs.len() == 0 {
log_err!(
"The interface {} does not have any IPv4 address. cannot start",
return Err(NgError::BrokerConfigError(format!(
"The interface {} does not have any IPv4 address.",
listener.interface_name
);
return Err(());
)));
}
if listener.ipv6 {
let mut ipv6s: Vec<SocketAddr> = interface
@ -753,8 +753,7 @@ pub async fn run_server_v0(
}
if listeners_addrs.len() == 0 {
log_err!("No listener configured. cannot start",);
return Err(());
return Err(NgError::BrokerConfigErrorStr("No listener configured."));
}
if !accept_clients {
@ -777,7 +776,7 @@ pub async fn run_server_v0(
std::fs::create_dir_all(path.clone()).unwrap();
// opening the server storage (that contains the encryption keys for each store/overlay )
let broker_storage = RocksDbServerStorage::open(
let server_storage = RocksDbServerStorage::open(
&mut path,
wallet_master_key,
if admin_invite {
@ -786,10 +785,15 @@ pub async fn run_server_v0(
None
},
)
.map_err(|e| log_err!("Error while opening server storage: {:?}", e))?;
.map_err(|e| {
NgError::BrokerConfigError(format!("Error while opening server storage: {}", e))
})?;
let server_broker = ServerBroker::new(server_storage);
let mut broker = BROKER.write().await;
broker.set_server_storage(broker_storage);
broker.set_server_broker(server_broker);
LISTENERS_INFO
.set(broker.set_listeners(listener_infos))
.unwrap();
@ -815,12 +819,12 @@ pub async fn run_server_v0(
for addr in addrs.0 {
let tcp_listener = TcpListener::bind(addr).await.map_err(|e| {
log_err!(
NgError::BrokerConfigError(format!(
"cannot bind to {} with addresses {} : {}",
addrs.1,
addrs_string,
e.to_string()
)
))
})?;
listeners.push(tcp_listener);
}

@ -102,7 +102,7 @@ impl EActor for Actor<'_, AddInvitation, AdminResponse> {
let req = AddInvitation::try_from(msg)?;
let broker = BROKER.read().await;
broker
.get_server_storage()?
.get_server_broker()?
.add_invitation(req.code(), req.expiry(), req.memo())?;
let invitation = crate::types::Invitation::V0(InvitationV0::new(

@ -101,7 +101,7 @@ impl EActor for Actor<'_, AddUser, AdminResponse> {
is_admin = true;
}
}
let res = broker.get_server_storage()?.add_user(req.user(), is_admin);
let res = broker.get_server_broker()?.add_user(req.user(), is_admin);
let response: AdminResponseV0 = res.into();
fsm.lock().await.send(response.into()).await?;
Ok(())

@ -90,7 +90,7 @@ impl EActor for Actor<'_, CommitGet, Block> {
log_info!("GOT CommitGet {:?}", req);
let broker = BROKER.read().await;
let blocks_res = broker
.get_server_storage()?
.get_server_broker()?
.get_commit(req.overlay(), req.id());
match blocks_res {

@ -109,7 +109,7 @@ impl EActor for Actor<'_, PinRepo, RepoOpened> {
//TODO implement all the server side logic
let broker = BROKER.read().await;
let res = broker.get_server_storage()?.pin_repo(
let res = broker.get_server_broker()?.pin_repo(
req.overlay(),
req.hash(),
req.ro_topics(),

@ -79,7 +79,7 @@ impl EActor for Actor<'_, RepoPinStatusReq, RepoPinStatus> {
let req = RepoPinStatusReq::try_from(msg)?;
let broker = BROKER.read().await;
let res = broker
.get_server_storage()?
.get_server_broker()?
.get_repo_pin_status(req.overlay(), req.hash());
fsm.lock()
.await

@ -100,7 +100,7 @@ impl EActor for Actor<'_, TopicSub, TopicSubRes> {
//TODO implement all the server side logic
let broker = BROKER.read().await;
let res = broker.get_server_storage()?.topic_sub(
let res = broker.get_server_broker()?.topic_sub(
req.overlay(),
req.hash(),
req.topic(),

@ -82,7 +82,7 @@ impl EActor for Actor<'_, DelUser, AdminResponse> {
) -> Result<(), ProtocolError> {
let req = DelUser::try_from(msg)?;
let broker = BROKER.read().await;
let res = broker.get_server_storage()?.del_user(req.user());
let res = broker.get_server_broker()?.del_user(req.user());
let response: AdminResponseV0 = res.into();
fsm.lock().await.send(response.into()).await?;
Ok(())

@ -97,7 +97,7 @@ impl EActor for Actor<'_, ListInvitations, AdminResponse> {
fsm: Arc<Mutex<NoiseFSM>>,
) -> Result<(), ProtocolError> {
let req = ListInvitations::try_from(msg)?;
let res = BROKER.read().await.get_server_storage()?.list_invitations(
let res = BROKER.read().await.get_server_broker()?.list_invitations(
req.admin(),
req.unique(),
req.multi(),

@ -86,7 +86,7 @@ impl EActor for Actor<'_, ListUsers, AdminResponse> {
let res = BROKER
.read()
.await
.get_server_storage()?
.get_server_broker()?
.list_users(req.admins());
let response: AdminResponseV0 = res.into();
fsm.lock().await.send(response.into()).await?;

@ -14,7 +14,7 @@
use crate::actor::EActor;
use crate::actor::SoS;
use crate::connection::*;
use crate::server_storage::ServerStorage;
use crate::server_broker::IServerBroker;
use crate::types::*;
use crate::utils::spawn_and_log_error;
use crate::utils::{Receiver, ResultSend, Sender};
@ -85,7 +85,7 @@ pub struct Broker<'a> {
shutdown: Option<Receiver<ProtocolError>>,
shutdown_sender: Sender<ProtocolError>,
closing: bool,
server_storage: Option<Box<dyn ServerStorage + Send + Sync + 'a>>,
server_broker: Option<Box<dyn IServerBroker + Send + Sync + 'a>>,
tauri_streams: HashMap<String, Sender<Commit>>,
disconnections_sender: Sender<String>,
@ -146,9 +146,9 @@ impl<'a> Broker<'a> {
.ok_or(ProtocolError::BrokerError)
}
pub fn set_server_storage(&mut self, storage: impl ServerStorage + 'a) {
//log_debug!("set_storage");
self.server_storage = Some(Box::new(storage));
pub fn set_server_broker(&mut self, broker: impl IServerBroker + 'a) {
//log_debug!("set_server_broker");
self.server_broker = Some(Box::new(broker));
}
pub fn set_local_broker(&mut self, broker: Arc<RwLock<dyn ILocalBroker + 'a>>) {
@ -178,11 +178,11 @@ impl<'a> Broker<'a> {
(copy_listeners, copy_bind_addresses)
}
pub fn get_server_storage(
pub fn get_server_broker(
&self,
) -> Result<&Box<dyn ServerStorage + Send + Sync + 'a>, ProtocolError> {
) -> Result<&Box<dyn IServerBroker + Send + Sync + 'a>, ProtocolError> {
//log_debug!("GET STORAGE {:?}", self.server_storage);
self.server_storage
self.server_broker
.as_ref()
.ok_or(ProtocolError::BrokerError)
}
@ -222,7 +222,7 @@ impl<'a> Broker<'a> {
Authorization::Client(user_and_registration) => {
if user_and_registration.1.is_some() {
// user wants to register
let storage = self.get_server_storage()?;
let storage = self.get_server_broker()?;
if storage.get_user(user_and_registration.0).is_ok() {
return Ok(());
}
@ -266,7 +266,7 @@ impl<'a> Broker<'a> {
storage.remove_invitation(code)?;
}
}
self.get_server_storage()?
self.get_server_broker()?
.add_user(user_and_registration.0, is_admin)?;
Ok(())
}
@ -290,7 +290,7 @@ impl<'a> Broker<'a> {
return Ok(());
}
}
let found = self.get_server_storage()?.get_user(admin_user);
let found = self.get_server_broker()?.get_user(admin_user);
if found.is_ok() && found.unwrap() {
return Ok(());
}
@ -302,11 +302,11 @@ impl<'a> Broker<'a> {
}
// pub fn add_user(&self, user: PubKey, is_admin: bool) -> Result<(), ProtocolError> {
// self.get_server_storage()?.add_user(user, is_admin)
// self.get_server_broker()?.add_user(user, is_admin)
// }
// pub fn list_users(&self, admins: bool) -> Result<Vec<PubKey>, ProtocolError> {
// self.get_server_storage()?.list_users(admins)
// self.get_server_broker()?.list_users(admins)
// }
pub async fn get_block_from_store_with_block_id(
@ -482,7 +482,7 @@ impl<'a> Broker<'a> {
peers: HashMap::new(),
tauri_streams: HashMap::new(),
closing: false,
server_storage: None,
server_broker: None,
disconnections_sender,
disconnections_receiver: Some(disconnections_receiver),
local_broker: None,

@ -17,7 +17,7 @@ pub mod errors;
pub mod broker;
pub mod server_storage;
pub mod server_broker;
pub mod connection;

@ -9,13 +9,13 @@
* according to those terms.
*/
//! Trait for ServerStorage
//! Trait for ServerBroker
use crate::types::*;
use ng_repo::errors::*;
use ng_repo::types::*;
pub trait ServerStorage: Send + Sync {
pub trait IServerBroker: Send + Sync {
fn get_user(&self, user_id: PubKey) -> Result<bool, ProtocolError>;
fn add_user(&self, user_id: PubKey, is_admin: bool) -> Result<(), ProtocolError>;
fn del_user(&self, user_id: PubKey) -> Result<(), ProtocolError>;

@ -66,6 +66,8 @@ pub enum NgError {
NotAServerError,
VerifierError(VerifierError),
SiteNotFoundOnBroker,
BrokerConfigErrorStr(&'static str),
BrokerConfigError(String),
}
impl Error for NgError {}
@ -75,6 +77,19 @@ impl fmt::Display for NgError {
match self {
Self::WalletError(string) => write!(f, "WalletError: {}", string),
Self::JsStorageWriteError(string) => write!(f, "JsStorageWriteError: {}", string),
Self::CommitVerifyError(commit_verify_error) => {
write!(f, "CommitVerifyError: {:?}", commit_verify_error)
}
Self::ProtocolError(error) => write!(f, "ProtocolError: {:?}", error),
Self::ServerError(error) => write!(f, "ServerError: {:?}", error),
Self::VerifierError(error) => write!(f, "VerifierError: {:?}", error),
Self::CommitLoadError(commit_load_error) => {
write!(f, "CommitLoadError: {:?}", commit_load_error)
}
Self::ObjectParseError(error) => write!(f, "ObjectParseError: {:?}", error),
Self::StorageError(storage_error) => write!(f, "StorageError: {:?}", storage_error),
Self::BrokerConfigErrorStr(s) => write!(f, "BrokerConfigError: {s}"),
Self::BrokerConfigError(s) => write!(f, "BrokerConfigError: {s}"),
_ => write!(f, "{:?}", self),
}
}
@ -85,38 +100,7 @@ impl From<NgError> for std::io::Error {
match err {
NgError::InvalidArgument => std::io::Error::from(std::io::ErrorKind::InvalidInput),
NgError::PermissionDenied => std::io::Error::from(std::io::ErrorKind::PermissionDenied),
NgError::CommitLoadError(commit_load_error) => std::io::Error::new(
std::io::ErrorKind::Other,
format!("CommitLoadError: {:?}", commit_load_error),
),
NgError::StorageError(storage_error) => std::io::Error::new(
std::io::ErrorKind::Other,
format!("StorageError: {:?}", storage_error),
),
NgError::NotFound => std::io::Error::from(std::io::ErrorKind::NotFound),
NgError::CommitVerifyError(commit_verify_error) => std::io::Error::new(
std::io::ErrorKind::Other,
format!("CommitVerifyError: {:?}", commit_verify_error),
),
/*NgError::InvalidSignature => ,
NgError::IncompleteSignature =>
NgError::SerializationError => ,
NgError::EncryptionError => ,
NgError::InvalidKey => ,
NgError::InvalidInvitation => ,
NgError::InvalidCreateAccount => ,
NgError::InvalidFileFormat => ,
NgError::LocalBrokerNotInitialized => ,
NgError::JsStorageReadError => ,
NgError::JsStorageWriteError(String) => ,
NgError::CannotSaveWhenInMemoryConfig => ,
NgError::WalletNotFound => ,
NgError::WalletAlreadyAdded => ,
NgError::WalletAlreadyOpened => ,
NgError::WalletError(String) => ,
NgError::BrokerError => ,
NgError::SessionNotFound,
NgError::IoError => ,*/
_ => std::io::Error::new(std::io::ErrorKind::Other, err.to_string().as_str()),
}
}

@ -184,7 +184,7 @@ impl fmt::Display for PubKey {
impl TryFrom<&str> for PubKey {
type Error = NgError;
fn try_from(str: &str) -> Result<Self, NgError> {
let key = decode_key(str).map_err(|_| NgError::InvalidKey)?;
let key = decode_key(str)?;
Ok(PubKey::Ed25519PubKey(key))
}
}
@ -254,7 +254,7 @@ impl TryFrom<&[u8]> for PrivKey {
impl TryFrom<&str> for PrivKey {
type Error = NgError;
fn try_from(str: &str) -> Result<Self, NgError> {
let key = decode_key(str).map_err(|_| NgError::InvalidKey)?;
let key = decode_key(str)?;
Ok(PrivKey::Ed25519PrivKey(key))
}
}

@ -53,11 +53,9 @@ pub fn from_ed_privkey_to_dh_privkey(private: &PrivKey) -> PrivKey {
}
/// don't forget to zeroize the string later on
pub fn decode_key(key_string: &str) -> 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"))?)
pub fn decode_key(key_string: &str) -> Result<[u8; 32], NgError> {
let vec = base64_url::decode(key_string).map_err(|_| NgError::InvalidKey)?;
Ok(*slice_as_array!(&vec, [u8; 32]).ok_or(NgError::InvalidKey)?)
}
pub fn ed_privkey_to_ed_pubkey(privkey: &PrivKey) -> PubKey {

@ -55,6 +55,7 @@ impl RocksDbBlockStorage {
opts.set_max_bytes_for_level_base(16 * 1024 * 1024);
opts.set_target_file_size_multiplier(10);
opts.set_level_compaction_dynamic_level_bytes(true);
opts.set_num_levels(7); // the default
opts.create_if_missing(true);
opts.create_missing_column_families(false);
@ -67,7 +68,7 @@ impl RocksDbBlockStorage {
opts.set_blob_compression_type(DBCompressionType::None);
opts.set_enable_blob_gc(true);
// the oldest half of blob files will be selected for GC
opts.set_blob_gc_age_cutoff(0.5);
opts.set_blob_gc_age_cutoff(0.75);
// in those oldest blob files, if 50% of it (8MB) is garbage, a forced compact will occur.
// this way we are reducing the space amplification by small decrements of 8MB
opts.set_blob_gc_force_threshold(0.5);

@ -676,6 +676,7 @@ impl RocksDbKCVStorage {
opts.set_max_bytes_for_level_base(256 * 1024 * 1024);
opts.set_target_file_size_multiplier(10);
opts.set_level_compaction_dynamic_level_bytes(true);
opts.set_num_levels(7); // the default
opts.create_if_missing(true);
opts.create_missing_column_families(true);
@ -685,6 +686,7 @@ impl RocksDbKCVStorage {
let cache = Cache::new_lru_cache(64 * 1024 * 1024);
block_based_opts.set_block_cache(&cache);
block_based_opts.set_cache_index_and_filter_blocks(true);
block_based_opts.set_pin_l0_filter_and_index_blocks_in_cache(true);
block_based_opts.set_block_size(16 * 1024);
block_based_opts.set_bloom_filter(10.0, false);
block_based_opts.set_format_version(6);

@ -39,9 +39,9 @@ impl RocksDbUserStorage {
}
impl UserStorage for RocksDbUserStorage {
fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError> {
unimplemented!();
}
// fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError> {
// unimplemented!();
// }
fn get_all_store_and_repo_ids(&self) -> Result<HashMap<StoreRepo, Vec<RepoId>>, StorageError> {
RepoStorage::get_all_store_and_repo_ids(&self.user_storage)

@ -15,7 +15,7 @@ use core::fmt;
//use oxigraph::model::GroundQuad;
#[cfg(not(target_family = "wasm"))]
use crate::rocksdb_user_storage::RocksDbUserStorage;
use crate::user_storage::{InMemoryUserStorage, UserStorage};
use crate::user_storage::UserStorage;
use async_std::sync::Mutex;
use std::{collections::HashMap, path::PathBuf, sync::Arc};

@ -26,8 +26,7 @@ use std::{
};
pub trait UserStorage: Send + Sync {
/// Gets the StoreRepo for a given RepoId
fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError>;
//fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError>;
fn get_all_store_and_repo_ids(&self) -> Result<HashMap<StoreRepo, Vec<RepoId>>, StorageError>;
@ -46,51 +45,51 @@ pub trait UserStorage: Send + Sync {
fn update_signer_cap(&self, signer_cap: &SignerCap) -> Result<(), StorageError>;
}
pub(crate) struct InMemoryUserStorage {
repo_id_to_store_overlay: HashMap<RepoId, StoreOverlay>,
}
impl InMemoryUserStorage {
pub fn new() -> Self {
InMemoryUserStorage {
repo_id_to_store_overlay: HashMap::new(),
}
}
}
impl UserStorage for InMemoryUserStorage {
fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError> {
Ok(self
.repo_id_to_store_overlay
.get(&id)
.ok_or(StorageError::NotFound)?
.to_owned())
}
fn get_all_store_and_repo_ids(&self) -> Result<HashMap<StoreRepo, Vec<RepoId>>, StorageError> {
unimplemented!();
}
fn load_store(
&self,
repo_store: &StoreRepo,
block_storage: Arc<RwLock<dyn BlockStorage + Send + Sync>>,
) -> Result<Repo, StorageError> {
unimplemented!();
}
fn load_repo(&self, repo_id: &RepoId, store: Arc<Store>) -> Result<Repo, StorageError> {
unimplemented!();
}
fn save_repo(&self, repo: &Repo) -> Result<(), StorageError> {
unimplemented!();
}
fn add_branch(&self, repo_id: &RepoId, branch_info: &BranchInfo) -> Result<(), StorageError> {
unimplemented!();
}
fn update_signer_cap(&self, signer_cap: &SignerCap) -> Result<(), StorageError> {
unimplemented!();
}
}
// pub(crate) struct InMemoryUserStorage {
// repo_id_to_store_overlay: HashMap<RepoId, StoreOverlay>,
// }
// impl InMemoryUserStorage {
// pub fn new() -> Self {
// InMemoryUserStorage {
// repo_id_to_store_overlay: HashMap::new(),
// }
// }
// }
// impl UserStorage for InMemoryUserStorage {
// fn repo_id_to_store_overlay(&self, id: &RepoId) -> Result<StoreOverlay, StorageError> {
// Ok(self
// .repo_id_to_store_overlay
// .get(&id)
// .ok_or(StorageError::NotFound)?
// .to_owned())
// }
// fn get_all_store_and_repo_ids(&self) -> Result<HashMap<StoreRepo, Vec<RepoId>>, StorageError> {
// unimplemented!();
// }
// fn load_store(
// &self,
// repo_store: &StoreRepo,
// block_storage: Arc<RwLock<dyn BlockStorage + Send + Sync>>,
// ) -> Result<Repo, StorageError> {
// unimplemented!();
// }
// fn load_repo(&self, repo_id: &RepoId, store: Arc<Store>) -> Result<Repo, StorageError> {
// unimplemented!();
// }
// fn save_repo(&self, repo: &Repo) -> Result<(), StorageError> {
// unimplemented!();
// }
// fn add_branch(&self, repo_id: &RepoId, branch_info: &BranchInfo) -> Result<(), StorageError> {
// unimplemented!();
// }
// fn update_signer_cap(&self, signer_cap: &SignerCap) -> Result<(), StorageError> {
// unimplemented!();
// }
// }

@ -35,7 +35,7 @@ use core::fmt;
//use oxigraph::model::GroundQuad;
#[cfg(not(target_family = "wasm"))]
use crate::rocksdb_user_storage::RocksDbUserStorage;
use crate::user_storage::{InMemoryUserStorage, UserStorage};
use crate::user_storage::UserStorage;
use async_std::sync::{Mutex, RwLockReadGuard, RwLockWriteGuard};
use std::{collections::HashMap, path::PathBuf, sync::Arc};
@ -1114,7 +1114,7 @@ impl Verifier {
let (graph, user, block) = match &config.config_type {
VerifierConfigType::Memory | VerifierConfigType::JsSaveSession(_) => (
Some(oxigraph::store::Store::new().unwrap()),
Some(Box::new(InMemoryUserStorage::new()) as Box<dyn UserStorage>),
None, //Some(Box::new(InMemoryUserStorage::new()) as Box<dyn UserStorage>),
Some(block_storage),
),
#[cfg(not(target_family = "wasm"))]

@ -9,6 +9,7 @@
use ed25519_dalek::*;
use core::fmt;
use duration_str::parse;
use futures::{future, pin_mut, stream, SinkExt, StreamExt};
use ng_net::actors::*;
@ -19,6 +20,7 @@ use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use serde_json::{from_str, to_string_pretty};
use std::collections::HashMap;
use std::error::Error;
use std::fs::{read_to_string, write};
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
@ -65,6 +67,66 @@ impl CliConfig {
}
}
#[derive(Debug)]
pub enum NgcliError {
IoError(std::io::Error),
NgError(NgError),
InvalidKeyFile(String),
CannotSaveKey(String),
InvalidConfigFile(String),
ProtocolError(ProtocolError),
OtherConfigError(String),
OtherConfigErrorStr(&'static str),
CannotSaveConfig(String),
}
impl Error for NgcliError {}
impl From<NgcliError> for std::io::Error {
fn from(err: NgcliError) -> std::io::Error {
match err {
NgcliError::NgError(e) => e.into(),
NgcliError::ProtocolError(e) => Into::<NgError>::into(e).into(),
NgcliError::IoError(e) => e,
_ => std::io::Error::new(std::io::ErrorKind::Other, err.to_string().as_str()),
}
}
}
impl From<NgError> for NgcliError {
fn from(err: NgError) -> NgcliError {
Self::NgError(err)
}
}
impl From<ProtocolError> for NgcliError {
fn from(err: ProtocolError) -> NgcliError {
Self::ProtocolError(err)
}
}
impl From<std::io::Error> for NgcliError {
fn from(io: std::io::Error) -> NgcliError {
NgcliError::IoError(io)
}
}
impl fmt::Display for NgcliError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidKeyFile(s) => write!(f, "provided key file is invalid. {}", s),
Self::CannotSaveKey(s) => write!(f, "cannot save key to file. {}", s),
Self::NgError(e) => write!(f, "{}", e.to_string()),
Self::InvalidConfigFile(s) => write!(f, "provided config file is invalid. {}", s),
Self::IoError(e) => write!(f, "IoError : {:?}", e),
Self::ProtocolError(e) => write!(f, "{}", e),
Self::OtherConfigError(s) => write!(f, "{}", s),
Self::OtherConfigErrorStr(s) => write!(f, "{}", s),
_ => write!(f, "{:?}", self),
}
}
}
fn gen_client_keys(key: Option<[u8; 32]>) -> [[u8; 32]; 4] {
let key = match key {
None => {
@ -87,7 +149,14 @@ fn gen_client_keys(key: Option<[u8; 32]>) -> [[u8; 32]; 4] {
}
#[async_std::main]
async fn main() -> Result<(), ProtocolError> {
async fn main() -> std::io::Result<()> {
if let Err(err) = main_inner().await {
log_err!("An error occurred: {}", err.to_string());
return Err(err.into());
}
Ok(())
}
async fn main_inner() -> Result<(), NgcliError> {
let matches = command!()
.arg(arg!(
-v --verbose ... "Increase the logging output. once : info, twice : debug, 3 times : trace"
@ -203,23 +272,19 @@ async fn main() -> Result<(), ProtocolError> {
// 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 mut file = read_to_string(key_path).map_err(|_| "")?;
let first_line = file.lines().nth(0).ok_or("empty file")?;
let res = decode_key(first_line.trim()).map_err(|_| "invalid file");
file.zeroize();
res
}(&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(ProtocolError::InvalidValue);
}
key_from_file = res.ok();
let key_from_file: Option<[u8; 32]> = match read_to_string(key_path.clone()) {
Err(_) => None,
Ok(mut file) => {
let first_line = file
.lines()
.nth(0)
.ok_or(NgcliError::InvalidKeyFile("empty file".to_string()))?;
let res = decode_key(first_line.trim())
.map_err(|_| NgcliError::InvalidKeyFile("deserialization error".to_string()))?;
file.zeroize();
Some(res)
}
};
let mut keys: [[u8; 32]; 4] = match matches.get_one::<String>("key") {
Some(key_string) => {
@ -229,15 +294,14 @@ async fn main() -> Result<(), ProtocolError> {
gen_client_keys(key_from_file)
} else {
let res = decode_key(key_string.as_str()).map_err(|_| {
log_err!("provided key is invalid. cannot start");
ProtocolError::InvalidValue
NgcliError::InvalidKeyFile(
"check the argument provided in command line".to_string(),
)
})?;
if matches.get_flag("save_key") {
let mut 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());
ProtocolError::InvalidValue
})?;
write(key_path.clone(), &master_key)
.map_err(|e| NgcliError::CannotSaveKey(e.to_string()))?;
master_key.zeroize();
log_info!("The key has been saved to {}", key_path.to_str().unwrap());
}
@ -252,10 +316,8 @@ async fn main() -> Result<(), ProtocolError> {
let res = gen_client_keys(None);
let mut master_key = base64_url::encode(&res[0]);
if matches.get_flag("save_key") {
write(key_path.clone(), &master_key).map_err(|e| {
log_err!("cannot save key to file. {}.cannot start", e.to_string());
ProtocolError::InvalidValue
})?;
write(key_path.clone(), &master_key)
.map_err(|e| NgcliError::CannotSaveKey(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
@ -277,47 +339,31 @@ async fn main() -> Result<(), ProtocolError> {
// reading config from file, if any
let mut config_path = path.clone();
config_path.push("config.json");
let mut config: Option<CliConfig>;
let res = |config_path| -> Result<CliConfig, 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. {}. cannot start",
res.unwrap_err()
);
return Err(ProtocolError::InvalidValue);
}
config = res.ok();
let mut config: Option<CliConfig> = match read_to_string(config_path.clone()) {
Err(_) => None,
Ok(file) => {
Some(from_str(&file).map_err(|e| NgcliError::InvalidConfigFile(e.to_string()))?)
}
};
if let Some(server) = matches.get_one::<String>("server") {
let addr: Vec<&str> = server.split(',').collect();
if addr.len() != 3 {
log_err!(
"NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. cannot start"
);
return Err(ProtocolError::InvalidValue);
return Err(NgcliError::OtherConfigErrorStr(
"NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID.",
));
}
let ip = IpAddr::from_str(addr[0]).map_err(|_| {
log_err!("NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. The first part is not an IP address. cannot start");
ProtocolError::InvalidValue
NgcliError::OtherConfigErrorStr("NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. The first part is not an IP address.")
})?;
let port = match from_str::<u16>(addr[1]) {
Err(_) => {
log_err!("NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. The port is invalid. It should be a number. cannot start");
return Err(ProtocolError::InvalidValue);
}
Ok(val) => val,
};
let port = from_str::<u16>(addr[1]).map_err(|_| {
NgcliError::OtherConfigErrorStr("NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. The port is invalid. It should be a number.")
})?;
let peer_id: PubKey = addr[2].try_into().map_err(|_| {
log_err!(
"NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID.
The PEER_ID is invalid. It should be a base64-url encoded serde serialization of a [u8; 32]. cannot start"
);
ProtocolError::InvalidValue
NgcliError::OtherConfigErrorStr(
"NG_CLIENT_SERVER or the --server option is invalid. format is IP,PORT,PEER_ID. The PEER_ID is invalid. It should be a base64-url encoded serde serialization of a [u8; 32]."
)
})?;
if config.is_some() {
log_warn!("Overriding the config found in file with new server parameters provided on command line!");
@ -331,20 +377,16 @@ async fn main() -> Result<(), ProtocolError> {
}
if config.is_none() {
log_err!(
"No config found for the server to connect to. The config file is missing.
You must provide NG_CLIENT_SERVER or the --server option. cannot start"
);
return Err(ProtocolError::InvalidValue);
return Err(NgcliError::OtherConfigErrorStr(
"No config found for the server to connect to. The config file is missing. You must provide NG_CLIENT_SERVER or the --server option.",
));
}
if let Some(user) = matches.get_one::<String>("user") {
let privkey: PrivKey = user.as_str().try_into().map_err(|_| {
log_err!(
"NG_CLIENT_USER or the --user option is invalid. It should be a base64-url encoded
serde serialization of a [u8; 32] of a private key for a user. cannot start"
);
ProtocolError::InvalidValue
NgcliError::OtherConfigErrorStr(
"NG_CLIENT_USER or the --user option is invalid. It should be a base64-url encoded serde serialization of a [u8; 32] of a private key for a user.",
)
})?;
if config.is_some() {
let CliConfig::V0(c) = config.as_mut().unwrap();
@ -359,23 +401,18 @@ async fn main() -> Result<(), ProtocolError> {
let CliConfig::V0(config_v0) = config.as_ref().unwrap();
if config_v0.user.is_none() {
log_err!(
"No config found for the user. The config file is missing.
You must provide NG_CLIENT_USER or the --user option. cannot start"
);
return Err(ProtocolError::InvalidValue);
return Err(NgcliError::OtherConfigErrorStr(
"No config found for the user. The config file is missing. You must provide NG_CLIENT_USER or the --user option.",
));
}
if matches.get_flag("save_config") {
// saves the config to file
let json_string = to_string_pretty(&config).unwrap();
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()
);
ProtocolError::InvalidValue
NgcliError::CannotSaveConfig(format!("cannot save config to file. {}.", e.to_string()))
})?;
log_info!(
"The config file has been saved to {}",
config_path.to_str().unwrap()
@ -430,18 +467,15 @@ async fn main() -> Result<(), ProtocolError> {
.as_str()
.try_into()
.map_err(|_| {
log_err!("supplied USER_ID is invalid");
ProtocolError::InvalidValue
NgcliError::OtherConfigErrorStr("supplied USER_ID is invalid")
})?,
is_admin: sub2_matches.get_flag("admin"),
}),
)
.await;
match &res {
Err(e) => log_err!("An error occurred: {e}"),
Ok(_) => println!("User added successfully"),
}
return res.map(|_| ());
.await?;
println!("User added successfully");
return Ok(());
}
Some(("del-user", sub2_matches)) => {
log_debug!("add-user");
@ -455,26 +489,21 @@ async fn main() -> Result<(), ProtocolError> {
.as_str()
.try_into()
.map_err(|_| {
log_err!("supplied USER_ID is invalid");
ProtocolError::InvalidValue
NgcliError::OtherConfigErrorStr("supplied USER_ID is invalid")
})?,
}),
)
.await;
match &res {
Err(e) => log_err!("An error occurred: {e}"),
Ok(_) => println!("User removed successfully"),
}
return res.map(|_| ());
.await?;
println!("User removed successfully");
return Ok(());
}
Some(("list-users", sub2_matches)) => {
log_debug!("list-users");
let admins = sub2_matches.get_flag("admin");
let res =
do_admin_call(keys[1], config_v0, ListUsers::V0(ListUsersV0 { admins })).await;
let res = do_admin_call(keys[1], config_v0, ListUsers::V0(ListUsersV0 { admins }))
.await?;
match &res {
Err(e) => log_err!("An error occurred: {e}"),
Ok(AdminResponseContentV0::Users(list)) => {
AdminResponseContentV0::Users(list) => {
println!(
"Found {} {}users",
list.len(),
@ -484,12 +513,9 @@ async fn main() -> Result<(), ProtocolError> {
println!("{user}");
}
}
_ => {
log_err!("Invalid response");
return Err(ProtocolError::InvalidValue);
}
_ => return Err(NgError::InvalidResponse.into()),
}
return res.map(|_| ());
return Ok(());
}
Some(("add-invitation", sub2_matches)) => {
log_debug!("add-invitation");
@ -523,10 +549,9 @@ async fn main() -> Result<(), ProtocolError> {
tos_url: !sub2_matches.get_flag("notos"),
}),
)
.await;
match res.as_mut() {
Err(e) => log_err!("An error occurred: {e}"),
Ok(AdminResponseContentV0::Invitation(invitation)) => {
.await?;
match &mut res {
AdminResponseContentV0::Invitation(invitation) => {
invitation
.set_name(sub2_matches.get_one::<String>("name").map(|s| s.clone()));
@ -536,12 +561,9 @@ async fn main() -> Result<(), ProtocolError> {
println!("The invitation link is: {}", link)
}
}
_ => {
log_err!("Invalid response");
return Err(ProtocolError::InvalidValue);
}
_ => return Err(NgError::InvalidResponse.into()),
}
return res.map(|_| ());
return Ok(());
}
Some(("list-invitations", sub2_matches)) => {
log_debug!("invitations");
@ -557,10 +579,9 @@ async fn main() -> Result<(), ProtocolError> {
unique,
}),
)
.await;
.await?;
match &res {
Err(e) => log_err!("An error occurred: {e}"),
Ok(AdminResponseContentV0::Invitations(list)) => {
AdminResponseContentV0::Invitations(list) => {
println!(
"Found {} {}invitations",
list.len(),
@ -593,12 +614,9 @@ async fn main() -> Result<(), ProtocolError> {
);
}
}
_ => {
log_err!("Invalid response");
return Err(ProtocolError::InvalidValue);
}
_ => return Err(NgError::InvalidResponse.into()),
}
return res.map(|_| ());
return Ok(());
}
_ => panic!("shouldn't happen"),
},

@ -14,6 +14,7 @@ mod cli;
use crate::cli::*;
use crate::types::*;
use clap::Parser;
use core::fmt;
use ng_broker::interfaces::*;
use ng_broker::server_ws::run_server_v0;
use ng_broker::types::*;
@ -27,6 +28,7 @@ use ng_net::utils::{
gen_dh_keys, is_ipv4_global, is_ipv4_private, is_ipv6_global, is_ipv6_private,
};
use ng_net::{WS_PORT, WS_PORT_REVERSE_PROXY};
use ng_repo::errors::NgError;
use ng_repo::log::*;
use ng_repo::types::Sig;
use ng_repo::types::SymKey;
@ -36,6 +38,7 @@ use ng_repo::{
utils::{decode_key, generate_keypair, sign, verify},
};
use serde_json::{from_str, to_string_pretty};
use std::error::Error;
use std::fs::{read_to_string, write};
use std::io::ErrorKind;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
@ -79,7 +82,7 @@ fn parse_interface_and_port_for(
string: &String,
for_option: &str,
default_port: u16,
) -> Result<(String, u16), ()> {
) -> Result<(String, u16), NgdError> {
let c = RE_INTERFACE.captures(string);
if c.is_some() && c.as_ref().unwrap().get(1).is_some() {
@ -104,20 +107,19 @@ fn parse_interface_and_port_for(
};
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. cannot start",
Err(NgdError::OtherConfigError(format!(
"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.",
for_option
);
Err(())
)))
}
}
fn parse_ipv6_for(string: String, for_option: &str) -> Result<Ipv6Addr, ()> {
fn parse_ipv6_for(string: String, for_option: &str) -> Result<Ipv6Addr, NgdError> {
string.parse::<Ipv6Addr>().map_err(|_| {
log_err!(
"The <IPv6> value submitted for the {} option is invalid. cannot start",
NgdError::OtherConfigError(format!(
"The <IPv6> value submitted for the {} option is invalid.",
for_option
)
))
})
}
@ -125,18 +127,17 @@ fn parse_ipv4_and_port_for(
string: String,
for_option: &str,
default_port: u16,
) -> Result<(Ipv4Addr, u16), ()> {
) -> Result<(Ipv4Addr, u16), NgdError> {
let parts: Vec<&str> = string.split(":").collect();
let ipv4 = parts[0].parse::<Ipv4Addr>().map_err(|_| {
log_err!(
"The <IPv4:PORT> value submitted for the {} option is invalid. cannot start",
NgdError::OtherConfigError(format!(
"The <IPv4:PORT> value submitted for the {} option is invalid.",
for_option
)
))
})?;
let port;
if parts.len() > 1 {
port = match from_str::<u16>(parts[1]) {
let port = if parts.len() > 1 {
match from_str::<u16>(parts[1]) {
Err(_) => default_port,
Ok(p) => {
if p == 0 {
@ -145,14 +146,14 @@ fn parse_ipv4_and_port_for(
p
}
}
};
}
} else {
port = default_port;
}
return Ok((ipv4, port));
default_port
};
Ok((ipv4, port))
}
fn parse_ip_and_port_for(string: String, for_option: &str) -> Result<(IpAddr, u16), ()> {
fn parse_ip_and_port_for(string: String, for_option: &str) -> Result<(IpAddr, u16), NgdError> {
let c = RE_IPV6_WITH_PORT.captures(&string);
let ipv6;
let port;
@ -177,24 +178,24 @@ fn parse_ip_and_port_for(string: String, for_option: &str) -> Result<(IpAddr, u1
}
};
let ipv6 = ipv6_str.parse::<Ipv6Addr>().map_err(|_| {
log_err!(
"The <[IPv6]:PORT> value submitted for the {} option is invalid. cannot start",
NgdError::OtherConfigError(format!(
"The <[IPv6]:PORT> value submitted for the {} option is invalid.",
for_option
)
))
})?;
return Ok((IpAddr::V6(ipv6), port));
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, DEFAULT_PORT)
.map(|ipv4| (IpAddr::V4(ipv4.0), ipv4.1));
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));
Ok((IpAddr::V6(ipv6), port))
}
}
}
@ -202,72 +203,59 @@ fn parse_ip_and_port_for(string: String, for_option: &str) -> Result<(IpAddr, u1
fn parse_triple_interface_and_port_for(
string: &String,
for_option: &str,
) -> Result<((String, u16), (Option<Ipv6Addr>, (Ipv4Addr, u16))), ()> {
) -> Result<((String, u16), (Option<Ipv6Addr>, (Ipv4Addr, u16))), NgdError> {
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. cannot start",
return Err(NgdError::OtherConfigError(format!(
"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.",
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())))
Ok((first_part, (middle_part, last_part)))
}
fn parse_domain_and_port(
domain_string: &String,
option: &str,
default_port: u16,
) -> Result<(String, String, u16), ()> {
) -> Result<(String, String, u16), NgdError> {
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",
return Err(NgdError::OtherConfigError(format!(
"The domain name provided for option {} is invalid. {}.",
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(());
return Err(NgdError::OtherConfigError(format!(
"The domain name provided for option {} is invalid. Unknown suffix in public list.", option
)));
}
}
}
@ -296,7 +284,7 @@ fn parse_domain_and_port(
fn prepare_accept_forward_for_domain(
domain: String,
args: &mut Cli,
) -> Result<AcceptForwardForV0, ()> {
) -> Result<AcceptForwardForV0, NgError> {
if args.domain_peer.is_some() {
let key = decode_key(args.domain_peer.as_ref().unwrap().as_str())?;
args.domain_peer.as_mut().unwrap().zeroize();
@ -310,15 +298,84 @@ fn prepare_accept_forward_for_domain(
Ok(AcceptForwardForV0::PublicDomain((domain, "".to_string())))
}
}
#[derive(Debug)]
pub enum NgdError {
IoError(std::io::Error),
NgError(NgError),
InvalidKeyFile(String),
CannotSaveKey(String),
InvalidSignature,
CannotSaveSignature(String),
InvalidConfigFile(String),
ConfigCannotSave,
ConfigFilePresent,
ConfigDomainPeerConflict,
NoLoopback,
OtherConfigError(String),
OtherConfigErrorStr(&'static str),
CannotSaveConfig(String),
}
impl Error for NgdError {}
impl From<NgdError> for std::io::Error {
fn from(err: NgdError) -> std::io::Error {
match err {
NgdError::NgError(e) => e.into(),
NgdError::IoError(e) => e,
_ => std::io::Error::new(std::io::ErrorKind::Other, err.to_string().as_str()),
}
}
}
impl From<NgError> for NgdError {
fn from(err: NgError) -> NgdError {
Self::NgError(err)
}
}
impl From<std::io::Error> for NgdError {
fn from(io: std::io::Error) -> NgdError {
NgdError::IoError(io)
}
}
impl fmt::Display for NgdError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidKeyFile(s) => write!(f, "provided key file is invalid. {}", s),
Self::CannotSaveKey(s) => write!(f, "cannot save key to file. {}", s),
Self::NgError(e) => write!(f, "{}", e.to_string()),
Self::InvalidConfigFile(s) => write!(f, "provided config file is invalid. {}", s),
Self::IoError(e) => write!(f, "IoError : {:?}", e),
Self::ConfigCannotSave => write!(
f,
"A config file is present. We cannot override it with Quick config options"
),
Self::ConfigFilePresent => write!(
f,
"A config file is present. You cannot use the Quick config options on the command-line. In order to use them, delete your config file first."
),
Self::ConfigDomainPeerConflict => write!(
f,"The --domain-peer option can only be set when the --domain or --domain-private option is also present on the command line."),
Self::NoLoopback => write!(
f,"That's pretty unusual, but no loopback interface could be found on your host. --domain option failed for that reason."),
Self::OtherConfigError(s) => write!(f, "{}", s),
Self::OtherConfigErrorStr(s) => write!(f, "{}", s),
_ => write!(f, "{:?}", self),
}
}
}
#[async_std::main]
async fn main() -> std::io::Result<()> {
main_inner()
.await
.map_err(|_| ErrorKind::InvalidInput.into())
if let Err(err) = main_inner().await {
log_err!("Cannot start: {}", err.to_string());
return Err(err.into());
}
Ok(())
}
async fn main_inner() -> Result<(), ()> {
async fn main_inner() -> Result<(), NgdError> {
let mut args = Cli::parse();
if args.list_interfaces {
@ -340,7 +397,10 @@ async fn main_inner() -> Result<(), ()> {
}
env_logger::init();
log_info!("Starting NextGraph daemon (ngd)");
log_info!(
"Starting NextGraph daemon (ngd) version {}",
env!("CARGO_PKG_VERSION").to_string()
);
log_debug!("base {:?}", args.base);
@ -357,23 +417,20 @@ async fn main_inner() -> Result<(), ()> {
// 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 mut file = read_to_string(key_path).map_err(|_| "")?;
let first_line = file.lines().nth(0).ok_or("empty file")?;
let res = decode_key(first_line.trim()).map_err(|_| "invalid file");
file.zeroize();
res
}(&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 key_from_file: Option<[u8; 32]> = match read_to_string(key_path.clone()) {
Err(_) => None,
Ok(mut file) => {
let first_line = file
.lines()
.nth(0)
.ok_or(NgdError::InvalidKeyFile("empty file".to_string()))?;
let res = decode_key(first_line.trim())
.map_err(|_| NgdError::InvalidKeyFile("deserialization error".to_string()))?;
file.zeroize();
Some(res)
}
};
let mut keys: [[u8; 32]; 4] = match &args.key {
Some(key_string) => {
@ -382,13 +439,15 @@ async fn main_inner() -> Result<(), ()> {
args.key.as_mut().unwrap().zeroize();
gen_broker_keys(key_from_file)
} else {
let res = decode_key(key_string.as_str())
.map_err(|_| log_err!("provided key is invalid. cannot start"))?;
let res = decode_key(key_string.as_str()).map_err(|_| {
NgdError::InvalidKeyFile(
"check the argument provided in command line".to_string(),
)
})?;
if args.save_key {
let mut 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())
})?;
write(key_path.clone(), &master_key)
.map_err(|e| NgdError::CannotSaveKey(e.to_string()))?;
master_key.zeroize();
log_info!("The key has been saved to {}", key_path.to_str().unwrap());
}
@ -403,9 +462,8 @@ async fn main_inner() -> Result<(), ()> {
let res = gen_broker_keys(None);
let mut 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())
})?;
write(key_path.clone(), &master_key)
.map_err(|e| NgdError::CannotSaveKey(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
@ -427,38 +485,25 @@ async fn main_inner() -> Result<(), ()> {
let mut sign_path = path.clone();
sign_path.push("sign");
let sign_from_file: Option<[u8; 32]>;
let res = |sign_path| -> Result<(), &str> {
let file = std::fs::read(sign_path).map_err(|_| "")?;
let sig: Sig = serde_bare::from_slice(&file).map_err(|_| "invalid serialization")?;
let privkey: PrivKey = keys[3].into();
let pubkey = privkey.to_pub();
verify(&vec![110u8, 103u8, 100u8], sig, pubkey).map_err(|_| "invalid signature")?;
Ok(())
}(&sign_path);
if res.is_err() {
if res.unwrap_err().len() > 0 {
log_err!(
"provided key is invalid. {}. cannot start",
res.unwrap_err()
);
return Err(());
} else {
// time to save the signature
let privkey: PrivKey = keys[3].into();
let pubkey = privkey.to_pub();
let sig = sign(&privkey, &pubkey, &vec![110u8, 103u8, 100u8]);
if sig.is_err() {
log_err!("cannot save signature. cannot start");
return Err(());
}
let sig_ser = serde_bare::to_vec(&sig.unwrap()).unwrap();
let res = std::fs::write(sign_path, sig_ser);
if res.is_err() {
log_err!("cannot save signature. {}. cannot start", res.unwrap_err());
return Err(());
}
let privkey: PrivKey = keys[3].into();
let pubkey = privkey.to_pub();
if match std::fs::read(sign_path.clone()) {
Err(_) => true,
Ok(file) => {
let sig: Sig = serde_bare::from_slice(&file).map_err(|_| NgdError::InvalidSignature)?;
verify(&vec![110u8, 103u8, 100u8], sig, pubkey)
.map_err(|_| NgdError::InvalidSignature)?;
false
}
} {
// time to save the signature
let sig = sign(&privkey, &pubkey, &vec![110u8, 103u8, 100u8])
.map_err(|e| NgdError::CannotSaveSignature(e.to_string()))?;
let sig_ser = serde_bare::to_vec(&sig).unwrap();
let res = std::fs::write(sign_path, sig_ser)
.map_err(|e| NgdError::CannotSaveSignature(e.to_string()))?;
}
// DEALING WITH CONFIG
@ -466,24 +511,13 @@ async fn main_inner() -> Result<(), ()> {
// 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. {}. cannot start",
res.unwrap_err()
);
return Err(());
}
config = res.ok();
let mut config: Option<DaemonConfig> = match read_to_string(config_path.clone()) {
Err(_) => None,
Ok(file) => Some(from_str(&file).map_err(|e| NgdError::InvalidConfigFile(e.to_string()))?),
};
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(());
return Err(NgdError::ConfigCannotSave);
}
if args.local.is_some()
@ -498,17 +532,11 @@ async fn main_inner() -> Result<(), ()> {
// QUICK CONFIG
if config.is_some() && !args.print_config {
log_err!(
"A config file is present. You cannot use the Quick config options on the command-line. In order to use them, delete your config file first. cannot start"
);
return Err(());
return Err(NgdError::ConfigFilePresent);
}
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(());
return Err(NgdError::ConfigCannotSave);
}
let mut listeners: Vec<ListenerV0> = vec![];
@ -541,17 +569,14 @@ async fn main_inner() -> Result<(), ()> {
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(());
return Err(NgdError::NoLoopback);
}
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, &mut 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")
NgdError::OtherConfigErrorStr("The --domain-peer option has an invalid key. it must be a base64_url encoded serialization of a PrivKey.")
})?;
listener.accept_forward_for = res;
listeners.push(listener);
@ -564,10 +589,7 @@ async fn main_inner() -> Result<(), ()> {
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(());
return Err(NgdError::OtherConfigErrorStr("That's pretty unusual, but no loopback interface could be found on your host."));
}
Some(loopback) => {
overlays_config.server = BrokerOverlayPermission::AllRegisteredUser;
@ -577,10 +599,7 @@ async fn main_inner() -> Result<(), ()> {
&& listeners.last().unwrap().port == args.local.unwrap()
{
if args.domain_peer.is_some() {
log_err!(
"--local is not allowed if --domain-peer is selected, as they both use the same port. change the port of one of them. cannot start"
);
return Err(());
return Err(NgdError::OtherConfigErrorStr( "--local is not allowed if --domain-peer is selected, as they both use the same port. change the port of one of them"));
}
let r = listeners.last_mut().unwrap();
r.accept_direct = true;
@ -605,18 +624,14 @@ async fn main_inner() -> Result<(), ()> {
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 if_name == "default" {
return Err(NgdError::OtherConfigErrorStr("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."));
} else {
return Err(NgdError::OtherConfigError(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(());
)));
}
}
Some(public) => {
overlays_config.core = BrokerOverlayPermission::AllRegisteredUser;
@ -644,19 +659,14 @@ async fn main_inner() -> Result<(), ()> {
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 if_name == "default" {
return Err(NgdError::OtherConfigErrorStr("We could not find a private IP interface on your host for --public option."));
} else {
return Err(NgdError::OtherConfigError(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(());
)));
}
}
Some(inter) => {
private_interface = inter;
@ -666,15 +676,15 @@ async fn main_inner() -> Result<(), ()> {
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(());
return Err(NgdError::OtherConfigErrorStr(
"The provided IPs are not public.",
));
}
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(());
return Err(NgdError::OtherConfigErrorStr(
"The public IP is IPv6 but you selected the --no-ipv6 option.",
));
}
overlays_config.core = BrokerOverlayPermission::AllRegisteredUser;
@ -738,19 +748,14 @@ async fn main_inner() -> Result<(), ()> {
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 if_name == "default" {
return Err(NgdError::OtherConfigErrorStr("We could not find a private IP interface on your host for --dynamic option."));
} else {
return Err(NgdError::OtherConfigError(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(());
)));
}
}
Some(inter) => {
overlays_config.core = BrokerOverlayPermission::AllRegisteredUser;
@ -764,8 +769,7 @@ async fn main_inner() -> Result<(), ()> {
{
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(());
return Err(NgdError::OtherConfigErrorStr("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."));
}
panic!("this should never happen. --dynamic created after a --private");
//r.ipv6 = !args.no_ipv6;
@ -804,25 +808,20 @@ async fn main_inner() -> Result<(), ()> {
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 if_name == "default" {
return Err(NgdError::OtherConfigErrorStr("We could not find a private IP interface on your host for --domain-private option."));
} else {
return Err(NgdError::OtherConfigError(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(());
)));
}
}
Some(inter) => {
overlays_config.server = BrokerOverlayPermission::AllRegisteredUser;
let res = prepare_accept_forward_for_domain(domain, &mut 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")})?;
NgdError::OtherConfigErrorStr("The --domain-peer option has an invalid key. it must be a base64_url encoded serialization of a PrivKey.")})?;
if listeners.last().is_some()
&& listeners.last().unwrap().interface_name == inter.name
@ -830,8 +829,7 @@ async fn main_inner() -> Result<(), ()> {
{
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(());
return Err(NgdError::OtherConfigErrorStr("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."));
}
panic!(
"this should never happen. --domain-private created after a --private"
@ -862,19 +860,17 @@ async fn main_inner() -> Result<(), ()> {
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 {
if if_name == "default" {
return Err(NgdError::OtherConfigErrorStr(
"We could not find a private IP interface on your host.",
));
} else {
return Err(NgdError::OtherConfigError(
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",
"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(());
)));
}
}
Some(inter) => {
overlays_config.server = BrokerOverlayPermission::AllRegisteredUser;
@ -884,10 +880,9 @@ async fn main_inner() -> Result<(), ()> {
&& listeners.last().unwrap().port == arg_value.1
{
if args.domain_peer.is_some() {
log_err!(
"--private is not allowed if --domain-peer is selected, and they both use the same port. change the port of one of them. cannot start"
return Err(NgdError::OtherConfigErrorStr(
"--private is not allowed if --domain-peer is selected, and they both use the same port. change the port of one of them.")
);
return Err(());
}
let r = listeners.last_mut().unwrap();
r.accept_direct = true;
@ -908,13 +903,15 @@ async fn main_inner() -> Result<(), ()> {
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(());
return Err(NgdError::OtherConfigErrorStr(
"The option --forward is invalid. It must contain two parts separated by a @ character."
));
}
let pub_key_array = decode_key(parts[1])
.map_err(|_| log_err!("The PEER_ID provided in the --forward option is invalid"))?;
let pub_key_array = decode_key(parts[1]).map_err(|_| {
NgdError::OtherConfigErrorStr(
"The PEER_ID provided in the --forward option is invalid",
)
})?;
let peer_id = PubKey::Ed25519PubKey(pub_key_array);
let server_type = if parts[0].len() > 0 {
@ -932,8 +929,9 @@ async fn main_inner() -> Result<(), ()> {
} else if is_public_ip(&bind.0) {
BrokerServerTypeV0::Public(vec![bind_addr])
} else {
log_err!("Invalid IP address given for --forward option. cannot start");
return Err(());
return Err(NgdError::OtherConfigErrorStr(
"Invalid IP address given for --forward option.",
));
}
} else {
// a domain name
@ -994,10 +992,10 @@ async fn main_inner() -> Result<(), ()> {
// 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",
NgdError::CannotSaveConfig(format!(
"cannot save config to file. {}.",
e.to_string()
)
))
})?;
log_info!(
"The config file has been saved to {}",
@ -1009,10 +1007,9 @@ async fn main_inner() -> Result<(), ()> {
}
} 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(());
return Err(NgdError::OtherConfigErrorStr(
"No Quick config option passed, neither is a config file present. Choose at least one Quick config option. see --help for details"
));
}
if args.print_config {
let json_string = to_string_pretty(config.as_ref().unwrap()).unwrap();

Loading…
Cancel
Save