Teaspeak-Server/server/src/client/voice/VoiceClientCommandHandler.cpp

122 lines
4.8 KiB
C++
Raw Normal View History

#include <log/LogUtils.h>
#include <misc/endianness.h>
#include <misc/base64.h>
#include <ThreadPool/Timer.h>
#include <openssl/sha.h>
#include <src/client/SpeakingClient.h>
#include "../../InstanceHandler.h"
#include "VoiceClient.h"
using namespace std;
using namespace std::chrono;
using namespace ts::server;
using namespace ts::protocol;
using namespace ts;
2021-01-28 20:59:15 +01:00
VoiceClientCommandHandler::VoiceClientCommandHandler(const std::shared_ptr<VoiceClient> &client) : client_ref{client} {}
bool VoiceClientCommandHandler::handle_command(const std::string_view &command_string) {
auto client = this->client_ref.lock();
if(!client) {
return false;
}
client->handlePacketCommand(command_string);
return true;
}
void VoiceClient::handlePacketCommand(const std::string_view& command_string) {
std::unique_ptr<Command> command;
command_result result{};
try {
command = make_unique<Command>(Command::parse(command_string, true, !ts::config::server::strict_ut8_mode));
} catch(std::invalid_argument& ex) {
result.reset(command_result{error::parameter_convert, std::string{ex.what()}});
goto handle_error;
} catch(std::exception& ex) {
result.reset(command_result{error::parameter_convert, std::string{ex.what()}});
goto handle_error;
}
this->handleCommandFull(*command, true);
return;
handle_error:
this->notifyError(result);
result.release_data();
}
2020-01-25 23:42:37 +01:00
command_result VoiceClient::handleCommand(ts::Command &command) {
2020-01-24 02:57:58 +01:00
threads::MutexLock l2(this->command_lock);
2020-01-25 23:42:37 +01:00
if(this->state == ConnectionState::DISCONNECTED) return command_result{error::client_not_logged_in};
if(!this->voice_server) return command_result{error::server_unbound};
if(this->state == ConnectionState::INIT_HIGH && this->handshake.state == HandshakeState::SUCCEEDED) {
if(command.command() == "clientinit")
2020-01-24 02:57:58 +01:00
return this->handleCommandClientInit(command);
} else if(command.command() == "clientdisconnect")
2020-01-24 02:57:58 +01:00
return this->handleCommandClientDisconnect(command);
return SpeakingClient::handleCommand(command);
}
inline bool calculate_security_level(int& result, ecc_key* pubKey, const std::string& offset) {
size_t pubLength = 256;
char pubBuffer[256];
2019-11-23 21:16:55 +01:00
if((result = ecc_export(reinterpret_cast<unsigned char *>(pubBuffer), &pubLength, PK_PUBLIC, pubKey)) != CRYPT_OK)
2020-01-24 02:57:58 +01:00
return false;
std::string hashStr = base64_encode(pubBuffer, pubLength) + offset;
char shaBuffer[SHA_DIGEST_LENGTH];
SHA1((const unsigned char *) hashStr.data(), hashStr.length(), (unsigned char *) shaBuffer);
//Leading zero bits
int zeroBits = 0;
int i;
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
if(shaBuffer[i] == 0) zeroBits += 8;
else break;
if(i < SHA_DIGEST_LENGTH) {
2020-02-01 14:32:16 +01:00
for(uint8_t bit = 0; bit < 8; bit++) {
if((shaBuffer[i] & (1U << bit)) == 0) zeroBits++;
2020-01-24 02:57:58 +01:00
else break;
}
}
2020-01-24 02:57:58 +01:00
result = zeroBits;
return true;
}
2020-01-25 23:42:37 +01:00
command_result VoiceClient::handleCommandClientInit(Command &cmd) {
2020-01-24 02:57:58 +01:00
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) {
auto client_identity = this->connection->crypt_setup_handler().identity_key();
int security_level;
if(!calculate_security_level(security_level, &*client_identity, cmd["client_key_offset"].string())) {
logError(this->getServerId(), "[{}] Failed to calculate security level. Error code: {}", CLIENT_STR_LOG_PREFIX, security_level);
2020-01-25 23:42:37 +01:00
return command_result{error::vs_critical};
2020-01-24 02:57:58 +01:00
}
if(security_level < 8) {
2020-01-25 23:42:37 +01:00
return command_result{error::client_could_not_validate_identity};
}
auto requiredLevel = this->getServer()->properties()[property::VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL].as_unchecked<uint8_t>();
if(security_level < requiredLevel) {
return command_result{error::client_could_not_validate_identity, to_string(requiredLevel)};
}
2020-01-24 02:57:58 +01:00
}
2020-01-24 02:57:58 +01:00
return SpeakingClient::handleCommandClientInit(cmd);
}
2020-01-25 23:42:37 +01:00
command_result VoiceClient::handleCommandClientDisconnect(Command& cmd) {
2020-01-24 02:57:58 +01:00
auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as<string>() : "";
2020-02-01 14:32:16 +01:00
this->notifyClientLeftView(this->ref(), nullptr, VREASON_SERVER_LEFT, reason, nullptr, false); //Before we're moving us out of the channel tree!
if(this->state == CONNECTED) {
unique_lock channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, nullptr, reason, VREASON_SERVER_LEFT, true, channel_lock);
}
logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason);
2020-02-01 14:32:16 +01:00
this->postCommandHandler.push_back([&]{
this->close_connection(std::chrono::system_clock::now() + std::chrono::seconds{1}); /* send acknowledge and close connection */
});
2020-01-25 23:42:37 +01:00
return command_result{error::ok};
}