forked from openrs2/openrs2
parent
508d9526ea
commit
6d43e0392e
@ -0,0 +1,19 @@ |
|||||||
|
package org.openrs2.protocol.common |
||||||
|
|
||||||
|
public enum class AntiAliasingMode { |
||||||
|
NONE, |
||||||
|
X2, |
||||||
|
X4; |
||||||
|
|
||||||
|
public companion object { |
||||||
|
private val values = values() |
||||||
|
|
||||||
|
public fun fromOrdinal(ordinal: Int): AntiAliasingMode? { |
||||||
|
return if (ordinal >= 0 && ordinal < values.size) { |
||||||
|
values[ordinal] |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package org.openrs2.protocol.common |
||||||
|
|
||||||
|
public enum class DisplayMode { |
||||||
|
SD, |
||||||
|
HD_SMALL, |
||||||
|
HD, |
||||||
|
HD_FULLSCREEN; |
||||||
|
|
||||||
|
public companion object { |
||||||
|
private val values = values() |
||||||
|
|
||||||
|
public fun fromOrdinal(ordinal: Int): DisplayMode? { |
||||||
|
return if (ordinal >= 0 && ordinal < values.size) { |
||||||
|
values[ordinal] |
||||||
|
} else { |
||||||
|
null |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
package org.openrs2.protocol.common |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import io.netty.buffer.ByteBufUtil |
||||||
|
|
||||||
|
public class Uid private constructor( |
||||||
|
private val bytes: ByteArray, |
||||||
|
) { |
||||||
|
init { |
||||||
|
require(bytes.size == LENGTH) |
||||||
|
} |
||||||
|
|
||||||
|
public fun write(buf: ByteBuf) { |
||||||
|
buf.writeBytes(bytes) |
||||||
|
} |
||||||
|
|
||||||
|
public override fun toString(): String { |
||||||
|
return ByteBufUtil.hexDump(bytes) |
||||||
|
} |
||||||
|
|
||||||
|
public companion object { |
||||||
|
public const val LENGTH: Int = 24 |
||||||
|
|
||||||
|
public fun read(buf: ByteBuf): Uid { |
||||||
|
val bytes = ByteArray(LENGTH) |
||||||
|
buf.readBytes(bytes) |
||||||
|
return Uid(bytes) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package org.openrs2.protocol.login.upstream |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import jakarta.inject.Inject |
||||||
|
import jakarta.inject.Singleton |
||||||
|
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters |
||||||
|
import org.openrs2.crypto.StreamCipher |
||||||
|
import org.openrs2.protocol.VariableShortPacketCodec |
||||||
|
|
||||||
|
@Singleton |
||||||
|
public class GameLoginCodec @Inject constructor( |
||||||
|
private val key: RSAPrivateCrtKeyParameters, |
||||||
|
) : VariableShortPacketCodec<LoginRequest.GameLogin>( |
||||||
|
type = LoginRequest.GameLogin::class.java, |
||||||
|
opcode = 16, |
||||||
|
) { |
||||||
|
override fun decode(input: ByteBuf, cipher: StreamCipher): LoginRequest.GameLogin { |
||||||
|
return LoginRequest.GameLogin(GameLoginPayload.read(input, key)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun encode(input: LoginRequest.GameLogin, output: ByteBuf, cipher: StreamCipher) { |
||||||
|
input.payload.write(output, key) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,143 @@ |
|||||||
|
package org.openrs2.protocol.login.upstream |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import org.bouncycastle.crypto.params.RSAKeyParameters |
||||||
|
import org.openrs2.buffer.readString |
||||||
|
import org.openrs2.buffer.use |
||||||
|
import org.openrs2.buffer.writeString |
||||||
|
import org.openrs2.crypto.Rsa |
||||||
|
import org.openrs2.crypto.XteaKey |
||||||
|
import org.openrs2.crypto.rsa |
||||||
|
import org.openrs2.protocol.common.AntiAliasingMode |
||||||
|
import org.openrs2.protocol.common.DisplayMode |
||||||
|
import org.openrs2.protocol.common.Uid |
||||||
|
import org.openrs2.util.Base37 |
||||||
|
|
||||||
|
public data class GameLoginPayload( |
||||||
|
val build: Int, |
||||||
|
val advertSuppressed: Boolean, |
||||||
|
val clientSigned: Boolean, |
||||||
|
val displayMode: DisplayMode, |
||||||
|
val canvasWidth: Int, |
||||||
|
val canvasHeight: Int, |
||||||
|
val antiAliasingMode: AntiAliasingMode, |
||||||
|
val uid: Uid, |
||||||
|
val siteSettings: String, |
||||||
|
val affiliate: Int, |
||||||
|
val detailOptions: Int, |
||||||
|
val verifyId: Int, |
||||||
|
val js5ArchiveChecksums: List<Int>, |
||||||
|
// TODO(gpe): XteaKey needs a better name, as it represents an ISAAC key here |
||||||
|
val key: XteaKey, |
||||||
|
val username: String, |
||||||
|
val password: String, |
||||||
|
) { |
||||||
|
init { |
||||||
|
require(js5ArchiveChecksums.size == JS5_ARCHIVES) |
||||||
|
} |
||||||
|
|
||||||
|
internal fun write(buf: ByteBuf, rsaKey: RSAKeyParameters) { |
||||||
|
buf.writeInt(build) |
||||||
|
buf.writeByte(0) |
||||||
|
buf.writeBoolean(advertSuppressed) |
||||||
|
buf.writeBoolean(clientSigned) |
||||||
|
buf.writeByte(displayMode.ordinal) |
||||||
|
buf.writeShort(canvasWidth) |
||||||
|
buf.writeShort(canvasHeight) |
||||||
|
buf.writeByte(antiAliasingMode.ordinal) |
||||||
|
uid.write(buf) |
||||||
|
buf.writeString(siteSettings) |
||||||
|
buf.writeInt(affiliate) |
||||||
|
buf.writeInt(detailOptions) |
||||||
|
buf.writeShort(verifyId) |
||||||
|
|
||||||
|
for (checksum in js5ArchiveChecksums) { |
||||||
|
buf.writeInt(checksum) |
||||||
|
} |
||||||
|
|
||||||
|
buf.alloc().buffer().use { plaintext -> |
||||||
|
plaintext.writeByte(Rsa.MAGIC) |
||||||
|
plaintext.writeInt(key.k0) |
||||||
|
plaintext.writeInt(key.k1) |
||||||
|
plaintext.writeInt(key.k2) |
||||||
|
plaintext.writeInt(key.k3) |
||||||
|
plaintext.writeLong(Base37.encode(username)) |
||||||
|
plaintext.writeString(password) |
||||||
|
|
||||||
|
plaintext.rsa(rsaKey).use { ciphertext -> |
||||||
|
buf.writeByte(ciphertext.readableBytes()) |
||||||
|
buf.writeBytes(ciphertext) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public companion object { |
||||||
|
public const val JS5_ARCHIVES: Int = 29 |
||||||
|
|
||||||
|
internal fun read(buf: ByteBuf, rsaKey: RSAKeyParameters): GameLoginPayload { |
||||||
|
val build = buf.readInt() |
||||||
|
|
||||||
|
require(buf.readUnsignedByte().toInt() == 0) { |
||||||
|
"Unknown byte is non-zero" |
||||||
|
} |
||||||
|
|
||||||
|
val advertSuppressed = buf.readBoolean() |
||||||
|
val clientSigned = buf.readBoolean() |
||||||
|
|
||||||
|
val displayMode = DisplayMode.fromOrdinal(buf.readUnsignedByte().toInt()) |
||||||
|
?: throw IllegalArgumentException("Invalid DisplayMode") |
||||||
|
|
||||||
|
val canvasWidth = buf.readUnsignedShort() |
||||||
|
val canvasHeight = buf.readUnsignedShort() |
||||||
|
|
||||||
|
val antiAliasingMode = AntiAliasingMode.fromOrdinal(buf.readUnsignedByte().toInt()) |
||||||
|
?: throw IllegalArgumentException("Invalid AntiAliasingMode") |
||||||
|
|
||||||
|
val uid = Uid.read(buf) |
||||||
|
val siteSettings = buf.readString() |
||||||
|
val affiliate = buf.readInt() |
||||||
|
val detailOptions = buf.readInt() |
||||||
|
val verifyId = buf.readUnsignedShort() |
||||||
|
|
||||||
|
val js5ArchiveChecksums = mutableListOf<Int>() |
||||||
|
for (i in 0 until JS5_ARCHIVES) { |
||||||
|
js5ArchiveChecksums += buf.readInt() |
||||||
|
} |
||||||
|
|
||||||
|
val ciphertextLen = buf.readUnsignedByte().toInt() |
||||||
|
val ciphertext = buf.readSlice(ciphertextLen) |
||||||
|
|
||||||
|
ciphertext.rsa(rsaKey).use { plaintext -> |
||||||
|
require(plaintext.readUnsignedByte().toInt() == Rsa.MAGIC) { |
||||||
|
"Invalid RSA magic" |
||||||
|
} |
||||||
|
|
||||||
|
val k0 = plaintext.readInt() |
||||||
|
val k1 = plaintext.readInt() |
||||||
|
val k2 = plaintext.readInt() |
||||||
|
val k3 = plaintext.readInt() |
||||||
|
val username = plaintext.readLong() |
||||||
|
val password = plaintext.readString() |
||||||
|
|
||||||
|
return GameLoginPayload( |
||||||
|
build, |
||||||
|
advertSuppressed, |
||||||
|
clientSigned, |
||||||
|
displayMode, |
||||||
|
canvasWidth, |
||||||
|
canvasHeight, |
||||||
|
antiAliasingMode, |
||||||
|
uid, |
||||||
|
siteSettings, |
||||||
|
affiliate, |
||||||
|
detailOptions, |
||||||
|
verifyId, |
||||||
|
js5ArchiveChecksums, |
||||||
|
XteaKey(k0, k1, k2, k3), |
||||||
|
Base37.decodeLowerCase(username), |
||||||
|
password, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package org.openrs2.protocol.login.upstream |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf |
||||||
|
import jakarta.inject.Inject |
||||||
|
import jakarta.inject.Singleton |
||||||
|
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters |
||||||
|
import org.openrs2.crypto.StreamCipher |
||||||
|
import org.openrs2.protocol.VariableShortPacketCodec |
||||||
|
|
||||||
|
@Singleton |
||||||
|
public class GameReconnectCodec @Inject constructor( |
||||||
|
private val key: RSAPrivateCrtKeyParameters, |
||||||
|
) : VariableShortPacketCodec<LoginRequest.GameReconnect>( |
||||||
|
type = LoginRequest.GameReconnect::class.java, |
||||||
|
opcode = 18, |
||||||
|
) { |
||||||
|
override fun decode(input: ByteBuf, cipher: StreamCipher): LoginRequest.GameReconnect { |
||||||
|
return LoginRequest.GameReconnect(GameLoginPayload.read(input, key)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun encode(input: LoginRequest.GameReconnect, output: ByteBuf, cipher: StreamCipher) { |
||||||
|
input.payload.write(output, key) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue