first commit
Build AsminVoicechat / prepare-release (push) Successful in 14s
Build AsminVoicechat / build-and-test (17) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (18) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (19) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (20) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (21) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (22) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (23) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (24) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (25) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (26) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (27-ea) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (16) (push) Canceled after 38s
Build AsminVoicechat / prepare-release (push) Successful in 14s
Build AsminVoicechat / build-and-test (17) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (18) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (19) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (20) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (21) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (22) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (23) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (24) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (25) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (26) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (27-ea) (push) Canceled after 0s
Build AsminVoicechat / build-and-test (16) (push) Canceled after 38s
This commit is contained in:
commit
bbccd4a815
454 files changed
+45050
No files matched your search
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
public class AudioUtils {
|
||||
public static final int MAX_OPUS_PAYLOAD_SIZE = 1275;
|
||||
|
||||
public static short[] bytesToShorts(byte[] bytes) {
|
||||
if (bytes.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("Input bytes need to be divisible by 2");
|
||||
}
|
||||
ShortBuffer sb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
short[] out = new short[sb.remaining()];
|
||||
sb.get(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
public static byte[] shortsToBytes(short[] shorts) {
|
||||
ByteBuffer bb = ByteBuffer.allocate(shorts.length * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||
for (short s : shorts) {
|
||||
bb.putShort(s);
|
||||
}
|
||||
return bb.array();
|
||||
}
|
||||
|
||||
public static short[] floatsToShorts(float[] floats) {
|
||||
short[] shorts = new short[floats.length];
|
||||
for (int i = 0; i < floats.length; ++i) {
|
||||
shorts[i] = Float.valueOf(floats[i]).shortValue();
|
||||
}
|
||||
return shorts;
|
||||
}
|
||||
|
||||
public static float[] shortsToFloats(short[] shorts) {
|
||||
float[] floats = new float[shorts.length];
|
||||
for (int i = 0; i < shorts.length; ++i) {
|
||||
floats[i] = Short.valueOf(shorts[i]).floatValue();
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
public static byte[] floatsToBytes(float[] floats) {
|
||||
byte[] bytes = new byte[floats.length * 2];
|
||||
for (int i = 0; i < floats.length; ++i) {
|
||||
short x = Float.valueOf(floats[i]).shortValue();
|
||||
bytes[i * 2] = (byte)(x & 0xFF);
|
||||
bytes[i * 2 + 1] = (byte)((x & 0xFF00) >> 8);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static float[] bytesToFloats(byte[] bytes) {
|
||||
float[] floats = new float[bytes.length / 2];
|
||||
for (int i = 0; i < bytes.length / 2; ++i) {
|
||||
floats[i] = (bytes[i * 2 + 1] & 0x80) != 0 ? (float)(Short.MIN_VALUE + ((bytes[i * 2 + 1] & 0x7F) << 8) | bytes[i * 2] & 0xFF) : (float)(bytes[i * 2 + 1] << 8 & 0xFF00 | bytes[i * 2] & 0xFF);
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
|
||||
public class AuthenticateAckPacket
|
||||
implements Packet<AuthenticateAckPacket> {
|
||||
@Override
|
||||
public AuthenticateAckPacket fromBytes(FriendlyByteBuf buf) {
|
||||
return new AuthenticateAckPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
import de.maxhenkel.voicechat.voice.common.Secret;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthenticatePacket
|
||||
implements Packet<AuthenticatePacket> {
|
||||
private UUID playerUUID;
|
||||
private Secret secret;
|
||||
|
||||
public AuthenticatePacket(UUID playerUUID, Secret secret) {
|
||||
this.playerUUID = playerUUID;
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public AuthenticatePacket() {
|
||||
}
|
||||
|
||||
public UUID getPlayerUUID() {
|
||||
return this.playerUUID;
|
||||
}
|
||||
|
||||
public Secret getSecret() {
|
||||
return this.secret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticatePacket fromBytes(FriendlyByteBuf buf) {
|
||||
AuthenticatePacket packet = new AuthenticatePacket();
|
||||
packet.playerUUID = buf.readUUID();
|
||||
packet.secret = Secret.fromBytes(buf);
|
||||
return packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.playerUUID);
|
||||
this.secret.toBytes(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.api.Group;
|
||||
import de.maxhenkel.voicechat.plugins.impl.GroupImpl;
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ClientGroup {
|
||||
private final UUID id;
|
||||
private final String name;
|
||||
private final boolean hasPassword;
|
||||
private final boolean persistent;
|
||||
private final boolean hidden;
|
||||
private final Group.Type type;
|
||||
|
||||
public ClientGroup(UUID id, String name, boolean hasPassword, boolean persistent, boolean hidden, Group.Type type) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.hasPassword = hasPassword;
|
||||
this.persistent = persistent;
|
||||
this.hidden = hidden;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public boolean hasPassword() {
|
||||
return this.hasPassword;
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return this.persistent;
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return this.hidden;
|
||||
}
|
||||
|
||||
public Group.Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public static ClientGroup fromBytes(FriendlyByteBuf buf) {
|
||||
return new ClientGroup(buf.readUUID(), buf.readUtf(512), buf.readBoolean(), buf.readBoolean(), buf.readBoolean(), GroupImpl.TypeImpl.fromInt(buf.readShort()));
|
||||
}
|
||||
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.id);
|
||||
buf.writeUtf(this.name, 512);
|
||||
buf.writeBoolean(this.hasPassword);
|
||||
buf.writeBoolean(this.persistent);
|
||||
buf.writeBoolean(this.hidden);
|
||||
buf.writeShort(GroupImpl.TypeImpl.toInt(this.type));
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || this.getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ClientGroup group = (ClientGroup)o;
|
||||
return Objects.equals(this.id, group.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
|
||||
public class ConnectionCheckAckPacket
|
||||
implements Packet<ConnectionCheckAckPacket> {
|
||||
@Override
|
||||
public ConnectionCheckAckPacket fromBytes(FriendlyByteBuf buf) {
|
||||
return new ConnectionCheckAckPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
|
||||
public class ConnectionCheckPacket
|
||||
implements Packet<ConnectionCheckPacket> {
|
||||
@Override
|
||||
public ConnectionCheckPacket fromBytes(FriendlyByteBuf buf) {
|
||||
return new ConnectionCheckPacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.annotation.Nullable
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.SoundPacket;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class GroupSoundPacket
|
||||
extends SoundPacket<GroupSoundPacket> {
|
||||
public GroupSoundPacket(UUID channelId, UUID sender, byte[] data, long sequenceNumber, @Nullable String category) {
|
||||
super(channelId, sender, data, sequenceNumber, category);
|
||||
}
|
||||
|
||||
public GroupSoundPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupSoundPacket fromBytes(FriendlyByteBuf buf) {
|
||||
GroupSoundPacket soundPacket = new GroupSoundPacket();
|
||||
soundPacket.channelId = buf.readUUID();
|
||||
soundPacket.sender = buf.readUUID();
|
||||
soundPacket.data = buf.readByteArray(1275);
|
||||
soundPacket.sequenceNumber = buf.readLong();
|
||||
byte data = buf.readByte();
|
||||
if (this.hasFlag(data, (byte)2)) {
|
||||
soundPacket.category = buf.readUtf(16);
|
||||
}
|
||||
return soundPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.channelId);
|
||||
buf.writeUUID(this.sender);
|
||||
buf.writeByteArray(this.data);
|
||||
buf.writeLong(this.sequenceNumber);
|
||||
byte data = 0;
|
||||
if (this.category != null) {
|
||||
data = this.setFlag(data, (byte)2);
|
||||
}
|
||||
buf.writeByte(data);
|
||||
if (this.category != null) {
|
||||
buf.writeUtf(this.category, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
|
||||
public class KeepAlivePacket
|
||||
implements Packet<KeepAlivePacket> {
|
||||
@Override
|
||||
public KeepAlivePacket fromBytes(FriendlyByteBuf buf) {
|
||||
return new KeepAlivePacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.annotation.Nullable
|
||||
* org.bukkit.Location
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.SoundPacket;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class LocationSoundPacket
|
||||
extends SoundPacket<LocationSoundPacket> {
|
||||
protected Location location;
|
||||
protected float distance;
|
||||
|
||||
public LocationSoundPacket(UUID channelId, UUID sender, Location location, byte[] data, long sequenceNumber, float distance, @Nullable String category) {
|
||||
super(channelId, sender, data, sequenceNumber, category);
|
||||
this.location = location;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public LocationSoundPacket() {
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
public float getDistance() {
|
||||
return this.distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationSoundPacket fromBytes(FriendlyByteBuf buf) {
|
||||
LocationSoundPacket soundPacket = new LocationSoundPacket();
|
||||
soundPacket.channelId = buf.readUUID();
|
||||
soundPacket.sender = buf.readUUID();
|
||||
soundPacket.location = new Location(null, buf.readDouble(), buf.readDouble(), buf.readDouble());
|
||||
soundPacket.data = buf.readByteArray(1275);
|
||||
soundPacket.sequenceNumber = buf.readLong();
|
||||
soundPacket.distance = buf.readFloat();
|
||||
byte data = buf.readByte();
|
||||
if (this.hasFlag(data, (byte)2)) {
|
||||
soundPacket.category = buf.readUtf(16);
|
||||
}
|
||||
return soundPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.channelId);
|
||||
buf.writeUUID(this.sender);
|
||||
buf.writeDouble(this.location.getX());
|
||||
buf.writeDouble(this.location.getY());
|
||||
buf.writeDouble(this.location.getZ());
|
||||
buf.writeByteArray(this.data);
|
||||
buf.writeLong(this.sequenceNumber);
|
||||
buf.writeFloat(this.distance);
|
||||
byte data = 0;
|
||||
if (this.category != null) {
|
||||
data = this.setFlag(data, (byte)2);
|
||||
}
|
||||
buf.writeByte(data);
|
||||
if (this.category != null) {
|
||||
buf.writeUtf(this.category, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
|
||||
public class MicPacket
|
||||
implements Packet<MicPacket> {
|
||||
private byte[] data;
|
||||
private boolean whispering;
|
||||
private long sequenceNumber;
|
||||
|
||||
public MicPacket(byte[] data, boolean whispering, long sequenceNumber) {
|
||||
this.data = data;
|
||||
this.whispering = whispering;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
}
|
||||
|
||||
public MicPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTTL() {
|
||||
return 500L;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public long getSequenceNumber() {
|
||||
return this.sequenceNumber;
|
||||
}
|
||||
|
||||
public boolean isWhispering() {
|
||||
return this.whispering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MicPacket fromBytes(FriendlyByteBuf buf) {
|
||||
MicPacket soundPacket = new MicPacket();
|
||||
soundPacket.data = buf.readByteArray(1275);
|
||||
soundPacket.sequenceNumber = buf.readLong();
|
||||
soundPacket.whispering = buf.readBoolean();
|
||||
return soundPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeByteArray(this.data);
|
||||
buf.writeLong(this.sequenceNumber);
|
||||
buf.writeBoolean(this.whispering);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* io.netty.buffer.Unpooled
|
||||
* io.netty.handler.codec.DecoderException
|
||||
* javax.annotation.Nonnull
|
||||
* javax.annotation.Nullable
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.Voicechat;
|
||||
import de.maxhenkel.voicechat.api.RawUdpPacket;
|
||||
import de.maxhenkel.voicechat.debug.PingHandler;
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.AuthenticateAckPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.AuthenticatePacket;
|
||||
import de.maxhenkel.voicechat.voice.common.ConnectionCheckAckPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.ConnectionCheckPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.GroupSoundPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.KeepAlivePacket;
|
||||
import de.maxhenkel.voicechat.voice.common.LocationSoundPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.MicPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
import de.maxhenkel.voicechat.voice.common.PingPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.PlayerSoundPacket;
|
||||
import de.maxhenkel.voicechat.voice.common.Secret;
|
||||
import de.maxhenkel.voicechat.voice.server.ClientConnection;
|
||||
import de.maxhenkel.voicechat.voice.server.Server;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
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;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
public class NetworkMessage {
|
||||
public static final byte MAGIC_BYTE = -1;
|
||||
private final long timestamp;
|
||||
private Packet<? extends Packet> packet;
|
||||
private SocketAddress address;
|
||||
private static final Map<Byte, Class<? extends Packet>> packetRegistry = new HashMap<Byte, Class<? extends Packet>>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Packet<? extends Packet> getPacket() {
|
||||
return this.packet;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public long getTTL() {
|
||||
return this.packet.getTTL();
|
||||
}
|
||||
|
||||
public SocketAddress getAddress() {
|
||||
return this.address;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static NetworkMessage readPacketServer(RawUdpPacket packet, Server server) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
|
||||
try {
|
||||
byte[] data = packet.getData();
|
||||
FriendlyByteBuf b = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])data));
|
||||
if (b.readByte() != -1) {
|
||||
Voicechat.LOGGER.debug("Received invalid packet from {}", packet.getSocketAddress());
|
||||
return null;
|
||||
}
|
||||
UUID playerID = b.readUUID();
|
||||
if (!server.hasSecret(playerID)) {
|
||||
if (PingHandler.onPacket(server, packet.getSocketAddress(), playerID, b)) {
|
||||
return null;
|
||||
}
|
||||
Voicechat.LOGGER.debug("Player {} does not have a secret", playerID);
|
||||
return null;
|
||||
}
|
||||
return NetworkMessage.readFromBytes(packet.getSocketAddress(), server.getSecret(playerID), b.readByteArray(2048), packet.getTimestamp());
|
||||
}
|
||||
catch (DecoderException | IndexOutOfBoundsException e) {
|
||||
Voicechat.LOGGER.debug("Received invalid packet from {}", packet.getSocketAddress());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NetworkMessage readFromBytes(SocketAddress socketAddress, Secret secret, byte[] encryptedPayload, long timestamp) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
||||
byte[] decrypt;
|
||||
try {
|
||||
decrypt = secret.decrypt(encryptedPayload);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Voicechat.LOGGER.debug("Failed to decrypt packet from {}", socketAddress);
|
||||
return null;
|
||||
}
|
||||
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.wrappedBuffer((byte[])decrypt));
|
||||
byte packetType = buffer.readByte();
|
||||
Class<? extends Packet> packetClass = packetRegistry.get(packetType);
|
||||
if (packetClass == null) {
|
||||
Voicechat.LOGGER.debug("Got invalid packet ID {}", packetType);
|
||||
return null;
|
||||
}
|
||||
Packet p = packetClass.getDeclaredConstructor(new Class[0]).newInstance(new Object[0]);
|
||||
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())) continue;
|
||||
return entry.getKey();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public byte[] writeServer(Server server, ClientConnection connection) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
||||
byte[] payload = this.write(server.getSecret(connection.getPlayerUUID()));
|
||||
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer((int)(1 + payload.length)));
|
||||
buffer.writeByte(-1);
|
||||
buffer.writeByteArray(payload);
|
||||
byte[] bytes = new byte[buffer.readableBytes()];
|
||||
buffer.readBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public byte[] write(Secret secret) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
|
||||
FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
byte type = NetworkMessage.getPacketType(this.packet);
|
||||
if (type < 0) {
|
||||
throw new IllegalArgumentException("Packet type not found");
|
||||
}
|
||||
buffer.writeByte(type);
|
||||
this.packet.toBytes(buffer);
|
||||
return secret.encrypt(buffer.array());
|
||||
}
|
||||
|
||||
static {
|
||||
packetRegistry.put((byte)1, MicPacket.class);
|
||||
packetRegistry.put((byte)2, PlayerSoundPacket.class);
|
||||
packetRegistry.put((byte)3, GroupSoundPacket.class);
|
||||
packetRegistry.put((byte)4, LocationSoundPacket.class);
|
||||
packetRegistry.put((byte)5, AuthenticatePacket.class);
|
||||
packetRegistry.put((byte)6, AuthenticateAckPacket.class);
|
||||
packetRegistry.put((byte)7, PingPacket.class);
|
||||
packetRegistry.put((byte)8, KeepAlivePacket.class);
|
||||
packetRegistry.put((byte)9, ConnectionCheckPacket.class);
|
||||
packetRegistry.put((byte)10, ConnectionCheckAckPacket.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
|
||||
public interface Packet<T extends Packet> {
|
||||
public T fromBytes(FriendlyByteBuf var1);
|
||||
|
||||
public void toBytes(FriendlyByteBuf var1);
|
||||
|
||||
default public long getTTL() {
|
||||
return 10000L;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PingPacket
|
||||
implements Packet<PingPacket> {
|
||||
private UUID id;
|
||||
private long timestamp;
|
||||
|
||||
public PingPacket(UUID id, long timestamp) {
|
||||
this.id = id;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public PingPacket() {
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PingPacket fromBytes(FriendlyByteBuf buf) {
|
||||
PingPacket soundPacket = new PingPacket();
|
||||
soundPacket.id = buf.readUUID();
|
||||
soundPacket.timestamp = buf.readLong();
|
||||
return soundPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.id);
|
||||
buf.writeLong(this.timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.annotation.Nullable
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import de.maxhenkel.voicechat.voice.common.SoundPacket;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlayerSoundPacket
|
||||
extends SoundPacket<PlayerSoundPacket> {
|
||||
protected boolean whispering;
|
||||
protected float distance;
|
||||
|
||||
public PlayerSoundPacket(UUID channelId, UUID sender, byte[] data, long sequenceNumber, boolean whispering, float distance, @Nullable String category) {
|
||||
super(channelId, sender, data, sequenceNumber, category);
|
||||
this.whispering = whispering;
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
public PlayerSoundPacket() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getSender() {
|
||||
return this.sender;
|
||||
}
|
||||
|
||||
public boolean isWhispering() {
|
||||
return this.whispering;
|
||||
}
|
||||
|
||||
public float getDistance() {
|
||||
return this.distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerSoundPacket fromBytes(FriendlyByteBuf buf) {
|
||||
PlayerSoundPacket soundPacket = new PlayerSoundPacket();
|
||||
soundPacket.channelId = buf.readUUID();
|
||||
soundPacket.sender = buf.readUUID();
|
||||
soundPacket.data = buf.readByteArray(1275);
|
||||
soundPacket.sequenceNumber = buf.readLong();
|
||||
soundPacket.distance = buf.readFloat();
|
||||
byte data = buf.readByte();
|
||||
soundPacket.whispering = this.hasFlag(data, (byte)1);
|
||||
if (this.hasFlag(data, (byte)2)) {
|
||||
soundPacket.category = buf.readUtf(16);
|
||||
}
|
||||
return soundPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.channelId);
|
||||
buf.writeUUID(this.sender);
|
||||
buf.writeByteArray(this.data);
|
||||
buf.writeLong(this.sequenceNumber);
|
||||
buf.writeFloat(this.distance);
|
||||
byte data = 0;
|
||||
if (this.whispering) {
|
||||
data = this.setFlag(data, (byte)1);
|
||||
}
|
||||
if (this.category != null) {
|
||||
data = this.setFlag(data, (byte)2);
|
||||
}
|
||||
buf.writeByte(data);
|
||||
if (this.category != null) {
|
||||
buf.writeUtf(this.category, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.annotation.Nullable
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.util.FriendlyByteBuf;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PlayerState {
|
||||
private UUID uuid;
|
||||
private String name;
|
||||
private boolean disabled;
|
||||
private boolean disconnected;
|
||||
@Nullable
|
||||
private UUID group;
|
||||
|
||||
public PlayerState(UUID uuid, String name, boolean disabled, boolean disconnected) {
|
||||
this.uuid = uuid;
|
||||
this.name = name;
|
||||
this.disabled = disabled;
|
||||
this.disconnected = disconnected;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return this.uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isDisabled() {
|
||||
return this.disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isDisconnected() {
|
||||
return this.disconnected;
|
||||
}
|
||||
|
||||
public void setDisconnected(boolean disconnected) {
|
||||
this.disconnected = disconnected;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UUID getGroup() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
public void setGroup(@Nullable UUID group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
public boolean hasGroup() {
|
||||
return this.group != null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "{disabled=" + this.disabled + ", disconnected=" + this.disconnected + ", uuid=" + this.uuid + ", name=" + this.name + ", group=" + this.group + '}';
|
||||
}
|
||||
|
||||
public static PlayerState fromBytes(FriendlyByteBuf buf) {
|
||||
boolean disabled = buf.readBoolean();
|
||||
boolean disconnected = buf.readBoolean();
|
||||
UUID uuid = buf.readUUID();
|
||||
String name = buf.readUtf(Short.MAX_VALUE);
|
||||
PlayerState state = new PlayerState(uuid, name, disabled, disconnected);
|
||||
if (buf.readBoolean()) {
|
||||
state.setGroup(buf.readUUID());
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
public void toBytes(FriendlyByteBuf buf) {
|
||||
buf.writeBoolean(this.disabled);
|
||||
buf.writeBoolean(this.disconnected);
|
||||
buf.writeUUID(this.uuid);
|
||||
buf.writeUtf(this.name);
|
||||
buf.writeBoolean(this.hasGroup());
|
||||
if (this.hasGroup()) {
|
||||
buf.writeUUID(this.group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* io.netty.buffer.ByteBuf
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class Secret {
|
||||
public static final int SECRET_SIZE_BYTES = 16;
|
||||
public static final int IV_SIZE_BYTES = 12;
|
||||
public static final int TAG_LEN_BITS = 128;
|
||||
public static final String CIPHER = "AES/GCM/NoPadding";
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
private final byte[] secret;
|
||||
private final SecretKeySpec keySpec;
|
||||
private volatile boolean legacyProtocol;
|
||||
|
||||
protected Secret(byte[] byArray) {
|
||||
if (byArray == null || byArray.length != 16) {
|
||||
throw new IllegalArgumentException("Voice chat secret must contain exactly 16 bytes");
|
||||
}
|
||||
this.secret = (byte[])byArray.clone();
|
||||
this.keySpec = new SecretKeySpec(this.secret, "AES");
|
||||
}
|
||||
|
||||
public static Secret generateNewRandomSecret() {
|
||||
byte[] byArray = new byte[16];
|
||||
RANDOM.nextBytes(byArray);
|
||||
return new Secret(byArray);
|
||||
}
|
||||
|
||||
public static Secret fromBytes(byte[] byArray) {
|
||||
return new Secret(byArray);
|
||||
}
|
||||
|
||||
public static Secret fromBytes(ByteBuf byteBuf) {
|
||||
byte[] byArray = new byte[16];
|
||||
byteBuf.readBytes(byArray);
|
||||
return Secret.fromBytes(byArray);
|
||||
}
|
||||
|
||||
public void toBytes(ByteBuf byteBuf) {
|
||||
byteBuf.writeBytes(this.secret);
|
||||
}
|
||||
|
||||
public byte[] getSecret() {
|
||||
return (byte[])this.secret.clone();
|
||||
}
|
||||
|
||||
public SecretKeySpec getKeySpec() {
|
||||
return this.keySpec;
|
||||
}
|
||||
|
||||
public void setLegacyProtocol(boolean bl) {
|
||||
this.legacyProtocol = bl;
|
||||
}
|
||||
|
||||
public boolean isLegacyProtocol() {
|
||||
return this.legacyProtocol;
|
||||
}
|
||||
|
||||
public static byte[] generateIV() {
|
||||
byte[] byArray = new byte[12];
|
||||
RANDOM.nextBytes(byArray);
|
||||
return byArray;
|
||||
}
|
||||
|
||||
private static byte[] generateLegacyIV() {
|
||||
byte[] byArray = new byte[16];
|
||||
RANDOM.nextBytes(byArray);
|
||||
return byArray;
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] byArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||
if (this.legacyProtocol) {
|
||||
byte[] byArray2 = Secret.generateLegacyIV();
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(1, (Key)this.keySpec, new IvParameterSpec(byArray2));
|
||||
byte[] byArray3 = cipher.doFinal(byArray);
|
||||
byte[] byArray4 = new byte[byArray2.length + byArray3.length];
|
||||
System.arraycopy(byArray2, 0, byArray4, 0, byArray2.length);
|
||||
System.arraycopy(byArray3, 0, byArray4, byArray2.length, byArray3.length);
|
||||
return byArray4;
|
||||
}
|
||||
byte[] byArray5 = Secret.generateIV();
|
||||
Cipher cipher = Cipher.getInstance(CIPHER);
|
||||
cipher.init(1, (Key)this.keySpec, new GCMParameterSpec(128, byArray5));
|
||||
byte[] byArray6 = cipher.doFinal(byArray);
|
||||
byte[] byArray7 = new byte[byArray5.length + byArray6.length];
|
||||
System.arraycopy(byArray5, 0, byArray7, 0, byArray5.length);
|
||||
System.arraycopy(byArray6, 0, byArray7, byArray5.length, byArray6.length);
|
||||
return byArray7;
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] byArray) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||
if (this.legacyProtocol) {
|
||||
if (byArray.length < 32 || (byArray.length - 16) % 16 != 0) {
|
||||
throw new IllegalBlockSizeException("Invalid legacy AES-CBC packet size");
|
||||
}
|
||||
byte[] byArray2 = Arrays.copyOfRange(byArray, 0, 16);
|
||||
byte[] byArray3 = Arrays.copyOfRange(byArray, 16, byArray.length);
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
cipher.init(2, (Key)this.keySpec, new IvParameterSpec(byArray2));
|
||||
return cipher.doFinal(byArray3);
|
||||
}
|
||||
if (byArray.length < 28) {
|
||||
throw new IllegalBlockSizeException("Invalid AES-GCM packet size");
|
||||
}
|
||||
byte[] byArray4 = Arrays.copyOfRange(byArray, 0, 12);
|
||||
byte[] byArray5 = Arrays.copyOfRange(byArray, 12, byArray.length);
|
||||
Cipher cipher = Cipher.getInstance(CIPHER);
|
||||
cipher.init(2, (Key)this.keySpec, new GCMParameterSpec(128, byArray4));
|
||||
return cipher.doFinal(byArray5);
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
return object instanceof Secret && Arrays.equals(this.secret, ((Secret)object).secret);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.secret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.annotation.Nullable
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.voice.common.Packet;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class SoundPacket<T extends SoundPacket>
|
||||
implements Packet<T> {
|
||||
public static final byte WHISPER_MASK = 1;
|
||||
public static final byte HAS_CATEGORY_MASK = 2;
|
||||
protected UUID channelId;
|
||||
protected UUID sender;
|
||||
protected byte[] data;
|
||||
protected long sequenceNumber;
|
||||
@Nullable
|
||||
protected String category;
|
||||
|
||||
public SoundPacket(UUID channelId, UUID sender, byte[] data, long sequenceNumber, @Nullable String category) {
|
||||
this.channelId = channelId;
|
||||
this.sender = sender;
|
||||
this.data = data;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public SoundPacket() {
|
||||
}
|
||||
|
||||
public UUID getChannelId() {
|
||||
return this.channelId;
|
||||
}
|
||||
|
||||
public UUID getSender() {
|
||||
return this.sender;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public long getSequenceNumber() {
|
||||
return this.sequenceNumber;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
protected boolean hasFlag(byte data, byte mask) {
|
||||
return (data & mask) != 0;
|
||||
}
|
||||
|
||||
protected byte setFlag(byte data, byte mask) {
|
||||
return (byte)(data | mask);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package de.maxhenkel.voicechat.voice.common;
|
||||
|
||||
import de.maxhenkel.voicechat.Voicechat;
|
||||
|
||||
public class Utils {
|
||||
public static final int MAX_VOICE_CHAT_PACKET_SIZE = 2048;
|
||||
|
||||
public static float getDefaultDistance() {
|
||||
return Voicechat.SERVER_CONFIG.voiceChatDistance.get().floatValue();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user