diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..44fa6b4 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[alias] +format = "+nightly fmt" +lint = "clippy --all-targets --all-features -- -D warnings" diff --git a/.env b/.env index 2f5ee4c..78b6033 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -DATABASE_URL="sqlite://emgauwa-dev.sqlite" +DATABASE_URL="sqlite://_local/emgauwa-dev.sqlite" diff --git a/.gitignore b/.gitignore index 734f922..be8fe54 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,10 @@ /tests/testing_bak/ /tests/testing_latest/ +/_local/ emgauwa-*.sqlite emgauwa-*.sqlite-* +emgauwa-*.json # Added by cargo diff --git a/.sqlx/query-0874e71c6206efc82528cc450bc86549c43e9be2f4ac3b257e836187fa9ed080.json b/.sqlx/query-0874e71c6206efc82528cc450bc86549c43e9be2f4ac3b257e836187fa9ed080.json new file mode 100644 index 0000000..9b1f908 Binary files /dev/null and b/.sqlx/query-0874e71c6206efc82528cc450bc86549c43e9be2f4ac3b257e836187fa9ed080.json differ diff --git a/.sqlx/query-1d658709678f72291d835ef2a4183d24f993442ea05e17910f587a4c92d4e7f5.json b/.sqlx/query-1d658709678f72291d835ef2a4183d24f993442ea05e17910f587a4c92d4e7f5.json deleted file mode 100644 index f9ef3de..0000000 Binary files a/.sqlx/query-1d658709678f72291d835ef2a4183d24f993442ea05e17910f587a4c92d4e7f5.json and /dev/null differ diff --git a/.sqlx/query-20e99a281e5e3e9c9d7375425d93d15ccf840e9f469007d37b6eb47f96f31dc7.json b/.sqlx/query-20e99a281e5e3e9c9d7375425d93d15ccf840e9f469007d37b6eb47f96f31dc7.json new file mode 100644 index 0000000..776039b Binary files /dev/null and b/.sqlx/query-20e99a281e5e3e9c9d7375425d93d15ccf840e9f469007d37b6eb47f96f31dc7.json differ diff --git a/.sqlx/query-3b5a701d0ace12125c573680bcd5d9768b3709b347afb04c329b8fb1d3972111.json b/.sqlx/query-3b5a701d0ace12125c573680bcd5d9768b3709b347afb04c329b8fb1d3972111.json new file mode 100644 index 0000000..390622e Binary files /dev/null and b/.sqlx/query-3b5a701d0ace12125c573680bcd5d9768b3709b347afb04c329b8fb1d3972111.json differ diff --git a/.sqlx/query-4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111.json b/.sqlx/query-4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111.json new file mode 100644 index 0000000..78e4867 Binary files /dev/null and b/.sqlx/query-4f5408e64f5e6a8dd923c3b147f993ce9e4cafc90204b06977481130ec06d111.json differ diff --git a/.sqlx/query-52958684fa52b7a4753cd4356482dc6c655102a501d8aa48e03b1fb3dbbad02d.json b/.sqlx/query-52958684fa52b7a4753cd4356482dc6c655102a501d8aa48e03b1fb3dbbad02d.json new file mode 100644 index 0000000..63080c4 Binary files /dev/null and b/.sqlx/query-52958684fa52b7a4753cd4356482dc6c655102a501d8aa48e03b1fb3dbbad02d.json differ diff --git a/.sqlx/query-5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465.json b/.sqlx/query-5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465.json new file mode 100644 index 0000000..67ea7e8 Binary files /dev/null and b/.sqlx/query-5865f27b97487b6dfd956a3d260b9bbb0e6c203b721d29cf9149f60bfdd93465.json differ diff --git a/.sqlx/query-711398eb64710a25cc818167be8f3b2d03cab39116c2732c06e3c74a02fb0367.json b/.sqlx/query-711398eb64710a25cc818167be8f3b2d03cab39116c2732c06e3c74a02fb0367.json new file mode 100644 index 0000000..4409006 Binary files /dev/null and b/.sqlx/query-711398eb64710a25cc818167be8f3b2d03cab39116c2732c06e3c74a02fb0367.json differ diff --git a/.sqlx/query-7bbe1a982c77194feba2ff610b01e824b99a3888adf5365619ecfed7ae6544a9.json b/.sqlx/query-7bbe1a982c77194feba2ff610b01e824b99a3888adf5365619ecfed7ae6544a9.json new file mode 100644 index 0000000..217c70f Binary files /dev/null and b/.sqlx/query-7bbe1a982c77194feba2ff610b01e824b99a3888adf5365619ecfed7ae6544a9.json differ diff --git a/.sqlx/query-7cd5b42013b4e6a37a670e55cd3ceb0911001eee41256f7b324edc72f5cadcba.json b/.sqlx/query-7cd5b42013b4e6a37a670e55cd3ceb0911001eee41256f7b324edc72f5cadcba.json new file mode 100644 index 0000000..8d846ef Binary files /dev/null and b/.sqlx/query-7cd5b42013b4e6a37a670e55cd3ceb0911001eee41256f7b324edc72f5cadcba.json differ diff --git a/.sqlx/query-7e7cdf2650c08feb10a35275e693d0d3c690b4e9bccc6f0f5fed2bfd2826b480.json b/.sqlx/query-7e7cdf2650c08feb10a35275e693d0d3c690b4e9bccc6f0f5fed2bfd2826b480.json new file mode 100644 index 0000000..c9df19d Binary files /dev/null and b/.sqlx/query-7e7cdf2650c08feb10a35275e693d0d3c690b4e9bccc6f0f5fed2bfd2826b480.json differ diff --git a/.sqlx/query-90ed2cd2f8161552dae06ab2d9cfee8914e253db00e6a648a78e99ade6a4de60.json b/.sqlx/query-90ed2cd2f8161552dae06ab2d9cfee8914e253db00e6a648a78e99ade6a4de60.json new file mode 100644 index 0000000..9be1170 Binary files /dev/null and b/.sqlx/query-90ed2cd2f8161552dae06ab2d9cfee8914e253db00e6a648a78e99ade6a4de60.json differ diff --git a/.sqlx/query-921a0775f75d9e2f67f604265872bf715af1e1ed4d420ac6fa132a94ff352e56.json b/.sqlx/query-921a0775f75d9e2f67f604265872bf715af1e1ed4d420ac6fa132a94ff352e56.json new file mode 100644 index 0000000..a7c8c1e Binary files /dev/null and b/.sqlx/query-921a0775f75d9e2f67f604265872bf715af1e1ed4d420ac6fa132a94ff352e56.json differ diff --git a/.sqlx/query-a1f5699889cfabb3f681e6bb71a8d7c739d0cb82eea1f8289d012c37bd30c776.json b/.sqlx/query-a1f5699889cfabb3f681e6bb71a8d7c739d0cb82eea1f8289d012c37bd30c776.json new file mode 100644 index 0000000..2dfa516 Binary files /dev/null and b/.sqlx/query-a1f5699889cfabb3f681e6bb71a8d7c739d0cb82eea1f8289d012c37bd30c776.json differ diff --git a/.sqlx/query-a64694ec1a81472a05a68b1caf64c32a261bb7d1f34577c0f4dc52e318124ecd.json b/.sqlx/query-a64694ec1a81472a05a68b1caf64c32a261bb7d1f34577c0f4dc52e318124ecd.json new file mode 100644 index 0000000..cd86c5f Binary files /dev/null and b/.sqlx/query-a64694ec1a81472a05a68b1caf64c32a261bb7d1f34577c0f4dc52e318124ecd.json differ diff --git a/.sqlx/query-ab8dafa95af67dc06074e83e1ec61be2fe713637f883d175f9b279f0f2f8fd87.json b/.sqlx/query-ab8dafa95af67dc06074e83e1ec61be2fe713637f883d175f9b279f0f2f8fd87.json new file mode 100644 index 0000000..24cf02e Binary files /dev/null and b/.sqlx/query-ab8dafa95af67dc06074e83e1ec61be2fe713637f883d175f9b279f0f2f8fd87.json differ diff --git a/.sqlx/query-b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153.json b/.sqlx/query-b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153.json new file mode 100644 index 0000000..94419bd Binary files /dev/null and b/.sqlx/query-b41855e635ac409559fa63cba4c1285034c573b86e3193da3995606dee412153.json differ diff --git a/.sqlx/query-c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2.json b/.sqlx/query-c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2.json new file mode 100644 index 0000000..10fe1a3 Binary files /dev/null and b/.sqlx/query-c9437ff0c3014b269dcb21304fbad12237b9cb69ea6aa4686df6d5262065faa2.json differ diff --git a/.sqlx/query-cbda6fd5137f3698537262772df22a0a66064e3416e4f5c89d8d83fa6c0536ad.json b/.sqlx/query-cbda6fd5137f3698537262772df22a0a66064e3416e4f5c89d8d83fa6c0536ad.json new file mode 100644 index 0000000..fb83516 Binary files /dev/null and b/.sqlx/query-cbda6fd5137f3698537262772df22a0a66064e3416e4f5c89d8d83fa6c0536ad.json differ diff --git a/.sqlx/query-acfc608095768f30a55eb0298dfe86d095af0af9545252cf06f30827e9ca502a.json b/.sqlx/query-cdcae4768f7b62390e5e5da850e301b502ffd56dd88485cd73b694f6559ccd4e.json similarity index 76% rename from .sqlx/query-acfc608095768f30a55eb0298dfe86d095af0af9545252cf06f30827e9ca502a.json rename to .sqlx/query-cdcae4768f7b62390e5e5da850e301b502ffd56dd88485cd73b694f6559ccd4e.json index a85a644..97b4b65 100644 Binary files a/.sqlx/query-acfc608095768f30a55eb0298dfe86d095af0af9545252cf06f30827e9ca502a.json and b/.sqlx/query-cdcae4768f7b62390e5e5da850e301b502ffd56dd88485cd73b694f6559ccd4e.json differ diff --git a/.sqlx/query-e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f.json b/.sqlx/query-e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f.json new file mode 100644 index 0000000..391ca72 Binary files /dev/null and b/.sqlx/query-e94ef5bc8b267d493375bb371dcfb7b09f6355ecbc8b6e1085d5f2f9a08cac3f.json differ diff --git a/.sqlx/query-ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d.json b/.sqlx/query-ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d.json new file mode 100644 index 0000000..c4ec08d Binary files /dev/null and b/.sqlx/query-ee7da56331bece2efe21b55dbd5f420d3abb08358a1abe301dc7e08693fbef4d.json differ diff --git a/.sqlx/query-f75318134ec1facc3de6b04232cb28a92524b8f556840b76f76c8f317059e668.json b/.sqlx/query-f75318134ec1facc3de6b04232cb28a92524b8f556840b76f76c8f317059e668.json new file mode 100644 index 0000000..88dc7d1 Binary files /dev/null and b/.sqlx/query-f75318134ec1facc3de6b04232cb28a92524b8f556840b76f76c8f317059e668.json differ diff --git a/.sqlx/query-f7b90a6a0af3f7d7c96158f96f1ada06827a0e5a2d2dbd48bfb8e04f973a6131.json b/.sqlx/query-f7b90a6a0af3f7d7c96158f96f1ada06827a0e5a2d2dbd48bfb8e04f973a6131.json new file mode 100644 index 0000000..caa30a4 Binary files /dev/null and b/.sqlx/query-f7b90a6a0af3f7d7c96158f96f1ada06827a0e5a2d2dbd48bfb8e04f973a6131.json differ diff --git a/Makefile b/Makefile index 9aa026d..09287c7 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,15 @@ - -build: - cargo build - -sqlx-prepare: - rm -f ./emgauwa-dev.sqlite +sqlx: + cargo sqlx database drop cargo sqlx database create cargo sqlx migrate run - -sqlx: sqlx-prepare cargo sqlx prepare --workspace build-rpi: cross build --target arm-unknown-linux-gnueabihf -clean-db: - rm ./emgauwa-*.sqlite || true - $(MAKE) sqlx-prepare +_local/emgauwa-%.json: config/emgauwa-%.pkl config/lib/%.pkl config/lib/common.pkl + pkl eval -f json -o $@ $< -format: - cargo +nightly fmt - -lint: - cargo clippy --all-targets --all-features -- -D warnings +configs: + $(MAKE) _local/emgauwa-core.json + $(MAKE) _local/emgauwa-controller.json diff --git a/config/emgauwa-controller.pkl b/config/emgauwa-controller.pkl new file mode 100644 index 0000000..e38f6d4 --- /dev/null +++ b/config/emgauwa-controller.pkl @@ -0,0 +1,71 @@ +amends "./lib/controller.pkl" + +server { + host = "127.0.0.1" + port = 4419 +} + +database = "sqlite://_local/emgauwa-controller.sqlite" + +permissions { + user = "emgauwa" + group = "emgauwa" +} + +logging { + level = "DEBUG" + file = "stdout" +} + +relays { + new { + driver = "gpio" + pin = 5 + inverted = true + } + new { + driver = "gpio" + pin = 4 + inverted = true + } + new { + driver = "gpio" + pin = 3 + inverted = true + } + new { + driver = "gpio" + pin = 2 + inverted = true + } + new { + driver = "gpio" + pin = 1 + inverted = true + } + new { + driver = "gpio" + pin = 0 + inverted = true + } + new { + driver = "gpio" + pin = 16 + inverted = true + } + new { + driver = "gpio" + pin = 15 + inverted = true + } + new { + driver = "piface" + pin = 1 + inverted = false + } + new { + driver = "piface" + pin = 0 + inverted = false + } +} diff --git a/config/emgauwa-core.pkl b/config/emgauwa-core.pkl new file mode 100644 index 0000000..e9f467d --- /dev/null +++ b/config/emgauwa-core.pkl @@ -0,0 +1,18 @@ +amends "./lib/core.pkl" + +server { + host = "127.0.0.1" + port = 4419 +} + +database = "sqlite://_local/emgauwa-core.sqlite" + +permissions { + user = "emgauwa" + group = "emgauwa" +} + +logging { + level = "DEBUG" + file = "stdout" +} diff --git a/config/lib/common.pkl b/config/lib/common.pkl new file mode 100644 index 0000000..e5bb22e --- /dev/null +++ b/config/lib/common.pkl @@ -0,0 +1,15 @@ +class ServerConfig { + host: String + port: UInt16 +} + +/// Set to a user and a group to drop privileges to after binding to the port +class PermissionsConfig { + user: String + group: String +} + +class LoggingConfig { + level: String + file: String +} diff --git a/config/lib/controller.pkl b/config/lib/controller.pkl new file mode 100644 index 0000000..05a8efd --- /dev/null +++ b/config/lib/controller.pkl @@ -0,0 +1,16 @@ +import "./common.pkl" + +server: common.ServerConfig + +database: String + +permissions: common.PermissionsConfig + +logging: common.LoggingConfig + +class RelayConfig { + driver: "gpio" | "piface" + pin: Number + inverted: Boolean +} +relays: Listing diff --git a/config/lib/core.pkl b/config/lib/core.pkl new file mode 100644 index 0000000..d522e17 --- /dev/null +++ b/config/lib/core.pkl @@ -0,0 +1,12 @@ +import "./common.pkl" + +server: common.ServerConfig + +database: String + +permissions: common.PermissionsConfig + +logging: common.LoggingConfig + +/// Leave empty to allow all origins (will always respond with Origin and not "*") +origins: Listing diff --git a/emgauwa-controller.toml b/emgauwa-controller.toml deleted file mode 100644 index 6e27e0a..0000000 --- a/emgauwa-controller.toml +++ /dev/null @@ -1,60 +0,0 @@ -database = "sqlite://emgauwa-controller.sqlite" -name = "Emgauwa Controller" - -[core] -port = 4419 -host = "127.0.0.1" - -[logging] -level = "DEBUG" -file = "stdout" - -[[relays]] -driver = "gpio" -pin = 5 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 4 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 3 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 2 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 1 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 0 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 16 -inverted = 1 - -[[relays]] -driver = "gpio" -pin = 15 -inverted = 1 - -[[relays]] -driver = "piface" -pin = 1 -inverted = 0 - -[[relays]] -driver = "piface" -pin = 0 -inverted = 0 diff --git a/emgauwa-controller/src/main.rs b/emgauwa-controller/src/main.rs index c6920fa..600e924 100644 --- a/emgauwa-controller/src/main.rs +++ b/emgauwa-controller/src/main.rs @@ -4,7 +4,7 @@ use emgauwa_lib::db::{DbController, DbJunctionRelaySchedule, DbRelay, DbSchedule use emgauwa_lib::errors::EmgauwaError; use emgauwa_lib::models::{Controller, FromDbModel}; use emgauwa_lib::types::ControllerUid; -use emgauwa_lib::utils::init_logging; +use emgauwa_lib::utils::{drop_privileges, init_logging}; use sqlx::pool::PoolConnection; use sqlx::Sqlite; @@ -59,6 +59,9 @@ async fn create_this_relay( #[actix::main] async fn main() -> Result<(), std::io::Error> { let settings = settings::init()?; + + drop_privileges(&settings.permissions)?; + init_logging(&settings.logging.level)?; let pool = db::init(&settings.database) @@ -105,7 +108,7 @@ async fn main() -> Result<(), std::io::Error> { let url = format!( "ws://{}:{}/api/v1/ws/controllers", - settings.core.host, settings.core.port + settings.server.host, settings.server.port ); diff --git a/emgauwa-controller/src/settings.rs b/emgauwa-controller/src/settings.rs index d9b86e4..8e0da84 100644 --- a/emgauwa-controller/src/settings.rs +++ b/emgauwa-controller/src/settings.rs @@ -1,25 +1,9 @@ use emgauwa_lib::errors::EmgauwaError; -use emgauwa_lib::{constants, utils}; +use emgauwa_lib::settings; use serde_derive::Deserialize; use crate::driver::Driver; -#[derive(Clone, Debug, Deserialize)] -#[serde(default)] -#[allow(unused)] -pub struct Core { - 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)] @@ -35,9 +19,11 @@ pub struct Relay { #[serde(default)] #[allow(unused)] pub struct Settings { - pub core: Core, + pub server: settings::Server, pub database: String, - pub logging: Logging, + pub permissions: settings::Permissions, + pub logging: settings::Logging, + pub name: String, pub relays: Vec, } @@ -45,9 +31,11 @@ pub struct Settings { impl Default for Settings { fn default() -> Self { Settings { - core: Core::default(), - database: String::from("sqlite://emgauwa-controller.sqlite"), - logging: Logging::default(), + server: settings::Server::default(), + database: String::from("sqlite://_local/emgauwa-controller.sqlite"), + permissions: settings::Permissions::default(), + logging: settings::Logging::default(), + name: String::from("Emgauwa Controller"), relays: Vec::new(), } @@ -66,26 +54,8 @@ impl Default for Relay { } } -impl Default for Core { - fn default() -> Self { - Core { - 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"), - } - } -} - pub fn init() -> Result { - let mut settings: Settings = utils::load_settings("controller", "CONTROLLER")?; + let mut settings: Settings = settings::load("controller", "CONTROLLER")?; for (num, relay) in settings.relays.iter_mut().enumerate() { if relay.number.is_none() { diff --git a/emgauwa-core.toml b/emgauwa-core.toml deleted file mode 100644 index e2f54d6..0000000 --- a/emgauwa-core.toml +++ /dev/null @@ -1,15 +0,0 @@ -port = 4419 -host = "127.0.0.1" - -# Set to a user and a group to drop privileges to after binding to the port -#user = "emgauwa" -#group = "emgauwa" - -# Leave empty to allow all origins (will always respond with Origin and not "*") -#origins = ["http://localhost", "https://emgauwa.app"] - -database = "sqlite://emgauwa-core.sqlite" - -[logging] -level = "DEBUG" -file = "stdout" diff --git a/emgauwa-core/Cargo.toml b/emgauwa-core/Cargo.toml index 731bff4..db61748 100644 --- a/emgauwa-core/Cargo.toml +++ b/emgauwa-core/Cargo.toml @@ -24,4 +24,3 @@ serde_derive = "1.0" sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio", "macros", "chrono"] } futures = "0.3.29" -libc = "0.2" diff --git a/emgauwa-core/build.rs b/emgauwa-core/build.rs index 41015be..9611aff 100644 --- a/emgauwa-core/build.rs +++ b/emgauwa-core/build.rs @@ -1,3 +1,3 @@ fn main() { - println!("cargo:rustc-env=DATABASE_URL=sqlite://emgauwa-core.sqlite") + println!("cargo:rustc-env=DATABASE_URL=sqlite://_local/emgauwa-core.sqlite") } diff --git a/emgauwa-core/src/main.rs b/emgauwa-core/src/main.rs index 10320cc..ba632af 100644 --- a/emgauwa-core/src/main.rs +++ b/emgauwa-core/src/main.rs @@ -6,10 +6,9 @@ use actix_web::middleware::TrailingSlash; use actix_web::{middleware, web, App, HttpServer}; use emgauwa_lib::db::DbController; use emgauwa_lib::errors::EmgauwaError; -use emgauwa_lib::utils::init_logging; +use emgauwa_lib::utils::{drop_privileges, init_logging}; use crate::app_state::AppState; -use crate::utils::drop_privileges; mod app_state; mod handlers; @@ -19,12 +18,12 @@ mod utils; #[actix_web::main] async fn main() -> Result<(), std::io::Error> { let settings = settings::init()?; + + let listener = TcpListener::bind(format!("{}:{}", settings.server.host, settings.server.port))?; + drop_privileges(&settings.permissions)?; + init_logging(&settings.logging.level)?; - let listener = TcpListener::bind(format!("{}:{}", settings.host, settings.port))?; - - drop_privileges(&settings)?; - let pool = emgauwa_lib::db::init(&settings.database).await?; let mut conn = pool.acquire().await.map_err(EmgauwaError::from)?; @@ -35,7 +34,11 @@ async fn main() -> Result<(), std::io::Error> { let app_state = AppState::new(pool.clone()).start(); - log::info!("Starting server on {}:{}", settings.host, settings.port); + log::info!( + "Starting server on {}:{}", + settings.server.host, + settings.server.port + ); HttpServer::new(move || { let cors = Cors::default().allow_any_method().allow_any_header(); diff --git a/emgauwa-core/src/settings.rs b/emgauwa-core/src/settings.rs index 115efa6..5277efa 100644 --- a/emgauwa-core/src/settings.rs +++ b/emgauwa-core/src/settings.rs @@ -1,57 +1,32 @@ use emgauwa_lib::errors::EmgauwaError; -use emgauwa_lib::{constants, utils}; +use emgauwa_lib::settings; use serde_derive::Deserialize; -#[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 Settings { + pub server: settings::Server, pub database: String, + pub permissions: settings::Permissions, + pub logging: settings::Logging, - pub host: String, - pub port: u16, pub origins: Vec, - - pub user: String, - pub group: String, - - pub logging: Logging, } impl Default for Settings { fn default() -> Self { Settings { - database: String::from("sqlite://emgauwa-core.sqlite"), + server: settings::Server::default(), + database: String::from("sqlite://_local/emgauwa-core.sqlite"), + permissions: settings::Permissions::default(), + logging: settings::Logging::default(), - host: String::from("127.0.0.1"), - port: constants::DEFAULT_PORT, origins: Vec::new(), - - user: String::from(""), - group: String::from(""), - - logging: Logging::default(), - } - } -} - -impl Default for Logging { - fn default() -> Self { - Logging { - level: String::from("info"), - file: String::from("stdout"), } } } pub fn init() -> Result { - utils::load_settings("core", "CORE") + settings::load("core", "CORE") } diff --git a/emgauwa-core/src/utils.rs b/emgauwa-core/src/utils.rs index 02f1d43..a35de53 100644 --- a/emgauwa-core/src/utils.rs +++ b/emgauwa-core/src/utils.rs @@ -1,8 +1,3 @@ -use std::ffi::CString; -use std::io::{Error, ErrorKind}; - -use crate::settings::Settings; - pub fn flatten_result(res: Result, E>) -> Result { match res { Ok(Ok(t)) => Ok(t), @@ -10,64 +5,3 @@ pub fn flatten_result(res: Result, E>) -> Result { Err(e) => Err(e), } } - -// https://blog.lxsang.me/post/id/28.0 -pub fn drop_privileges(settings: &Settings) -> Result<(), Error> { - log::info!( - "Dropping privileges to {}:{}", - settings.user, - settings.group - ); - - // the group id need to be set first, because, when the user privileges drop, - // we are unable to drop the group privileges - if !settings.group.is_empty() { - drop_privileges_group(&settings.group)?; - } - if !settings.user.is_empty() { - drop_privileges_user(&settings.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(()) -} diff --git a/emgauwa-lib/Cargo.toml b/emgauwa-lib/Cargo.toml index bca69c9..d4ffd05 100644 --- a/emgauwa-lib/Cargo.toml +++ b/emgauwa-lib/Cargo.toml @@ -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" diff --git a/emgauwa-lib/build.rs b/emgauwa-lib/build.rs index 65d8d11..493491e 100644 --- a/emgauwa-lib/build.rs +++ b/emgauwa-lib/build.rs @@ -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"); } diff --git a/emgauwa-lib/src/lib.rs b/emgauwa-lib/src/lib.rs index ddaf738..f939d0c 100644 --- a/emgauwa-lib/src/lib.rs +++ b/emgauwa-lib/src/lib.rs @@ -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; diff --git a/emgauwa-lib/src/settings.rs b/emgauwa-lib/src/settings.rs new file mode 100644 index 0000000..1e83244 --- /dev/null +++ b/emgauwa-lib/src/settings.rs @@ -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(config_name: &str, env_prefix: &str) -> Result +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::() + .map_err(EmgauwaError::from) +} diff --git a/emgauwa-lib/src/utils.rs b/emgauwa-lib/src/utils.rs index 8c4f17e..b6419ad 100644 --- a/emgauwa-lib/src/utils.rs +++ b/emgauwa-lib/src/utils.rs @@ -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(config_name: &str, env_prefix: &str) -> Result -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::() - .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()