Derive the server's unique id from its handshake key
TS3 derives a virtual server's unique identifier from its public key the same way as a client's: base64(SHA-1(key)). The server never tells a guest otherwise, as serverinfo is refused and neither initserver nor notifyserverupdated carries it. The socket now keeps the key from initivexpand(2) and offers getServerUid(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+2
@@ -204,6 +204,7 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
|
||||
byte[] alpha = Base64.getDecoder().decode(command.get("alpha").getValue()); // alpha
|
||||
byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
|
||||
byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega
|
||||
getClient().setServerPublicKey(command.get("omega").getValue());
|
||||
|
||||
getClient().setSecureParameters(Ts3Crypt.cryptoInit(alpha, beta, omega, getClient().getIdentity()));
|
||||
|
||||
@@ -224,6 +225,7 @@ public class LocalClientHandlerConnecting extends LocalClientHandler {
|
||||
|
||||
byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
|
||||
byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega
|
||||
getClient().setServerPublicKey(command.get("omega").getValue());
|
||||
byte[] proof = Base64.getDecoder().decode(command.get("proof").getValue());
|
||||
|
||||
Pair<byte[], byte[]> keyPair = Ts3Crypt.generateKeypair();
|
||||
|
||||
+27
@@ -32,6 +32,9 @@ import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Function;
|
||||
@@ -59,6 +62,9 @@ public class LocalTeamspeakClientSocket
|
||||
/** The virtual server's properties as announced by <b>initserver</b>. */
|
||||
private volatile Map<String, String> serverProperties = Collections.emptyMap();
|
||||
|
||||
/** The public key the server identified itself with in the handshake, base64 as sent. */
|
||||
private volatile String serverPublicKey;
|
||||
|
||||
/**
|
||||
* The internal command buffer
|
||||
* <p>
|
||||
@@ -325,6 +331,7 @@ public class LocalTeamspeakClientSocket
|
||||
|
||||
serverId = null;
|
||||
serverProperties = Collections.emptyMap();
|
||||
serverPublicKey = null;
|
||||
|
||||
remote = null;
|
||||
}
|
||||
@@ -399,6 +406,7 @@ public class LocalTeamspeakClientSocket
|
||||
// Free stuff
|
||||
serverId = null;
|
||||
serverProperties = Collections.emptyMap();
|
||||
serverPublicKey = null;
|
||||
|
||||
|
||||
synchronized (commandSendLock) {
|
||||
@@ -840,6 +848,25 @@ public class LocalTeamspeakClientSocket
|
||||
return serverProperties;
|
||||
}
|
||||
|
||||
public void setServerPublicKey(String serverPublicKey) {
|
||||
this.serverPublicKey = serverPublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* The virtual server's unique identifier, or null before the handshake. It is derived from
|
||||
* the server's public key as a client's is from its own; the server tells a client no other
|
||||
* way, as guests may not read it with <b>serverinfo</b>.
|
||||
*/
|
||||
public Uid getServerUid() {
|
||||
String key = serverPublicKey;
|
||||
if (key == null) return null;
|
||||
try {
|
||||
return new Uid(MessageDigest.getInstance("SHA-1").digest(key.getBytes(StandardCharsets.US_ASCII)));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** The virtual server's name, or null if it was not announced. */
|
||||
public String getServerName() {
|
||||
return serverProperties.get("virtualserver_name");
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.github.manevolent.ts3j;
|
||||
|
||||
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ServerUidTest extends TestCase {
|
||||
/** A real server's handshake key, and the unique id the official client files its chat logs under. */
|
||||
public void testDerivedFromTheHandshakeKey() {
|
||||
LocalTeamspeakClientSocket client = new LocalTeamspeakClientSocket();
|
||||
assertNull(client.getServerUid());
|
||||
|
||||
client.setServerPublicKey("MEwDAgcAAgEgAiEAtg1UQ4UpfiyTjrYPQcWV7Pa04/HTWr/viRhqEOg7+MQCIH/FqUKJDpBJDn/v01KOR+snSWlcoxOsfb2R8C02T3/z");
|
||||
assertEquals("+Tyg2JtxE8vRNZp+JiUBnmBh0MY=", client.getServerUid().toBase64());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user