diff --git a/pom.xml b/pom.xml index 9b4b2b9..7a85e9b 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ com.eu.habbo Habbo - 2.5.0 + 3.0.0 \ No newline at end of file diff --git a/src/main/java/org/krews/plugin/nitro/Utils.java b/src/main/java/org/krews/plugin/nitro/Utils.java new file mode 100644 index 0000000..5f643e4 --- /dev/null +++ b/src/main/java/org/krews/plugin/nitro/Utils.java @@ -0,0 +1,22 @@ +package org.krews.plugin.nitro; + +import java.net.URI; + +public class Utils { + public static String getDomainNameFromUrl(String url) throws Exception { + URI uri = new URI(url); + String domain = uri.getHost(); + return domain.startsWith("www.") ? domain.substring(4) : domain; + } + + public static boolean isWhitelisted(String toCheck, String[] whitelist) { + for(String whitelistEntry : whitelist) { + if(whitelistEntry.startsWith("*")) { + if(toCheck.endsWith(whitelistEntry.substring(1)) || ("." + toCheck).equals(whitelistEntry.substring(1))) return true; + } else { + if(toCheck.equals(whitelistEntry)) return true; + } + } + return false; + } +} diff --git a/src/main/java/org/krews/plugin/nitro/main.java b/src/main/java/org/krews/plugin/nitro/main.java index c0cf407..b5a163f 100644 --- a/src/main/java/org/krews/plugin/nitro/main.java +++ b/src/main/java/org/krews/plugin/nitro/main.java @@ -6,12 +6,16 @@ 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.eu.habbo.plugin.events.users.UserGetIPAddressEvent; +import io.netty.channel.Channel; +import io.netty.util.AttributeKey; import org.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(main.class); + public static final AttributeKey WS_IP = AttributeKey.valueOf("WS_IP"); public void onEnable() throws Exception { Emulator.getPluginManager().registerEvents(this, this); @@ -34,6 +38,7 @@ public class main extends HabboPlugin implements EventListener { Emulator.getConfig().register("websockets.whitelist", "localhost"); Emulator.getConfig().register("ws.nitro.host", "0.0.0.0"); Emulator.getConfig().register("ws.nitro.port", "2096"); + Emulator.getConfig().register("ws.nitro.ip.header", ""); Emulator.getGameServer().getServerBootstrap().childHandler(new NetworkChannelInitializer()); @@ -42,4 +47,15 @@ public class main extends HabboPlugin implements EventListener { 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)); } + + @EventHandler + public void onUserGetIPEvent(UserGetIPAddressEvent e) { + Channel channel = e.habbo.getClient().getChannel(); + if(channel != null && channel.hasAttr(main.WS_IP)) { + String ip = channel.attr(main.WS_IP).get(); + if(!ip.isEmpty()) { + e.setUpdatedIp(ip); + } + } + } } diff --git a/src/main/java/org/krews/plugin/nitro/websockets/codec/WebSocketCodec.java b/src/main/java/org/krews/plugin/nitro/websockets/codec/WebSocketCodec.java index c7afa24..e1a9fc2 100644 --- a/src/main/java/org/krews/plugin/nitro/websockets/codec/WebSocketCodec.java +++ b/src/main/java/org/krews/plugin/nitro/websockets/codec/WebSocketCodec.java @@ -1,19 +1,16 @@ package org.krews.plugin.nitro.websockets.codec; -import com.eu.habbo.Emulator; import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; -import io.netty.handler.codec.http.websocketx.*; +import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import io.netty.handler.codec.http.websocketx.WebSocketFrame; -import java.net.URI; -import java.net.URISyntaxException; import java.util.List; public class WebSocketCodec extends MessageToMessageCodec { @Override - protected void encode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + protected void encode(ChannelHandlerContext ctx, ByteBuf in, List out) { out.add(new BinaryWebSocketFrame(in).retain()); } @@ -21,39 +18,5 @@ public class WebSocketCodec extends MessageToMessageCodec 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/org/krews/plugin/nitro/websockets/handlers/CustomHTTPHandler.java b/src/main/java/org/krews/plugin/nitro/websockets/handlers/CustomHTTPHandler.java new file mode 100644 index 0000000..16153f1 --- /dev/null +++ b/src/main/java/org/krews/plugin/nitro/websockets/handlers/CustomHTTPHandler.java @@ -0,0 +1,53 @@ +package org.krews.plugin.nitro.websockets.handlers; + +import com.eu.habbo.Emulator; +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 org.krews.plugin.nitro.Utils; +import org.krews.plugin.nitro.main; + +public class CustomHTTPHandler extends ChannelInboundHandlerAdapter { + private static final String ORIGIN_HEADER = "Origin"; + //private static final String FORWARD_PROXY_REALIP = "X-Forwarded-For"; + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if(msg instanceof HttpMessage) { + if(!handleHttpRequest(ctx, (HttpMessage) msg)) + { + ReferenceCountUtil.release(msg);//discard message + return; + } + } + super.channelRead(ctx, msg); + ctx.pipeline().remove(this); + } + + public boolean handleHttpRequest(ChannelHandlerContext ctx, HttpMessage req) { + String origin = "error"; + + try { + if(req.headers().contains(ORIGIN_HEADER)) { + origin = Utils.getDomainNameFromUrl(req.headers().get(ORIGIN_HEADER)); + } + } catch (Exception ignored) { } + + if(!Utils.isWhitelisted(origin, Emulator.getConfig().getValue("websockets.whitelist", "localhost").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 header = Emulator.getConfig().getValue("ws.nitro.ip.header", ""); + + if(!header.isEmpty() && req.headers().contains(header)) { + String ip = req.headers().get(header); + ctx.channel().attr(main.WS_IP).set(ip); + } + return true; + } +} diff --git a/src/main/java/org/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java b/src/main/java/org/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java index 5f5ad86..1a5460a 100644 --- a/src/main/java/org/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java +++ b/src/main/java/org/krews/plugin/nitro/websockets/handlers/MessageInterceptorHandler.java @@ -1,6 +1,5 @@ package org.krews.plugin.nitro.websockets.handlers; -import org.krews.plugin.nitro.websockets.codec.WebSocketCodec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; @@ -8,6 +7,7 @@ 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 org.krews.plugin.nitro.websockets.codec.WebSocketCodec; import java.util.List; @@ -18,6 +18,7 @@ public class MessageInterceptorHandler extends ByteToMessageDecoder { // this is a websocket upgrade request, so add the appropriate decoders/encoders ctx.pipeline().addAfter("messageInterceptor", "websocketCodec", new WebSocketCodec()); ctx.pipeline().addAfter("messageInterceptor", "protocolHandler", new WebSocketServerProtocolHandler("/", true)); + ctx.pipeline().addAfter("messageInterceptor", "customhttpHandler", new CustomHTTPHandler()); ctx.pipeline().addAfter("messageInterceptor", "objectAggregator", new HttpObjectAggregator(65536)); ctx.pipeline().addAfter("messageInterceptor", "httpCodec", new HttpServerCodec()); }