summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-04 14:05:15 +0200
committersalmonik <salmonik@tuta.io>2026-08-04 14:05:15 +0200
commitea1bc7db954030ad5e4b40391e8e0d655b9d7e9a (patch)
treeb1dd5f3a1602fb17d883df237a248e4f71b792da
parentConfig editor, host networking, whitelist RCON (diff)
downloadminecraft-ui-ea1bc7db954030ad5e4b40391e8e0d655b9d7e9a.tar.gz
minecraft-ui-ea1bc7db954030ad5e4b40391e8e0d655b9d7e9a.zip
small changesHEADmaster
-rw-r--r--src/docker.rs8
-rw-r--r--src/main.rs2
-rw-r--r--src/mods.rs30
3 files changed, 20 insertions, 20 deletions
diff --git a/src/docker.rs b/src/docker.rs
index f171d43..fe2232f 100644
--- a/src/docker.rs
+++ b/src/docker.rs
@@ -125,6 +125,7 @@ impl DockerManager {
125 "ENABLE_RCON=true".into(), 125 "ENABLE_RCON=true".into(),
126 format!("RCON_PASSWORD={}", instance.rcon_password), 126 format!("RCON_PASSWORD={}", instance.rcon_password),
127 "RCON_PORT=25575".into(), 127 "RCON_PORT=25575".into(),
128 "JVM_OPTS=-Dfml.queryResult=confirm".into(),
128 format!("MOTD={}", instance.motd), 129 format!("MOTD={}", instance.motd),
129 format!("GAMEMODE={}", instance.gamemode), 130 format!("GAMEMODE={}", instance.gamemode),
130 format!("LEVEL_TYPE={}", instance.level_type), 131 format!("LEVEL_TYPE={}", instance.level_type),
@@ -137,9 +138,10 @@ impl DockerManager {
137 } 138 }
138 139
139 if let Some(ref seed) = instance.world_seed 140 if let Some(ref seed) = instance.world_seed
140 && !seed.is_empty() { 141 && !seed.is_empty()
141 env_strings.push(format!("LEVEL_SEED={seed}")); 142 {
142 } 143 env_strings.push(format!("LEVEL_SEED={seed}"));
144 }
143 145
144 let mut exposed_ports: HashMap<String, HashMap<(), ()>> = HashMap::new(); 146 let mut exposed_ports: HashMap<String, HashMap<(), ()>> = HashMap::new();
145 exposed_ports.insert("25565/tcp".into(), HashMap::new()); 147 exposed_ports.insert("25565/tcp".into(), HashMap::new());
diff --git a/src/main.rs b/src/main.rs
index 666b2d1..28579f3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -64,7 +64,7 @@ async fn main() {
64 64
65 let router = routes::build_router(state); 65 let router = routes::build_router(state);
66 66
67 let addr = format!("127.0.0.1:{}", config.webui_port); 67 let addr = format!("0.0.0.0:{}", config.webui_port);
68 tracing::info!("Starting Minecraft UI on http://{addr}"); 68 tracing::info!("Starting Minecraft UI on http://{addr}");
69 69
70 let listener = tokio::net::TcpListener::bind(&addr) 70 let listener = tokio::net::TcpListener::bind(&addr)
diff --git a/src/mods.rs b/src/mods.rs
index 10799f0..e165f20 100644
--- a/src/mods.rs
+++ b/src/mods.rs
@@ -4,12 +4,10 @@
4//! 2. Class scan — walks `.class` entries looking for `net/minecraft/server` 4//! 2. Class scan — walks `.class` entries looking for `net/minecraft/server`
5//! vs `net/minecraft/client` references. 5//! vs `net/minecraft/client` references.
6//! 6//!
7//! **Rejection policy:** only mods that explicitly declare themselves client-only 7//! **Rejection policy:** only structurally invalid mods (oversized, unreadable
8//! in their metadata (`mods.toml` side=CLIENT, `fabric.mod.json` environment=client) 8//! archive) are rejected. Client-only and ambiguous mods are accepted — Forge
9//! are rejected. The class scan is purely informational — many Forge mods that 9//! ignores client-only mods on the server, but they may still be needed for
10//! work on servers reference `net/minecraft/client/…` for rendering/GUI but do 10//! client-server handshake compatibility (e.g. AppleSkin, TrashSlot).
11//! their server work through common API classes (`net/minecraft/block/Block`, etc.)
12//! without ever referencing `net/minecraft/server/…` directly.
13 11
14use std::io::{Cursor, Read}; 12use std::io::{Cursor, Read};
15use zip::ZipArchive; 13use zip::ZipArchive;
@@ -51,13 +49,10 @@ const MAX_MOD_SIZE_BYTES: usize = 500 * 1024 * 1024;
51/// Returns a `ValidationResult` indicating whether the mod is safe to install. 49/// Returns a `ValidationResult` indicating whether the mod is safe to install.
52/// 50///
53/// **Rejection policy:** 51/// **Rejection policy:**
54/// - Only mods that explicitly declare themselves client-only **in their metadata** 52/// - Only mods that fail structural checks (oversized, unreadable archive) are
55/// (`mods.toml` side=CLIENT, `fabric.mod.json` environment=client) are rejected 53/// rejected outright. Client-only and ambiguous mods are accepted — Forge
56/// outright. The class-file scan is purely informational — many Forge mods that 54/// ignores client-only mods on the server, but they may still be needed for
57/// work perfectly on a server reference `net/minecraft/client/…` classes for 55/// client-server handshake compatibility (e.g. AppleSkin, TrashSlot).
58/// rendering/GUI while doing their server logic through common API classes
59/// (`net/minecraft/block/Block`, `net/minecraft/item/Item`, …) without ever
60/// referencing `net/minecraft/server/…` directly.
61pub fn validate_mod(data: &[u8], filename: &str) -> ValidationResult { 56pub fn validate_mod(data: &[u8], filename: &str) -> ValidationResult {
62 // Reject oversized files early to prevent DoS 57 // Reject oversized files early to prevent DoS
63 if data.len() > MAX_MOD_SIZE_BYTES { 58 if data.len() > MAX_MOD_SIZE_BYTES {
@@ -75,13 +70,16 @@ pub fn validate_mod(data: &[u8], filename: &str) -> ValidationResult {
75 // Phase 1: metadata check 70 // Phase 1: metadata check
76 let (meta_side, meta_display_name) = read_metadata(data); 71 let (meta_side, meta_display_name) = read_metadata(data);
77 72
78 // Only reject based on metadata — the mod author's explicit declaration. 73 // Client-only mods are accepted — Forge simply ignores them on the
74 // server side, and they may still be required in the mods folder for
75 // client-server compatibility handshake or anti-cheat measures.
79 if meta_side == Some(ModSide::Client) { 76 if meta_side == Some(ModSide::Client) {
80 return ValidationResult { 77 return ValidationResult {
81 accepted: false, 78 accepted: true,
82 rejection_reason: Some(format!( 79 rejection_reason: Some(format!(
83 "Mod '{}' declares itself as client-only in its metadata. \ 80 "Mod '{}' declares itself as client-only in its metadata. \
84 It would crash the server.", 81 It is accepted — Forge ignores client-only mods on the server, \
82 but they may be needed for client-server compatibility.",
85 meta_display_name.as_deref().unwrap_or(filename) 83 meta_display_name.as_deref().unwrap_or(filename)
86 )), 84 )),
87 display_name: meta_display_name, 85 display_name: meta_display_name,