almost working but still not... :(

the issue is in the VoiceChatPlugin at line 146 BTW
also ignore the sussy debug lines
This commit is contained in:
Chayapak 2023-06-14 19:10:05 +07:00
parent ca830ed9bf
commit 5c53842157
10 changed files with 400 additions and 34 deletions

View file

@ -0,0 +1,7 @@
package land.chipmunk.chayapak.chomens_bot.data.voiceChat;
public enum Codec {
VOIP,
AUDIO,
RESTRICTED_LOWDELAY;
}

View file

@ -0,0 +1,13 @@
package land.chipmunk.chayapak.chomens_bot.data.voiceChat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.net.SocketAddress;
@AllArgsConstructor
public class RawUdpPacket {
@Getter private final byte[] data;
@Getter private final SocketAddress socketAddress;
@Getter private final long timestamp;
}

View file

@ -7,36 +7,31 @@ import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.packet.Packet;
import io.netty.buffer.Unpooled;
import land.chipmunk.chayapak.chomens_bot.Bot;
import land.chipmunk.chayapak.chomens_bot.util.AES;
import land.chipmunk.chayapak.chomens_bot.data.voiceChat.RawUdpPacket;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import land.chipmunk.chayapak.chomens_bot.voiceChat.InitializationData;
import land.chipmunk.chayapak.chomens_bot.voiceChat.NetworkMessage;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.KeepAlivePacket;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.PingPacket;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.SecretPacket;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.AuthenticatePacket;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.util.Arrays;
import java.net.*;
// exists for some reason, still wip and will be finished in the next 69 years
// and i prob implemented it in a wrong way lol
// at least when you do `/voicechat test (bot username)` it will show `Client not connected`
// instead of `(bot username) does not have Simple Voice Chat installed`
public class VoiceChatPlugin extends Bot.Listener {
public static final byte MAGIC_BYTE = (byte) 0b11111111;
private final Bot bot;
private final ClientVoiceChatSocket socket;
private InitializationData initializationData;
private ClientVoiceChatSocket socket;
private InetAddress address;
private InetSocketAddress socketAddress;
public VoiceChatPlugin(Bot bot) {
this.bot = bot;
this.socket = new ClientVoiceChatSocket();
try {
socket.open();
} catch (Exception e) {
e.printStackTrace();
}
bot.addListener(this);
}
@ -56,43 +51,102 @@ public class VoiceChatPlugin extends Bot.Listener {
bot.session().send(new ServerboundCustomPayloadPacket(
"voicechat:request_secret",
new byte[] { 0, 0, 0, 17 } // what are these bytes?
new FriendlyByteBuf(Unpooled.buffer()).writeInt(17).array()
));
bot.session().send(new ServerboundCustomPayloadPacket(
"voicechat:update_state",
new FriendlyByteBuf(Unpooled.buffer()).writeBoolean(false).array()
));
}
public void packetReceived(ClientboundCustomPayloadPacket _packet) {
// sus
/*
System.out.println(_packet.getChannel());
System.out.println("\"" + _packet.getChannel() + "\"");
System.out.println(Arrays.toString(_packet.getData()));
System.out.println(new String(_packet.getData()));
*/
// for some reason this entire part is not running
if (_packet.getChannel().equals("voicechat:secret")) {
System.out.println("got the secret packet");
final byte[] bytes = _packet.getData();
final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
final SecretPacket secretPacket = new SecretPacket().fromBytes(buf);
System.out.println(secretPacket.secret());
System.out.println(secretPacket.serverPort());
initializationData = new InitializationData(bot.options().host(), secretPacket);
try {
address = InetAddress.getByName(bot.options().host());
socketAddress = new InetSocketAddress(address, initializationData.serverPort());
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
System.out.println("address " + address.getHostName());
socket = new ClientVoiceChatSocket();
try {
socket.open();
} catch (Exception e) {
e.printStackTrace();
}
bot.executorService().submit(() -> {
while (true) {
final RawUdpPacket packet = socket.read();
try {
if (socket.isClosed()) continue;
if (packet == null) return;
System.out.println("reading packet");
final NetworkMessage message = NetworkMessage.readPacket(socket.read(), initializationData);
System.out.println("DONE reading packet, this message will; prob nto woshow");
byte[] data = packet.data();
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(data));
if (message == null) continue;
if (buf.readByte() != MAGIC_BYTE) return;
// AES.decrypt(secret, payload) ?
if (message.packet() instanceof AuthenticatePacket) {
System.out.println("SERVER AUTHENTICATED FINALLYYYYYYYYYYYYYYYY");
} else if (message.packet() instanceof PingPacket pingPacket) {
System.out.println("got ping packet");
sendToServer(new NetworkMessage(pingPacket));
} else if (message.packet() instanceof KeepAlivePacket) {
System.out.println("got keep alive packet");
sendToServer(new NetworkMessage(new KeepAlivePacket()));
} else {
System.out.println("got " + message.packet().getClass().getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
public void sendToServer (NetworkMessage message) throws Exception {
socket.send(
message.writeClient(initializationData),
socketAddress
);
}
private static class VoiceChatSocketBase {
private final byte[] BUFFER = new byte[4096];
public RawUdpPacket read (DatagramSocket socket) {
try {
DatagramPacket packet = new DatagramPacket(BUFFER, BUFFER.length);
System.out.println("receiving packet");
// the problem is this next line, just this 1 line. it makes the entire thing froze
socket.receive(packet);
System.out.println("FINALLY DONE RECEIVING AAAAHHHHHHHHHHHHHHHHHHH");
// Setting the timestamp after receiving the packet
long timestamp = System.currentTimeMillis();
byte[] data = new byte[packet.getLength()];
@ -138,11 +192,4 @@ public class VoiceChatPlugin extends Bot.Listener {
return socket == null;
}
}
@AllArgsConstructor
private static class RawUdpPacket {
@Getter private final byte[] data;
@Getter private final SocketAddress socketAddress;
@Getter private final long timestamp;
}
}

View file

@ -0,0 +1,44 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat;
import land.chipmunk.chayapak.chomens_bot.data.voiceChat.Codec;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.SecretPacket;
import lombok.Getter;
import java.util.UUID;
public class InitializationData {
@Getter private final String serverIP;
@Getter private final int serverPort;
@Getter private final UUID playerUUID;
@Getter private final UUID secret;
@Getter private final Codec codec;
@Getter private final int mtuSize;
@Getter private final double voiceChatDistance;
@Getter private final int keepAlive;
@Getter private final boolean groupsEnabled;
@Getter private final boolean allowRecording;
public InitializationData(String serverIP, SecretPacket secretPacket) {
this.serverIP = serverIP;
this.serverPort = secretPacket.serverPort();
this.playerUUID = secretPacket.playerUUID();
this.secret = secretPacket.secret();
this.codec = secretPacket.codec();
this.mtuSize = secretPacket.mtuSize();
this.voiceChatDistance = secretPacket.voiceChatDistance();
this.keepAlive = secretPacket.keepAlive();
this.groupsEnabled = secretPacket.groupsEnabled();
this.allowRecording = secretPacket.allowRecording();
}
private static class HostData {
private final String ip;
private final int port;
public HostData(String ip, int port) {
this.ip = ip;
this.port = port;
}
}
}

View file

@ -0,0 +1,129 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat;
import io.netty.buffer.Unpooled;
import land.chipmunk.chayapak.chomens_bot.data.voiceChat.RawUdpPacket;
import land.chipmunk.chayapak.chomens_bot.util.AES;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import land.chipmunk.chayapak.chomens_bot.voiceChat.packets.AuthenticatePacket;
import lombok.Getter;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.lang.reflect.InvocationTargetException;
import java.net.SocketAddress;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class NetworkMessage {
public static final byte MAGIC_BYTE = (byte) 0b11111111;
@Getter private final long timestamp;
@Getter private Packet<? extends Packet<?>> packet;
@Getter private SocketAddress address;
public NetworkMessage(long timestamp, Packet<?> packet) {
this(timestamp);
this.packet = packet;
}
public NetworkMessage(Packet<?> packet) {
this(System.currentTimeMillis());
this.packet = packet;
}
private NetworkMessage(long timestamp) {
this.timestamp = timestamp;
}
private static final Map<Byte, Class<? extends Packet<?>>> packetRegistry;
static {
packetRegistry = new HashMap<>();
// packetRegistry.put((byte) 0x1, MicPacket.class);
// packetRegistry.put((byte) 0x2, PlayerSoundPacket.class);
// packetRegistry.put((byte) 0x3, GroupSoundPacket.class);
// packetRegistry.put((byte) 0x4, LocationSoundPacket.class);
packetRegistry.put((byte) 0x5, AuthenticatePacket.class);
// packetRegistry.put((byte) 0x6, AuthenticateAckPacket.class);
// packetRegistry.put((byte) 0x7, PingPacket.class);
// packetRegistry.put((byte) 0x8, KeepAlivePacket.class);
// packetRegistry.put((byte) 0x9, ConnectionCheckPacket.class);
// packetRegistry.put((byte) 0xA, ConnectionCheckAckPacket.class);
}
public static NetworkMessage readPacket (RawUdpPacket packet, InitializationData initializationData) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
final byte[] data = packet.data();
final FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.wrappedBuffer(data));
if (b.readByte() != MAGIC_BYTE) return null;
return readFromBytes(packet.socketAddress(), initializationData.secret(), b.readByteArray(), System.currentTimeMillis());
}
private static NetworkMessage readFromBytes(SocketAddress socketAddress, UUID secret, byte[] encryptedPayload, long timestamp) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
byte[] decrypt;
try {
decrypt = AES.decrypt(secret, encryptedPayload);
} catch (Exception e) {
e.printStackTrace();
return null;
}
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer(decrypt));
byte packetType = buffer.readByte();
final Class<? extends Packet<?>> packetClass = packetRegistry.get(packetType);
if (packetClass == null) {
System.out.println("packet type is null " + packetType);
return null;
}
Packet<?> p = packetClass.getDeclaredConstructor().newInstance();
NetworkMessage message = new NetworkMessage(timestamp);
message.address = socketAddress;
message.packet = p.fromBytes(buffer);
return message;
}
private static byte getPacketType(Packet<? extends Packet<?>> packet) {
for (Map.Entry<Byte, Class<? extends Packet<?>>> entry : packetRegistry.entrySet()) {
if (packet.getClass().equals(entry.getValue())) {
return entry.getKey();
}
}
return -1;
}
public byte[] writeClient(InitializationData data) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
byte[] payload = write(data.secret());
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer(1 + 16 + payload.length));
buffer.writeByte(MAGIC_BYTE);
buffer.writeUUID(data.playerUUID());
buffer.writeByteArray(payload);
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes);
return bytes;
}
public byte[] write(UUID secret) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
byte type = getPacketType(packet);
if (type < 0) {
throw new IllegalArgumentException("Packet type not found");
}
buffer.writeByte(type);
packet.toBytes(buffer);
byte[] bytes = new byte[buffer.readableBytes()];
buffer.readBytes(bytes);
return AES.encrypt(secret, bytes);
}
}

View file

@ -0,0 +1,9 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
public interface Packet<T extends Packet<T>> {
T fromBytes (FriendlyByteBuf buf);
void toBytes (FriendlyByteBuf buf);
}

View file

@ -0,0 +1,26 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat.packets;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import land.chipmunk.chayapak.chomens_bot.voiceChat.Packet;
import lombok.Getter;
import java.util.UUID;
public class AuthenticatePacket implements Packet<AuthenticatePacket> {
@Getter private UUID playerUUID;
@Getter private UUID secret;
@Override
public AuthenticatePacket fromBytes (FriendlyByteBuf buf) {
AuthenticatePacket packet = new AuthenticatePacket();
packet.playerUUID = buf.readUUID();
packet.secret = buf.readUUID();
return packet;
}
@Override
public void toBytes (FriendlyByteBuf buf) {
buf.writeUUID(playerUUID);
buf.writeUUID(secret);
}
}

View file

@ -0,0 +1,15 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat.packets;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import land.chipmunk.chayapak.chomens_bot.voiceChat.Packet;
public class KeepAlivePacket implements Packet<KeepAlivePacket> {
@Override
public KeepAlivePacket fromBytes(FriendlyByteBuf buf) {
return new KeepAlivePacket();
}
@Override
public void toBytes(FriendlyByteBuf buf) {
}
}

View file

@ -0,0 +1,26 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat.packets;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import land.chipmunk.chayapak.chomens_bot.voiceChat.Packet;
import lombok.Getter;
import java.util.UUID;
public class PingPacket implements Packet<PingPacket> {
@Getter private UUID id;
@Getter private long timestamp;
@Override
public PingPacket fromBytes(FriendlyByteBuf buf) {
final PingPacket pingPacket = new PingPacket();
pingPacket.id = buf.readUUID();
pingPacket.timestamp = buf.readLong();
return pingPacket;
}
@Override
public void toBytes(FriendlyByteBuf buf) {
buf.writeUUID(id);
buf.writeLong(timestamp);
}
}

View file

@ -0,0 +1,50 @@
package land.chipmunk.chayapak.chomens_bot.voiceChat.packets;
import land.chipmunk.chayapak.chomens_bot.data.voiceChat.Codec;
import land.chipmunk.chayapak.chomens_bot.util.FriendlyByteBuf;
import land.chipmunk.chayapak.chomens_bot.voiceChat.Packet;
import lombok.Getter;
import java.util.UUID;
public class SecretPacket implements Packet<SecretPacket> {
@Getter private UUID secret;
@Getter private int serverPort;
@Getter private UUID playerUUID;
@Getter private Codec codec;
@Getter private int mtuSize;
@Getter private double voiceChatDistance;
@Getter private int keepAlive;
@Getter private boolean groupsEnabled;
@Getter private String voiceHost;
@Getter private boolean allowRecording;
@Override
public SecretPacket fromBytes(FriendlyByteBuf buf) {
secret = buf.readUUID();
serverPort = buf.readInt();
playerUUID = buf.readUUID();
codec = Codec.values()[buf.readByte()];
mtuSize = buf.readInt();
voiceChatDistance = buf.readDouble();
keepAlive = buf.readInt();
groupsEnabled = buf.readBoolean();
voiceHost = buf.readUtf();
allowRecording = buf.readBoolean();
return this;
}
@Override
public void toBytes (FriendlyByteBuf buf) {
buf.writeUUID(secret);
buf.writeInt(serverPort);
buf.writeUUID(playerUUID);
buf.writeByte(codec.ordinal());
buf.writeInt(mtuSize);
buf.writeDouble(voiceChatDistance);
buf.writeInt(keepAlive);
buf.writeBoolean(groupsEnabled);
buf.writeUtf(voiceHost);
buf.writeBoolean(allowRecording);
}
}