diff --git a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStackEntry.kt b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStackEntry.kt
index 111f42e14..90238eb33 100644
--- a/src/main/java/de/bixilon/minosoft/commands/stack/CommandStackEntry.kt
+++ b/src/main/java/de/bixilon/minosoft/commands/stack/CommandStackEntry.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -25,6 +25,6 @@ data class CommandStackEntry(
) {
fun sign(connection: PlayConnection, chain: MessageChain, key: PrivateKey, salt: Long, time: Instant): ByteArray {
- return chain.signMessage(connection.version, key, data.toString(), null, salt, connection.player.uuid, time, LastSeenMessageList(emptyArray()))
+ return chain.signMessage(key, data.toString(), null, salt, connection.player.uuid, time, LastSeenMessageList(emptyArray()))
}
}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/MessageChain.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/MessageChain.kt
index 288b9d280..39ed6ba80 100644
--- a/src/main/java/de/bixilon/minosoft/data/chat/signature/MessageChain.kt
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/MessageChain.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -13,68 +13,17 @@
package de.bixilon.minosoft.data.chat.signature
-import com.fasterxml.jackson.core.io.JsonStringEncoder
-import com.google.common.hash.Hashing
-import com.google.common.primitives.Longs
+import de.bixilon.minosoft.data.chat.signature.signer.MessageSigner
import de.bixilon.minosoft.data.text.ChatComponent
-import de.bixilon.minosoft.protocol.ProtocolUtil.encodeNetwork
-import de.bixilon.minosoft.protocol.protocol.OutByteBuffer
-import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
-import de.bixilon.minosoft.protocol.protocol.encryption.CryptManager
import de.bixilon.minosoft.protocol.versions.Version
import java.security.PrivateKey
import java.time.Instant
import java.util.*
-class MessageChain {
- private var previous: ByteArray? = null
+class MessageChain(version: Version) {
+ val signer = MessageSigner.forVersion(version)
- fun signMessage(version: Version, privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
- val signature = CryptManager.createSignature(version)
-
- signature.initSign(privateKey)
-
- if (version < ProtocolVersions.V_1_19_1_PRE4) {
- signature.update(Longs.toByteArray(salt))
- signature.update(Longs.toByteArray(sender.mostSignificantBits))
- signature.update(Longs.toByteArray(sender.leastSignificantBits))
- signature.update(Longs.toByteArray(time.epochSecond))
- signature.update(message.getSignatureBytes())
- } else {
- val buffer = OutByteBuffer()
- buffer.writeLong(salt)
- buffer.writeLong(time.epochSecond)
- if (version.versionId >= ProtocolVersions.V_1_19_2) { // ToDo: This changed somewhere after 1.19.1-pre5
- buffer.writeBareString(message)
- } else {
- buffer.writeBareByteArray(message.getSignatureBytes())
- }
-
- if (version.versionId >= ProtocolVersions.V_1_19_1_PRE5) {
- buffer.writeByte(0x46)
- // ToDo: send preview text (optional)
-
- for (entry in lastSeen.messages) {
- buffer.writeByte(0x46)
- buffer.writeUUID(entry.profile)
- buffer.writeBareByteArray(entry.signature)
- }
- }
- val hash = Hashing.sha256().hashBytes(buffer.toArray()).asBytes()
-
- previous?.let { signature.update(it) }
- signature.update(Longs.toByteArray(sender.mostSignificantBits))
- signature.update(Longs.toByteArray(sender.leastSignificantBits))
- signature.update(hash)
- }
-
- val singed = signature.sign()
- this.previous = singed
-
- return singed
- }
-
- private fun String.getSignatureBytes(): ByteArray {
- return """{"text":"${String(JsonStringEncoder.getInstance().quoteAsString(this))}"}""".encodeNetwork()
+ fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
+ return signer.signMessage(privateKey, message, preview, salt, sender, time, lastSeen)
}
}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner.kt
new file mode 100644
index 000000000..22dba6be8
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner.kt
@@ -0,0 +1,41 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.chat.signature.signer
+
+import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
+import de.bixilon.minosoft.data.text.ChatComponent
+import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
+import de.bixilon.minosoft.protocol.versions.Version
+import java.security.PrivateKey
+import java.time.Instant
+import java.util.*
+
+interface MessageSigner {
+
+ fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray
+
+
+ companion object {
+
+ fun forVersion(version: Version): MessageSigner {
+ if (version < ProtocolVersions.V_1_19_1_PRE4) {
+ return MessageSigner1(version)
+ }
+ if (version < ProtocolVersions.V_22W42A) {
+ return MessageSigner2(version)
+ }
+ return MessageSigner3(version)
+ }
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner1.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner1.kt
new file mode 100644
index 000000000..c37cd4e13
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner1.kt
@@ -0,0 +1,43 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.chat.signature.signer
+
+import com.google.common.primitives.Longs
+import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
+import de.bixilon.minosoft.data.chat.signature.signer.MessageSigningUtil.getSignatureBytes
+import de.bixilon.minosoft.data.text.ChatComponent
+import de.bixilon.minosoft.protocol.protocol.encryption.CryptManager
+import de.bixilon.minosoft.protocol.versions.Version
+import java.security.PrivateKey
+import java.time.Instant
+import java.util.*
+
+class MessageSigner1(
+ private val version: Version,
+) : MessageSigner {
+
+ override fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
+ val signature = CryptManager.createSignature(version)
+
+ signature.initSign(privateKey)
+
+ signature.update(Longs.toByteArray(salt))
+ signature.update(Longs.toByteArray(sender.mostSignificantBits))
+ signature.update(Longs.toByteArray(sender.leastSignificantBits))
+ signature.update(Longs.toByteArray(time.epochSecond))
+ signature.update(message.getSignatureBytes())
+
+ return signature.sign()
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner2.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner2.kt
new file mode 100644
index 000000000..6726b2583
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner2.kt
@@ -0,0 +1,68 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.chat.signature.signer
+
+import com.google.common.hash.Hashing
+import com.google.common.primitives.Longs
+import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
+import de.bixilon.minosoft.data.chat.signature.signer.MessageSigningUtil.getSignatureBytes
+import de.bixilon.minosoft.data.text.ChatComponent
+import de.bixilon.minosoft.protocol.protocol.OutByteBuffer
+import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
+import de.bixilon.minosoft.protocol.protocol.encryption.CryptManager
+import de.bixilon.minosoft.protocol.versions.Version
+import java.security.PrivateKey
+import java.time.Instant
+import java.util.*
+
+class MessageSigner2(
+ private val version: Version,
+) : MessageSigner {
+ private var previous: ByteArray? = null
+
+ override fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
+ val signature = CryptManager.createSignature(version)
+
+ signature.initSign(privateKey)
+
+
+ val buffer = OutByteBuffer()
+ buffer.writeLong(salt)
+ buffer.writeLong(time.epochSecond)
+ if (version.versionId >= ProtocolVersions.V_1_19_2) { // ToDo: This changed somewhere after 1.19.1-pre5
+ buffer.writeBareString(message)
+ } else {
+ buffer.writeBareByteArray(message.getSignatureBytes())
+ }
+
+ if (version.versionId >= ProtocolVersions.V_1_19_1_PRE5) {
+ buffer.writeByte(0x46)
+ // ToDo: send preview text (optional)
+
+ for (entry in lastSeen.messages) {
+ buffer.writeByte(0x46)
+ buffer.writeUUID(entry.profile)
+ buffer.writeBareByteArray(entry.signature)
+ }
+ }
+ val hash = Hashing.sha256().hashBytes(buffer.toArray()).asBytes()
+
+ previous?.let { signature.update(it) }
+ signature.update(Longs.toByteArray(sender.mostSignificantBits))
+ signature.update(Longs.toByteArray(sender.leastSignificantBits))
+ signature.update(hash)
+
+ return signature.sign()
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner3.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner3.kt
new file mode 100644
index 000000000..c80c621db
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigner3.kt
@@ -0,0 +1,30 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.chat.signature.signer
+
+import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
+import de.bixilon.minosoft.data.text.ChatComponent
+import de.bixilon.minosoft.protocol.versions.Version
+import java.security.PrivateKey
+import java.time.Instant
+import java.util.*
+
+class MessageSigner3(
+ private val version: Version,
+) : MessageSigner {
+
+ override fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
+ TODO("Not yet implemented!")
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigningUtil.kt b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigningUtil.kt
new file mode 100644
index 000000000..972e00a57
--- /dev/null
+++ b/src/main/java/de/bixilon/minosoft/data/chat/signature/signer/MessageSigningUtil.kt
@@ -0,0 +1,24 @@
+/*
+ * Minosoft
+ * Copyright (C) 2020-2023 Moritz Zwerger
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program. If not, see .
+ *
+ * This software is not affiliated with Mojang AB, the original developer of Minecraft.
+ */
+
+package de.bixilon.minosoft.data.chat.signature.signer
+
+import com.fasterxml.jackson.core.io.JsonStringEncoder
+import de.bixilon.minosoft.protocol.ProtocolUtil.encodeNetwork
+
+object MessageSigningUtil {
+
+ fun String.getSignatureBytes(): ByteArray {
+ return """{"text":"${String(JsonStringEncoder.getInstance().quoteAsString(this))}"}""".encodeNetwork()
+ }
+}
diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt
index 715d751e4..4b052c236 100644
--- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt
+++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/ConnectionUtil.kt
@@ -1,6 +1,6 @@
/*
* Minosoft
- * Copyright (C) 2020-2022 Moritz Zwerger
+ * Copyright (C) 2020-2023 Moritz Zwerger
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
@@ -47,19 +47,19 @@ import java.time.Instant
class ConnectionUtil(
private val connection: PlayConnection,
) {
- private val chain = MessageChain()
+ private val chain = MessageChain(connection.version)
private val random = SecureRandom()
fun sendDebugMessage(message: Any) {
val component = BaseComponent(RenderConstants.DEBUG_MESSAGES_PREFIX, ChatComponent.of(message).apply { this.setFallbackColor(ChatColors.BLUE) })
- connection.fire(InternalMessageReceiveEvent(connection, InternalChatMessage(component)))
+ connection.events.fire(InternalMessageReceiveEvent(connection, InternalChatMessage(component)))
Log.log(LogMessageType.CHAT_IN, LogLevels.INFO) { component }
}
fun sendInternal(message: Any) {
val component = ChatComponent.of(message)
val prefixed = BaseComponent(RenderConstants.INTERNAL_MESSAGES_PREFIX, component)
- connection.fire(InternalMessageReceiveEvent(connection, InternalChatMessage(if (connection.profiles.gui.chat.internal.hidden) prefixed else component)))
+ connection.events.fire(InternalMessageReceiveEvent(connection, InternalChatMessage(if (connection.profiles.gui.chat.internal.hidden) prefixed else component)))
Log.log(LogMessageType.CHAT_IN, LogLevels.INFO) { prefixed }
}
@@ -78,7 +78,7 @@ class ConnectionUtil(
if (message.length > connection.version.maxChatMessageSize) {
throw IllegalArgumentException("Message length (${message.length} can not exceed ${connection.version.maxChatMessageSize})")
}
- if (connection.fire(ChatMessageSendEvent(connection, message))) {
+ if (connection.events.fire(ChatMessageSendEvent(connection, message))) {
return
}
Log.log(LogMessageType.CHAT_OUT) { message }
@@ -97,7 +97,7 @@ class ConnectionUtil(
val acknowledgement = Acknowledgement.EMPTY
val signature: ByteArray? = if (connection.network.encrypted) {
- chain.signMessage(connection.version, privateKey, message, null, salt, uuid, time, acknowledgement.lastSeen)
+ chain.signMessage(privateKey, message, null, salt, uuid, time, acknowledgement.lastSeen)
} else {
null
}
@@ -129,7 +129,7 @@ class ConnectionUtil(
connection.world.particleRenderer?.removeAllParticles()
connection.player.openedContainer?.let {
connection.player.openedContainer = null
- connection.fire(ContainerCloseEvent(connection, it.id ?: -1, it))
+ connection.events.fire(ContainerCloseEvent(connection, it.id ?: -1, it))
}
connection.player.healthCondition = HealthCondition()
connection.world.time = WorldTime()