Add cross-domain policy support

Required by the most recent versions of the Java plugin (before it was
killed).

Signed-off-by: Graham <gpe@openrs2.org>
pull/132/head
Graham 3 years ago
parent 2a6b97480c
commit 92a01b6262
  1. 46
      game/src/main/kotlin/org/openrs2/game/net/crossdomain/CrossDomainChannelHandler.kt
  2. 20
      game/src/main/kotlin/org/openrs2/game/net/http/Http.kt
  3. 16
      game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelHandler.kt
  4. 6
      game/src/main/kotlin/org/openrs2/game/net/http/HttpChannelInitializer.kt
  5. 22
      game/src/main/kotlin/org/openrs2/game/net/login/LoginChannelHandler.kt
  6. 4
      protocol/src/main/kotlin/org/openrs2/protocol/Protocol.kt
  7. 8
      protocol/src/main/kotlin/org/openrs2/protocol/login/InitCrossDomainConnectionCodec.kt
  8. 1
      protocol/src/main/kotlin/org/openrs2/protocol/login/LoginRequest.kt

@ -0,0 +1,46 @@
package org.openrs2.game.net.crossdomain
import io.netty.buffer.Unpooled
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpMethod
import io.netty.handler.codec.http.HttpRequest
import io.netty.handler.codec.http.HttpResponseStatus
import org.openrs2.game.net.http.Http
@ChannelHandler.Sharable
public object CrossDomainChannelHandler : SimpleChannelInboundHandler<HttpRequest>() {
private const val ENDPOINT = "/crossdomain.xml"
private val POLICY = """
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only" />
<allow-access-from domain="*" />
</cross-domain-policy>
""".trimIndent().plus("\n").toByteArray(Charsets.UTF_8)
override fun handlerAdded(ctx: ChannelHandlerContext) {
ctx.read()
}
override fun channelRead0(ctx: ChannelHandlerContext, msg: HttpRequest) {
if (msg.method() != HttpMethod.GET || msg.uri() != ENDPOINT) {
ctx.write(Http.createResponse(HttpResponseStatus.BAD_REQUEST)).addListener(ChannelFutureListener.CLOSE)
return
}
val response = Http.createResponse(HttpResponseStatus.OK)
response.headers().add(HttpHeaderNames.CONTENT_TYPE, Http.TEXT_X_CROSS_DOMAIN_POLICY)
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, POLICY.size)
ctx.write(response, ctx.voidPromise())
ctx.write(Unpooled.wrappedBuffer(POLICY)).addListener(ChannelFutureListener.CLOSE)
}
override fun channelReadComplete(ctx: ChannelHandlerContext) {
ctx.flush()
}
}

@ -0,0 +1,20 @@
package org.openrs2.game.net.http
import io.netty.handler.codec.http.DefaultHttpResponse
import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpHeaderValues
import io.netty.handler.codec.http.HttpResponse
import io.netty.handler.codec.http.HttpResponseStatus
import io.netty.handler.codec.http.HttpVersion
public object Http {
public const val MAX_CONTENT_LENGTH: Int = 65536
public const val TEXT_X_CROSS_DOMAIN_POLICY: String = "text/x-cross-domain-policy"
public fun createResponse(status: HttpResponseStatus): HttpResponse {
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, status)
response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
response.headers().add(HttpHeaderNames.SERVER, "OpenRS2")
return response
}
}

