From c260548d73d9a5ee2412cb87e5d8ebdf181dd6e9 Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 14 Feb 2021 21:43:39 +0000 Subject: [PATCH] Add command for downloading keys from RuneLite and OpenOSRS Signed-off-by: Graham --- archive/build.gradle.kts | 2 + .../org/openrs2/archive/ArchiveModule.kt | 10 +++ .../openrs2/archive/key/DownloadCommand.kt | 14 ++++ .../org/openrs2/archive/key/KeyCommand.kt | 1 + .../org/openrs2/archive/key/KeyDownloader.kt | 7 ++ .../org/openrs2/archive/key/KeyImporter.kt | 13 +++- .../archive/key/OpenOsrsKeyDownloader.kt | 38 +++++++++++ .../archive/key/RuneLiteKeyDownloader.kt | 65 +++++++++++++++++++ 8 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 archive/src/main/kotlin/org/openrs2/archive/key/DownloadCommand.kt create mode 100644 archive/src/main/kotlin/org/openrs2/archive/key/KeyDownloader.kt create mode 100644 archive/src/main/kotlin/org/openrs2/archive/key/OpenOsrsKeyDownloader.kt create mode 100644 archive/src/main/kotlin/org/openrs2/archive/key/RuneLiteKeyDownloader.kt diff --git a/archive/build.gradle.kts b/archive/build.gradle.kts index 960a7c07..0dfec0b1 100644 --- a/archive/build.gradle.kts +++ b/archive/build.gradle.kts @@ -15,6 +15,7 @@ dependencies { implementation(project(":cache")) implementation(project(":cli")) implementation(project(":db")) + implementation(project(":http")) implementation(project(":json")) implementation(project(":json")) implementation(project(":net")) @@ -26,6 +27,7 @@ dependencies { implementation("io.ktor:ktor-thymeleaf:${Versions.ktor}") implementation("io.ktor:ktor-webjars:${Versions.ktor}") implementation("org.flywaydb:flyway-core:${Versions.flyway}") + implementation("org.jdom:jdom2:${Versions.jdom}") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}") implementation("org.postgresql:postgresql:${Versions.postgres}") implementation("org.thymeleaf:thymeleaf:${Versions.thymeleaf}") diff --git a/archive/src/main/kotlin/org/openrs2/archive/ArchiveModule.kt b/archive/src/main/kotlin/org/openrs2/archive/ArchiveModule.kt index 1d9bc165..fb92e236 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/ArchiveModule.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/ArchiveModule.kt @@ -2,9 +2,14 @@ package org.openrs2.archive import com.google.inject.AbstractModule import com.google.inject.Scopes +import com.google.inject.multibindings.Multibinder +import org.openrs2.archive.key.KeyDownloader +import org.openrs2.archive.key.OpenOsrsKeyDownloader +import org.openrs2.archive.key.RuneLiteKeyDownloader import org.openrs2.buffer.BufferModule import org.openrs2.cache.CacheModule import org.openrs2.db.Database +import org.openrs2.http.HttpModule import org.openrs2.json.JsonModule import org.openrs2.net.NetworkModule @@ -12,11 +17,16 @@ public object ArchiveModule : AbstractModule() { override fun configure() { install(BufferModule) install(CacheModule) + install(HttpModule) install(JsonModule) install(NetworkModule) bind(Database::class.java) .toProvider(DatabaseProvider::class.java) .`in`(Scopes.SINGLETON) + + val binder = Multibinder.newSetBinder(binder(), KeyDownloader::class.java) + binder.addBinding().to(OpenOsrsKeyDownloader::class.java) + binder.addBinding().to(RuneLiteKeyDownloader::class.java) } } diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/DownloadCommand.kt b/archive/src/main/kotlin/org/openrs2/archive/key/DownloadCommand.kt new file mode 100644 index 00000000..ee022e08 --- /dev/null +++ b/archive/src/main/kotlin/org/openrs2/archive/key/DownloadCommand.kt @@ -0,0 +1,14 @@ +package org.openrs2.archive.key + +import com.github.ajalt.clikt.core.CliktCommand +import com.google.inject.Guice +import kotlinx.coroutines.runBlocking +import org.openrs2.archive.ArchiveModule + +public class DownloadCommand : CliktCommand(name = "download") { + override fun run(): Unit = runBlocking { + val injector = Guice.createInjector(ArchiveModule) + val importer = injector.getInstance(KeyImporter::class.java) + importer.download() + } +} diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/KeyCommand.kt b/archive/src/main/kotlin/org/openrs2/archive/key/KeyCommand.kt index e2011b71..0efce58f 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/key/KeyCommand.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/key/KeyCommand.kt @@ -7,6 +7,7 @@ public class KeyCommand : NoOpCliktCommand(name = "key") { init { subcommands( BruteForceCommand(), + DownloadCommand(), ImportCommand() ) } diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/KeyDownloader.kt b/archive/src/main/kotlin/org/openrs2/archive/key/KeyDownloader.kt new file mode 100644 index 00000000..d2e1a916 --- /dev/null +++ b/archive/src/main/kotlin/org/openrs2/archive/key/KeyDownloader.kt @@ -0,0 +1,7 @@ +package org.openrs2.archive.key + +import org.openrs2.crypto.XteaKey + +public interface KeyDownloader { + public suspend fun download(): Sequence +} diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/KeyImporter.kt b/archive/src/main/kotlin/org/openrs2/archive/key/KeyImporter.kt index d88472b0..9b9e3cfe 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/key/KeyImporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/key/KeyImporter.kt @@ -10,7 +10,8 @@ import javax.inject.Singleton @Singleton public class KeyImporter @Inject constructor( private val database: Database, - private val jsonKeyReader: JsonKeyReader + private val jsonKeyReader: JsonKeyReader, + private val downloaders: Set ) { public suspend fun import(path: Path) { val keys = mutableSetOf() @@ -38,6 +39,16 @@ public class KeyImporter @Inject constructor( import(keys) } + public suspend fun download() { + val keys = mutableSetOf() + for (downloader in downloaders) { + keys += downloader.download() + } + keys -= XteaKey.ZERO + + import(keys) + } + public suspend fun import(keys: Iterable) { database.execute { connection -> connection.prepareStatement( diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/OpenOsrsKeyDownloader.kt b/archive/src/main/kotlin/org/openrs2/archive/key/OpenOsrsKeyDownloader.kt new file mode 100644 index 00000000..aec6c896 --- /dev/null +++ b/archive/src/main/kotlin/org/openrs2/archive/key/OpenOsrsKeyDownloader.kt @@ -0,0 +1,38 @@ +package org.openrs2.archive.key + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.withContext +import org.openrs2.crypto.XteaKey +import org.openrs2.http.checkStatusCode +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +public class OpenOsrsKeyDownloader @Inject constructor( + private val client: HttpClient, + private val jsonKeyReader: JsonKeyReader +) : KeyDownloader { + override suspend fun download(): Sequence { + val request = HttpRequest.newBuilder(ENDPOINT) + .GET() + .build() + + val response = client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()).await() + response.checkStatusCode() + + return withContext(Dispatchers.IO) { + response.body().use { input -> + jsonKeyReader.read(input) + } + } + } + + private companion object { + private val ENDPOINT = URI("https://xtea.openosrs.dev/get") + } +} diff --git a/archive/src/main/kotlin/org/openrs2/archive/key/RuneLiteKeyDownloader.kt b/archive/src/main/kotlin/org/openrs2/archive/key/RuneLiteKeyDownloader.kt new file mode 100644 index 00000000..0f037b93 --- /dev/null +++ b/archive/src/main/kotlin/org/openrs2/archive/key/RuneLiteKeyDownloader.kt @@ -0,0 +1,65 @@ +package org.openrs2.archive.key + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.future.await +import kotlinx.coroutines.withContext +import org.jdom2.input.SAXBuilder +import org.openrs2.crypto.XteaKey +import org.openrs2.http.checkStatusCode +import java.net.URI +import java.net.http.HttpClient +import java.net.http.HttpRequest +import java.net.http.HttpResponse +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +public class RuneLiteKeyDownloader @Inject constructor( + private val client: HttpClient, + private val jsonKeyReader: JsonKeyReader +) : KeyDownloader { + override suspend fun download(): Sequence { + val version = getVersion() + + val request = HttpRequest.newBuilder(getXteaEndpoint(version)) + .GET() + .build() + + val response = client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()).await() + response.checkStatusCode() + + return withContext(Dispatchers.IO) { + response.body().use { input -> + jsonKeyReader.read(input) + } + } + } + + private suspend fun getVersion(): String { + val request = HttpRequest.newBuilder(VERSION_ENDPOINT) + .GET() + .build() + + val response = client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()).await() + response.checkStatusCode() + + val document = withContext(Dispatchers.IO) { + response.body().use { input -> + SAXBuilder().build(input) + } + } + + return document.rootElement + .getChild("versioning") + .getChild("release") + .textTrim + } + + private companion object { + private val VERSION_ENDPOINT = URI("https://repo.runelite.net/net/runelite/runelite-parent/maven-metadata.xml") + + private fun getXteaEndpoint(version: String): URI { + return URI("https://api.runelite.net/runelite-$version/xtea") + } + } +}