1
0
mirror of https://git.ngram.ca/OpenJam/rc-servers synced 2026-08-23 23:08:52 +00:00

Add API endpoint for retrieving config.json (without any secure access details)

This commit is contained in:
NG (Graham)
2026-06-21 21:58:36 -04:00
parent c4f297eb18
commit e60a4927a6
8 changed files with 102 additions and 0 deletions

View File

@@ -610,4 +610,19 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
team_deathmatch: self.battle.games.team_deathmatch.team_chooser.clone(), 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")
}
} }

View File

@@ -3,6 +3,7 @@ pub use cubes_json::CubeConfig;
mod traits; 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 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; mod validation;
pub use validation::{SelfValidator, ValidationInfo, ValidationMessage}; pub use validation::{SelfValidator, ValidationInfo, ValidationMessage};

View File

@@ -45,6 +45,7 @@ pub trait ConfigProvider<C: Clone> {
fn vehicle_validation(&self) -> VehicleValidators; fn vehicle_validation(&self) -> VehicleValidators;
fn garage_slot_limit(&self) -> i32; fn garage_slot_limit(&self) -> i32;
fn team_choosers(&self) -> TeamChoosers; fn team_choosers(&self) -> TeamChoosers;
fn redacted_json(&self) -> String;
} }
pub struct DevMessageProvider<C: Clone> { pub struct DevMessageProvider<C: Clone> {
@@ -573,3 +574,7 @@ pub struct PlatformConfig {
pub enable_analytics: bool, pub enable_analytics: bool,
pub enable_standard_units: bool, pub enable_standard_units: bool,
} }
pub trait RedactedClone {
fn redacted_clone(&self) -> Self;
}

View File

@@ -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 { fn default_gameplay_settings() -> super::GameplaySettings {
super::GameplaySettings { super::GameplaySettings {
show_tutorial_after_date: "2077-01-01".to_owned(), show_tutorial_after_date: "2077-01-01".to_owned(),
@@ -112,6 +123,16 @@ pub struct ServerSettings {
pub maintenance_message: Option<String>, pub maintenance_message: Option<String>,
} }
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)] #[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub enum QueueMode { pub enum QueueMode {
Upgrade, // move enqueued players into newer gamemode Upgrade, // move enqueued players into newer gamemode

View File

@@ -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 { fn default_variant() -> AdapterSettings {
AdapterSettings::BuiltIn AdapterSettings::BuiltIn
} }
@@ -36,6 +45,22 @@ pub enum AdapterSettings {
None, 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)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ArcFactorySettings { pub struct ArcFactorySettings {
pub uri: String, pub uri: String,

View File

@@ -0,0 +1,28 @@
use actix_web::{HttpResponse, Responder, get, web::Query, http::header::{ContentDisposition, ContentType}};
static JSON_DATA: std::sync::OnceLock<String> = 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<ConfigQuery>) -> 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)
}
}

View File

@@ -1 +1,6 @@
pub mod garage; pub mod garage;
pub mod config;
pub fn init(config: &dyn oj_rc_core::ConfigProvider<()>) {
config::init(config);
}

View File

@@ -24,6 +24,7 @@ async fn main() -> std::io::Result<()> {
let cli_args = cli::CliArgs::get(); let cli_args = cli::CliArgs::get();
let config = oj_rc_core::ConfigImpl::load(&cli_args.assets_robocraft)?; let config = oj_rc_core::ConfigImpl::load(&cli_args.assets_robocraft)?;
api::init(&config);
let server_settings = actix_web::web::Data::new(<oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::server_config(&config)); let server_settings = actix_web::web::Data::new(<oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::server_config(&config));
let server_links = actix_web::web::Data::new(<oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::url_links(&config)); let server_links = actix_web::web::Data::new(<oj_rc_core::ConfigImpl as oj_rc_core::ConfigProvider<()>>::url_links(&config));
@@ -94,6 +95,7 @@ async fn main() -> std::io::Result<()> {
.service(web::garage::import::get_new) .service(web::garage::import::get_new)
.service(web::garage::import::post) .service(web::garage::import::post)
.service(web::garage::selected::get) .service(web::garage::selected::get)
.service(api::config::get)
}) })
.bind((cli_args.ip, cli_args.port))? .bind((cli_args.ip, cli_args.port))?
.run() .run()