Fix some clientbound message bugs
send signed message{wip}
This commit is contained in:
37 files changed
+689
-1206
No files matched your search
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.context
|
||||
|
||||
public interface HttpClientProvider {
|
||||
public suspend fun post(url: String, headers: Map<String, String>?, body: String?): String
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.crypto
|
||||
package cn.rtast.libmc.context
|
||||
|
||||
public interface NetworkChannelCipher {
|
||||
public fun encrypt(buffer: ByteArray, offset: Int, length: Int)
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.context
|
||||
|
||||
import cn.rtast.libmc.network.SocketContext
|
||||
import cn.rtast.libmc.network.SocketEngine
|
||||
|
||||
public data class ProtocolContext(
|
||||
val httpClientProvider: HttpClientProvider?,
|
||||
override val socketEngine: SocketEngine,
|
||||
) : SocketContext()
|
||||
|
||||
public class ProtocolContextBuilder(private val onlineMode: Boolean) {
|
||||
public lateinit var httpClientProvider: HttpClientProvider
|
||||
public lateinit var socketEngine: SocketEngine
|
||||
|
||||
public fun build(): ProtocolContext =
|
||||
ProtocolContext(
|
||||
httpClientProvider = if (onlineMode) {
|
||||
if (::httpClientProvider.isInitialized) httpClientProvider else error("authProvider is required in online mode")
|
||||
} else if (::httpClientProvider.isInitialized) httpClientProvider else null,
|
||||
socketEngine = if (::socketEngine.isInitialized) socketEngine else error("SocketEngine is not configured"),
|
||||
)
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.crypto
|
||||
|
||||
public fun interface AuthenticationProvider {
|
||||
public suspend fun joinServer(url: String, accessToken: String, uuid: String, serverIdHash: String)
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/7
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.crypto
|
||||
|
||||
import cn.rtast.libmc.network.SocketContext
|
||||
import cn.rtast.libmc.network.SocketEngine
|
||||
|
||||
public data class ProtocolContext(
|
||||
val authProvider: AuthenticationProvider?,
|
||||
override val engine: SocketEngine,
|
||||
) : SocketContext()
|
||||
|
||||
public class ProtocolContextBuilder(private val onlineMode: Boolean) {
|
||||
public lateinit var authProvider: AuthenticationProvider
|
||||
public lateinit var socketEngine: SocketEngine
|
||||
|
||||
public fun build(): ProtocolContext =
|
||||
ProtocolContext(
|
||||
authProvider = if (onlineMode) {
|
||||
if (::authProvider.isInitialized) authProvider else error("authProvider is required in online mode")
|
||||
} else if (::authProvider.isInitialized) authProvider else null,
|
||||
|
||||
engine = if (::socketEngine.isInitialized) socketEngine else error("SocketEngine is not configured"),
|
||||
)
|
||||
}
|
||||
|
||||
public fun interface RSA1024Encryptor {
|
||||
public fun encrypt(key: ByteArray, data: ByteArray): ByteArray
|
||||
}
|
||||
|
||||
public fun interface Sha1Hasher {
|
||||
public fun hash(serverId: String, secretKey: ByteArray, publicKey: ByteArray): String
|
||||
}
|
||||
@@ -7,12 +7,12 @@
|
||||
|
||||
package cn.rtast.libmc.network
|
||||
|
||||
import cn.rtast.libmc.crypto.ProtocolContextBuilder
|
||||
import cn.rtast.libmc.context.ProtocolContextBuilder
|
||||
|
||||
public abstract class SocketContext {
|
||||
public abstract val engine: SocketEngine
|
||||
public abstract val socketEngine: SocketEngine
|
||||
|
||||
public fun createSocket(host: String, port: Int): RawSocket = engine.create(host, port)
|
||||
public fun createSocket(host: String, port: Int): RawSocket = socketEngine.create(host, port)
|
||||
}
|
||||
|
||||
public fun (ProtocolContextBuilder.() -> Unit).withCustom(
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/12
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.serialization
|
||||
|
||||
public object LiteralJsonParser {
|
||||
public fun extractString(json: String, keyPath: List<String>): String? {
|
||||
var currentScope = json
|
||||
for (i in keyPath.indices) {
|
||||
val key = keyPath[i]
|
||||
val value = extractRawValue(currentScope, key) ?: return null
|
||||
if (i == keyPath.lastIndex) return parseJsonString(value)
|
||||
currentScope = value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun extractRawValue(json: String, targetKey: String): String? {
|
||||
val keyPattern = "\"$targetKey\""
|
||||
val keyIndex = json.indexOf(keyPattern)
|
||||
if (keyIndex == -1) return null
|
||||
val colonIndex = json.indexOf(':', keyIndex + keyPattern.length)
|
||||
if (colonIndex == -1) return null
|
||||
var startIndex = colonIndex + 1
|
||||
while (startIndex < json.length && json[startIndex].isWhitespace()) startIndex++
|
||||
if (startIndex >= json.length) return null
|
||||
val firstChar = json[startIndex]
|
||||
return when (firstChar) {
|
||||
'"' -> extractStringLiteral(json, startIndex)
|
||||
'{' -> extractObjectLiteral(json, startIndex)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractStringLiteral(json: String, startIndex: Int): String? {
|
||||
var inEscape = false
|
||||
for (i in startIndex + 1 until json.length) {
|
||||
val c = json[i]
|
||||
if (inEscape) {
|
||||
inEscape = false
|
||||
} else if (c == '\\') {
|
||||
inEscape = true
|
||||
} else if (c == '"') return json.substring(startIndex, i + 1)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun extractObjectLiteral(json: String, startIndex: Int): String? {
|
||||
var depth = 0
|
||||
var inString = false
|
||||
var inEscape = false
|
||||
for (i in startIndex until json.length) {
|
||||
val c = json[i]
|
||||
if (inString) {
|
||||
if (inEscape) {
|
||||
inEscape = false
|
||||
} else if (c == '\\') {
|
||||
inEscape = true
|
||||
} else if (c == '"') {
|
||||
inString = false
|
||||
}
|
||||
} else {
|
||||
when (c) {
|
||||
'"' -> inString = true
|
||||
'{' -> depth++
|
||||
'}' -> {
|
||||
depth--
|
||||
if (depth == 0) return json.substring(startIndex, i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun parseJsonString(rawJsonString: String): String? {
|
||||
if (rawJsonString.length < 2 || !rawJsonString.startsWith('"') || !rawJsonString.endsWith('"')) return null
|
||||
val content = rawJsonString.substring(1, rawJsonString.length - 1)
|
||||
val sb = StringBuilder()
|
||||
var i = 0
|
||||
while (i < content.length) {
|
||||
val c = content[i]
|
||||
if (c == '\\' && i + 1 < content.length) {
|
||||
when (val next = content[i + 1]) {
|
||||
'n' -> sb.append('\n')
|
||||
'r' -> sb.append('\r')
|
||||
't' -> sb.append('\t')
|
||||
'"' -> sb.append('"')
|
||||
'\\' -> sb.append('\\')
|
||||
'/' -> sb.append('/')
|
||||
'u' -> {
|
||||
if (i + 5 < content.length) {
|
||||
val hex = content.substring(i + 2, i + 6)
|
||||
sb.append(hex.toInt(16).toChar())
|
||||
i += 5
|
||||
} else {
|
||||
sb.append(c)
|
||||
}
|
||||
}
|
||||
else -> sb.append(next)
|
||||
}
|
||||
i += 2
|
||||
} else {
|
||||
sb.append(c)
|
||||
i++
|
||||
}
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/12
|
||||
*/
|
||||
|
||||
|
||||
package test
|
||||
|
||||
import cn.rtast.libmc.serialization.LiteralJsonParser
|
||||
import kotlin.test.Test
|
||||
|
||||
class TestJsonParser {
|
||||
@Test
|
||||
fun testJsonParser() {
|
||||
val input = """
|
||||
{
|
||||
|
||||
"keyPair": {
|
||||
|
||||
"privateKey": "-----BEGIN RSA PRIVATE KEY-----",
|
||||
|
||||
"publicKey": "-----BEGIN RSA PUBLIC KEY-----"
|
||||
|
||||
},
|
||||
|
||||
"publicKeySignature": "",
|
||||
|
||||
"publicKeySignatureV2": "",
|
||||
|
||||
"expiresAt": "2026-09-13T03:52:50.501218Z",
|
||||
|
||||
"refreshedAfter": "2026-09-12T19:52:50.501218Z"
|
||||
|
||||
}
|
||||
""".trimIndent()
|
||||
println(LiteralJsonParser.extractString(input, listOf("keyPair", "privateKey")))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user