feat: draft for extras messaging on chomens mod, not sure how to implement on minecraft side :(

This commit is contained in:
ChomeNS
2025-04-19 14:05:27 +07:00
parent 2f65276225
commit 14bdf45c89
4 changed files with 75 additions and 28 deletions

View File

@@ -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];

View File

@@ -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<String> 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<byte[]> 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<String> 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
);

View File

@@ -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;