Splitting config

This commit is contained in:
Nadja Reitzenstein 2022-03-20 21:22:15 +01:00
parent 28d90f1078
commit b02afe5575
10 changed files with 137 additions and 74 deletions

View File

@ -56,6 +56,7 @@ ptr_meta = "0.1"
rkyv_typename = "0.7" rkyv_typename = "0.7"
rkyv_dyn = "0.7" rkyv_dyn = "0.7"
inventory = "0.1" inventory = "0.1"
linkme = "0.2.10"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
# Password hashing for internal users # Password hashing for internal users
@ -77,7 +78,6 @@ capnp-rpc = "0.14.1"
rsasl = { git = "https://github.com/dequbed/rsasl.git", branch = "main", default_features = false, features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"] } rsasl = { git = "https://github.com/dequbed/rsasl.git", branch = "main", default_features = false, features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"] }
desfire = "0.2.0-alpha1" desfire = "0.2.0-alpha1"
hex = { version = "0.4.3", features = ["serde"] } hex = { version = "0.4.3", features = ["serde"] }
linkme = "0.2.10"
futures-signals = "0.3.22" futures-signals = "0.3.22"
async-oneshot = "0.5" async-oneshot = "0.5"

59
bffhd/capnp/config.rs Normal file
View File

@ -0,0 +1,59 @@
use std::fmt::Formatter;
use std::net::ToSocketAddrs;
use std::path::PathBuf;
use serde::{Serialize, Deserialize};
use crate::config::deser_option;
#[derive(Debug, Clone, Serialize, Deserialize)]
/// API Socket Configuration block.
///
/// One configuration block can result in several sockets if the given `address` resolves to more
/// than one SocketAddr. BFFH will attempt to bind to all of them.
pub struct Listen {
pub address: String,
#[serde(default, skip_serializing_if = "Option::is_none", deserialize_with = "deser_option")]
pub port: Option<u16>,
}
impl Listen {
pub fn to_tuple(&self) -> (&str, u16) {
(self.address.as_str(), self.port.unwrap_or(DEFAULT_PORT))
}
}
impl std::fmt::Display for Listen {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", &self.address, self.port.unwrap_or(DEFAULT_PORT))
}
}
impl ToSocketAddrs for Listen {
type Iter = <(String, u16) as ToSocketAddrs>::Iter;
fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
if let Some(port) = self.port {
(self.address.as_str(), port).to_socket_addrs()
} else {
(self.address.as_str(), DEFAULT_PORT).to_socket_addrs()
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TlsListen {
pub certfile: PathBuf,
pub keyfile: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ciphers: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tls_min_version: Option<String>,
#[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
pub protocols: Vec<String>,
}
// The default port in the non-assignable i.e. free-use area
pub const DEFAULT_PORT: u16 = 59661;

View File

@ -1,6 +1,3 @@
use crate::config::Listen;
use async_net::TcpListener; use async_net::TcpListener;
@ -18,13 +15,12 @@ use std::io;
use std::net::SocketAddr; use std::net::SocketAddr;
use crate::authentication::AuthenticationHandle; use crate::authentication::AuthenticationHandle;
use crate::session::SessionManager; use crate::session::SessionManager;
mod config;
pub use config::{Listen, TlsListen};
mod authenticationsystem; mod authenticationsystem;
mod connection; mod connection;
mod machine; mod machine;

8
bffhd/config/dhall.rs Normal file
View File

@ -0,0 +1,8 @@
use std::path::Path;
use crate::Config;
pub fn read_config_file(path: impl AsRef<Path>) -> Result<Config, serde_dhall::Error> {
serde_dhall::from_file(path)
.parse()
.map_err(Into::into)
}

View File

@ -6,17 +6,23 @@ use serde::{Serialize, Deserialize};
use std::fmt::Formatter; use std::fmt::Formatter;
use std::net::{ToSocketAddrs}; use std::net::{ToSocketAddrs};
use serde_dhall::{SimpleType};
mod dhall;
pub use dhall::read_config_file as read;
use crate::authorization::permissions::{PrivilegesBuf}; use crate::authorization::permissions::{PrivilegesBuf};
use crate::authorization::roles::Role; use crate::authorization::roles::Role;
use crate::capnp::{Listen, TlsListen};
use crate::logging::LogConfig;
type Result<T> = std::result::Result<T, serde_dhall::Error>; pub fn load(path: impl AsRef<Path>, args: &clap::ArgMatches) -> anyhow::Result<Config> {
unimplemented!()
}
pub fn read(path: &Path) -> Result<Config> { pub struct ConfigBlock {
serde_dhall::from_file(path) static_type: SimpleType,
.parse()
.map_err(Into::into)
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -78,7 +84,7 @@ pub struct Config {
pub verbosity: isize, pub verbosity: isize,
#[serde(default, skip)] #[serde(default, skip)]
pub log_format: String, pub logging: LogConfig,
} }
impl Config { impl Config {
@ -105,49 +111,6 @@ pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result<Option<T>, D:
Ok(T::deserialize(d).ok()) Ok(T::deserialize(d).ok())
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Listen {
address: String,
#[serde(default, skip_serializing_if = "Option::is_none", deserialize_with = "deser_option")]
port: Option<u16>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TlsListen {
pub certfile: PathBuf,
pub keyfile: PathBuf,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ciphers: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tls_min_version: Option<String>,
#[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
pub protocols: Vec<String>,
}
impl Listen {
pub fn to_tuple(&self) -> (&str, u16) {
(self.address.as_str(), self.port.unwrap_or(DEFAULT_PORT))
}
}
impl std::fmt::Display for Listen {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", &self.address, self.port.unwrap_or(DEFAULT_PORT))
}
}
impl ToSocketAddrs for Listen {
type Iter = <(String, u16) as ToSocketAddrs>::Iter;
fn to_socket_addrs(&self) -> std::io::Result<Self::Iter> {
if let Some(port) = self.port {
(self.address.as_str(), port).to_socket_addrs()
} else {
(self.address.as_str(), DEFAULT_PORT).to_socket_addrs()
}
}
}
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
@ -194,10 +157,7 @@ impl Default for Config {
tlskeylog: None, tlskeylog: None,
verbosity: 0, verbosity: 0,
log_format: "Full".to_string(), logging: LogConfig::default(),
} }
} }
} }
// The default port in the non-assignable i.e. free-use area
pub const DEFAULT_PORT: u16 = 59661;

