Skip to content

Commit

Permalink
refactor: store modulus as a global property
Browse files Browse the repository at this point in the history
This allows us to separate launching the proxy service, and booting
corresponding clients. The modulus between all clients on a specific
platform is guaranteed to be identical anyhow.
  • Loading branch information
Z-Kris committed Jul 9, 2024
1 parent baeb85f commit ae068cf
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 18 deletions.
33 changes: 24 additions & 9 deletions proxy/src/main/kotlin/net/rsprox/proxy/ProxyService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import net.rsprox.proxy.config.ProxyProperty.Companion.PROXY_HTTP_PORT
import net.rsprox.proxy.config.ProxyProperty.Companion.PROXY_PORT
import net.rsprox.proxy.config.ProxyProperty.Companion.WORLDLIST_ENDPOINT
import net.rsprox.proxy.config.ProxyProperty.Companion.WORLDLIST_REFRESH_SECONDS
import net.rsprox.proxy.config.patchedRsaModulus
import net.rsprox.proxy.downloader.NativeClientDownloader
import net.rsprox.proxy.futures.asCompletableFuture
import net.rsprox.proxy.huffman.HuffmanProvider
Expand Down Expand Up @@ -70,23 +71,34 @@ public class ProxyService(
val worldListProvider = loadWorldListProvider(javConfig.getWorldListUrl())
val replacementWorld = findCodebaseReplacementWorld(javConfig, worldListProvider)
val updatedJavConfig = rebuildJavConfig(javConfig, replacementWorld)
val port = properties.getProperty(PROXY_PORT)
val webPort = properties.getProperty(PROXY_HTTP_PORT)
val javConfigEndpoint = properties.getProperty(JAV_CONFIG_ENDPOINT)
val worldlistEndpoint = properties.getProperty(WORLDLIST_ENDPOINT)

val os = getOperatingSystem()
logger.debug { "Proxy launched on $os" }
if (os == OperatingSystem.UNIX || os == OperatingSystem.SOLARIS) {
throw IllegalStateException("Operating system not supported for native: $os")
}

launchHttpServer(factory, worldListProvider, updatedJavConfig)
launchProxyServer(factory, worldListProvider, rsa)

// Immediately launch the corresponding native client
launchNativeClient(os, rsa)
}

private fun launchNativeClient(
os: OperatingSystem,
rsa: RSAPrivateCrtKeyParameters,
) {
val port = properties.getProperty(PROXY_PORT)
val webPort = properties.getProperty(PROXY_HTTP_PORT)
val javConfigEndpoint = properties.getProperty(JAV_CONFIG_ENDPOINT)
val worldlistEndpoint = properties.getProperty(WORLDLIST_ENDPOINT)
val nativeClientType =
when (os) {
OperatingSystem.WINDOWS -> NativeClientType.WIN
OperatingSystem.MAC -> NativeClientType.MAC
else -> throw IllegalStateException()
}

val binary = NativeClientDownloader.download(nativeClientType)
val extension = if (binary.extension.isNotEmpty()) ".${binary.extension}" else ""
val patched = binary.parent.resolve("${binary.nameWithoutExtension}-patched$extension")
Expand All @@ -107,8 +119,13 @@ public class ProxyService(
"Failed to patch"
}
val originalModulus = BigInteger(result.oldModulus, 16)
launchHttpServer(factory, worldListProvider, updatedJavConfig)
launchProxyServer(factory, worldListProvider, rsa, originalModulus)
val patchedModulus = patchedRsaModulus
if (patchedModulus != null) {
check(patchedModulus == originalModulus) {
"Unable to launch client due to different modulus being used. Reboot proxy."
}
}
patchedRsaModulus = originalModulus
launchExecutable(result.outputPath, os)
}

