diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java index ec84c5b..dc5fe7a 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/handler/client/LocalClientHandlerConnecting.java @@ -355,7 +355,8 @@ public class LocalClientHandlerConnecting extends LocalClientHandler { ) ); - Ts3Debugging.debug(clientinit.build()); + getClient().addMyTeamSpeakParameters(clientinit); + Ts3Debugging.debug("Sending clientinit"); getClient().writePacket(new PacketBody2Command(ProtocolRole.CLIENT, clientinit)); } diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java index c2a8a3f..9a695f9 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/packet/transformation/PacketTransformation.java @@ -32,6 +32,12 @@ public class PacketTransformation { return fakeMac; } + /** Connection binding used by myTeamSpeak, in the AES-128/SHA-256 protocol mode. */ + public byte[] getMyTeamSpeakChallenge() { + return Ts3Crypt.hash256(ByteBuffer.allocate(6 + ivStruct.length) + .put(new byte[] {0x30, 8, 0, 0, 0, 0}).put(ivStruct).array()); + } + public Pair computeParameters(PacketHeader header) { ByteBuffer temporaryByteBuffer = ByteBuffer .allocate(ivStruct.length == 20 ? 26 : 70) diff --git a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java index 68ff69d..05846fd 100644 --- a/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java +++ b/src/main/java/com/github/manevolent/ts3j/protocol/socket/client/AbstractTeamspeakClientSocket.java @@ -3,6 +3,7 @@ package com.github.manevolent.ts3j.protocol.socket.client; import com.github.manevolent.ts3j.command.CommandException; import com.github.manevolent.ts3j.command.*; +import com.github.manevolent.ts3j.command.parameter.CommandSingleParameter; import com.github.manevolent.ts3j.identity.Identity; import com.github.manevolent.ts3j.protocol.NetworkPacket; import com.github.manevolent.ts3j.protocol.Packet; @@ -36,6 +37,7 @@ import java.nio.*; import java.util.*; import java.util.concurrent.*; import java.util.function.Consumer; +import java.util.function.Function; /** * Server/client common abstract client socket, used to interact with the UDP connection. Provides most of the protocol @@ -165,6 +167,21 @@ public abstract class AbstractTeamspeakClientSocket setTransformation(new PacketTransformation(parameters.getIvStruct(), parameters.getFakeSignature())); } + private volatile Function> myTeamSpeakAuthenticator; + + /** Set before connecting; invoked after the handshake with this connection's challenge. */ + public void setMyTeamSpeakAuthenticator(Function> authenticator) { + myTeamSpeakAuthenticator = authenticator; + } + + public void addMyTeamSpeakParameters(Command command) { + Function> authenticator = myTeamSpeakAuthenticator; + if (authenticator == null) return; + Map parameters = authenticator.apply(transformation.getMyTeamSpeakChallenge()); + for (Map.Entry entry : parameters.entrySet()) + command.add(new CommandSingleParameter(entry.getKey(), entry.getValue())); + } + protected abstract NetworkPacket readNetworkPacket(int timeout) throws IOException; protected abstract void writeNetworkPacket(NetworkPacket packet) throws IOException;