You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-20 15:36:17 +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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user