Expand Down Expand Up @@ -275,14 +292,12 @@ public class ProxyService(
factory: BootstrapFactory,
worldListProvider: WorldListProvider,
rsa: RSAPrivateCrtKeyParameters,
originalModulus: BigInteger,
) {
runCatching("Failure to launch HTTP server") {
val serverBootstrap =
factory.createServerBootStrap(
worldListProvider,
rsa,
originalModulus,
properties.getProperty(BINARY_WRITE_INTERVAL_SECONDS),
)
val port = properties.getProperty(PROXY_PORT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import net.rsprox.proxy.http.HttpServerHandler
import net.rsprox.proxy.server.ServerConnectionInitializer
import net.rsprox.proxy.worlds.WorldListProvider
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters
import java.math.BigInteger

public class BootstrapFactory(
private val allocator: ByteBufAllocator,
Expand All @@ -32,7 +31,6 @@ public class BootstrapFactory(
public fun createServerBootStrap(
worldListProvider: WorldListProvider,
rsa: RSAPrivateCrtKeyParameters,
originalModulus: BigInteger,
binaryWriteInterval: Int,
): ServerBootstrap {
return ServerBootstrap()
Expand All @@ -50,7 +48,6 @@ public class BootstrapFactory(
this,
worldListProvider,
rsa,
originalModulus,
binaryWriteInterval,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import net.rsprox.proxy.channel.getWorld
import net.rsprox.proxy.channel.remove
import net.rsprox.proxy.channel.replace
import net.rsprox.proxy.client.prot.LoginClientProt
import net.rsprox.proxy.config.patchedRsaModulus
import net.rsprox.proxy.js5.Js5MasterIndexArchive
import net.rsprox.proxy.rsa.Rsa
import net.rsprox.proxy.rsa.rsa
Expand All @@ -31,12 +32,10 @@ import net.rsprox.proxy.server.prot.LoginServerProtId
import net.rsprox.proxy.server.prot.LoginServerProtProvider
import net.rsprox.proxy.worlds.WorldListProvider
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters
import java.math.BigInteger

public class ClientLoginHandler(
private val serverChannel: Channel,
private val rsa: RSAPrivateCrtKeyParameters,
private val originalModulus: BigInteger,
private val binaryWriteInterval: Int,
private val worldListProvider: WorldListProvider,
) : SimpleChannelInboundHandler<ClientPacket<LoginClientProt>>() {
Expand Down Expand Up @@ -162,10 +161,14 @@ public class ClientLoginHandler(
val encoded = ctx.alloc().buffer(msg.payload.readableBytes())
encoded.writeBytes(msg.payload, msg.start, headerSize)
decryptedRsaBuffer.readerIndex(rsaStart)
val modulus =
checkNotNull(patchedRsaModulus) {
"Patched RSA modulus has not been assigned yet!"
}
val encrypted =
decryptedRsaBuffer.buffer.decipherRsa(
Rsa.PUBLIC_EXPONENT,
originalModulus,
modulus,
decryptedRsaBuffer.readableBytes(),
)
encoded.p2(encrypted.readableBytes())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ import net.rsprox.proxy.util.ChannelConnectionHandler
import net.rsprox.proxy.worlds.LocalHostAddress
import net.rsprox.proxy.worlds.WorldListProvider
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters
import java.math.BigInteger
import java.net.Inet4Address
import java.net.InetSocketAddress

public class ClientLoginInitializer(
private val bootstrapFactory: BootstrapFactory,
private val worldListProvider: WorldListProvider,
private val rsa: RSAPrivateCrtKeyParameters,
private val originalModulus: BigInteger,
private val binaryWriteInterval: Int,
) : ChannelInitializer<Channel>() {
override fun initChannel(clientChannel: Channel) {
Expand Down Expand Up @@ -61,7 +59,7 @@ public class ClientLoginInitializer(
}
clientChannel.pipeline().addLast(
ClientGenericDecoder(NopStreamCipher, LoginClientProtProvider),
ClientLoginHandler(serverChannel, rsa, originalModulus, binaryWriteInterval, worldListProvider),
ClientLoginHandler(serverChannel, rsa, binaryWriteInterval, worldListProvider),
)
clientChannel.pipeline().addLast(ChannelConnectionHandler(serverChannel))
serverChannel.pipeline().addLast(ChannelConnectionHandler(clientChannel))
Expand Down
2 changes: 2 additions & 0 deletions proxy/src/main/kotlin/net/rsprox/proxy/config/RSProx.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package net.rsprox.proxy.config

import java.math.BigInteger
import java.nio.file.Path
import kotlin.io.path.Path

internal val CONFIGURATION_PATH: Path = Path(System.getProperty("user.home"), ".rsprox")
internal val BINARY_PATH: Path = CONFIGURATION_PATH.resolve("binary")
internal val CLIENTS_DIRECTORY: Path = CONFIGURATION_PATH.resolve("clients")
internal var patchedRsaModulus: BigInteger? = null

0 comments on commit ae068cf

Please sign in to comment.