diff --git a/build.gradle.kts b/build.gradle.kts index 117c4e90..f56054a0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ allprojects { apply(plugin = "maven-publish") group = "net.rsprox" - version = "1.0.3" + version = "1.0.4" repositories { mavenCentral() diff --git a/patch/patch-runelite/build.gradle.kts b/patch/patch-runelite/build.gradle.kts deleted file mode 100644 index 6a33d0a6..00000000 --- a/patch/patch-runelite/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -plugins { - `maven-publish` -} - -publishing { - publications { - create("mavenJava") { - from(components["java"]) - } - } -} - -dependencies { - implementation(projects.patch) - implementation(rootProject.libs.inline.logger) - implementation(libs.zip4j) -} diff --git a/patch/patch-runelite/src/main/kotlin/net/rsprox/patch/runelite/RuneLitePatcher.kt b/patch/patch-runelite/src/main/kotlin/net/rsprox/patch/runelite/RuneLitePatcher.kt deleted file mode 100644 index 9851d209..00000000 --- a/patch/patch-runelite/src/main/kotlin/net/rsprox/patch/runelite/RuneLitePatcher.kt +++ /dev/null @@ -1,540 +0,0 @@ -package net.rsprox.patch.runelite - -import com.github.michaelbull.logging.InlineLogger -import jdk.security.jarsigner.JarSigner -import net.lingala.zip4j.ZipFile -import net.rsprox.patch.PatchResult -import net.rsprox.patch.Patcher -import net.rsprox.patch.findBoyerMoore -import java.io.File -import java.nio.file.Files -import java.nio.file.LinkOption -import java.nio.file.Path -import java.security.KeyStore -import java.security.KeyStore.PasswordProtection -import java.security.KeyStore.PrivateKeyEntry -import java.security.MessageDigest -import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.Path -import kotlin.io.path.copyTo -import kotlin.io.path.deleteIfExists -import kotlin.io.path.deleteRecursively -import kotlin.io.path.exists -import kotlin.io.path.extension -import kotlin.io.path.isRegularFile -import kotlin.io.path.moveTo -import kotlin.io.path.nameWithoutExtension -import kotlin.io.path.readBytes -import kotlin.io.path.readText -import kotlin.io.path.writeBytes -import kotlin.io.path.writeText - -@Suppress("DuplicatedCode", "SameParameterValue") -public class RuneLitePatcher : Patcher { - public fun patch( - path: Path, - rsa: String, - port: Int, - ): PatchResult { - return patch( - path, - rsa, - "", - "", - port, - Unit, - ) - } - - @OptIn(ExperimentalPathApi::class) - override fun patch( - path: Path, - rsa: String, - javConfigUrl: String, - worldListUrl: String, - port: Int, - metadata: Unit, - ): PatchResult { - if (!path.isRegularFile(LinkOption.NOFOLLOW_LINKS)) { - throw IllegalArgumentException("Path $path does not point to a file.") - } - logger.debug { "Attempting to patch $path" } - val time = System.currentTimeMillis() - val outputFolder = path.parent.resolve("runelite-injected-client-$time") - val oldModulus: String - val patchedJar: Path - try { - logger.debug { "Attempting to patch a jar." } - Files.createDirectories(outputFolder) - ZipFile(path.toFile()).use { inputFile -> - logger.debug { "Extracting existing classes from a zip file." } - inputFile.extractAll(outputFolder.toFile().absolutePath) - - logger.debug { "Patching class files." } - oldModulus = overwriteModulus(outputFolder, rsa) - overwriteLocalHost(outputFolder) - patchPort(outputFolder, port) - patchedJar = path.parent.resolve(path.nameWithoutExtension + "-$time-patched." + path.extension) - ZipFile(patchedJar.toFile()).use { outputFile -> - val parentDir = outputFolder.toFile() - val files = parentDir.walkTopDown().maxDepth(1) - logger.debug { "Building a patched jar." } - for (file in files) { - if (file == parentDir) continue - if (file.isFile) { - outputFile.addFile(file) - } else { - outputFile.addFolder(file) - } - } - outputFile.charset = inputFile.charset - } - } - } finally { - logger.debug { "Deleting temporary extracted class files." } - outputFolder.deleteRecursively() - } - logger.debug { "Jar patching complete." } - return PatchResult.Success( - oldModulus, - patchedJar, - ) - } - - @OptIn(ExperimentalStdlibApi::class) - public fun sha256Hash(bytes: ByteArray): String { - val messageDigest = MessageDigest.getInstance("SHA-256") - messageDigest.update(bytes) - return messageDigest.digest().toHexString(HexFormat.UpperCase) - } - - @OptIn(ExperimentalPathApi::class) - public fun patchLocalHostSupport(path: Path): Path { - val time = System.currentTimeMillis() - val inputPath = path.parent.resolve(path.nameWithoutExtension + "-$time-patched." + path.extension) - val configurationPath = Path(System.getProperty("user.home"), ".rsprox") - val runelitePath = configurationPath.resolve("runelite") - val shaPath = runelitePath.resolve("latest-runelite.sha256") - val existingClient = runelitePath.resolve("latest-runelite.jar") - val currentSha256 = sha256Hash(path.readBytes()) - if (shaPath.exists(LinkOption.NOFOLLOW_LINKS) && - existingClient.exists(LinkOption.NOFOLLOW_LINKS) - ) { - val existingSha256 = shaPath.readText(Charsets.UTF_8) - if (existingSha256 == currentSha256) { - logger.debug { "Using cached runelite-client as sha-256 matches" } - inputPath.writeBytes(existingClient.readBytes()) - return inputPath - } - } - existingClient.deleteIfExists() - val copy = path.copyTo(inputPath) - val outputFolder = path.parent.resolve("runelite-client-$time") - try { - ZipFile(copy.toFile()).use { inputFile -> - inputFile.extractAll(outputFolder.toFile().absolutePath) - - val patchedJar = - path.parent - .resolve(path.nameWithoutExtension + "-$time-patched." + path.extension) - ZipFile(patchedJar.toFile()).use { outputFile -> - val parentDir = outputFolder.toFile() - val metaInf = parentDir.resolve("META-INF") - metaInf.resolve("MANIFEST.MF").delete() - metaInf.resolve("RL.RSA").delete() - metaInf.resolve("RL.SF").delete() - - replaceClass( - parentDir - .resolve("net") - .resolve("runelite") - .resolve("client") - .resolve("game") - .resolve("WorldClient.class"), - "Original WorldClient.class", - "WorldClient.class", - ) - - replaceClass( - parentDir - .resolve("net") - .resolve("runelite") - .resolve("client") - .resolve("RuneLite.class"), - "Original RuneLite.class", - "RuneLite.class", - ) - - replaceClass( - parentDir - .resolve("net") - .resolve("runelite") - .resolve("client") - .resolve("rs") - .resolve("ClientLoader.class"), - "Original ClientLoader.class", - "ClientLoader.class", - ) - - val files = parentDir.walkTopDown().maxDepth(1) - logger.debug { "Building a patched jar." } - for (file in files) { - if (file == parentDir) continue - if (file.isFile) { - outputFile.addFile(file) - } else { - outputFile.addFolder(file) - } - } - outputFile.charset = inputFile.charset - } - val jarFile = patchedJar.toFile() - sign(patchedJar) - jarFile.copyTo(existingClient.toFile()) - shaPath.writeText(currentSha256, Charsets.UTF_8) - } - } finally { - outputFolder.deleteRecursively() - } - return copy - } - - @OptIn(ExperimentalPathApi::class) - public fun patchRuneLiteApi(path: Path): Path { - val time = System.currentTimeMillis() - val inputPath = path.parent.resolve(path.nameWithoutExtension + "-$time-patched." + path.extension) - val copy = path.copyTo(inputPath) - val outputFolder = path.parent.resolve("runelite-api-$time") - try { - ZipFile(copy.toFile()).use { inputFile -> - inputFile.extractAll(outputFolder.toFile().absolutePath) - val patchedJar = - path.parent - .resolve(path.nameWithoutExtension + "-$time-patched." + path.extension) - ZipFile(patchedJar.toFile()).use { outputFile -> - val parentDir = outputFolder.toFile() - - writeFile("Varbits.class", parentDir) - writeFile("VarPlayer.class", parentDir) - writeFile("VarClientInt.class", parentDir) - writeFile("VarClientStr.class", parentDir) - writeFile("ComponentID.class", parentDir, "widgets") - writeFile("InterfaceID.class", parentDir, "widgets") - - val files = parentDir.walkTopDown().maxDepth(1) - logger.debug { "Building a patched API jar." } - for (file in files) { - if (file == parentDir) continue - if (file.isFile) { - outputFile.addFile(file) - } else { - outputFile.addFolder(file) - } - } - outputFile.charset = inputFile.charset - } - } - } finally { - outputFolder.deleteRecursively() - } - return copy - } - - private fun sign(path: Path) { - val fakeCertificate = - Path(System.getProperty("user.home")) - .resolve(".rsprox") - .resolve("signkey") - .resolve("fake-cert.jks") - val password = "123456".toCharArray() - val store = KeyStore.getInstance(fakeCertificate.toFile(), password) - val entry = store.getEntry("test", PasswordProtection(password)) as PrivateKeyEntry - val signer = JarSigner.Builder(entry).build() - val output = path.parent.resolve(path.nameWithoutExtension + "-signed.${path.extension}") - signer.sign(java.util.zip.ZipFile(path.toFile()), output.toFile().outputStream()) - output.moveTo(path, overwrite = true) - } - - private fun writeFile( - name: String, - folder: File, - subDir: String? = null, - ) { - // In order for developer mode to work, we must re-add the Var*.class that - // RuneLite excludes from the API unless building from source - val classByteArray = - RuneLitePatcher::class.java - .getResourceAsStream(name) - ?.readAllBytes() - ?: throw IllegalStateException("$name resource not available.") - - val apiDirectory = - folder - .toPath() - .resolve("net") - .resolve("runelite") - .resolve("api") - val subApiDir = - if (subDir != null) { - apiDirectory.resolve(subDir) - } else { - apiDirectory - } - Files.createDirectories(subApiDir) - val classPath = subApiDir.resolve(name) - classPath.writeBytes(classByteArray) - } - - private fun replaceClass( - classFile: File, - originalResource: String, - replacementResource: String, - ) { - val replacementResourceFile = - RuneLitePatcher::class.java - .getResourceAsStream(replacementResource) - ?.readAllBytes() - ?: throw IllegalStateException("$replacementResource resource not available") - - val originalResourceFile = - RuneLitePatcher::class.java - .getResourceAsStream(originalResource) - ?.readAllBytes() - ?: throw IllegalStateException("$originalResource resource not available.") - - val originalBytes = classFile.readBytes() - if (!originalBytes.contentEquals(originalResourceFile)) { - throw IllegalStateException("Unable to patch RuneLite $replacementResource - out of date.") - } - - // Overwrite the WorldClient.class file to read worlds from our proxied-list - // This ensures that the world switcher still goes through the proxy tool, - // instead of just connecting to RuneLite's own world list API. - classFile.writeBytes(replacementResourceFile) - } - - private fun patchPort( - outputFolder: Path, - port: Int, - ) { - val inputPort = toByteArray(listOf(3, 0, 0, 43594 ushr 8 and 0xFF, 43594 and 0xFF)) - val outputPort = toByteArray(listOf(3, 0, 0, port ushr 8 and 0xFF, port and 0xFF)) - for (file in outputFolder.toFile().walkTopDown()) { - if (!file.isFile) continue - val bytes = file.readBytes() - val index = bytes.indexOf(inputPort) - if (index == -1) { - continue - } - logger.debug { "Patching port from 43594 to $port in ${file.name}" } - bytes.replaceBytes(inputPort, outputPort) - file.writeBytes(bytes) - } - } - - private fun toByteArray(list: List): ByteArray { - return list.map(Int::toByte).toByteArray() - } - - private fun ByteArray.replaceBytes( - input: ByteArray, - output: ByteArray, - ) { - val index = indexOf(input) - check(index != -1) { - "Unable to find byte sequence: ${input.contentToString()}" - } - overwrite(index, output) - } - - private fun ByteArray.overwrite( - index: Int, - replacement: ByteArray, - ) { - for (i in replacement.indices) { - this[i + index] = replacement[i] - } - } - - private fun overwriteModulus( - outputFolder: Path, - rsa: String, - ): String { - for (file in outputFolder.toFile().walkTopDown()) { - if (!file.isFile) continue - val bytes = file.readBytes() - val index = bytes.indexOf("10001".toByteArray(Charsets.UTF_8)) - if (index == -1) { - continue - } - logger.debug { "Attempting to patch modulus in class ${file.name}" } - val (replacementBytes, oldModulus) = - patchModulus( - bytes, - rsa, - ) - file.writeBytes(replacementBytes) - return oldModulus - } - throw IllegalStateException("Unable to find modulus.") - } - - private fun overwriteLocalHost(outputFolder: Path) { - for (file in outputFolder.toFile().walkTopDown()) { - if (!file.isFile) continue - val bytes = file.readBytes() - val index = bytes.indexOf("127.0.0.1".toByteArray(Charsets.UTF_8)) - if (index == -1) continue - logger.debug { "Patching localhost in file ${file.name}." } - val new = patchLocalhost(bytes) - file.writeBytes(new) - return - } - throw IllegalStateException("Unable to find localhost.") - } - - private fun patchModulus( - bytes: ByteArray, - replacement: String, - ): Pair { - val sliceIndices = - bytes.firstSliceIndices(0, 256) { - isHex(it.toInt().toChar()) - } - check(!isHex(bytes[sliceIndices.first - 1].toInt().toChar())) - check(!isHex(bytes[sliceIndices.last + 1].toInt().toChar())) - val slice = bytes.sliceArray(sliceIndices) - val oldModulus = slice.toString(Charsets.UTF_8) - val newModulus = replacement.toByteArray(Charsets.UTF_8) - if (newModulus.size > slice.size) { - throw IllegalStateException("New modulus cannot be larger than the old.") - } - val output = bytes.setString(sliceIndices.first, replacement) - - logger.debug { "Patched RSA modulus" } - logger.debug { "Old modulus: $oldModulus" } - logger.debug { "New modulus: $replacement" } - return output to oldModulus - } - - private fun patchLocalhost(bytes: ByteArray): ByteArray { - // Rather than only accept the localhost below - val searchInput = "127.0.0.1" - // Due to the Java client using "endsWith" function, we can't set any string here - val replacement = "" - - val newSet = replaceText(bytes, searchInput, replacement) - logger.debug { "Replaced localhost from $searchInput to $replacement" } - return newSet - } - - private fun replaceText( - bytes: ByteArray, - input: String, - replacement: String, - ): ByteArray { - require(replacement.length <= input.length) { - "Replacement string cannot be longer than the input" - } - val searchBytes = input.toByteArray(Charsets.UTF_8) - val index = bytes.indexOf(searchBytes) - if (index == -1) { - throw IllegalArgumentException("Unable to locate input $input") - } - return bytes.setString(index, replacement) - } - - private fun ByteArray.setString( - stringStartIndex: Int, - replacementString: String, - ): ByteArray { - val oldLenByte1 = this[stringStartIndex - 2].toInt() and 0xFF - val oldLenByte2 = this[stringStartIndex - 1].toInt() and 0xFF - val oldLength = (oldLenByte1 shl 8) or oldLenByte2 - val lengthDelta = replacementString.length - oldLength - val replacement = ByteArray(size + lengthDelta) - - // Fill in the bytes right up until the length of the string (unmodified) - copyInto(replacement, 0, 0, stringStartIndex - 2) - - // Fill in the length of the replacement string - check(replacementString.length in 0..<0xFFFF) - val newSizeByte1 = replacementString.length ushr 8 and 0xFF - val newSizeByte2 = replacementString.length and 0xFF - replacement[stringStartIndex - 2] = newSizeByte1.toByte() - replacement[stringStartIndex - 1] = newSizeByte2.toByte() - - // Fill in the actual replacement string itself - val replacementBytes = replacementString.toByteArray(Charsets.UTF_8) - for (i in replacementBytes.indices) { - replacement[stringStartIndex + i] = replacementBytes[i] - } - - // Fill in the trailing bytes that come after the string (unmodified) - copyInto( - replacement, - stringStartIndex + replacementString.length, - stringStartIndex + oldLength, - ) - return replacement - } - - private fun ByteArray.firstSliceIndices( - startIndex: Int, - length: Int = -1, - condition: (Byte) -> Boolean, - ): IntRange { - var start = startIndex - val size = this.size - while (true) { - // First locate the starting index where a byte is being accepted - while (start < size) { - val byte = this[start] - if (condition(byte)) { - break - } - start++ - } - var end = start + 1 - // Now find the end index where a byte is not being accepted - while (end < size) { - val byte = this[end] - if (!condition(byte)) { - break - } - end++ - } - if (length != -1 && end - start < length) { - start = end - continue - } - return start..= 0) { - "Start index is negative" - } - return findBoyerMoore(this, search, startIndex) - } - - private fun isHex(char: Char): Boolean { - return char in lowercaseHexStringCharRange || - char in uppercaseHexStringCharRange || - char in hexDigitsCharRange - } - - private companion object { - private val lowercaseHexStringCharRange = 'a'..'f' - private val uppercaseHexStringCharRange = 'A'..'F' - private val hexDigitsCharRange = '0'..'9' - private val logger = InlineLogger() - } -} diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ClientLoader.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ClientLoader.class deleted file mode 100644 index 3f3b33fd..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ClientLoader.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ComponentID.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ComponentID.class deleted file mode 100644 index 13f1cc67..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/ComponentID.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/InterfaceID.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/InterfaceID.class deleted file mode 100644 index c51105b2..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/InterfaceID.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original ClientLoader.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original ClientLoader.class deleted file mode 100644 index b9a8f75a..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original ClientLoader.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original RuneLite.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original RuneLite.class deleted file mode 100644 index 2f6c8354..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original RuneLite.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original WorldClient.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original WorldClient.class deleted file mode 100644 index e12df9cf..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Original WorldClient.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/RuneLite.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/RuneLite.class deleted file mode 100644 index 305344f0..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/RuneLite.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientInt.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientInt.class deleted file mode 100644 index 4ea48df7..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientInt.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientStr.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientStr.class deleted file mode 100644 index 98a33a78..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarClientStr.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarPlayer.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarPlayer.class deleted file mode 100644 index a58e1b8e..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/VarPlayer.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Varbits.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Varbits.class deleted file mode 100644 index 76804230..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/Varbits.class and /dev/null differ diff --git a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/WorldClient.class b/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/WorldClient.class deleted file mode 100644 index 0ed66ec8..00000000 Binary files a/patch/patch-runelite/src/main/resources/net/rsprox/patch/runelite/WorldClient.class and /dev/null differ diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 8416633c..84c2926f 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -20,7 +20,6 @@ dependencies { implementation(rootProject.libs.bundles.jackson) implementation(projects.patch) implementation(projects.patch.patchNative) - implementation(projects.patch.patchRunelite) implementation(projects.protocol) implementation(projects.transcriber) implementation(rootProject.libs.clikt) diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/client/ClientLoginHandler.kt b/proxy/src/main/kotlin/net/rsprox/proxy/client/ClientLoginHandler.kt index 0af91086..f78050bc 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/client/ClientLoginHandler.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/client/ClientLoginHandler.kt @@ -234,10 +234,18 @@ public class ClientLoginHandler( } val siteSettings = buffer.gjstr() val affiliate = buffer.g4() - val constZero = buffer.g1() + val deepLinkCount = buffer.g1() + val deepLinks = + if (deepLinkCount == 0) { + emptyList() + } else { + List(deepLinkCount) { + buffer.g4() + } + } val hostPlatformStats = decodeHostPlatformStats(buffer) val secondClientType = buffer.g1() - val crcBlockHeader = buffer.g4() + val reflectionCheckerConst = buffer.g4() val crc = buffer.buffer.readBytes(buffer.readableBytes()) return LoginXteaBlock( username, @@ -247,10 +255,10 @@ public class ClientLoginHandler( uuid, siteSettings, affiliate, - constZero, + deepLinks, hostPlatformStats, secondClientType, - crcBlockHeader, + reflectionCheckerConst, crc, ) } @@ -268,7 +276,10 @@ public class ClientLoginHandler( } buffer.pjstr(block.siteSettings) buffer.p4(block.affiliate) - buffer.p1(block.constZero) + buffer.p1(block.deepLinks.size) + for (link in block.deepLinks) { + buffer.p4(link) + } val hostBuf = Unpooled.buffer() encodeHostPlatformStats(block.hostPlatformStats, hostBuf.toJagByteBuf()) try { @@ -277,7 +288,7 @@ public class ClientLoginHandler( hostBuf.release() } buffer.p1(block.secondClientType) - buffer.p4(block.crcBlockHeader) + buffer.p4(block.reflectionCheckerConst) try { buffer.pdata(block.crc) } finally { diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/client/util/LoginXteaBlock.kt b/proxy/src/main/kotlin/net/rsprox/proxy/client/util/LoginXteaBlock.kt index dc0f17a8..a6abb857 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/client/util/LoginXteaBlock.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/client/util/LoginXteaBlock.kt @@ -11,10 +11,10 @@ public data class LoginXteaBlock( public val uuid: ByteArray, public val siteSettings: String, public val affiliate: Int, - public val constZero: Int, + public val deepLinks: List, public val hostPlatformStats: HostPlatformStats, public val secondClientType: Int, - public val crcBlockHeader: Int, + public val reflectionCheckerConst: Int, public val crc: ByteBuf, ) { override fun equals(other: Any?): Boolean { @@ -30,10 +30,10 @@ public data class LoginXteaBlock( if (!uuid.contentEquals(other.uuid)) return false if (siteSettings != other.siteSettings) return false if (affiliate != other.affiliate) return false - if (constZero != other.constZero) return false + if (deepLinks != other.deepLinks) return false if (hostPlatformStats != other.hostPlatformStats) return false if (secondClientType != other.secondClientType) return false - if (crcBlockHeader != other.crcBlockHeader) return false + if (reflectionCheckerConst != other.reflectionCheckerConst) return false if (crc != other.crc) return false return true @@ -47,10 +47,10 @@ public data class LoginXteaBlock( result = 31 * result + uuid.contentHashCode() result = 31 * result + siteSettings.hashCode() result = 31 * result + affiliate - result = 31 * result + constZero + result = 31 * result + deepLinks.hashCode() result = 31 * result + hostPlatformStats.hashCode() result = 31 * result + secondClientType - result = 31 * result + crcBlockHeader + result = 31 * result + reflectionCheckerConst result = 31 * result + crc.hashCode() return result } @@ -64,10 +64,10 @@ public data class LoginXteaBlock( "uuid=${uuid.contentToString()}, " + "siteSettings='$siteSettings', " + "affiliate=$affiliate, " + - "constZero=$constZero, " + + "deepLinks=$deepLinks, " + "hostPlatformStats=$hostPlatformStats, " + "secondClientType=$secondClientType, " + - "crcBlockHeader=$crcBlockHeader, " + + "reflectionCheckerConst=$reflectionCheckerConst, " + "crc=$crc" + ")" } diff --git a/proxy/src/main/kotlin/net/rsprox/proxy/runelite/RuneliteLauncher.kt b/proxy/src/main/kotlin/net/rsprox/proxy/runelite/RuneliteLauncher.kt index fabb3a4c..20293c70 100644 --- a/proxy/src/main/kotlin/net/rsprox/proxy/runelite/RuneliteLauncher.kt +++ b/proxy/src/main/kotlin/net/rsprox/proxy/runelite/RuneliteLauncher.kt @@ -75,7 +75,10 @@ public class RuneliteLauncher { } classpath.append(RUNELITE_LAUNCHER_REPO_DIRECTORY.resolve(artifact.name).absolutePathString()) } - + val repository = "https://raw.githubusercontent.com/runelite/static.runelite.net" + val commit = "dc197f1c305c712fcf496d8a2c3c0d02f3824d18" + val bootstrapUrl = "$repository/$commit/bootstrap.json" + val bootstrapSigUrl = "$repository/$commit/bootstrap.json.sha256" return listOf( getJava(), "-cp", @@ -86,6 +89,10 @@ public class RuneliteLauncher { "--jav_config=$javConfig", "--socket_id=$socket", "--developer-mode", + "--bootstrap_url=$bootstrapUrl", + "--bootstrap_sig_url=$bootstrapSigUrl", + "--disable-telemetry", + "--noupdate", *guiArgs.toTypedArray(), ) }