81 lines
3.0 KiB
C++
81 lines
3.0 KiB
C++
|
#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 "../../geo/GeoLocation.h"
|
||
|
#include "VoiceClient.h"
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace std::chrono;
|
||
|
using namespace ts::server;
|
||
|
using namespace ts::protocol;
|
||
|
using namespace ts;
|
||
|
|
||
|
|
||
|
CommandResult VoiceClient::handleCommand(ts::Command &command) {
|
||
|
threads::MutexLock l2(this->command_lock);
|
||
|
if(this->state == ConnectionState::DISCONNECTED) return CommandResult::NotImplemented;
|
||
|
if(!this->voice_server) return CommandResult::NotImplemented;
|
||
|
|
||
|
if(this->state == ConnectionState::INIT_HIGH && this->handshake.state == HandshakeState::SUCCEEDED) {
|
||
|
if(command.command() == "clientinit")
|
||
|
return this->handleCommandClientInit(command);
|
||
|
} else if(command.command() == "clientdisconnect")
|
||
|
return this->handleCommandClientDisconnect(command);
|
||
|
return SpeakingClient::handleCommand(command);
|
||
|
}
|
||
|
|
||
|
inline int getSecurityLevel(ecc_key* pubKey, size_t offset) {
|
||
|
size_t pubLength = 256;
|
||
|
char pubBuffer[256];
|
||
|
if(ecc_export(reinterpret_cast<unsigned char *>(pubBuffer), &pubLength, PK_PUBLIC, pubKey) != CRYPT_OK){
|
||
|
logError(lstream << "failed to export pub key" << endl);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
std::string hashStr = base64_encode(pubBuffer, pubLength) + to_string(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) {
|
||
|
for(int bit = 0; bit < 8; bit++) {
|
||
|
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
|
||
|
else break;
|
||
|
}
|
||
|
}
|
||
|
return zeroBits;
|
||
|
}
|
||
|
|
||
|
CommandResult VoiceClient::handleCommandClientInit(Command &cmd) {
|
||
|
this->crypto.client_init = true;
|
||
|
this->connection->acknowledge_handler.reset();
|
||
|
|
||
|
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) {
|
||
|
auto securityLevel = getSecurityLevel(this->crypto.remote_key.get(), cmd["client_key_offset"]);
|
||
|
if(securityLevel < 8)
|
||
|
return {findError("channel_invalid_security_hash"), "cant calculate security level"};
|
||
|
|
||
|
auto requiredLevel = this->getServer()->properties()[property::VIRTUALSERVER_NEEDED_IDENTITY_SECURITY_LEVEL].as<uint8_t>();
|
||
|
if(securityLevel < requiredLevel) return {findError("client_could_not_validate_identity"), to_string(requiredLevel)};
|
||
|
}
|
||
|
|
||
|
this->lastPingResponse = std::chrono::system_clock::now();
|
||
|
return SpeakingClient::handleCommandClientInit(cmd);
|
||
|
}
|
||
|
|
||
|
CommandResult VoiceClient::handleCommandClientDisconnect(Command& cmd) {
|
||
|
auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as<string>() : "";
|
||
|
this->disconnect(VREASON_SERVER_LEFT, reason, nullptr, true);
|
||
|
logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason);
|
||
|
return CommandResult::Success;
|
||
|
}
|