You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
🆙 No more Websocket plugin required
- Remove the websocket plugin, and edit the config.ini as in the example
This commit is contained in:
@@ -14,6 +14,7 @@ import com.eu.habbo.messages.outgoing.rooms.FloodCounterComposer;
|
||||
import com.eu.habbo.messages.outgoing.rooms.ForwardToRoomComposer;
|
||||
import com.eu.habbo.messages.outgoing.rooms.users.*;
|
||||
import com.eu.habbo.messages.outgoing.users.*;
|
||||
import com.eu.habbo.networking.gameserver.GameServerAttributes;
|
||||
import com.eu.habbo.plugin.events.users.UserCreditsEvent;
|
||||
import com.eu.habbo.plugin.events.users.UserDisconnectEvent;
|
||||
import com.eu.habbo.plugin.events.users.UserGetIPAddressEvent;
|
||||
@@ -118,15 +119,20 @@ public class Habbo implements Runnable {
|
||||
|
||||
public boolean connect() {
|
||||
String ip = "";
|
||||
String ProxyIP = "";
|
||||
String proxyInfo = "";
|
||||
|
||||
if (!Emulator.getConfig().getBoolean("networking.tcp.proxy") && this.client.getChannel().remoteAddress() != null) {
|
||||
String wsIp = this.client.getChannel().attr(GameServerAttributes.WS_IP).get();
|
||||
if (wsIp != null && !wsIp.isEmpty()) {
|
||||
ip = wsIp;
|
||||
SocketAddress address = this.client.getChannel().remoteAddress();
|
||||
proxyInfo = ((InetSocketAddress) address).getAddress().getHostAddress();
|
||||
} else if (!Emulator.getConfig().getBoolean("networking.tcp.proxy") && this.client.getChannel().remoteAddress() != null) {
|
||||
SocketAddress address = this.client.getChannel().remoteAddress();
|
||||
ip = ((InetSocketAddress) address).getAddress().getHostAddress();
|
||||
ProxyIP = "- no proxy server used";
|
||||
proxyInfo = "- no proxy server used";
|
||||
} else {
|
||||
SocketAddress address = this.client.getChannel().remoteAddress();
|
||||
ProxyIP = ((InetSocketAddress) address).getAddress().getHostAddress();
|
||||
proxyInfo = ((InetSocketAddress) address).getAddress().getHostAddress();
|
||||
}
|
||||
|
||||
if (Emulator.getPluginManager().isRegistered(UserGetIPAddressEvent.class, true)) {
|
||||
@@ -170,7 +176,7 @@ public class Habbo implements Runnable {
|
||||
this.messenger.connectionChanged(this, true, false);
|
||||
|
||||
Emulator.getGameEnvironment().getRoomManager().loadRoomsForHabbo(this);
|
||||
LOGGER.info("{} logged in from IP {} using proxyserver {}", this.habboInfo.getUsername(), this.habboInfo.getIpLogin(), ProxyIP);
|
||||
LOGGER.info("{} logged in from IP {} using proxyserver {}", this.habboInfo.getUsername(), this.habboInfo.getIpLogin(), proxyInfo);
|
||||
LOGGER.info("{} client MachineId = {}", this.habboInfo.getUsername(), this.client.getMachineId());
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ public class RequestRoomSettingsEvent extends MessageHandler {
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(roomId);
|
||||
if (room == null) return;
|
||||
if (!room.hasRights(this.client.getHabbo()) || !this.client.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER)) return;
|
||||
if (!room.hasRights(this.client.getHabbo()) && !this.client.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER)) return;
|
||||
|
||||
this.client.sendResponse(new RoomSettingsComposer(room));
|
||||
}
|
||||
|
||||
@@ -8,13 +8,24 @@ import com.eu.habbo.networking.gameserver.decoders.*;
|
||||
import com.eu.habbo.networking.gameserver.encoders.GameServerMessageEncoder;
|
||||
import com.eu.habbo.networking.gameserver.encoders.GameServerMessageLogger;
|
||||
import com.eu.habbo.networking.gameserver.handlers.IdleTimeoutHandler;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.FixedRecvByteBufAllocator;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class GameServer extends Server {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(GameServer.class);
|
||||
|
||||
private final PacketManager packetManager;
|
||||
private final GameClientManager gameClientManager;
|
||||
private ServerBootstrap webSocketBootstrap;
|
||||
|
||||
public GameServer(String host, int port) throws Exception {
|
||||
super("Game Server", host, port, Emulator.getConfig().getInt("io.bossgroup.threads"), Emulator.getConfig().getInt("io.workergroup.threads"));
|
||||
@@ -51,6 +62,41 @@ public class GameServer extends Server {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
initializeWebSocketServer();
|
||||
}
|
||||
|
||||
private void initializeWebSocketServer() {
|
||||
if (!Emulator.getConfig().getBoolean("ws.enabled", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String wsHost = Emulator.getConfig().getValue("ws.host", "0.0.0.0");
|
||||
int wsPort = Emulator.getConfig().getInt("ws.port", 2096);
|
||||
|
||||
WebSocketChannelInitializer wsInitializer = new WebSocketChannelInitializer();
|
||||
|
||||
this.webSocketBootstrap = new ServerBootstrap();
|
||||
this.webSocketBootstrap.group(this.getBossGroup(), this.getWorkerGroup());
|
||||
this.webSocketBootstrap.channel(NioServerSocketChannel.class);
|
||||
this.webSocketBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
|
||||
this.webSocketBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
|
||||
this.webSocketBootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
|
||||
this.webSocketBootstrap.childOption(ChannelOption.SO_RCVBUF, 4096);
|
||||
this.webSocketBootstrap.childOption(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(4096));
|
||||
this.webSocketBootstrap.childOption(ChannelOption.ALLOCATOR, new UnpooledByteBufAllocator(false));
|
||||
this.webSocketBootstrap.childHandler(wsInitializer);
|
||||
|
||||
ChannelFuture wsFuture = this.webSocketBootstrap.bind(wsHost, wsPort);
|
||||
|
||||
while (!wsFuture.isDone()) {
|
||||
}
|
||||
|
||||
if (!wsFuture.isSuccess()) {
|
||||
LOGGER.error("Failed to start WebSocket server on {}:{}", wsHost, wsPort);
|
||||
} else {
|
||||
LOGGER.info("WebSocket server started on {}:{} (SSL: {})", wsHost, wsPort, wsInitializer.isSslEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
public PacketManager getPacketManager() {
|
||||
|
||||
@@ -9,5 +9,5 @@ public class GameServerAttributes {
|
||||
public static final AttributeKey<GameClient> CLIENT = AttributeKey.valueOf("GameClient");
|
||||
public static final AttributeKey<HabboRC4> CRYPTO_CLIENT = AttributeKey.valueOf("CryptoClient");
|
||||
public static final AttributeKey<HabboRC4> CRYPTO_SERVER = AttributeKey.valueOf("CryptoServer");
|
||||
|
||||
public static final AttributeKey<String> WS_IP = AttributeKey.valueOf("WebSocketIP");
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.eu.habbo.networking.gameserver;
|
||||
|
||||
import com.eu.habbo.messages.PacketManager;
|
||||
import com.eu.habbo.networking.gameserver.codec.WebSocketCodec;
|
||||
import com.eu.habbo.networking.gameserver.decoders.*;
|
||||
import com.eu.habbo.networking.gameserver.encoders.GameServerMessageEncoder;
|
||||
import com.eu.habbo.networking.gameserver.encoders.GameServerMessageLogger;
|
||||
import com.eu.habbo.networking.gameserver.handlers.IdleTimeoutHandler;
|
||||
import com.eu.habbo.networking.gameserver.handlers.WebSocketHttpHandler;
|
||||
import com.eu.habbo.networking.gameserver.ssl.SSLCertificateLoader;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolConfig;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
|
||||
private static final int MAX_FRAME_SIZE = 500000;
|
||||
|
||||
private final SslContext sslContext;
|
||||
private final boolean sslEnabled;
|
||||
private final WebSocketServerProtocolConfig wsConfig;
|
||||
|
||||
public WebSocketChannelInitializer() {
|
||||
this.sslContext = SSLCertificateLoader.getContext();
|
||||
this.sslEnabled = this.sslContext != null;
|
||||
this.wsConfig = WebSocketServerProtocolConfig.newBuilder()
|
||||
.websocketPath("/")
|
||||
.checkStartsWith(true)
|
||||
.maxFramePayloadLength(MAX_FRAME_SIZE)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) {
|
||||
ch.pipeline().addLast("logger", new LoggingHandler());
|
||||
|
||||
if (this.sslEnabled) {
|
||||
SSLEngine engine = this.sslContext.newEngine(ch.alloc());
|
||||
ch.pipeline().addLast(new SslHandler(engine));
|
||||
}
|
||||
|
||||
ch.pipeline().addLast("httpCodec", new HttpServerCodec());
|
||||
ch.pipeline().addLast("httpAggregator", new HttpObjectAggregator(MAX_FRAME_SIZE));
|
||||
ch.pipeline().addLast("wsHttpHandler", new WebSocketHttpHandler());
|
||||
ch.pipeline().addLast("wsProtocolHandler", new WebSocketServerProtocolHandler(this.wsConfig));
|
||||
ch.pipeline().addLast("wsCodec", new WebSocketCodec());
|
||||
|
||||
// Standard game decoders
|
||||
ch.pipeline().addLast(new GamePolicyDecoder());
|
||||
ch.pipeline().addLast(new GameByteFrameDecoder());
|
||||
ch.pipeline().addLast(new GameByteDecoder());
|
||||
|
||||
if (PacketManager.DEBUG_SHOW_PACKETS) {
|
||||
ch.pipeline().addLast(new GameClientMessageLogger());
|
||||
}
|
||||
|
||||
ch.pipeline().addLast("idleEventHandler", new IdleTimeoutHandler(30, 60));
|
||||
ch.pipeline().addLast(new GameMessageRateLimit());
|
||||
ch.pipeline().addLast(new GameMessageHandler());
|
||||
|
||||
// Encoders
|
||||
ch.pipeline().addLast("messageEncoder", new GameServerMessageEncoder());
|
||||
|
||||
if (PacketManager.DEBUG_SHOW_PACKETS) {
|
||||
ch.pipeline().addLast(new GameServerMessageLogger());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSslEnabled() {
|
||||
return this.sslEnabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.eu.habbo.networking.gameserver.codec;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageCodec;
|
||||
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WebSocketCodec extends MessageToMessageCodec<WebSocketFrame, ByteBuf> {
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
|
||||
out.add(new BinaryWebSocketFrame(in).retain());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, WebSocketFrame in, List<Object> out) {
|
||||
out.add(in.content().retain());
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.eu.habbo.networking.gameserver.handlers;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.networking.gameserver.GameServerAttributes;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public class WebSocketHttpHandler extends ChannelInboundHandlerAdapter {
|
||||
private static final String ORIGIN_HEADER = "Origin";
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
if (msg instanceof HttpMessage) {
|
||||
if (!handleHttpRequest(ctx, (HttpMessage) msg)) {
|
||||
ReferenceCountUtil.release(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
ctx.pipeline().remove(this);
|
||||
}
|
||||
|
||||
private boolean handleHttpRequest(ChannelHandlerContext ctx, HttpMessage req) {
|
||||
String origin = "error";
|
||||
|
||||
try {
|
||||
if (req.headers().contains(ORIGIN_HEADER)) {
|
||||
origin = getDomainNameFromUrl(req.headers().get(ORIGIN_HEADER));
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
String whitelist = Emulator.getConfig().getValue("ws.whitelist", "localhost");
|
||||
if (!isWhitelisted(origin, whitelist.split(","))) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||
HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.FORBIDDEN,
|
||||
Unpooled.wrappedBuffer("Origin forbidden".getBytes())
|
||||
);
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
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;
|
||||
}
|
||||
|
||||
private static String getDomainNameFromUrl(String url) throws Exception {
|
||||
URI uri = new URI(url);
|
||||
String domain = uri.getHost();
|
||||
return domain.startsWith("www.") ? domain.substring(4) : domain;
|
||||
}
|
||||
|
||||
private static boolean isWhitelisted(String toCheck, String[] whitelist) {
|
||||
for (String entry : whitelist) {
|
||||
String trimmed = entry.trim();
|
||||
if (trimmed.equals("*")) {
|
||||
return true;
|
||||
}
|
||||
if (trimmed.startsWith("*")) {
|
||||
String suffix = trimmed.substring(1);
|
||||
if (toCheck.endsWith(suffix) || ("." + toCheck).equals(suffix)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (toCheck.equals(trimmed)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.eu.habbo.networking.gameserver.ssl;
|
||||
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslContextBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SSLCertificateLoader {
|
||||
private static final String SSL_PATH = "ssl";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SSLCertificateLoader.class);
|
||||
|
||||
public static SslContext getContext() {
|
||||
try {
|
||||
File certFile = new File(SSL_PATH + File.separator + "cert.pem");
|
||||
File keyFile = new File(SSL_PATH + File.separator + "privkey.pem");
|
||||
|
||||
if (!certFile.exists() || !keyFile.exists()) {
|
||||
LOGGER.debug("SSL certificates not found in '{}' directory, WSS disabled", SSL_PATH);
|
||||
return null;
|
||||
}
|
||||
|
||||
SslContext context = SslContextBuilder.forServer(certFile, keyFile).build();
|
||||
LOGGER.info("SSL certificates loaded successfully, WSS enabled");
|
||||
return context;
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Failed to load SSL certificates: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#Database Configuration.
|
||||
db.hostname=localhost
|
||||
db.port=3306
|
||||
db.database=ms
|
||||
db.username=root
|
||||
db.password=root
|
||||
db.params=
|
||||
db.pool.minsize=25
|
||||
db.pool.maxsize=100
|
||||
|
||||
#Game Configuration.
|
||||
#Host IP. Most likely just 0.0.0.0 Use 127.0.0.1 if you want to play on LAN.
|
||||
game.host=0.0.0.0
|
||||
game.port=3000
|
||||
|
||||
#RCON Configuration.
|
||||
#RCON Host IP. Leave this at 127.0.0.1 if you're running your website on the same server as the emulator.
|
||||
rcon.host=127.0.0.1
|
||||
rcon.port=3001
|
||||
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=
|
||||
|
||||
enc.enabled=false
|
||||
enc.e=3
|
||||
enc.n=86851dd364d5c5cece3c883171cc6ddc5760779b992482bd1e20dd296888df91b33b936a7b93f06d29e8870f703a216257dec7c81de0058fea4cc5116f75e6efc4e9113513e45357dc3fd43d4efab5963ef178b78bd61e81a14c603b24c8bcce0a12230b320045498edc29282ff0603bc7b7dae8fc1b05b52b2f301a9dc783b7
|
||||
enc.d=59ae13e243392e89ded305764bdd9e92e4eafa67bb6dac7e1415e8c645b0950bccd26246fd0d4af37145af5fa026c0ec3a94853013eaae5ff1888360f4f9449ee023762ec195dff3f30ca0b08b8c947e3859877b5d7dced5c8715c58b53740b84e11fbc71349a27c31745fcefeeea57cff291099205e230e0c7c27e8e1c0512b
|
||||
Reference in New Issue
Block a user