@ -4,13 +4,10 @@ import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandler import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.codec.http.DefaultHttpResponse
import io.netty.handler.codec.http.HttpHeaderNames import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpHeaderValues import io.netty.handler.codec.http.HttpHeaderValues
import io.netty.handler.codec.http.HttpRequest import io.netty.handler.codec.http.HttpRequest
import io.netty.handler.codec.http.HttpResponse
import io.netty.handler.codec.http.HttpResponseStatus import io.netty.handler.codec.http.HttpResponseStatus
import io.netty.handler.codec.http.HttpVersion
import org.openrs2.game.net.FileProvider import org.openrs2.game.net.FileProvider
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -27,17 +24,17 @@ public class HttpChannelHandler @Inject constructor(
override fun channelRead0(ctx: ChannelHandlerContext, msg: HttpRequest) { override fun channelRead0(ctx: ChannelHandlerContext, msg: HttpRequest) {
val uri = msg.uri() val uri = msg.uri()
if (!uri.startsWith("/")) { if (!uri.startsWith("/")) {
ctx.write(createResponse(HttpResponseStatus.BAD_REQUEST)).addListener(ChannelFutureListener.CLOSE) ctx.write(Http.createResponse(HttpResponseStatus.BAD_REQUEST)).addListener(ChannelFutureListener.CLOSE)
return return
} }
val file = fileProvider.get(uri.substring(1)) val file = fileProvider.get(uri.substring(1))
if (file == null) { if (file == null) {
ctx.write(createResponse(HttpResponseStatus.NOT_FOUND)).addListener(ChannelFutureListener.CLOSE) ctx.write(Http.createResponse(HttpResponseStatus.NOT_FOUND)).addListener(ChannelFutureListener.CLOSE)
return return
} }
val response = createResponse(HttpResponseStatus.OK) val response = Http.createResponse(HttpResponseStatus.OK)
response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_OCTET_STREAM) response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_OCTET_STREAM)
response.headers().add(HttpHeaderNames.CONTENT_LENGTH, file.count()) response.headers().add(HttpHeaderNames.CONTENT_LENGTH, file.count())
@ -48,11 +45,4 @@ public class HttpChannelHandler @Inject constructor(
override fun channelReadComplete(ctx: ChannelHandlerContext) { override fun channelReadComplete(ctx: ChannelHandlerContext) {
ctx.flush() ctx.flush()
} }
private fun createResponse(status: HttpResponseStatus): HttpResponse {
val response = DefaultHttpResponse(HttpVersion.HTTP_1_1, status)
response.headers().add(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
response.headers().add(HttpHeaderNames.SERVER, "OpenRS2")
return response
}
} }

@ -16,12 +16,8 @@ public class HttpChannelInitializer @Inject constructor(
ch.pipeline().addLast( ch.pipeline().addLast(
HttpRequestDecoder(), HttpRequestDecoder(),
HttpResponseEncoder(), HttpResponseEncoder(),
HttpObjectAggregator(MAX_CONTENT_LENGTH), HttpObjectAggregator(Http.MAX_CONTENT_LENGTH),
handler handler
) )
} }
private companion object {
private const val MAX_CONTENT_LENGTH = 65536
}
} }

