diff --git a/rc_core/src/persist/config/cubes_json.rs b/rc_core/src/persist/config/cubes_json.rs index f5a920a..4418ca0 100644 --- a/rc_core/src/persist/config/cubes_json.rs +++ b/rc_core/src/persist/config/cubes_json.rs @@ -610,4 +610,19 @@ impl super::ConfigProvider for CubeConfig { team_deathmatch: self.battle.games.team_deathmatch.team_chooser.clone(), } } + + fn redacted_json(&self) -> String { + use super::RedactedClone; + let redacted_self = Self { + cubes: self.cubes.clone(), + movement: self.movement.clone(), + lerp_value: self.lerp_value, + battle: self.battle.clone(), + chat: self.chat.clone(), + factory: self.factory.redacted_clone(), + shop: self.shop.clone(), + settings: self.settings.redacted_clone(), + }; + serde_json::to_string(&redacted_self).expect("Failed to re-serialize config.json") + } } diff --git a/rc_core/src/persist/config/mod.rs b/rc_core/src/persist/config/mod.rs index a40dd52..dffb01c 100644 --- a/rc_core/src/persist/config/mod.rs +++ b/rc_core/src/persist/config/mod.rs @@ -3,6 +3,7 @@ pub use cubes_json::CubeConfig; mod traits; pub use traits::{ConfigProvider, DevMessageProvider, ServerConfig, GarageUpgrades, GarageUpgradeIncrement, ChatSystemConfig, GameEventSequence, GameEvents, GameRotationStrategy, GameEvent, GameMap, GameVisibility, GameType, SingleplayerConfig, VehicleInfo, VehicleDescriptor, QueueChangeMode, Point, Sphere, MapConfig, LinksConfig, FakePlayer, ClientEmulator, EnergyConfig, BattleArenaResolver, PitSettings, PitWinCondition, TeamDeathMatchSettings, ShopEntriesResolver, ShopAction, ShopGain, PromoCode, MultiplayerSettings, BattleArenaCrystalParams, VehicleValidators, TeamChoosers, FactoryConfig, PlatformConfig}; +pub(super) use traits::RedactedClone; mod validation; pub use validation::{SelfValidator, ValidationInfo, ValidationMessage}; diff --git a/rc_core/src/persist/config/traits.rs b/rc_core/src/persist/config/traits.rs index bbcb950..391ea76 100644 --- a/rc_core/src/persist/config/traits.rs +++ b/rc_core/src/persist/config/traits.rs @@ -45,6 +45,7 @@ pub trait ConfigProvider { fn vehicle_validation(&self) -> VehicleValidators; fn garage_slot_limit(&self) -> i32; fn team_choosers(&self) -> TeamChoosers; + fn redacted_json(&self) -> String; } pub struct DevMessageProvider { @@ -573,3 +574,7 @@ pub struct PlatformConfig { pub enable_analytics: bool, pub enable_standard_units: bool, } + +pub trait RedactedClone { + fn redacted_clone(&self) -> Self; +} diff --git a/rc_core/src/persist/settings.rs b/rc_core/src/persist/settings.rs index 2ff45b6..2a8ad27 100644 --- a/rc_core/src/persist/settings.rs +++ b/rc_core/src/persist/settings.rs @@ -20,6 +20,17 @@ impl super::config::SelfValidator for Settings { } } +impl super::config::RedactedClone for Settings { + fn redacted_clone(&self) -> Self { + Self { + gameplay: self.gameplay.clone(), + banners: self.banners.clone(), + garage_upgrades: self.garage_upgrades.clone(), + server: self.server.redacted_clone(), + } + } +} + fn default_gameplay_settings() -> super::GameplaySettings { super::GameplaySettings { show_tutorial_after_date: "2077-01-01".to_owned(), @@ -112,6 +123,16 @@ pub struct ServerSettings { pub maintenance_message: Option, } +impl super::config::RedactedClone for ServerSettings { + fn redacted_clone(&self) -> Self { + let mut redacted = self.clone(); + redacted.database = "[REDACTED]".to_owned(); + redacted.intercom_url = "[REDACTED]".to_owned(); + redacted.dos_protection = true; + redacted + } +} + #[derive(Serialize, Deserialize, Clone, Debug, Default)] pub enum QueueMode { Upgrade, // move enqueued players into newer gamemode diff --git a/rc_core/src/persist/vehicle_factory.rs b/rc_core/src/persist/vehicle_factory.rs index a587336..4100e01 100644 --- a/rc_core/src/persist/vehicle_factory.rs +++ b/rc_core/src/persist/vehicle_factory.rs @@ -16,6 +16,15 @@ impl super::config::SelfValidator for FactoryConfig { } } +impl super::config::RedactedClone for FactoryConfig { + fn redacted_clone(&self) -> Self { + Self { + adapter: self.adapter.redacted_clone(), + upload_limit: self.upload_limit, + } + } +} + fn default_variant() -> AdapterSettings { AdapterSettings::BuiltIn } @@ -36,6 +45,22 @@ pub enum AdapterSettings { None, } +impl super::config::RedactedClone for AdapterSettings { + fn redacted_clone(&self) -> Self { + match self { + Self::Arc(arc) => { + Self::Arc(ArcFactorySettings { + uri: "[REDACTED]".to_owned(), + show_expired: arc.show_expired, + override_cdn: arc.override_cdn, + spoof_username: arc.spoof_username, + }) + }, + x => x.clone(), + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ArcFactorySettings { pub uri: String, diff --git a/rc_society/src/api/config.rs b/rc_society/src/api/config.rs new file mode 100644 index 0000000..5b47581 --- /dev/null +++ b/rc_society/src/api/config.rs @@ -0,0 +1,28 @@ +use actix_web::{HttpResponse, Responder, get, web::Query, http::header::{ContentDisposition, ContentType}}; + +static JSON_DATA: std::sync::OnceLock = std::sync::OnceLock::new(); + +pub(super) fn init(config: &dyn oj_rc_core::ConfigProvider<()>) { + JSON_DATA.get_or_init(|| config.redacted_json()); +} + +#[derive(serde::Deserialize)] +struct ConfigQuery { + #[serde(default)] + pub download: bool, +} + +#[get("/api/v1/config.json")] +pub async fn get(query: Query) -> impl Responder { + let data = JSON_DATA.get().expect("Config JSON init failure").to_owned(); + if query.download { + HttpResponse::Ok() + .insert_header(ContentDisposition::attachment("config.json")) + .insert_header(ContentType::json()) + .body(data) + } else { + HttpResponse::Ok() + .insert_header(ContentType::json()) + .body(data) + } +} diff --git a/rc_society/src/api/mod.rs b/rc_society/src/api/mod.rs index 46b5f68..b7279ab 100644 --- a/rc_society/src/api/mod.rs +++ b/rc_society/src/api/mod.rs @@ -1 +1,6 @@ pub mod garage; +pub mod config; + +pub fn init(config: &dyn oj_rc_core::ConfigProvider<()>) { + config::init(config); +} diff --git a/rc_society/src/main.rs b/rc_society/src/main.rs index 02dbb5d..0947db8 100644 --- a/rc_society/src/main.rs +++ b/rc_society/src/main.rs @@ -24,6 +24,7 @@ async fn main() -> std::io::Result<()> { let cli_args = cli::CliArgs::get(); let config = oj_rc_core::ConfigImpl::load(&cli_args.assets_robocraft)?; + api::init(&config); let server_settings = actix_web::web::Data::new(>::server_config(&config)); let server_links = actix_web::web::Data::new(>::url_links(&config)); @@ -94,6 +95,7 @@ async fn main() -> std::io::Result<()> { .service(web::garage::import::get_new) .service(web::garage::import::post) .service(web::garage::selected::get) + .service(api::config::get) }) .bind((cli_args.ip, cli_args.port))? .run()