Improve config system

Add pkl to generate configs
This commit is contained in:
Tobias Reisinger 2024-02-18 19:50:22 +01:00
parent 8785186dfa
commit b2ff632e64
Signed by: serguzim
GPG key ID: 13AD60C237A28DFE
47 changed files with 916 additions and 277 deletions

View file

@ -25,3 +25,4 @@ sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chro
libsqlite3-sys = { version = "*", features = ["bundled"] }
uuid = "1.6"
futures = "0.3"
libc = "0.2"

View file

@ -1,4 +1,4 @@
fn main() {
println!("cargo:rerun-if-changed=migrations");
println!("cargo:rustc-env=DATABASE_URL=sqlite://emgauwa-dev.sqlite");
println!("cargo:rustc-env=DATABASE_URL=sqlite://_local/emgauwa-dev.sqlite");
}

View file

@ -2,5 +2,6 @@ pub mod constants;
pub mod db;
pub mod errors;
pub mod models;
pub mod settings;
pub mod types;
pub mod utils;

View file

@ -0,0 +1,77 @@
use serde_derive::Deserialize;
use crate::constants;
use crate::errors::EmgauwaError;
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
#[allow(unused)]
pub struct Server {
pub host: String,
pub port: u16,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
#[allow(unused)]
pub struct Logging {
pub level: String,
pub file: String,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
#[allow(unused)]
pub struct Permissions {
pub user: String,
pub group: String,
}
impl Default for Server {
fn default() -> Self {
Server {
host: String::from("127.0.0.1"),
port: constants::DEFAULT_PORT,
}
}
}
impl Default for Logging {
fn default() -> Self {
Logging {
level: String::from("info"),
file: String::from("stdout"),
}
}
}
impl Default for Permissions {
fn default() -> Self {
Permissions {
user: String::from(""),
group: String::from(""),
}
}
}
pub fn load<T>(config_name: &str, env_prefix: &str) -> Result<T, EmgauwaError>
where
for<'de> T: serde::Deserialize<'de>,
{
// TODO: Add switch to only include local config if in development mode
let dev_file =
config::File::with_name(&format!("./_local/emgauwa-{}", config_name)).required(false);
let local_file = config::File::with_name(&format!("./emgauwa-{}", config_name)).required(false);
config::Config::builder()
.add_source(dev_file)
.add_source(local_file)
.add_source(
config::Environment::with_prefix(&format!("EMGAUWA_{}", env_prefix))
.prefix_separator("__")
.separator("__"),
)
.build()?
.try_deserialize::<T>()
.map_err(EmgauwaError::from)
}

View file

@ -1,3 +1,5 @@
use std::ffi::CString;
use std::io::{Error, ErrorKind};
use std::str::FromStr;
use chrono::Datelike;
@ -5,25 +7,9 @@ use log::LevelFilter;
use simple_logger::SimpleLogger;
use crate::errors::EmgauwaError;
use crate::settings::Permissions;
use crate::types::Weekday;
pub fn load_settings<T>(config_name: &str, env_prefix: &str) -> Result<T, EmgauwaError>
where
for<'de> T: serde::Deserialize<'de>,
{
let default_file = config::File::with_name(&format!("emgauwa-{}", config_name)).required(false);
config::Config::builder()
.add_source(default_file)
.add_source(
config::Environment::with_prefix(&format!("EMGAUWA_{}", env_prefix))
.prefix_separator("__")
.separator("__"),
)
.build()?
.try_deserialize::<T>()
.map_err(EmgauwaError::from)
}
pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
let log_level: LevelFilter = LevelFilter::from_str(level)
@ -38,6 +24,67 @@ pub fn init_logging(level: &str) -> Result<(), EmgauwaError> {
Ok(())
}
// https://blog.lxsang.me/post/id/28.0
pub fn drop_privileges(permissions: &Permissions) -> Result<(), Error> {
log::info!(
"Dropping privileges to {}:{}",
permissions.user,
permissions.group
);
// the group id need to be set first, because, when the user privileges drop,
// we are unable to drop the group privileges
if !permissions.group.is_empty() {
drop_privileges_group(&permissions.group)?;
}
if !permissions.user.is_empty() {
drop_privileges_user(&permissions.user)?;
}
Ok(())
}
fn drop_privileges_group(group: &str) -> Result<(), Error> {
// get the gid from username
if let Ok(cstr) = CString::new(group.as_bytes()) {
let p = unsafe { libc::getgrnam(cstr.as_ptr()) };
if p.is_null() {
log::error!("Unable to getgrnam of group: {}", group);
return Err(Error::last_os_error());
}
if unsafe { libc::setgid((*p).gr_gid) } != 0 {
log::error!("Unable to setgid of group: {}", group);
return Err(Error::last_os_error());
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Cannot create CString from String (group)!",
));
}
Ok(())
}
fn drop_privileges_user(user: &str) -> Result<(), Error> {
// get the uid from username
if let Ok(cstr) = CString::new(user.as_bytes()) {
let p = unsafe { libc::getpwnam(cstr.as_ptr()) };
if p.is_null() {
log::error!("Unable to getpwnam of user: {}", user);
return Err(Error::last_os_error());
}
if unsafe { libc::setuid((*p).pw_uid) } != 0 {
log::error!("Unable to setuid of user: {}", user);
return Err(Error::last_os_error());
}
} else {
return Err(Error::new(
ErrorKind::Other,
"Cannot create CString from String (user)!",
));
}
Ok(())
}
pub fn get_weekday() -> Weekday {
(chrono::offset::Local::now()
.date_naive()