@ -5,8 +5,13 @@ import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler import io.netty.channel.SimpleChannelInboundHandler
import io.netty.handler.codec.DelimiterBasedFrameDecoder import io.netty.handler.codec.DelimiterBasedFrameDecoder
import io.netty.handler.codec.http.HttpObjectAggregator
import io.netty.handler.codec.http.HttpRequestDecoder
import io.netty.handler.codec.http.HttpResponseEncoder
import io.netty.handler.codec.string.StringDecoder import io.netty.handler.codec.string.StringDecoder
import org.openrs2.buffer.copiedBuffer import org.openrs2.buffer.copiedBuffer
import org.openrs2.game.net.crossdomain.CrossDomainChannelHandler
import org.openrs2.game.net.http.Http
import org.openrs2.game.net.jaggrab.JaggrabChannelHandler import org.openrs2.game.net.jaggrab.JaggrabChannelHandler
import org.openrs2.game.net.js5.Js5ChannelHandler import org.openrs2.game.net.js5.Js5ChannelHandler
import org.openrs2.protocol.Rs2Decoder import org.openrs2.protocol.Rs2Decoder
@ -32,6 +37,7 @@ public class LoginChannelHandler @Inject constructor(
when (msg) { when (msg) {
is LoginRequest.InitJs5RemoteConnection -> handleInitJs5RemoteConnection(ctx, msg) is LoginRequest.InitJs5RemoteConnection -> handleInitJs5RemoteConnection(ctx, msg)
is LoginRequest.InitJaggrabConnection -> handleInitJaggrabConnection(ctx) is LoginRequest.InitJaggrabConnection -> handleInitJaggrabConnection(ctx)
is LoginRequest.InitCrossDomainConnection -> handleInitCrossDomainConnection(ctx)
} }
} }
@ -67,6 +73,21 @@ public class LoginChannelHandler @Inject constructor(
ctx.pipeline().remove(this) ctx.pipeline().remove(this)
} }
private fun handleInitCrossDomainConnection(ctx: ChannelHandlerContext) {
ctx.pipeline().addLast(
HttpRequestDecoder(),
HttpResponseEncoder(),
HttpObjectAggregator(Http.MAX_CONTENT_LENGTH),
CrossDomainChannelHandler
)
ctx.fireChannelRead(Unpooled.wrappedBuffer(G))
ctx.pipeline().remove(Rs2Decoder::class.java)
ctx.pipeline().remove(Rs2Encoder::class.java)
ctx.pipeline().remove(this)
}
override fun channelReadComplete(ctx: ChannelHandlerContext) { override fun channelReadComplete(ctx: ChannelHandlerContext) {
ctx.flush() ctx.flush()
} }
@ -75,5 +96,6 @@ public class LoginChannelHandler @Inject constructor(
private const val BUILD = 550 private const val BUILD = 550
private const val JAGGRAB_MAX_FRAME_LENGTH = 4096 private const val JAGGRAB_MAX_FRAME_LENGTH = 4096
private val JAGGRAB_DELIMITER = Unpooled.unreleasableBuffer(copiedBuffer("\n\n")) private val JAGGRAB_DELIMITER = Unpooled.unreleasableBuffer(copiedBuffer("\n\n"))
private val G = byteArrayOf('G'.code.toByte())
} }
} }

@ -1,6 +1,7 @@
package org.openrs2.protocol package org.openrs2.protocol
import org.openrs2.protocol.login.ClientOutOfDateCodec import org.openrs2.protocol.login.ClientOutOfDateCodec
import org.openrs2.protocol.login.InitCrossDomainConnectionCodec
import org.openrs2.protocol.login.InitJaggrabConnectionCodec import org.openrs2.protocol.login.InitJaggrabConnectionCodec
import org.openrs2.protocol.login.InitJs5RemoteConnectionCodec import org.openrs2.protocol.login.InitJs5RemoteConnectionCodec
import org.openrs2.protocol.login.IpLimitCodec import org.openrs2.protocol.login.IpLimitCodec
@ -32,7 +33,8 @@ public class Protocol(vararg codecs: PacketCodec<*>) {
public val LOGIN_UPSTREAM: Protocol = Protocol( public val LOGIN_UPSTREAM: Protocol = Protocol(
InitJs5RemoteConnectionCodec, InitJs5RemoteConnectionCodec,
InitJaggrabConnectionCodec, InitJaggrabConnectionCodec,
RequestWorldListCodec RequestWorldListCodec,
InitCrossDomainConnectionCodec
) )
public val LOGIN_DOWNSTREAM: Protocol = Protocol( public val LOGIN_DOWNSTREAM: Protocol = Protocol(
Js5OkCodec, Js5OkCodec,

@ -0,0 +1,8 @@
package org.openrs2.protocol.login
import org.openrs2.protocol.EmptyPacketCodec
public object InitCrossDomainConnectionCodec : EmptyPacketCodec<LoginRequest.InitCrossDomainConnection>(
opcode = 'G'.code,
packet = LoginRequest.InitCrossDomainConnection
)

@ -6,4 +6,5 @@ public sealed class LoginRequest : Packet {
public data class InitJs5RemoteConnection(public val build: Int) : LoginRequest() public data class InitJs5RemoteConnection(public val build: Int) : LoginRequest()
public object InitJaggrabConnection : LoginRequest() public object InitJaggrabConnection : LoginRequest()
public data class RequestWorldList(public val checksum: Int) : LoginRequest() public data class RequestWorldList(public val checksum: Int) : LoginRequest()
public object InitCrossDomainConnection : LoginRequest()
} }

Loading…
Cancel
Save