From 14bdf45c89cf6b68254533ab72674f3aa1b6aed0 Mon Sep 17 00:00:00 2001 From: ChomeNS <95471003+ChomeNS@users.noreply.github.com> Date: Sat, 19 Apr 2025 14:05:27 +0700 Subject: [PATCH] feat: draft for extras messaging on chomens mod, not sure how to implement on minecraft side :( --- build-number.txt | 2 +- .../chomens_bot/chomeNSMod/Encryptor.java | 11 +-- .../plugins/ChomeNSModIntegrationPlugin.java | 79 ++++++++++++++----- .../plugins/ExtrasMessengerPlugin.java | 11 ++- 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/build-number.txt b/build-number.txt index 47fd2ab3..51680442 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -2865 \ No newline at end of file +2874 \ No newline at end of file diff --git a/src/main/java/me/chayapak1/chomens_bot/chomeNSMod/Encryptor.java b/src/main/java/me/chayapak1/chomens_bot/chomeNSMod/Encryptor.java index 284760e7..010fea06 100644 --- a/src/main/java/me/chayapak1/chomens_bot/chomeNSMod/Encryptor.java +++ b/src/main/java/me/chayapak1/chomens_bot/chomeNSMod/Encryptor.java @@ -1,7 +1,5 @@ package me.chayapak1.chomens_bot.chomeNSMod; -import me.chayapak1.chomens_bot.util.Ascii85; - import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -12,6 +10,7 @@ import java.security.SecureRandom; import java.security.spec.KeySpec; // inspired from smp encryption plugin +// Author: ChatGPT public class Encryptor { private static final SecureRandom RANDOM = new SecureRandom(); @@ -20,7 +19,7 @@ public class Encryptor { private static final int ITERATIONS = 65536; private static final int KEY_LENGTH = 256; - public static String encrypt (final byte[] data, final String password) throws Exception { + public static byte[] encrypt (final byte[] data, final String password) throws Exception { final byte[] salt = generateRandomBytes(SALT_LENGTH); final SecretKey key = deriveKey(password, salt); @@ -36,12 +35,10 @@ public class Encryptor { System.arraycopy(iv, 0, combined, salt.length, iv.length); System.arraycopy(encrypted, 0, combined, salt.length + iv.length, encrypted.length); - return Ascii85.encode(combined); + return combined; } - public static byte[] decrypt (final String ascii85Data, final String password) throws Exception { - final byte[] combined = Ascii85.decode(ascii85Data); - + public static byte[] decrypt (final byte[] combined, final String password) throws Exception { final byte[] salt = new byte[SALT_LENGTH]; final byte[] iv = new byte[IV_LENGTH]; final byte[] encrypted = new byte[combined.length - SALT_LENGTH - IV_LENGTH]; diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/ChomeNSModIntegrationPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/ChomeNSModIntegrationPlugin.java index 2d160e18..7de2b1e7 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/ChomeNSModIntegrationPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/ChomeNSModIntegrationPlugin.java @@ -17,6 +17,7 @@ import me.chayapak1.chomens_bot.data.chomeNSMod.PayloadState; import me.chayapak1.chomens_bot.data.listener.Listener; import me.chayapak1.chomens_bot.data.logging.LogType; import me.chayapak1.chomens_bot.data.player.PlayerEntry; +import me.chayapak1.chomens_bot.util.Ascii85; import me.chayapak1.chomens_bot.util.UUIDUtilities; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; @@ -31,7 +32,9 @@ import java.util.concurrent.ConcurrentHashMap; // This is inspired from the ChomeNS Bot Proxy which is in the JavaScript version of ChomeNS Bot. public class ChomeNSModIntegrationPlugin implements Listener { private static final String ID = "chomens_mod"; - private static final int ENCODED_PAYLOAD_LENGTH = 31_000; // just 32767 trimmed "a bit" + + private static final int ASCII85_CHUNK_SIZE = 31_000; // just 32767 trimmed "a bit" + private static final int EXTRAS_CHUNK_SIZE = 32_500; // just 32767 trimmed a bit private static final long NONCE_EXPIRATION_MS = 30 * 1000; // 30 seconds @@ -59,6 +62,8 @@ public class ChomeNSModIntegrationPlugin implements Listener { this.bot = bot; this.handler = new PacketHandler(bot); + bot.extrasMessenger.registerChannel(ID); + bot.listener.addListener(this); } @@ -88,28 +93,66 @@ public class ChomeNSModIntegrationPlugin implements Listener { try { final int messageId = RANDOM.nextInt(); - final String encrypted = Encryptor.encrypt(bytes, bot.config.chomeNSMod.password); + final byte[] encrypted = Encryptor.encrypt(bytes, bot.config.chomeNSMod.password); - final Iterable split = Splitter.fixedLength(ENCODED_PAYLOAD_LENGTH).split(encrypted); + // FIXME: not sure how to implement on the mod side yet + final boolean supportsExtrasMessaging = false; // bot.extrasMessenger.isSupported; - int i = 1; + if (supportsExtrasMessaging) { + // TODO: test this + // TODO: implement receiver + final List chunks = new ArrayList<>(); - for (final String part : split) { - final PayloadState state = i == Iterables.size(split) - ? PayloadState.DONE - : PayloadState.JOINING; + for (int i = 0; i < encrypted.length; i += EXTRAS_CHUNK_SIZE) { + final int end = Math.min(encrypted.length, i + EXTRAS_CHUNK_SIZE); + final byte[] chunk = Arrays.copyOfRange(encrypted, i, end); + chunks.add(chunk); + } - final Component component = Component.translatable( - "", - Component.text(ID), - Component.text(messageId), - Component.text(state.ordinal()), - Component.text(part) - ); + int i = 1; - bot.chat.actionBar(component, target.profile.getId()); + for (final byte[] chunk : chunks) { + final PayloadState state = i == chunks.size() + ? PayloadState.DONE + : PayloadState.JOINING; - i++; + final ByteBuf extrasBuf = Unpooled.buffer(); + + extrasBuf.writeInt(messageId); + extrasBuf.writeShort(state.ordinal()); // short or byte? + extrasBuf.writeBytes(chunk); + + final byte[] extrasBytes = new byte[buf.readableBytes()]; + extrasBuf.readBytes(extrasBytes); + + bot.extrasMessenger.sendPayload(ID, extrasBytes); + + i++; + } + } else { + final String encryptedAscii85 = Ascii85.encode(encrypted); + + final Iterable chunks = Splitter.fixedLength(ASCII85_CHUNK_SIZE).split(encryptedAscii85); + + int i = 1; + + for (final String chunk : chunks) { + final PayloadState state = i == Iterables.size(chunks) + ? PayloadState.DONE + : PayloadState.JOINING; + + final Component component = Component.translatable( + "", + Component.text(ID), + Component.text(messageId), + Component.text(state.ordinal()), + Component.text(chunk) + ); + + bot.chat.actionBar(component, target.profile.getId()); + + i++; + } } } catch (final Exception ignored) { } } @@ -220,7 +263,7 @@ public class ChomeNSModIntegrationPlugin implements Listener { playerReceivedParts.remove(messageId); final byte[] decryptedFullPayload = Encryptor.decrypt( - builder.toString(), + Ascii85.decode(builder.toString()), bot.config.chomeNSMod.password ); diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java index ecb999f2..2bc6e2ad 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/ExtrasMessengerPlugin.java @@ -106,6 +106,8 @@ public class ExtrasMessengerPlugin implements Listener { } public void sendPayload (final String name, final byte[] data) { + if (!bot.loggedIn) return; + final ByteBuf buf = Unpooled.buffer(); writeString(buf, chomens_namespace + name); @@ -122,6 +124,11 @@ public class ExtrasMessengerPlugin implements Listener { } public void registerChannel (final String channel) { + if (!bot.loggedIn) { + registeredChannels.add(channel); + return; + } + final ByteBuf buf = Unpooled.buffer(); writeString(buf, chomens_namespace + channel); @@ -139,7 +146,7 @@ public class ExtrasMessengerPlugin implements Listener { public void unregisterChannel (final String channel) { final boolean removed = registeredChannels.remove(channel); - if (!removed) return; + if (!removed || !bot.loggedIn) return; final ByteBuf buf = Unpooled.buffer(); @@ -164,7 +171,7 @@ public class ExtrasMessengerPlugin implements Listener { final byte[] buf = new byte[255]; int idx = 0; - for (; ; ) { + while (true) { final byte input = byteBuf.readByte(); if (idx == buf.length) break;