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[] alpha = Base64.getDecoder().decode(command.get("alpha").getValue()); // alpha
|
||||||
byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
|
byte[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
|
||||||
byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega
|
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()));
|
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[] beta = Base64.getDecoder().decode(command.get("beta").getValue()); // beta
|
||||||
byte[] omega = Base64.getDecoder().decode(command.get("omega").getValue()); // omega
|
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());
|
byte[] proof = Base64.getDecoder().decode(command.get("proof").getValue());
|
||||||
|
|
||||||
Pair<byte[], byte[]> keyPair = Ts3Crypt.generateKeypair();
|
Pair<byte[], byte[]> keyPair = Ts3Crypt.generateKeypair();
|
||||||
|
|||||||
+27
@@ -32,6 +32,9 @@ import java.io.IOException;
|
|||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -59,6 +62,9 @@ public class LocalTeamspeakClientSocket
|
|||||||
/** The virtual server's properties as announced by <b>initserver</b>. */
|
/** The virtual server's properties as announced by <b>initserver</b>. */
|
||||||
private volatile Map<String, String> serverProperties = Collections.emptyMap();
|
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
|
* The internal command buffer
|
||||||
* <p>
|
* <p>
|
||||||
@@ -325,6 +331,7 @@ public class LocalTeamspeakClientSocket
|
|||||||
|
|
||||||
serverId = null;
|
serverId = null;
|
||||||
serverProperties = Collections.emptyMap();
|
serverProperties = Collections.emptyMap();
|
||||||
|
serverPublicKey = null;
|
||||||
|
|
||||||
remote = null;
|
remote = null;
|
||||||
}
|
}
|
||||||
@@ -399,6 +406,7 @@ public class LocalTeamspeakClientSocket
|
|||||||
// Free stuff
|
// Free stuff
|
||||||
serverId = null;
|
serverId = null;
|
||||||
serverProperties = Collections.emptyMap();
|
serverProperties = Collections.emptyMap();
|
||||||
|
serverPublicKey = null;
|
||||||
|
|
||||||
|
|
||||||
synchronized (commandSendLock) {
|
synchronized (commandSendLock) {
|
||||||
@@ -840,6 +848,25 @@ public class LocalTeamspeakClientSocket
|
|||||||
return serverProperties;
|
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. */
|
/** The virtual server's name, or null if it was not announced. */
|
||||||
public String getServerName() {
|
public String getServerName() {
|
||||||
return serverProperties.get("virtualserver_name");
|
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