From f0edaeae90973a55c26d2e20d49c26960403b602 Mon Sep 17 00:00:00 2001 From: Dank074 Date: Wed, 7 Oct 2020 18:03:13 -0500 Subject: [PATCH] initial commit --- .gitignore | 3 + pom.xml | 30 ++++++++++ .../java/com/krews/plugin/nitro/main.java | 45 +++++++++++++++ .../websockets/NetworkChannelInitializer.java | 39 +++++++++++++ .../HabboFrameToWebSocketFrameEncoder.java | 29 ++++++++++ .../WebSocketFrameToHabboFrameDecoder.java | 55 +++++++++++++++++++ .../handlers/MessageInterceptorHandler.java | 29 ++++++++++ src/main/resources/plugin.json | 5 ++ 8 files changed, 235 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/krews/plugin/nitro/main.java create mode 100644 src/main/java/com/krews/plugin/nitro/websockets/NetworkChannelInitializer.java create mode 100644 src/main/java/com/krews/plugin/nitro/websockets/codec/HabboFrameToWebSocketFrameEncoder.java create mode 100644 src/main/java/com/krews/plugin/nitro/websockets/codec/WebSocketFrameToHabboFrameDecoder.java create mode 100644 src/main/java/com/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java create mode 100644 src/main/resources/plugin.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66761f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +.idea/workspace.xml +target/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e8e8362 --- /dev/null +++ b/pom.xml @@ -0,0 +1,30 @@ + + + 4.0.0 + + org.krews.nitro + NitroWebsockets + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 6 + 6 + + + + + + + + com.eu.habbo + Habbo + 2.4.0 + + + \ No newline at end of file diff --git a/src/main/java/com/krews/plugin/nitro/main.java b/src/main/java/com/krews/plugin/nitro/main.java new file mode 100644 index 0000000..35a7053 --- /dev/null +++ b/src/main/java/com/krews/plugin/nitro/main.java @@ -0,0 +1,45 @@ +package com.krews.plugin.nitro; + +import com.eu.habbo.Emulator; +import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.plugin.EventHandler; +import com.eu.habbo.plugin.EventListener; +import com.eu.habbo.plugin.HabboPlugin; +import com.eu.habbo.plugin.events.emulator.EmulatorLoadedEvent; +import com.krews.plugin.nitro.websockets.NetworkChannelInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class main extends HabboPlugin implements EventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(Emulator.class); + + public void onEnable() throws Exception { + Emulator.getPluginManager().registerEvents(this, this); + if(Emulator.isReady && !Emulator.isShuttingDown) { + this.onEmulatorLoadedEvent(null); + } + } + + public void onDisable() throws Exception { + + } + + public boolean hasPermission(Habbo habbo, String s) { + return false; + } + + @EventHandler + public void onEmulatorLoadedEvent (EmulatorLoadedEvent e) { + //add missing db entry + Emulator.getConfig().register("websockets.whitelist", "localhost"); + Emulator.getConfig().register("ws.nitro.host", "0.0.0.0"); + Emulator.getConfig().register("ws.nitro.port", "2096"); + + Emulator.getGameServer().getServerBootstrap().childHandler(new NetworkChannelInitializer()); + + Emulator.getGameServer().getServerBootstrap().bind(Emulator.getConfig().getValue("ws.nitro.host", "0.0.0.0"), Emulator.getConfig().getInt("ws.nitro.port", 2096)).syncUninterruptibly(); + + LOGGER.info("OFFICIAL PLUGIN - Nitro Websockets has started!"); + LOGGER.info("Nitro Websockets Listening on " + Emulator.getConfig().getValue("ws.nitro.host", "0.0.0.0") + ":" + Emulator.getConfig().getInt("ws.nitro.port", 2096)); + } +} diff --git a/src/main/java/com/krews/plugin/nitro/websockets/NetworkChannelInitializer.java b/src/main/java/com/krews/plugin/nitro/websockets/NetworkChannelInitializer.java new file mode 100644 index 0000000..83843ab --- /dev/null +++ b/src/main/java/com/krews/plugin/nitro/websockets/NetworkChannelInitializer.java @@ -0,0 +1,39 @@ +package com.krews.plugin.nitro.websockets; + +import com.eu.habbo.messages.PacketManager; +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.krews.plugin.nitro.websockets.handlers.MessageInterceptorHandler; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.logging.LoggingHandler; + +public class NetworkChannelInitializer extends ChannelInitializer { + + @Override + public void initChannel(SocketChannel ch) throws Exception { + ch.pipeline().addLast("logger", new LoggingHandler()); + + ch.pipeline().addLast("messageInterceptor", new MessageInterceptorHandler()); + + // 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(new GameMessageRateLimit()); + ch.pipeline().addLast(new GameMessageHandler()); + + // Encoders. + ch.pipeline().addLast("messageEncoder", new GameServerMessageEncoder()); + + if (PacketManager.DEBUG_SHOW_PACKETS) { + ch.pipeline().addLast(new GameServerMessageLogger()); + } + } +} diff --git a/src/main/java/com/krews/plugin/nitro/websockets/codec/HabboFrameToWebSocketFrameEncoder.java b/src/main/java/com/krews/plugin/nitro/websockets/codec/HabboFrameToWebSocketFrameEncoder.java new file mode 100644 index 0000000..c758c86 --- /dev/null +++ b/src/main/java/com/krews/plugin/nitro/websockets/codec/HabboFrameToWebSocketFrameEncoder.java @@ -0,0 +1,29 @@ +package com.krews.plugin.nitro.websockets.codec; + +import com.eu.habbo.messages.ServerMessage; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageEncoder; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.util.IllegalReferenceCountException; + +import java.io.IOException; +import java.util.List; + +public class HabboFrameToWebSocketFrameEncoder extends MessageToMessageEncoder { + + @Override + protected void encode(ChannelHandlerContext channelHandlerContext, ServerMessage message, List out) throws Exception { + try { + BinaryWebSocketFrame frame = new BinaryWebSocketFrame(message.get()); + try { + out.add(frame.retain()); + } finally { + // Release copied buffer. + frame.release(); + } + } catch (IllegalReferenceCountException e) { + throw new IOException(String.format("IllegalReferenceCountException happened for ServerMessage with packet id %d.", message.getHeader()), e); + } + } +} + diff --git a/src/main/java/com/krews/plugin/nitro/websockets/codec/WebSocketFrameToHabboFrameDecoder.java b/src/main/java/com/krews/plugin/nitro/websockets/codec/WebSocketFrameToHabboFrameDecoder.java new file mode 100644 index 0000000..4e0eb14 --- /dev/null +++ b/src/main/java/com/krews/plugin/nitro/websockets/codec/WebSocketFrameToHabboFrameDecoder.java @@ -0,0 +1,55 @@ +package com.krews.plugin.nitro.websockets.codec; + +import com.eu.habbo.Emulator; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageDecoder; +import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +public class WebSocketFrameToHabboFrameDecoder extends MessageToMessageDecoder { + @Override + protected void decode(ChannelHandlerContext ctx, WebSocketFrame in, List out) { + out.add(in.content().retain()); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + // only allow websockets connections from the whitelist + if(evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) { + WebSocketServerProtocolHandler.HandshakeComplete handshake = (WebSocketServerProtocolHandler.HandshakeComplete)evt; + String origin = getDomainName(handshake.requestHeaders().get("Origin")); + + if(!isWhitelisted(origin)) { + ctx.channel().writeAndFlush(new CloseWebSocketFrame(403, "Origin forbidden")).addListener(ChannelFutureListener.CLOSE); + } + } + else { + super.userEventTriggered(ctx, evt); + } + } + + public static String getDomainName(String url) throws URISyntaxException { + URI uri = new URI(url); + String domain = uri.getHost(); + return domain.startsWith("www.") ? domain.substring(4) : domain; + } + + public static boolean isWhitelisted(String origin) { + String[] allowedOrigins = Emulator.getConfig().getValue("websockets.whitelist", "localhost").split(","); + for(String entry : allowedOrigins) { + if(entry.startsWith("*")) { + if(origin.endsWith(entry.substring(1)) || ("." + origin).equals(entry.substring(1))) return true; + } else { + if(origin.equals(entry)) return true; + } + } + return false; + } +} + diff --git a/src/main/java/com/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java b/src/main/java/com/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java new file mode 100644 index 0000000..92c2c2b --- /dev/null +++ b/src/main/java/com/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java @@ -0,0 +1,29 @@ +package com.krews.plugin.nitro.websockets.handlers; + +import com.krews.plugin.nitro.websockets.codec.HabboFrameToWebSocketFrameEncoder; +import com.krews.plugin.nitro.websockets.codec.WebSocketFrameToHabboFrameDecoder; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.util.CharsetUtil; + +import java.util.List; + +public class MessageInterceptorHandler extends ByteToMessageDecoder { + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if(in.toString(CharsetUtil.UTF_8).startsWith("GET")) { + // this is a websocket upgrade request, so add the appropriate decoders/encoders + ctx.pipeline().addAfter("messageInterceptor", "websocketHandler", new WebSocketFrameToHabboFrameDecoder()); + ctx.pipeline().addAfter("messageInterceptor", "protocolHandler", new WebSocketServerProtocolHandler("/", true)); + ctx.pipeline().addAfter("messageInterceptor", "objectAggregator", new HttpObjectAggregator(65536)); + ctx.pipeline().addAfter("messageInterceptor", "httpCodec", new HttpServerCodec()); + ctx.pipeline().replace("messageEncoder", "websocketFrameEncoder", new HabboFrameToWebSocketFrameEncoder()); + } + // Remove ourselves + ctx.pipeline().remove(this); + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.json b/src/main/resources/plugin.json new file mode 100644 index 0000000..123b506 --- /dev/null +++ b/src/main/resources/plugin.json @@ -0,0 +1,5 @@ +{ + "main" : "com.krews.plugin.nitro.main", + "name" : "Nitro Websockets", + "author" : "Krews" +} \ No newline at end of file