View File

@ -40,7 +40,6 @@ mod session;
use std::sync::{Arc}; use std::sync::{Arc};
use anyhow::Context; use anyhow::Context;
@ -79,7 +78,7 @@ pub static RESOURCES: OnceCell<ResourcesHandle> = OnceCell::new();
impl Diflouroborane { impl Diflouroborane {
pub fn new(config: Config) -> anyhow::Result<Self> { pub fn new(config: Config) -> anyhow::Result<Self> {
logging::init(&config); logging::init(&config.logging);
tracing::info!(version=RELEASE_STRING, "Starting"); tracing::info!(version=RELEASE_STRING, "Starting");
let span = tracing::info_span!("setup"); let span = tracing::info_span!("setup");

View File

@ -1,16 +1,46 @@
use tracing_subscriber::{EnvFilter}; use tracing_subscriber::{EnvFilter};
use crate::Config; use crate::Config;
pub fn init(config: &Config) { use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
/// Log filter string in the tracing format `target[span{field=value}]=level`.
/// lvalue is optional and multiple filters can be combined with comma.
/// e.g. `warn,diflouroborane::actors=debug` will only print `WARN` and `ERROR` unless the
/// message is logged in a span below `diflouroborane::actors` (i.e. by an actor task) in
/// which case `DEBUG` and `INFO` will also be printed.
pub filter: Option<String>,
pub format: String,
}
impl Default for LogConfig {
fn default() -> Self {
Self {
filter: None,
format: "full".to_string(),
}
}
}
pub fn init(config: &LogConfig) {
let filter = if let Some(ref filter) = config.filter {
EnvFilter::new(filter.as_str())
} else {
EnvFilter::from_env("BFFH_LOG")
};
let builder = tracing_subscriber::fmt() let builder = tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env()); .with_env_filter(filter);
let format = config.log_format.to_lowercase();
let format = config.format.to_lowercase();
match format.as_str() { match format.as_str() {
"compact" => builder.compact().init(), "compact" => builder.compact().init(),
"pretty" => builder.pretty().init(), "pretty" => builder.pretty().init(),
"full" => builder.init(), "full" => builder.init(),
_ => builder.init(), _ => builder.init(),
} }
tracing::info!(format = format.as_str(), "Logging initialized") tracing::info!(format = format.as_str(), "Logging initialized")
} }

View File

@ -9,7 +9,10 @@ use rkyv_dyn::{DynDeserializer, DynError, DynSerializer};
use crate::utils::oid::ObjectIdentifier; use crate::utils::oid::ObjectIdentifier;
// Not using linkme because dynamically loaded modules
use inventory; use inventory;
use rkyv::ser::{ScratchSpace, Serializer}; use rkyv::ser::{ScratchSpace, Serializer};
use serde::de::Error as SerdeError; use serde::de::Error as SerdeError;
use serde::ser::SerializeMap; use serde::ser::SerializeMap;

View File

@ -8,6 +8,7 @@ use futures_rustls::TlsAcceptor;
use rustls::{Certificate, PrivateKey, ServerConfig, SupportedCipherSuite}; use rustls::{Certificate, PrivateKey, ServerConfig, SupportedCipherSuite};
use rustls::version::{TLS12, TLS13}; use rustls::version::{TLS12, TLS13};
use tracing::{Level}; use tracing::{Level};
use crate::capnp::TlsListen;
use crate::config; use crate::config;
use crate::keylog::KeyLogFile; use crate::keylog::KeyLogFile;
@ -61,7 +62,7 @@ impl TlsConfig {
} }
} }
pub fn make_tls_acceptor(&self, config: &config::TlsListen) -> anyhow::Result<TlsAcceptor> { pub fn make_tls_acceptor(&self, config: &TlsListen) -> anyhow::Result<TlsAcceptor> {
let span = tracing::debug_span!("tls"); let span = tracing::debug_span!("tls");
let _guard = span.enter(); let _guard = span.enter();

View File

@ -1,4 +1,4 @@
use clap::{Arg, Command}; use clap::{Arg, Command, Parser};
use diflouroborane::{config, Diflouroborane}; use diflouroborane::{config, Diflouroborane};
@ -91,16 +91,23 @@ fn main() -> anyhow::Result<()> {
// invalidate the generated TOML // invalidate the generated TOML
let stdout = io::stdout(); let stdout = io::stdout();
let mut handle = stdout.lock(); let mut handle = stdout.lock();
handle.write_all(&encoded.as_bytes()).unwrap(); handle.write_all(encoded.as_bytes()).unwrap();
// Early return to exit. // Early return to exit.
return Ok(()); return Ok(());
} else if matches.is_present("check config") { } else if matches.is_present("check config") {
match config::read(&PathBuf::from_str(configpath).unwrap()) { match config::read(&PathBuf::from_str(configpath).unwrap()) {
Ok(c) => { Ok(c) => {
println!("{:#?}", c); let formatted = format!("{:#?}", c);
println!("config is valid");
std::process::exit(0); // Direct writing to fd 1 is faster but also prevents any print-formatting that could
// invalidate the generated TOML
let stdout = io::stdout();
let mut handle = stdout.lock();
handle.write_all(formatted.as_bytes()).unwrap();
// Early return to exit.
return Ok(());
} }
Err(e) => { Err(e) => {
eprintln!("{}", e); eprintln!("{}", e);
@ -140,7 +147,7 @@ fn main() -> anyhow::Result<()> {
if config.verbosity == 0 && matches.is_present("quiet") { if config.verbosity == 0 && matches.is_present("quiet") {
config.verbosity = -1; config.verbosity = -1;
} }
config.log_format = matches.value_of("log format").unwrap_or("Full").to_string(); config.logging.format = matches.value_of("log format").unwrap_or("full").to_string();
let mut bffh = Diflouroborane::new(config)?; let mut bffh = Diflouroborane::new(config)?;
bffh.run()?; bffh.run()?;