From 7024a1fa280602a96c0ca3eecce5a40149f496c9 Mon Sep 17 00:00:00 2001 From: reidlab Date: Tue, 17 Oct 2023 17:19:50 -0700 Subject: [PATCH] config rework --- config.example.toml | 2 - readme.md | 9 ++- src/config.rs | 65 +++++++--------------- src/endpoints/accounts/register_account.rs | 10 ++-- src/endpoints/levels/download_level.rs | 3 +- src/endpoints/levels/upload_level.rs | 12 ++-- src/main.rs | 11 ++-- src/template_endpoints/reupload.rs | 7 ++- 8 files changed, 49 insertions(+), 70 deletions(-) diff --git a/config.example.toml b/config.example.toml index 16a518f..d0a834d 100644 --- a/config.example.toml +++ b/config.example.toml @@ -13,8 +13,6 @@ append_path = "/" # where can your server be accessible? port = 8000 -# your realip header, if you're behind a reverse proxy -realip_header = "X-Real-IP" [accounts] # allow new accounts to be created diff --git a/readme.md b/readme.md index a5ec559..e316e8f 100644 --- a/readme.md +++ b/readme.md @@ -33,8 +33,9 @@ i've run out of ideas. ## todo - User icons in account management pages +- Flesh out account management page - Account settings page -- Better web design +- Better web design (make formatting more consistant) - Use chrono for dates in database, add recent - 2.2's friends only unlisted - Dailies, weeklies, events(?) @@ -43,4 +44,8 @@ i've run out of ideas. - Cache authentication - Panic less - Make a proper rank system (reuploading, uploading music, rating, etc.) -- Swap to a better web framework \ No newline at end of file +- Use serde to make the forms whateverCaseThisIs rather than breaking our lint convention +- Swap to `sqlx` im gonna be honest `diesel` is pretty shit. +- Swap to `sqlite` from `postgres`. Postgres feels too clunky and it just solos honestly +- Add back `realip` header support +- Add configurable form limits \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 4b73286..df09291 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,52 +1,27 @@ -use serde::Deserialize; - use std::fs; use std::sync::LazyLock; -#[derive(Deserialize)] -pub struct Config { - pub general: ConfigGeneral, - pub accounts: ConfigAccounts, - pub db: ConfigDB, - pub levels: ConfigLevels -} +use toml::Table; -#[derive(Deserialize)] -pub struct ConfigGeneral { - pub append_path: String, - pub port: u16, - pub realip_header: String -} +pub static CONFIG: LazyLock = LazyLock::new(|| { + let toml_str = fs::read_to_string("config.toml").expect("error finding toml config"); + let config: Table = toml::from_str(toml_str.as_str()).expect("error parsing toml config"); -#[derive(Deserialize)] -pub struct ConfigAccounts { - pub allow_registration: bool -} - -#[derive(Deserialize)] -pub struct ConfigDB { - pub data_folder: String -} - -#[derive(Deserialize)] -pub struct ConfigLevels { - pub max_objects: i32, - pub blocklist: Vec, - pub reupload: bool -} - -impl Config { - pub fn load_from_file(file_path: &str) -> Self { - let toml_str = fs::read_to_string(file_path).expect("Error finding toml config:"); - let config: Config = toml::from_str(toml_str.as_str()).expect("Error parsing toml config:"); - - return config; - } -} - -pub static CONFIG: LazyLock = LazyLock::new(|| { - let config = Config::load_from_file("config.toml"); - return config; -}); \ No newline at end of file +}); + +pub fn config_get(key: &str) -> Option<&toml::Value> { + let this = &CONFIG; + let mut current = this.get(key)?; + for val in key.split(".").skip(1) { + current = current.as_table()?.get(val)?; + } + Some(current) +} + +pub fn config_get_with_default>(key: &str, default: T) -> T { + config_get(key) + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or(default) +} \ No newline at end of file diff --git a/src/endpoints/accounts/register_account.rs b/src/endpoints/accounts/register_account.rs index de04a33..86776fd 100644 --- a/src/endpoints/accounts/register_account.rs +++ b/src/endpoints/accounts/register_account.rs @@ -7,7 +7,7 @@ use diesel::result::Error; use password_auth::generate_hash; -use crate::CONFIG; +use crate::config; use crate::helpers; use crate::db; @@ -22,7 +22,7 @@ pub struct FormRegisterAccount { pub fn register_account(input: Form) -> status::Custom<&'static str> { let connection = &mut db::establish_connection_pg(); - if CONFIG.accounts.allow_registration == false { + if config::config_get_with_default("accounts.allow_registration", true) == false { return status::Custom(Status::Ok, "-1") } @@ -55,7 +55,7 @@ pub fn register_account(input: Form) -> status::Custom<&'st use crate::schema::accounts::dsl::*; let account_name_usage = accounts.filter(username.eq(input.userName.clone())).count().get_result::(connection) as Result; - let account_name_used = account_name_usage.expect("Fatal database name query error") != 0; + let account_name_used = account_name_usage.expect("database name query error") != 0; if account_name_used { return status::Custom(Status::Ok, "-2") } @@ -70,7 +70,7 @@ pub fn register_account(input: Form) -> status::Custom<&'st inserted_account = diesel::insert_into(accounts) .values(&new_account) .get_result::(connection) - .expect("Fatal error saving the new account"); + .expect("error saving the new account"); } // user management @@ -88,7 +88,7 @@ pub fn register_account(input: Form) -> status::Custom<&'st diesel::insert_into(users) .values(&new_user) .get_result::(connection) - .expect("Fatal error saving the new user"); + .expect("error saving the new user"); } return status::Custom(Status::Ok, "1") diff --git a/src/endpoints/levels/download_level.rs b/src/endpoints/levels/download_level.rs index 44d02a3..1949611 100644 --- a/src/endpoints/levels/download_level.rs +++ b/src/endpoints/levels/download_level.rs @@ -13,6 +13,7 @@ use std::fs; use std::io::prelude::*; use crate::helpers; +use crate::config; use crate::db; #[derive(FromForm)] @@ -98,7 +99,7 @@ pub fn download_level(input: Form) -> status::Custom<&'static xor_pass = level.password.clone().unwrap_or(String::from("0")); } - let compressed_level_data = fs::read(format!("{}/{}/{}.lvl", crate::CONFIG.db.data_folder, "levels", level.id)).expect("couldnt read level file"); + let compressed_level_data = fs::read(format!("{}/{}/{}.lvl", config::config_get_with_default("db.data_folder", "data"), "levels", level.id)).expect("couldnt read level file"); let uncompressed_level_data = String::from_utf8(if compressed_level_data.starts_with(&[0x1F, 0x8B]) { // gzip!! diff --git a/src/endpoints/levels/upload_level.rs b/src/endpoints/levels/upload_level.rs index ece7568..a67206e 100644 --- a/src/endpoints/levels/upload_level.rs +++ b/src/endpoints/levels/upload_level.rs @@ -8,7 +8,7 @@ use base64::{Engine as _, engine::general_purpose}; use std::fs; -use crate::config::CONFIG; +use crate::config; use crate::helpers; use crate::db; @@ -98,12 +98,12 @@ pub fn upload_level(input: Form) -> status::Custom<&'static str } // too many objects - if objects_val > CONFIG.levels.max_objects as usize { + if config::config_get_with_default("levels.max_objects", 0) != 0 && objects_val > config::config_get_with_default("levels.max_objects", 0) { return status::Custom(Status::Ok, "-1") } - + // forbidden object checking - if let Some(_forbidden_object) = level_objects.iter().find(|obj| crate::CONFIG.levels.blocklist.contains(&obj.id())) { + if let Some(_forbidden_object) = level_objects.iter().find(|obj| config::config_get_with_default("levels.blocklist", Vec::new() as Vec).contains(&obj.id())) { return status::Custom(Status::Ok, "-1") } @@ -158,7 +158,7 @@ pub fn upload_level(input: Form) -> status::Custom<&'static str .get_result::(connection) .expect("failed to update level"); - fs::write(format!("{}/levels/{}.lvl", crate::CONFIG.db.data_folder, updated_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file"); + fs::write(format!("{}/levels/{}.lvl", config::config_get_with_default("db.data_folder", "data"), updated_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file"); return status::Custom(Status::Ok, Box::leak(input.levelID.to_string().into_boxed_str())) } else { @@ -194,7 +194,7 @@ pub fn upload_level(input: Form) -> status::Custom<&'static str .get_result::(connection) .expect("failed to insert level"); - fs::write(format!("{}/levels/{}.lvl", crate::CONFIG.db.data_folder, inserted_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file"); + fs::write(format!("{}/levels/{}.lvl", config::config_get_with_default("db.data_folder", "data"), inserted_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file"); return status::Custom(Status::Ok, "1") } diff --git a/src/main.rs b/src/main.rs index dcf71dc..58456e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,15 +38,14 @@ fn rocket() -> _ { crate::helpers::reupload::init(); // data directories - // this is a bit scuffed - fs::create_dir_all(&CONFIG.db.data_folder).expect("failed to create data directory!"); - fs::create_dir_all(format!("{}/levels", &CONFIG.db.data_folder)).expect("failed to create data directory for levels"); + // unhardcore this maybe? + fs::create_dir_all(config::config_get_with_default("db.data_folder", "data")).expect("failed to create data directory!"); + fs::create_dir_all(format!("{}/levels", config::config_get_with_default("db.data_folder", "data"))).expect("failed to create data directory for levels"); rocket::build() // conf .configure(rocket::Config::figment() - .merge(("port", CONFIG.general.port)) - .merge(("ip_header", CONFIG.general.realip_header.as_str())) + .merge(("port", config::config_get_with_default("general.port", 8000))) .merge(("limits", Limits::new().limit("forms", 10.megabytes())))) // actual website .mount("/", routes![ @@ -67,7 +66,7 @@ fn rocket() -> _ { files ]) // https://www.youtube.com/watch?v=_pLrtsf5yfE - .mount(CONFIG.general.append_path.as_str(), routes![ + .mount(config::config_get_with_default("general.append_path", "/"), routes![ endpoints::accounts::login_account::login_account, endpoints::accounts::register_account::register_account, endpoints::accounts::update_account_settings::update_account_settings, diff --git a/src/template_endpoints/reupload.rs b/src/template_endpoints/reupload.rs index 36fa2f6..9ab1e2e 100644 --- a/src/template_endpoints/reupload.rs +++ b/src/template_endpoints/reupload.rs @@ -16,6 +16,7 @@ use diesel::prelude::*; use crate::helpers; use crate::db; +use crate::config; #[derive(Deserialize)] struct LevelResults { @@ -39,7 +40,7 @@ pub struct FormReupload { pub async fn post_reupload(input: Form) -> Template { let connection = &mut db::establish_connection_pg(); - let disabled = !crate::CONFIG.levels.reupload; + let disabled = !config::config_get_with_default("levels.reupload", true); if !disabled { let remote_level_id = input.level_id; @@ -105,7 +106,7 @@ pub async fn post_reupload(input: Form) -> Template { .get_result::(connection) .expect("failed to insert level"); - fs::write(format!("{}/levels/{}.lvl", crate::CONFIG.db.data_folder, inserted_level.id), general_purpose::URL_SAFE.decode(level_data.get("k4").expect("no level data?!").as_bytes()).expect("user provided invalid level string")).expect("couldnt write level to file"); + fs::write(format!("{}/levels/{}.lvl", config::config_get_with_default("db.data_folder", "data"), inserted_level.id), general_purpose::URL_SAFE.decode(level_data.get("k4").expect("no level data?!").as_bytes()).expect("user provided invalid level string")).expect("couldnt write level to file"); return Template::render("reupload", context! { level_id: inserted_level.id @@ -119,7 +120,7 @@ pub async fn post_reupload(input: Form) -> Template { #[get("/tools/reupload")] pub fn get_reupload() -> Template { - let disabled = !crate::CONFIG.levels.reupload; + let disabled = !config::config_get_with_default("levels.reupload", true); Template::render("reupload", context! { disabled: disabled