SMall fix for CORS

This commit is contained in:
duckietm
2026-05-19 11:41:17 +02:00
parent 033faaeab6
commit d958fbc0ab
3 changed files with 51 additions and 16 deletions
+7
View File
@@ -34,3 +34,10 @@ SET @ddl = IF(@col_exists = 0,
PREPARE stmt FROM @ddl; PREPARE stmt FROM @ddl;
EXECUTE stmt; EXECUTE stmt;
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
UPDATE emulator_settings SET `key`='ws.whitelist' WHERE `key`='websockets.whitelist';
UPDATE emulator_settings SET `key`='ws.host' WHERE `key`='ws.nitro.host';
UPDATE emulator_settings SET `key`='ws.port' WHERE `key`='ws.nitro.port';
INSERT emulator_settings (`key`, `value`) VALUES ('ws.ip.header', 'X-Forwarded-For');
INSERT emulator_settings (`key`, `value`) VALUES ('ws.enabled', 'true');
@@ -8,10 +8,13 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.*;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI; import java.net.URI;
public class WebSocketHttpHandler extends ChannelInboundHandlerAdapter { public class WebSocketHttpHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHttpHandler.class);
private static final String ORIGIN_HEADER = "Origin"; private static final String ORIGIN_HEADER = "Origin";
@Override @Override
@@ -27,6 +30,12 @@ public class WebSocketHttpHandler extends ChannelInboundHandlerAdapter {
} }
private boolean handleHttpRequest(ChannelHandlerContext ctx, HttpMessage req) { private boolean handleHttpRequest(ChannelHandlerContext ctx, HttpMessage req) {
captureForwardedIp(ctx, req);
if (!isWebSocketUpgrade(req)) {
return true;
}
String origin = "error"; String origin = "error";
try { try {
@@ -38,27 +47,47 @@ public class WebSocketHttpHandler extends ChannelInboundHandlerAdapter {
String whitelist = Emulator.getConfig().getValue("ws.whitelist", "localhost"); String whitelist = Emulator.getConfig().getValue("ws.whitelist", "localhost");
if (!isWhitelisted(origin, whitelist.split(","))) { if (!isWhitelisted(origin, whitelist.split(","))) {
LOGGER.warn("WebSocket upgrade rejected — origin '{}' not in ws.whitelist='{}'",
req.headers().get(ORIGIN_HEADER), whitelist);
FullHttpResponse response = new DefaultFullHttpResponse( FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpVersion.HTTP_1_1,
HttpResponseStatus.FORBIDDEN, HttpResponseStatus.FORBIDDEN,
Unpooled.wrappedBuffer("Origin forbidden".getBytes()) Unpooled.wrappedBuffer("Origin forbidden".getBytes())
); );
response.headers().set("Vary", "Origin");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
return false; return false;
} }
String ipHeader = Emulator.getConfig().getValue("ws.ip.header", "");
if (!ipHeader.isEmpty() && req.headers().contains(ipHeader)) {
String ip = req.headers().get(ipHeader);
ctx.channel().attr(GameServerAttributes.WS_IP).set(ip);
}
return true; return true;
} }
private static void captureForwardedIp(ChannelHandlerContext ctx, HttpMessage req) {
String ipHeader = Emulator.getConfig().getValue("ws.ip.header", "");
if (!ipHeader.isEmpty() && req.headers().contains(ipHeader)) {
String ip = req.headers().get(ipHeader);
ctx.channel().attr(GameServerAttributes.WS_IP).set(ip);
}
}
private static boolean isWebSocketUpgrade(HttpMessage req) {
String upgrade = req.headers().get(HttpHeaderNames.UPGRADE);
if (upgrade == null || !"websocket".equalsIgnoreCase(upgrade)) return false;
String connection = req.headers().get(HttpHeaderNames.CONNECTION);
if (connection == null) return false;
for (String token : connection.split(",")) {
if ("upgrade".equalsIgnoreCase(token.trim())) return true;
}
return false;
}
private static String getDomainNameFromUrl(String url) throws Exception { private static String getDomainNameFromUrl(String url) throws Exception {
URI uri = new URI(url); URI uri = new URI(url);
String domain = uri.getHost(); String domain = uri.getHost();
if (domain == null) return "error";
return domain.startsWith("www.") ? domain.substring(4) : domain; return domain.startsWith("www.") ? domain.substring(4) : domain;
} }
+9 -10
View File
@@ -27,16 +27,6 @@ rcon.host=127.0.0.1
rcon.port=3001 rcon.port=3001
rcon.allowed=127.0.0.1;127.0.0.2 rcon.allowed=127.0.0.1;127.0.0.2
#WebSocket Configuration (for Nitro)
#Set ws.enabled to true to enable WebSocket connections.
ws.enabled=false
ws.host=0.0.0.0
ws.port=2096
#Comma-separated whitelist of allowed origins. Supports wildcards: *.example.com, * (allow all)
ws.whitelist=localhost
#Header name for real client IP when behind a proxy (e.g., X-Forwarded-For, CF-Connecting-IP). Leave empty if not using a proxy.
ws.ip.header=
# Databse configuration # Databse configuration
db.pool.connection_timeout_ms = 10000 db.pool.connection_timeout_ms = 10000
db.pool.idle_timeout_ms = 600000 db.pool.idle_timeout_ms = 600000
@@ -69,3 +59,12 @@ login.remember.jwt.secret=
# Login news API. # Login news API.
login.news.limit=5 login.news.limit=5
#WebSocket Configuration (for Nitro)
#Please adjust this setting in the Database !!!!
### ws.enabled=false
### ws.host=0.0.0.0
### ws.port=2096
### ws.whitelist=localhost #Comma-separated whitelist of allowed origins. Supports wildcards: *.example.com, * (allow all)
### ws.ip.header=X-Forwarded-For #Header name for real client IP when behind a proxy (e.g., X-Forwarded-For, CF-Connecting-IP). Leave empty if not using a proxy.