mirror of https://github.com/hykilpikonna/AquaDX
[+] AimeDB client
parent
af734b7814
commit
c3963e7fe2
|
@ -192,8 +192,7 @@ val Any?.str get() = toString()
|
||||||
// Collections
|
// Collections
|
||||||
fun <T> ls(vararg args: T) = args.toList()
|
fun <T> ls(vararg args: T) = args.toList()
|
||||||
inline fun <reified T> arr(vararg args: T) = arrayOf(*args)
|
inline fun <reified T> arr(vararg args: T) = arrayOf(*args)
|
||||||
operator fun <K, V> Map<K, V>.plus(map: Map<K, V>) =
|
operator fun <K, V> Map<K, V>.plus(map: Map<K, V>) = mut.apply { putAll(map) }
|
||||||
(if (this is MutableMap) this else mut).apply { putAll(map) }
|
|
||||||
operator fun <K, V> MutableMap<K, V>.plusAssign(map: Map<K, V>) { putAll(map) }
|
operator fun <K, V> MutableMap<K, V>.plusAssign(map: Map<K, V>) { putAll(map) }
|
||||||
fun <K, V: Any> Map<K, V?>.vNotNull(): Map<K, V> = filterValues { it != null }.mapValues { it.value!! }
|
fun <K, V: Any> Map<K, V?>.vNotNull(): Map<K, V> = filterValues { it != null }.mapValues { it.value!! }
|
||||||
fun <T> MutableList<T>.popAll(list: List<T>) = list.also { removeAll(it) }
|
fun <T> MutableList<T>.popAll(list: List<T>) = list.also { removeAll(it) }
|
||||||
|
|
|
@ -10,6 +10,7 @@ val client = HttpClient.newBuilder().build()
|
||||||
fun HttpRequest.Builder.send() = client.send(this.build(), HttpResponse.BodyHandlers.ofString())
|
fun HttpRequest.Builder.send() = client.send(this.build(), HttpResponse.BodyHandlers.ofString())
|
||||||
fun HttpRequest.Builder.header(pair: Pair<Any, Any>) = this.header(pair.first.toString(), pair.second.toString())
|
fun HttpRequest.Builder.header(pair: Pair<Any, Any>) = this.header(pair.first.toString(), pair.second.toString())
|
||||||
fun String.request() = HttpRequest.newBuilder(URI.create(this))
|
fun String.request() = HttpRequest.newBuilder(URI.create(this))
|
||||||
|
inline fun <reified T> String.postJson(body: Any) = request().post(body).json<T>()
|
||||||
|
|
||||||
fun HttpRequest.Builder.post(body: Any? = null) = this.POST(when (body) {
|
fun HttpRequest.Builder.post(body: Any? = null) = this.POST(when (body) {
|
||||||
is ByteArray -> HttpRequest.BodyPublishers.ofByteArray(body)
|
is ByteArray -> HttpRequest.BodyPublishers.ofByteArray(body)
|
||||||
|
@ -17,3 +18,6 @@ fun HttpRequest.Builder.post(body: Any? = null) = this.POST(when (body) {
|
||||||
is HttpRequest.BodyPublisher -> body
|
is HttpRequest.BodyPublisher -> body
|
||||||
else -> throw Exception("Unsupported body type")
|
else -> throw Exception("Unsupported body type")
|
||||||
}).send()
|
}).send()
|
||||||
|
|
||||||
|
inline fun <reified T> HttpResponse<String>.json(): T = body().json()
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ import io.netty.buffer.Unpooled
|
||||||
import io.netty.channel.ChannelHandler
|
import io.netty.channel.ChannelHandler
|
||||||
import io.netty.channel.ChannelHandlerContext
|
import io.netty.channel.ChannelHandlerContext
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter
|
import io.netty.channel.ChannelInboundHandlerAdapter
|
||||||
import org.slf4j.Logger
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
@ -127,8 +125,7 @@ class AimeDB(
|
||||||
*/
|
*/
|
||||||
fun doFelicaLookupV2(msg: ByteBuf): ByteBuf {
|
fun doFelicaLookupV2(msg: ByteBuf): ByteBuf {
|
||||||
val idm = msg.slice(0x30, 0x38 - 0x30).getLong(0)
|
val idm = msg.slice(0x30, 0x38 - 0x30).getLong(0)
|
||||||
val dfc = msg.slice(0x38, 0x40 - 0x38).getLong(0)
|
logger.info("> Felica Lookup v2 (idm $idm)")
|
||||||
logger.info("> Felica Lookup v2 (idm $idm, dfc $dfc)")
|
|
||||||
|
|
||||||
// Get the decimal represent of the hex value, same from minime
|
// Get the decimal represent of the hex value, same from minime
|
||||||
val accessCode = idm.toString().replace("-", "").padStart(20, '0')
|
val accessCode = idm.toString().replace("-", "").padStart(20, '0')
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package icu.samnyan.aqua.sega.aimedb
|
||||||
|
|
||||||
|
import icu.samnyan.aqua.sega.aimedb.AimeDbClient.Companion.sendAimePacket
|
||||||
|
import io.netty.buffer.ByteBuf
|
||||||
|
import io.netty.buffer.ByteBufUtil
|
||||||
|
import io.netty.buffer.Unpooled
|
||||||
|
import java.net.Socket
|
||||||
|
|
||||||
|
class AimeDbClient(val gameId: String, val keychipShort: String) {
|
||||||
|
// https://sega.bsnk.me/allnet/aimedb/common/#packet-header
|
||||||
|
fun createRequest(type: UShort, writer: ByteBuf.() -> Unit): ByteBuf
|
||||||
|
= AimeDbEncryption.encrypt(Unpooled.buffer(1024).clear().run {
|
||||||
|
writeShortLE(0xa13e) // 00 2b: Magic
|
||||||
|
writeShortLE(0x3087) // 02 2b: Version
|
||||||
|
writeShortLE(type.toInt()) // 04 2b: Type
|
||||||
|
writeShortLE(0) // 06 2b: Length
|
||||||
|
writeShortLE(0) // 08 2b: Result
|
||||||
|
writeAscii(gameId, 6) // 0A 6b: Game ID
|
||||||
|
writeIntLE(0) // 10 4b: Store ID (Place ID)
|
||||||
|
writeAscii(keychipShort, 12) // 14 12b: Keychip ID
|
||||||
|
writer() // Write Payload
|
||||||
|
setShortLE(6, writerIndex()) // Update Length
|
||||||
|
copy(0, writerIndex()) // Trim unused bytes
|
||||||
|
})
|
||||||
|
|
||||||
|
private fun ByteBuf.writeAscii(value: String, length: Int)
|
||||||
|
= writeBytes(value.toByteArray(Charsets.US_ASCII).copyOf(length))
|
||||||
|
|
||||||
|
fun createReqLookupV2(accessCode: String)
|
||||||
|
= createRequest(0x0fu) {
|
||||||
|
// Access code is a 20-digit number, should be converted to a 10-byte array
|
||||||
|
writeBytes(ByteBufUtil.decodeHexDump(accessCode.padStart(20, '0')))
|
||||||
|
writeByte(0) // 0A 1b: Company code
|
||||||
|
writeByte(0) // 0B 1b: R/W Firmware version
|
||||||
|
writeIntLE(0) // 0C 4b: Serial number
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createReqFelicaLookupV2(felicaIdm: String)
|
||||||
|
= createRequest(0x11u) {
|
||||||
|
writeBytes(ByteArray(16)) // 00 16b: Random Challenge
|
||||||
|
// 10 8b: Felica IDm
|
||||||
|
writeBytes(ByteBufUtil.decodeHexDump(felicaIdm.padStart(16, '0')))
|
||||||
|
writeBytes(ByteArray(8)) // 18 8b: Felica PMm
|
||||||
|
writeBytes(ByteArray(16)) // 20 16b: Card key version
|
||||||
|
writeBytes(ByteArray(16)) // 30 16b: Write count
|
||||||
|
writeBytes(ByteArray(8)) // 40 8b: MACA
|
||||||
|
writeByte(0) // 48 1b: Company code
|
||||||
|
writeByte(0) // 49 1b: R/W Firmware version
|
||||||
|
writeShortLE(0) // 4A 2b: DFC
|
||||||
|
writeIntLE(0) // 4C 4b: Unknown padding
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun ByteBuf.sendAimePacket(server: String): ByteBuf
|
||||||
|
= Unpooled.wrappedBuffer(Socket(server, 22345).use {
|
||||||
|
it.getOutputStream().write(array())
|
||||||
|
it.getInputStream().readBytes()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue