Fix two exceptions and fix channel password support

This commit is contained in:
Manevolent
2019-11-22 09:07:38 -07:00
parent 547947c95d
commit 92d97f96dc
8 changed files with 161 additions and 69 deletions
@@ -0,0 +1,51 @@
package com.github.manevolent.ts3j.event;
/*
* #%L
* TeamSpeak 3 Java API
* %%
* Copyright (C) 2014 Bert De Geyter
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import com.github.manevolent.ts3j.api.*;
import java.util.*;
public class ChannelPermHintsEvent extends BaseEvent {
public ChannelPermHintsEvent(Map<String, String> map) {
super(map);
}
public int getChannelId() {
return getInt(ChannelProperty.CID);
}
@Override
public void fire(TS3Listener listener) {
listener.onChannelPermHints(this);
}
public int getFlags() {
return getInt("flags");
}
}
@@ -0,0 +1,26 @@
package com.github.manevolent.ts3j.event;
import java.util.*;
public class ClientPermHintsEvent extends BaseEvent {
public ClientPermHintsEvent(Map<String, String> map) {
super(map);
}
@Override
public void fire(TS3Listener listener) {
listener.onClientPermHints(this);
}
public int getClientId() {
return getInt("clid");
}
public int getPermId() {
return getInt("permid");
}
public int getPermValue() {
return getInt("permvalue");
}
}
@@ -12,10 +12,10 @@ package com.github.manevolent.ts3j.event;
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,62 +29,66 @@ package com.github.manevolent.ts3j.event;
import com.github.manevolent.ts3j.command.Command; import com.github.manevolent.ts3j.command.Command;
public interface TS3Event { public interface TS3Event {
void fire(TS3Listener listener); void fire(TS3Listener listener);
static TS3Event createEvent(Command command) { static TS3Event createEvent(Command command) {
switch (command.getName()) { switch (command.getName()) {
case "notifytextmessage": case "notifytextmessage":
return new TextMessageEvent(command.toMap()); return new TextMessageEvent(command.toMap());
case "notifycliententerview": case "notifycliententerview":
return new ClientJoinEvent(command.toMap()); return new ClientJoinEvent(command.toMap());
case "notifyclientleftview": case "notifyclientleftview":
return new ClientLeaveEvent(command.toMap()); return new ClientLeaveEvent(command.toMap());
case "notifyserveredited": case "notifyserveredited":
return new ServerEditedEvent(command.toMap()); return new ServerEditedEvent(command.toMap());
case "notifychanneledited": case "notifychanneledited":
return new ChannelEditedEvent(command.toMap()); return new ChannelEditedEvent(command.toMap());
case "notifychanneldescriptionchanged": case "notifychanneldescriptionchanged":
return new ChannelDescriptionEditedEvent(command.toMap()); return new ChannelDescriptionEditedEvent(command.toMap());
case "notifyclientmoved": case "notifyclientmoved":
return new ClientMovedEvent(command.toMap()); return new ClientMovedEvent(command.toMap());
case "notifychannelcreated": case "notifychannelcreated":
return new ChannelCreateEvent(command.toMap()); return new ChannelCreateEvent(command.toMap());
case "notifychanneldeleted": case "notifychanneldeleted":
return new ChannelDeletedEvent(command.toMap()); return new ChannelDeletedEvent(command.toMap());
case "notifychannelmoved": case "notifychannelmoved":
return new ChannelMovedEvent(command.toMap()); return new ChannelMovedEvent(command.toMap());
case "notifychannelpasswordchanged": case "notifychannelpasswordchanged":
return new ChannelPasswordChangedEvent(command.toMap()); return new ChannelPasswordChangedEvent(command.toMap());
case "notifytokenused": case "notifytokenused":
return new PrivilegeKeyUsedEvent(command.toMap()); return new PrivilegeKeyUsedEvent(command.toMap());
case "notifyservergrouplist": // CLIENT case "notifyservergrouplist": // CLIENT
return new ServerGroupListEvent(command.toMap()); return new ServerGroupListEvent(command.toMap());
case "notifychannelgrouplist": // CLIENT case "notifychannelgrouplist": // CLIENT
return new ChannelGroupListEvent(command.toMap()); return new ChannelGroupListEvent(command.toMap());
case "notifyclientchannelgroupchanged": // CLIENT case "notifyclientchannelgroupchanged": // CLIENT
return new ClientChannelGroupChangedEvent(command.toMap()); return new ClientChannelGroupChangedEvent(command.toMap());
case "notifyclientneededpermissions": // CLIENT case "notifyclientneededpermissions": // CLIENT
return new ClientNeededPermissionsEvent(command.toMap()); return new ClientNeededPermissionsEvent(command.toMap());
case "notifyclientupdated": // CLIENT case "notifyclientupdated": // CLIENT
return new ClientUpdatedEvent(command.toMap()); return new ClientUpdatedEvent(command.toMap());
case "notifychannelsubscribed": // CLIENT case "notifychannelsubscribed": // CLIENT
return new ChannelSubscribedEvent(command.toMap()); return new ChannelSubscribedEvent(command.toMap());
case "notifychannelunsubscribed": // CLIENT case "notifychannelunsubscribed": // CLIENT
return new ChannelUnsubscribedEvent(command.toMap()); return new ChannelUnsubscribedEvent(command.toMap());
case "notifyservergroupclientadded": // CLIENT case "notifyservergroupclientadded": // CLIENT
return new ServerGroupClientAddedEvent(command.toMap()); return new ServerGroupClientAddedEvent(command.toMap());
case "notifyservergroupclientdeleted": // CLIENT case "notifyservergroupclientdeleted": // CLIENT
return new ServerGroupClientDeletedEvent(command.toMap()); return new ServerGroupClientDeletedEvent(command.toMap());
case "notifyclientpoke": // CLIENT case "notifyclientpoke": // CLIENT
return new ClientPokeEvent(command.toMap()); return new ClientPokeEvent(command.toMap());
case "notifyclientchatcomposing": // CLIENT case "notifyclientchatcomposing": // CLIENT
return new ClientChatComposingEvent(command.toMap()); return new ClientChatComposingEvent(command.toMap());
case "notifyclientchatclosed": // CLIENT case "notifyclientchatclosed": // CLIENT
return new ClientChatClosedEvent(command.toMap()); return new ClientChatClosedEvent(command.toMap());
case "notifypermissionlist": // CLIENT case "notifypermissionlist": // CLIENT
return new PermissionListEvent(command.toMap()); return new PermissionListEvent(command.toMap());
default: case "notifyclientpermhints": // CLIENT
throw new IllegalArgumentException("unknown event: " + command.getName()); return new ClientPermHintsEvent(command.toMap());
} case "notifychannelpermhints": // CLIENT
return new ChannelPermHintsEvent(command.toMap());
default:
throw new IllegalArgumentException("unknown event: " + command.getName());
} }
}
} }
@@ -55,4 +55,6 @@ public interface TS3Listener {
default void onPermissionList(PermissionListEvent e) {} default void onPermissionList(PermissionListEvent e) {}
default void onConnected(ConnectedEvent e) {} default void onConnected(ConnectedEvent e) {}
default void onClientChatClosed(ClientChatClosedEvent e) {} default void onClientChatClosed(ClientChatClosedEvent e) {}
default void onClientPermHints(ClientPermHintsEvent e) {}
default void onChannelPermHints(ChannelPermHintsEvent e) {}
} }
@@ -594,7 +594,6 @@ public abstract class AbstractTeamspeakClientSocket
packet.readBody(packetBuffer); packet.readBody(packetBuffer);
} }
PacketKind kind = networkPacket.getHeader().getType().getKind(); PacketKind kind = networkPacket.getHeader().getType().getKind();
if (kind != null) if (kind != null)
packetStatistics packetStatistics
@@ -615,8 +614,7 @@ public abstract class AbstractTeamspeakClientSocket
while (isReading()) { while (isReading()) {
// De-spool spooled-up packets // De-spool spooled-up packets
if (handlerBacklog.size() > 0) { if (handlerBacklog.size() > 0) {
Packet packet = handlerBacklog.remove(0); return handlerBacklog.remove(0);
return packet;
} }
try { try {
@@ -780,7 +778,8 @@ public abstract class AbstractTeamspeakClientSocket
Packet reassembled; Packet reassembled;
while ((reassembled = reassembly.next()) != null) { while ((reassembled = reassembly.next()) != null) {
Ts3Debugging.debug("[PROTOCOL] REASSEMBLE " + reassembled.getHeader().getType().name() + Ts3Debugging.debug("[PROTOCOL] REASSEMBLE " + reassembled.getHeader().getType().name() +
" id=" + reassembled.getHeader().getPacketId() + " len=" + reassembled.getSize()); " id=" + reassembled.getHeader().getPacketId() + " len=" + reassembled.getSize() +
" bodyType=" + reassembled.getBody().getClass().getSimpleName());
handlerBacklog.add(reassembled); handlerBacklog.add(reassembled);
} }
} else { } else {
@@ -934,6 +933,7 @@ public abstract class AbstractTeamspeakClientSocket
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
Ts3Debugging.debug("Problem reading packet", e);
getExceptionHandler().accept(e); getExceptionHandler().accept(e);
} }
} }
@@ -25,9 +25,7 @@ import com.github.manevolent.ts3j.protocol.packet.handler.client.LocalClientHand
import com.github.manevolent.ts3j.protocol.packet.handler.client.LocalClientHandlerRetrievingData; import com.github.manevolent.ts3j.protocol.packet.handler.client.LocalClientHandlerRetrievingData;
import com.github.manevolent.ts3j.protocol.packet.statistics.PacketStatistics; import com.github.manevolent.ts3j.protocol.packet.statistics.PacketStatistics;
import com.github.manevolent.ts3j.protocol.packet.transformation.InitPacketTransformation; import com.github.manevolent.ts3j.protocol.packet.transformation.InitPacketTransformation;
import com.github.manevolent.ts3j.util.HighPrecisionTimer; import com.github.manevolent.ts3j.util.*;
import com.github.manevolent.ts3j.util.Ts3Debugging;
import com.github.manevolent.ts3j.util.Pair;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
@@ -448,6 +446,8 @@ public class LocalTeamspeakClientSocket
if (awaitingCommandProcessor != null) if (awaitingCommandProcessor != null)
awaitingCommandProcessor.process(client, singleCommand); awaitingCommandProcessor.process(client, singleCommand);
else
Ts3Debugging.info("Dropping command, no awaiting processor: " + singleCommand.toString());
} }
} }
@@ -1098,7 +1098,7 @@ public class LocalTeamspeakClientSocket
Command command = new SingleCommand("clientmove", ProtocolRole.CLIENT); Command command = new SingleCommand("clientmove", ProtocolRole.CLIENT);
command.add(new CommandSingleParameter("cid", Integer.toString(channelId))); command.add(new CommandSingleParameter("cid", Integer.toString(channelId)));
if (password != null) command.add(new CommandSingleParameter("cpw", Integer.toString(channelId))); if (password != null) command.add(new CommandSingleParameter("cpw", Ts3Crypt.hashPassword(password)));
command.add(new CommandSingleParameter("clid", Integer.toString(clientId))); command.add(new CommandSingleParameter("clid", Integer.toString(clientId)));
executeCommand(command).complete(); executeCommand(command).complete();
@@ -23,8 +23,9 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.*;
import java.security.*; import java.security.*;
import java.util.List; import java.util.*;
public final class Ts3Crypt { public final class Ts3Crypt {
static { static {
@@ -312,6 +313,10 @@ public final class Ts3Crypt {
return new LocalIdentity(publicKey, privateKey); return new LocalIdentity(publicKey, privateKey);
} }
public static String hashPassword(String password) {
return Base64.getEncoder().encodeToString(hash128(password.getBytes(StandardCharsets.UTF_8)));
}
public static final class SecureChannelParameters { public static final class SecureChannelParameters {
private final byte[] fakeSignature; private final byte[] fakeSignature;
private final byte[] ivStruct; private final byte[] ivStruct;
@@ -1,11 +1,14 @@
package com.github.manevolent.ts3j; package com.github.manevolent.ts3j;
import com.github.manevolent.ts3j.command.*;
import com.github.manevolent.ts3j.event.*;
import com.github.manevolent.ts3j.identity.LocalIdentity; import com.github.manevolent.ts3j.identity.LocalIdentity;
import com.github.manevolent.ts3j.protocol.client.ClientConnectionState; import com.github.manevolent.ts3j.protocol.client.ClientConnectionState;
import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket; import com.github.manevolent.ts3j.protocol.socket.client.LocalTeamspeakClientSocket;
import com.github.manevolent.ts3j.util.Ts3Debugging; import com.github.manevolent.ts3j.util.Ts3Debugging;
import java.io.File; import java.io.*;
import java.util.concurrent.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@@ -25,10 +28,11 @@ public class ServerConnectionTest {
"teamlixo.net", "teamlixo.net",
10000L 10000L
); );
client.getChannels().get().forEach(x -> System.err.println(x.getTopic()));
assertEquals(client.getState(), ClientConnectionState.CONNECTED); assertEquals(client.getState(), ClientConnectionState.CONNECTED);
Thread.sleep(1000);
client.setDescription("Heyo"); client.setDescription("Heyo");
client.subscribeAll(); client.subscribeAll();