From ee34620d5319c2b3b32223dfe6fa0752050eea86 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 1 Jul 2024 21:17:20 +0900 Subject: [PATCH] WIP --- fishctl/src/command/config/update/v1.rs | 310 +++++++++++++++--------- fishctl/src/config/server.rs | 10 +- 2 files changed, 199 insertions(+), 121 deletions(-) diff --git a/fishctl/src/command/config/update/v1.rs b/fishctl/src/command/config/update/v1.rs index 9db4d1a..94f0713 100644 --- a/fishctl/src/command/config/update/v1.rs +++ b/fishctl/src/command/config/update/v1.rs @@ -469,126 +469,204 @@ fn create_new_server_config( None => None, }; + let network = server::Network { + protocol: match protocol.as_str() { + "http" => Some(server::HttpProtocol::Http), + _ => None, + }, + domain, + port: parsed_server_url.port(), + listen: server::Listen { + host: default_yml + .get("bind") + .and_then(|v| v.as_str()) + .map(|v| v.to_string()), + port: default_yml + .get("port") + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidConfig("port"))? + .try_into() + .map_err(|_| Error::InvalidConfig("Invalid `port` number"))?, + }, + email, + http_proxy, + media_proxy, + summaly_proxy, + smtp_proxy, + }; + + let database = server::Database { + host: db + .get(&Yaml::String("host".to_string())) + .and_then(|v| v.as_str()) + .ok_or(Error::InvalidConfig("db.host"))? + .to_string(), + port: db + .get(&Yaml::String("port".to_string())) + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidConfig("db.port"))? + .try_into() + .map_err(|_| Error::InvalidConfig("Invalid `db.port` number"))?, + user: db + .get(&Yaml::String("user".to_string())) + .and_then(|v| v.as_str()) + .ok_or(Error::InvalidConfig("db.user"))? + .to_string(), + password: db + .get(&Yaml::String("pass".to_string())) + .and_then(|v| v.as_str()) + .ok_or(Error::InvalidConfig("db.pass"))? + .to_string(), + name: db + .get(&Yaml::String("db".to_string())) + .and_then(|v| v.as_str()) + .ok_or(Error::InvalidConfig("db.db"))? + .to_string(), + }; + + let cache_server = server::CacheServer { + host: redis + .get(&Yaml::String("host".to_string())) + .and_then(|v| v.as_str()) + .ok_or(Error::InvalidConfig("redis.host"))? + .to_string(), + port: redis + .get(&Yaml::String("port".to_string())) + .and_then(|v| v.as_i64()) + .ok_or(Error::InvalidConfig("redis.port"))? + .try_into() + .map_err(|_| Error::InvalidConfig("Invalid `redis.port` number"))?, + user: match redis.get(&Yaml::String("user".to_string())) { + Some(user) => Some( + user.as_str() + .ok_or(Error::InvalidConfig("redis.user"))? + .to_string(), + ), + None => None, + }, + password: match redis.get(&Yaml::String("pass".to_string())) { + Some(pass) => Some( + pass.as_str() + .ok_or(Error::InvalidConfig("redis.pass"))? + .to_string(), + ), + None => None, + }, + index: match redis.get(&Yaml::String("db".to_string())) { + Some(db) => Some( + db.as_i64() + .ok_or(Error::InvalidConfig("redis.db"))? + .try_into() + .map_err(|_| Error::InvalidConfig("Invalid `redis.db` number"))?, + ), + None => None, + }, + prefix: match redis.get(&Yaml::String("prefix".to_string())) { + Some(prefix) => Some( + prefix + .as_str() + .ok_or(Error::InvalidConfig("redis.prefix"))? + .to_string(), + ), + None => None, + }, + }; + + let server_info = Some(server::ServerInfo { + name: meta.name.to_owned(), + description: meta.description.to_owned(), + maintainer_name: meta.maintainer_name.to_owned(), + contact_info: meta.maintainer_email.to_owned(), + open_registrations: !meta.disable_registration, + repository_url, + default_reaction: Some(meta.default_reaction.to_owned()), + }); + + let timeline = Some(server::Timeline { + local: !meta.disable_local_timeline, + global: !meta.disable_global_timeline, + recommended: !meta.disable_recommended_timeline, + publish: meta.enable_guest_timeline, + }); + + if meta.enable_hcaptcha && meta.enable_recaptcha { + return Err(Error::InvalidConfig( + "Both hCaptcha and reCAPTCHA are enabled", + )); + } + + let captcha = match (meta.enable_hcaptcha, meta.enable_recaptcha) { + (false, false) => None, + (true, true) => { + return Err(Error::InvalidConfig( + "Both hCaptcha and reCAPTCHA are enabled", + )) + } + (true, false) => Some(server::Captcha { + enabled: true, + provider: server::CaptchaProvider::HCaptcha, + site_key: meta + .hcaptcha_site_key + .to_owned() + .ok_or(Error::InvalidConfig("hCaptcha site key is not set"))?, + secret_key: meta + .hcaptcha_secret_key + .to_owned() + .ok_or(Error::InvalidConfig("hCaptcha secret key is not set"))?, + }), + (false, true) => Some(server::Captcha { + enabled: true, + provider: server::CaptchaProvider::ReCaptcha, + site_key: meta + .recaptcha_site_key + .to_owned() + .ok_or(Error::InvalidConfig("reCAPTCHA site key is not set"))?, + secret_key: meta + .recaptcha_secret_key + .to_owned() + .ok_or(Error::InvalidConfig("reCAPTCHA secret key is not set"))?, + }), + }; + + let mut security: Option = None; + + if meta.secure_mode + || meta.private_mode + || captcha.is_some() + || meta.enable_active_email_validation + || meta.enable_ip_logging + { + security = Some(server::Security { + require_authorized_fetch: match meta.secure_mode { + false => None, + true => Some(true), + }, + private_mode: match meta.private_mode { + false => None, + true => Some(true), + }, + captcha, + enable_strict_email_check: match meta.enable_active_email_validation { + false => None, + true => Some(true), + }, + enable_ip_logging: match meta.enable_ip_logging { + false => None, + true => Some(true), + }, + }); + } + let server_config = server::Config { config_revision: Revision::V1, - server_info: Some(server::ServerInfo { - name: meta.name.to_owned(), - description: meta.description.to_owned(), - maintainer_name: meta.maintainer_name.to_owned(), - contact_info: meta.maintainer_email.to_owned(), - open_registrations: !meta.disable_registration, - repository_url, - default_reaction: Some(meta.default_reaction.to_owned()), - }), - timeline: Some(server::Timeline { - local: !meta.disable_local_timeline, - global: !meta.disable_global_timeline, - recommended: !meta.disable_recommended_timeline, - publish: meta.enable_guest_timeline, - }), - network: server::Network { - protocol: match protocol.as_str() { - "http" => Some(server::HttpProtocol::Http), - _ => None, - }, - domain, - port: parsed_server_url.port(), - listen: server::Listen { - host: default_yml - .get("bind") - .and_then(|v| v.as_str()) - .map(|v| v.to_string()), - port: default_yml - .get("port") - .and_then(|v| v.as_i64()) - .ok_or(Error::InvalidConfig("port"))? - .try_into() - .map_err(|_| Error::InvalidConfig("Invalid `port` number"))?, - }, - email, - http_proxy, - media_proxy, - summaly_proxy, - smtp_proxy, - }, - database: server::Database { - host: db - .get(&Yaml::String("host".to_string())) - .and_then(|v| v.as_str()) - .ok_or(Error::InvalidConfig("db.host"))? - .to_string(), - port: db - .get(&Yaml::String("port".to_string())) - .and_then(|v| v.as_i64()) - .ok_or(Error::InvalidConfig("db.port"))? - .try_into() - .map_err(|_| Error::InvalidConfig("Invalid `db.port` number"))?, - user: db - .get(&Yaml::String("user".to_string())) - .and_then(|v| v.as_str()) - .ok_or(Error::InvalidConfig("db.user"))? - .to_string(), - password: db - .get(&Yaml::String("pass".to_string())) - .and_then(|v| v.as_str()) - .ok_or(Error::InvalidConfig("db.pass"))? - .to_string(), - name: db - .get(&Yaml::String("db".to_string())) - .and_then(|v| v.as_str()) - .ok_or(Error::InvalidConfig("db.db"))? - .to_string(), - }, - cache_server: server::CacheServer { - host: redis - .get(&Yaml::String("host".to_string())) - .and_then(|v| v.as_str()) - .ok_or(Error::InvalidConfig("redis.host"))? - .to_string(), - port: redis - .get(&Yaml::String("port".to_string())) - .and_then(|v| v.as_i64()) - .ok_or(Error::InvalidConfig("redis.port"))? - .try_into() - .map_err(|_| Error::InvalidConfig("Invalid `redis.port` number"))?, - user: match redis.get(&Yaml::String("user".to_string())) { - Some(user) => Some( - user.as_str() - .ok_or(Error::InvalidConfig("redis.user"))? - .to_string(), - ), - None => None, - }, - password: match redis.get(&Yaml::String("pass".to_string())) { - Some(pass) => Some( - pass.as_str() - .ok_or(Error::InvalidConfig("redis.pass"))? - .to_string(), - ), - None => None, - }, - index: match redis.get(&Yaml::String("db".to_string())) { - Some(db) => Some( - db.as_i64() - .ok_or(Error::InvalidConfig("redis.db"))? - .try_into() - .map_err(|_| Error::InvalidConfig("Invalid `redis.db` number"))?, - ), - None => None, - }, - prefix: match redis.get(&Yaml::String("prefix".to_string())) { - Some(prefix) => Some( - prefix - .as_str() - .ok_or(Error::InvalidConfig("redis.prefix"))? - .to_string(), - ), - None => None, - }, - }, + server_info, + timeline, + network, + database, + cache_server, id, service_worker, - security: todo!(), + security, file, }; diff --git a/fishctl/src/config/server.rs b/fishctl/src/config/server.rs index 29eb858..be85b06 100644 --- a/fishctl/src/config/server.rs +++ b/fishctl/src/config/server.rs @@ -164,21 +164,21 @@ pub struct Security { pub require_authorized_fetch: Option, pub private_mode: Option, #[validate(nested)] - pub captcha: Option, + pub captcha: Option, pub enable_strict_email_check: Option, - pub log_ip_address: Option, + pub enable_ip_logging: Option, } #[derive(Deserialize, Serialize, Validate, Debug, Clone)] -pub struct CaptchaConfig { +pub struct Captcha { pub enabled: bool, - pub kind: Captcha, + pub provider: CaptchaProvider, pub site_key: String, pub secret_key: String, } #[derive(Deserialize, Serialize, Debug, Clone)] -pub enum Captcha { +pub enum CaptchaProvider { #[serde(rename = "hCaptcha")] HCaptcha, #[serde(rename = "reCAPTCHA")]