use std::collections::HashMap; use std::default::Default; use std::fmt::Debug; use std::path::PathBuf; use serde::{Deserialize, Serialize}; use crate::authorization::permissions::{PermRule, PermissionBuf, PrivilegesBuf}; use crate::authorization::roles::Role; use crate::capnp::{Listen, TlsListen}; use crate::logging::LogConfig; use std::path::Path; #[derive(Debug)] struct DhallConfig<'a> { path: &'a Path, } pub fn read_config_file(path: impl AsRef) -> Result { serde_dhall::from_file(path).parse().map_err(Into::into) } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(deny_unknown_fields)] /// A description of a machine /// /// This is the struct that a machine is serialized to/from. /// Combining this with the actual state of the system will return a machine pub struct MachineDescription { /// The name of the machine. Doesn't need to be unique but is what humans will be presented. pub name: String, /// An optional description of the Machine. #[serde( default, skip_serializing_if = "Option::is_none", deserialize_with = "deser_option" )] pub description: Option, #[serde( default, skip_serializing_if = "Option::is_none", deserialize_with = "deser_option" )] pub wiki: Option, #[serde( default, skip_serializing_if = "Option::is_none", deserialize_with = "deser_option" )] pub category: Option, /// The permission required #[serde(flatten)] pub privs: PrivilegesBuf, #[serde(default = "default_prodable", skip_serializing_if = "bool_is_false", deserialize_with = "deser_bool")] pub prodable: bool, } fn default_prodable() -> bool { false } fn bool_is_false(b: &bool) -> bool { !b } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { pub spacename: String, pub instanceurl: String, /// A list of address/port pairs to listen on. pub listens: Vec, #[serde(flatten)] pub tlsconfig: TlsListen, #[serde(default, skip_serializing_if = "Option::is_none")] pub tlskeylog: Option, #[serde(default, skip)] pub verbosity: isize, #[serde(default, skip)] pub logging: LogConfig, pub mqtt_url: String, pub db_path: PathBuf, pub auditlog_path: PathBuf, pub roles: HashMap, /// Machine descriptions to load pub machines: HashMap, /// Actors to load and their configuration options pub actors: HashMap, pub actor_connections: Vec, /// Initiators to load and their configuration options pub initiators: HashMap, pub init_connections: Vec, } impl Config { pub fn is_quiet(&self) -> bool { self.verbosity < 0 } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ModuleConfig { pub module: String, pub params: HashMap, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ParamsConfig { pub module: String, pub params: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ActorConnectionConfig { pub machine: String, pub actor: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitiatorConnectionConfig { pub machine: String, pub initiator: String, } fn deser_bool<'de, D>(d: D) -> Result where D: serde::Deserializer<'de>, { Ok(bool::deserialize(d).unwrap_or(false)) } pub(crate) fn deser_option<'de, D, T>(d: D) -> std::result::Result, D::Error> where D: serde::Deserializer<'de>, T: serde::Deserialize<'de>, { Ok(T::deserialize(d).ok()) } impl Default for Config { fn default() -> Self { let mut actors: HashMap = HashMap::new(); let mut initiators: HashMap = HashMap::new(); let mut roles: HashMap = HashMap::new(); let mut machines: HashMap = HashMap::new(); let mut initiator_123_params: HashMap = HashMap::new(); initiator_123_params.insert("args".to_string(), "".to_string()); initiator_123_params.insert("cmd".to_string(), "echo".to_string()); let actor_connections_vec: Vec = vec![ActorConnectionConfig { machine: "resource_a".to_string(), actor: "actor_123".to_string(), }]; let initiator_connections_vec: Vec = vec![InitiatorConnectionConfig { machine: "resource_a".to_string(), initiator: "initiator_123".to_string(), }]; roles.insert( "admin".to_string(), Role { parents: Vec::new(), permissions: vec![ PermRule::Base(PermissionBuf { inner: "bffh.users.info".to_string(), }), PermRule::Base(PermissionBuf { inner: "bffh.users.manage".to_string(), }), PermRule::Base(PermissionBuf { inner: "bffh.users.admin".to_string(), }), ], }, ); roles.insert( "member".to_string(), Role { parents: Vec::new(), permissions: vec![ PermRule::Base(PermissionBuf { inner: "lab.some.disclose".to_string(), }), PermRule::Base(PermissionBuf { inner: "lab.some.read".to_string(), }), PermRule::Base(PermissionBuf { inner: "lab.some.write".to_string(), }), PermRule::Base(PermissionBuf { inner: "lab.some.manage".to_string(), }), ], }, ); machines.insert( "resource_a".to_string(), MachineDescription { name: "Resource A".to_string(), description: Option::from("A description".to_string()), wiki: Option::from("https://some.wiki.url".to_string()), category: Option::from("A category".to_string()), prodable: true, privs: PrivilegesBuf { disclose: PermissionBuf { inner: "lab.some.disclose".to_string(), }, read: PermissionBuf { inner: "lab.some.read".to_string(), }, write: PermissionBuf { inner: "lab.some.write".to_string(), }, manage: PermissionBuf { inner: "lab.some.manage".to_string(), }, }, }, ); machines.insert( "resource_b".to_string(), MachineDescription { name: "Resource B".to_string(), description: Option::from("A description".to_string()), wiki: Option::from("https://some.wiki.url".to_string()), category: Option::from("A category".to_string()), prodable: false, privs: PrivilegesBuf { disclose: PermissionBuf { inner: "lab.some.disclose".to_string(), }, read: PermissionBuf { inner: "lab.some.read".to_string(), }, write: PermissionBuf { inner: "lab.some.write".to_string(), }, manage: PermissionBuf { inner: "lab.some.manage".to_string(), }, }, }, ); actors.insert( "actor_123".to_string(), ModuleConfig { module: "Shelly".to_string(), params: HashMap::new(), }, ); initiators.insert( "initiator_123".to_string(), ModuleConfig { module: "Process".to_string(), params: initiator_123_params, }, ); Config { spacename: "fabaccess.sample.space".into(), instanceurl: "https://fabaccess.sample.space".into(), listens: vec![Listen { address: "127.0.0.1".to_string(), port: None, }], tlsconfig: TlsListen { certfile: PathBuf::from("/etc/bffh/certs/bffh.crt"), keyfile: PathBuf::from("/etc/bffh/certs/bffh.key"), ..Default::default() }, tlskeylog: None, verbosity: 0, logging: LogConfig::default(), mqtt_url: "mqtt://127.0.0.1:1883".to_string(), db_path: PathBuf::from("/var/lib/bffh/bffh.db"), auditlog_path: PathBuf::from("/var/log/bffh/audit.json"), roles, machines, actors, actor_connections: actor_connections_vec, initiators, init_connections: initiator_connections_vec, } } }