Using new command error system

This commit is contained in:
WolverinDEV 2020-01-25 23:42:37 +01:00
parent 10092cfab0
commit bb2e7699dc
18 changed files with 1223 additions and 1190 deletions

View File

@ -578,18 +578,24 @@ bool ConnectedClient::notifyClientNeededPermissions() {
return true;
}
bool ConnectedClient::notifyError(const CommandResult& result, const std::string& retCode) {
bool ConnectedClient::notifyError(const command_result& result, const std::string& retCode) {
Command cmd("error");
cmd["id"] = result.error.errorId;
cmd["msg"] = result.error.message;
if(result.is_detailed()) {
auto detailed = result.details();
cmd["id"] = (int) detailed->error_id;
cmd["msg"] = findError(detailed->error_id).message;
for(const auto& extra : detailed->extra_properties)
cmd[extra.first] = extra.second;
} else {
cmd["id"] = (int) result.error_code();
cmd["msg"] = findError(result.error_code()).message;
}
if(retCode.length() > 0)
cmd["return_code"] = retCode;
for(const auto& extra : result.extraProperties)
cmd[extra.first] = extra.second;
this->sendCommand(cmd);
return true;
}
@ -792,60 +798,46 @@ bool ConnectedClient::handleCommandFull(Command& cmd, bool disconnectOnFail) {
logTrace(this->getServerId() == 0 ? LOG_QUERY : this->getServerId(), "{}[Command][Client -> Server] Processing command: {}", CLIENT_STR_LOG_PREFIX, cmd.build(false));
#endif
CommandResult result;
command_result result;
try {
result = this->handleCommand(cmd);
} catch(invalid_argument& ex){
debugMessage(this->getServerId(), "{}[Command] Execution throws invalid_argument exception ({}).", CLIENT_STR_LOG_PREFIX, ex.what());
logWarning(this->getServerId(), "{}[Command] Failed to handle command. Received invalid argument exception: {}", CLIENT_STR_LOG_PREFIX, ex.what());
if(disconnectOnFail) {
this->disconnect("Invalid argument (" + string(ex.what()) + ")");
return false;
} else {
result = {findError("parameter_convert"), "Invalid argument (" + string(ex.what()) + ")"};
result = command_result{error::parameter_convert};
}
} catch (exception& ex) {
logWarning(this->getServerId(), "{}[Command] Failed to handle command. Received exception with message: {}", CLIENT_STR_LOG_PREFIX, ex.what());
if(disconnectOnFail) {
this->disconnect("Error while command handling (" + string(ex.what()) + ")!");
return false;
} else {
result = {findError("vs_critical"), "error while command handling (" + string(ex.what()) + ")"};
result = command_result{error::vs_critical};
}
} catch (...) {
this->disconnect("Error while command handling! (unknown)");
return false;
}
bool generateReturnStatus = false;
if(result.type() == PERM_ERROR){
if(result.error_code() != error::ok || this->getType() == ClientType::CLIENT_QUERY){
generateReturnStatus = true;
} else if(cmd["return_code"].size() > 0) {
generateReturnStatus = !cmd["return_code"].string().empty();
}
if(this->getType() == ClientType::CLIENT_QUERY)
generateReturnStatus = true;
if (!result) {
generateReturnStatus = true;
stringstream ss;
ss << "{";
for(auto it = result.extraProperties.begin(); it != result.extraProperties.end();){
ss << it->first << " = " << it->second;
if(++it != result.extraProperties.end())
ss << ", ";
}
ss << "}" << endl;
logTrace(this->getServerId(), "{}[Command] Command {} with return code {} fails and returns error code {:#06x}. Properties: {}", CLIENT_STR_LOG_PREFIX, cmd.command(), cmd["return_code"].size() ? "\"" + cmd["return_code"].first().as<std::string>() + "\"" : "<undefined>", result.error.errorId, ss.str());
}
if(generateReturnStatus)
this->notifyError(result, cmd["return_code"].size() > 0 ? cmd["return_code"].first().as<std::string>() : "");
if(!result && this->state == ConnectionState::INIT_HIGH) {
if(result.error_code() != error::ok && this->state == ConnectionState::INIT_HIGH)
this->closeConnection(system_clock::now()); //Disconnect now
}
for (const auto& handler : postCommandHandler)
handler();
postCommandHandler.clear();
end = system_clock::now();
if(end - start > milliseconds(10)) {
@ -854,6 +846,7 @@ bool ConnectedClient::handleCommandFull(Command& cmd, bool disconnectOnFail) {
else
logWarning(this->getServerId(), "Command handling of command {} needs {}ms.", cmd.command(), duration_cast<milliseconds>(end - start).count());
}
result.release_details();
return true;
}

View File

@ -7,22 +7,19 @@
#include "../channel/ClientChannelView.h"
#include "DataClient.h"
#define CLIENT_LOG_PREFIX_(this) "[" << this->getLoggingPeerIp() << ":" << this->getPeerPort() << "/" << this->getDisplayName() << "]"
#define CLIENT_LOG_PREFIX CLIENT_LOG_PREFIX_(this)
#define CLIENT_STR_LOG_PREFIX_(this) (std::string("[") + this->getLoggingPeerIp() + ":" + std::to_string(this->getPeerPort()) + "/" + this->getDisplayName() + " | " + std::to_string(this->getClientId()) + "]")
#define CLIENT_STR_LOG_PREFIX CLIENT_STR_LOG_PREFIX_(this)
#define CMD_REQ_SERVER \
if(!this->server) return {findError("server_invalid_id"), "invalid bound server"}
if(!this->server) return command_result{error::server_invalid_id};
/* TODO: Play lock the server here with read? So the client dosn't get kicked within that moment */
#define CMD_REF_SERVER(variable_name) \
std::shared_ptr<TSServer> variable_name = this->getServer(); \
if(!variable_name) return {findError("server_invalid_id"), "invalid bound server"}
if(!variable_name) return command_result{error::server_invalid_id};
#define CMD_REQ_CHANNEL \
if(!this->currentChannel) return {findError("channel_invalid_id"), "invalid bound channel"}
if(!this->currentChannel) return command_result{error::channel_invalid_id};
#define CMD_RESET_IDLE \
do { \
@ -30,22 +27,22 @@ do { \
} while(false)
#define CMD_REQ_PARM(parm) \
if(!cmd[0].has(parm)) return {findError("parameter_not_found"), parm}
if(!cmd[0].has(parm)) return command_result{error::parameter_not_found};
//the message here is show to the manager!
#define CMD_CHK_AND_INC_FLOOD_POINTS(num) \
this->increaseFloodPoints(num); \
if(this->shouldFloodBlock()) return {findError("ban_flooding"), "You reached the flood limit"};
if(this->shouldFloodBlock()) return command_result{error::ban_flooding};
#define CMD_CHK_PARM_COUNT(count) \
if(cmd.bulkCount() != count) return {findError("parameter_invalid_count"), ""};
if(cmd.bulkCount() != count) return command_result{error::parameter_invalid_count};
#define PERM_CHECK_CHANNEL_CR(pr, required, channel, req, cache) \
do { \
if(!this->permissionGranted(permission::PERMTEST_ORDERED, pr, required, channel, req, cache)) {\
return ts::CommandResultPermissionError(pr); \
return command_result{pr}; \
}\
} while(false)
@ -62,7 +59,7 @@ do { \
#define CACHED_PERM_CHECK(permission_type, required, ...) \
do { \
if(!this->permission_granted(this->cached_permission_value(permission_type), required, #__VA_ARGS__)) \
return CommandResultPermissionError{permission_type}; \
return command_result{permission_type}; \
} while(0)
//p = permission | target_permission = channel permission | channel = target channel | requires a power
@ -148,7 +145,7 @@ namespace ts {
}
/** Notifies general stuff **/
virtual bool notifyError(const CommandResult&, const std::string& retCode = "");
virtual bool notifyError(const command_result&, const std::string& retCode = "");
/** Notifies (after request) */
bool sendNeededPermissions(bool /* force an update */); /* invoke this because it dosn't spam the client */
@ -387,189 +384,189 @@ namespace ts {
threads::Mutex command_lock; /* Note: This mutex must be recursive! */
std::vector<std::function<void()>> postCommandHandler;
virtual bool handleCommandFull(Command&, bool disconnectOnFail = false);
virtual CommandResult handleCommand(Command&);
virtual command_result handleCommand(Command&);
CommandResult handleCommandServerGetVariables(Command&);
CommandResult handleCommandServerEdit(Command&);
command_result handleCommandServerGetVariables(Command&);
command_result handleCommandServerEdit(Command&);
CommandResult handleCommandGetConnectionInfo(Command&);
CommandResult handleCommandSetConnectionInfo(Command&);
CommandResult handleCommandServerRequestConnectionInfo(Command&);
CommandResult handleCommandConnectionInfoAutoUpdate(Command&);
CommandResult handleCommandPermissionList(Command&);
CommandResult handleCommandPropertyList(Command&);
command_result handleCommandGetConnectionInfo(Command&);
command_result handleCommandSetConnectionInfo(Command&);
command_result handleCommandServerRequestConnectionInfo(Command&);
command_result handleCommandConnectionInfoAutoUpdate(Command&);
command_result handleCommandPermissionList(Command&);
command_result handleCommandPropertyList(Command&);
CommandResult handleCommandServerGroupList(Command&);
command_result handleCommandServerGroupList(Command&);
CommandResult handleCommandClientGetIds(Command&);
CommandResult handleCommandClientUpdate(Command&);
CommandResult handleCommandClientEdit(Command&);
CommandResult handleCommandClientEdit(Command&, const std::shared_ptr<ConnectedClient>& /* target */);
CommandResult handleCommandClientMove(Command&);
CommandResult handleCommandClientGetVariables(Command&);
CommandResult handleCommandClientKick(Command&);
CommandResult handleCommandClientPoke(Command&);
command_result handleCommandClientGetIds(Command&);
command_result handleCommandClientUpdate(Command&);
command_result handleCommandClientEdit(Command&);
command_result handleCommandClientEdit(Command&, const std::shared_ptr<ConnectedClient>& /* target */);
command_result handleCommandClientMove(Command&);
command_result handleCommandClientGetVariables(Command&);
command_result handleCommandClientKick(Command&);
command_result handleCommandClientPoke(Command&);
CommandResult handleCommandChannelSubscribe(Command&);
CommandResult handleCommandChannelSubscribeAll(Command&);
CommandResult handleCommandChannelUnsubscribe(Command&);
CommandResult handleCommandChannelUnsubscribeAll(Command&);
CommandResult handleCommandChannelCreate(Command&);
CommandResult handleCommandChannelDelete(Command&);
CommandResult handleCommandChannelEdit(Command&);
CommandResult handleCommandChannelGetDescription(Command&);
CommandResult handleCommandChannelMove(Command&);
CommandResult handleCommandChannelPermList(Command&);
CommandResult handleCommandChannelAddPerm(Command&);
CommandResult handleCommandChannelDelPerm(Command&);
command_result handleCommandChannelSubscribe(Command&);
command_result handleCommandChannelSubscribeAll(Command&);
command_result handleCommandChannelUnsubscribe(Command&);
command_result handleCommandChannelUnsubscribeAll(Command&);
command_result handleCommandChannelCreate(Command&);
command_result handleCommandChannelDelete(Command&);
command_result handleCommandChannelEdit(Command&);
command_result handleCommandChannelGetDescription(Command&);
command_result handleCommandChannelMove(Command&);
command_result handleCommandChannelPermList(Command&);
command_result handleCommandChannelAddPerm(Command&);
command_result handleCommandChannelDelPerm(Command&);
//Server group manager management
CommandResult handleCommandServerGroupCopy(Command&);
CommandResult handleCommandServerGroupAdd(Command&);
CommandResult handleCommandServerGroupRename(Command&);
CommandResult handleCommandServerGroupDel(Command&);
CommandResult handleCommandServerGroupClientList(Command&);
CommandResult handleCommandServerGroupDelClient(Command&);
CommandResult handleCommandServerGroupAddClient(Command&);
CommandResult handleCommandServerGroupPermList(Command&);
CommandResult handleCommandServerGroupAddPerm(Command&);
CommandResult handleCommandServerGroupDelPerm(Command&);
command_result handleCommandServerGroupCopy(Command&);
command_result handleCommandServerGroupAdd(Command&);
command_result handleCommandServerGroupRename(Command&);
command_result handleCommandServerGroupDel(Command&);
command_result handleCommandServerGroupClientList(Command&);
command_result handleCommandServerGroupDelClient(Command&);
command_result handleCommandServerGroupAddClient(Command&);
command_result handleCommandServerGroupPermList(Command&);
command_result handleCommandServerGroupAddPerm(Command&);
command_result handleCommandServerGroupDelPerm(Command&);
CommandResult handleCommandServerGroupAutoAddPerm(Command&);
CommandResult handleCommandServerGroupAutoDelPerm(Command&);
command_result handleCommandServerGroupAutoAddPerm(Command&);
command_result handleCommandServerGroupAutoDelPerm(Command&);
CommandResult handleCommandClientAddPerm(Command&); //TODO: Use cached permission values
CommandResult handleCommandClientDelPerm(Command&); //TODO: Use cached permission values
CommandResult handleCommandClientPermList(Command&); //TODO: Use cached permission values
command_result handleCommandClientAddPerm(Command&); //TODO: Use cached permission values
command_result handleCommandClientDelPerm(Command&); //TODO: Use cached permission values
command_result handleCommandClientPermList(Command&); //TODO: Use cached permission values
CommandResult handleCommandChannelClientAddPerm(Command&); //TODO: Use cached permission values
CommandResult handleCommandChannelClientDelPerm(Command&); //TODO: Use cached permission values
CommandResult handleCommandChannelClientPermList(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientAddPerm(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientDelPerm(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientPermList(Command&); //TODO: Use cached permission values
CommandResult handleCommandChannelGroupAdd(Command&);
CommandResult handleCommandChannelGroupCopy(Command&);
CommandResult handleCommandChannelGroupRename(Command&);
CommandResult handleCommandChannelGroupDel(Command&);
CommandResult handleCommandChannelGroupList(Command&);
CommandResult handleCommandChannelGroupClientList(Command&);
CommandResult handleCommandChannelGroupPermList(Command&);
CommandResult handleCommandChannelGroupAddPerm(Command&);
CommandResult handleCommandChannelGroupDelPerm(Command&);
CommandResult handleCommandSetClientChannelGroup(Command&);
command_result handleCommandChannelGroupAdd(Command&);
command_result handleCommandChannelGroupCopy(Command&);
command_result handleCommandChannelGroupRename(Command&);
command_result handleCommandChannelGroupDel(Command&);
command_result handleCommandChannelGroupList(Command&);
command_result handleCommandChannelGroupClientList(Command&);
command_result handleCommandChannelGroupPermList(Command&);
command_result handleCommandChannelGroupAddPerm(Command&);
command_result handleCommandChannelGroupDelPerm(Command&);
command_result handleCommandSetClientChannelGroup(Command&);
CommandResult handleCommandSendTextMessage(Command&);
CommandResult handleCommandClientChatComposing(Command&);
CommandResult handleCommandClientChatClosed(Command&);
command_result handleCommandSendTextMessage(Command&);
command_result handleCommandClientChatComposing(Command&);
command_result handleCommandClientChatClosed(Command&);
//File transfare commands
CommandResult handleCommandFTGetFileList(Command&); //TODO: Use cached permission values
CommandResult handleCommandFTCreateDir(Command&); //TODO: Use cached permission values
CommandResult handleCommandFTDeleteFile(Command&); //TODO: Use cached permission values
CommandResult handleCommandFTInitUpload(Command&); //TODO: Use cached permission values
CommandResult handleCommandFTInitDownload(Command&); //TODO: Use cached permission values
CommandResult handleCommandFTGetFileInfo(Command&); //TODO: Use cached permission values
command_result handleCommandFTGetFileList(Command&); //TODO: Use cached permission values
command_result handleCommandFTCreateDir(Command&); //TODO: Use cached permission values
command_result handleCommandFTDeleteFile(Command&); //TODO: Use cached permission values
command_result handleCommandFTInitUpload(Command&); //TODO: Use cached permission values
command_result handleCommandFTInitDownload(Command&); //TODO: Use cached permission values
command_result handleCommandFTGetFileInfo(Command&); //TODO: Use cached permission values
//CMD_TODO handleCommandFTGetFileInfo -> 5 points
//CMD_TODO handleCommandFTStop -> 5 points
//CMD_TODO handleCommandFTRenameFile -> 5 points
//CMD_TODO handleCommandFTList -> 5 points
CommandResult handleCommandBanList(Command&);
CommandResult handleCommandBanAdd(Command&);
CommandResult handleCommandBanEdit(Command&);
CommandResult handleCommandBanClient(Command&);
CommandResult handleCommandBanDel(Command&);
CommandResult handleCommandBanDelAll(Command&);
CommandResult handleCommandBanTriggerList(Command&);
command_result handleCommandBanList(Command&);
command_result handleCommandBanAdd(Command&);
command_result handleCommandBanEdit(Command&);
command_result handleCommandBanClient(Command&);
command_result handleCommandBanDel(Command&);
command_result handleCommandBanDelAll(Command&);
command_result handleCommandBanTriggerList(Command&);
CommandResult handleCommandTokenList(Command&);
CommandResult handleCommandTokenAdd(Command&);
CommandResult handleCommandTokenUse(Command&);
CommandResult handleCommandTokenDelete(Command&);
command_result handleCommandTokenList(Command&);
command_result handleCommandTokenAdd(Command&);
command_result handleCommandTokenUse(Command&);
command_result handleCommandTokenDelete(Command&);
CommandResult handleCommandClientDbList(Command&);
CommandResult handleCommandClientDBEdit(Command&);
CommandResult handleCommandClientDbInfo(Command&);
CommandResult handleCommandClientDBDelete(Command&);
CommandResult handleCommandClientDBFind(Command&);
command_result handleCommandClientDbList(Command&);
command_result handleCommandClientDBEdit(Command&);
command_result handleCommandClientDbInfo(Command&);
command_result handleCommandClientDBDelete(Command&);
command_result handleCommandClientDBFind(Command&);
CommandResult handleCommandPluginCmd(Command&);
command_result handleCommandPluginCmd(Command&);
CommandResult handleCommandClientMute(Command&);
CommandResult handleCommandClientUnmute(Command&);
command_result handleCommandClientMute(Command&);
command_result handleCommandClientUnmute(Command&);
CommandResult handleCommandComplainAdd(Command&);
CommandResult handleCommandComplainList(Command&);
CommandResult handleCommandComplainDel(Command&);
CommandResult handleCommandComplainDelAll(Command&);
command_result handleCommandComplainAdd(Command&);
command_result handleCommandComplainList(Command&);
command_result handleCommandComplainDel(Command&);
command_result handleCommandComplainDelAll(Command&);
CommandResult handleCommandClientGetDBIDfromUID(Command&);
CommandResult handleCommandClientGetNameFromDBID(Command&);
CommandResult handleCommandClientGetNameFromUid(Command&);
CommandResult handleCommandClientGetUidFromClid(Command&);
command_result handleCommandClientGetDBIDfromUID(Command&);
command_result handleCommandClientGetNameFromDBID(Command&);
command_result handleCommandClientGetNameFromUid(Command&);
command_result handleCommandClientGetUidFromClid(Command&);
//Original from query but still reachable for all
CommandResult handleCommandClientList(Command&);
CommandResult handleCommandWhoAmI(Command&);
CommandResult handleCommandServerGroupsByClientId(Command &); //Maybe not query?
command_result handleCommandClientList(Command&);
command_result handleCommandWhoAmI(Command&);
command_result handleCommandServerGroupsByClientId(Command &); //Maybe not query?
CommandResult handleCommandClientFind(Command&);
CommandResult handleCommandClientInfo(Command&);
CommandResult handleCommandVersion(Command&);
command_result handleCommandClientFind(Command&);
command_result handleCommandClientInfo(Command&);
command_result handleCommandVersion(Command&);
CommandResult handleCommandVerifyChannelPassword(Command&);
CommandResult handleCommandVerifyServerPassword(Command&);
command_result handleCommandVerifyChannelPassword(Command&);
command_result handleCommandVerifyServerPassword(Command&);
CommandResult handleCommandMessageList(Command&);
CommandResult handleCommandMessageAdd(Command&);
CommandResult handleCommandMessageGet(Command&);
CommandResult handleCommandMessageUpdateFlag(Command&);
CommandResult handleCommandMessageDel(Command&);
command_result handleCommandMessageList(Command&);
command_result handleCommandMessageAdd(Command&);
command_result handleCommandMessageGet(Command&);
command_result handleCommandMessageUpdateFlag(Command&);
command_result handleCommandMessageDel(Command&);
CommandResult handleCommandPermGet(Command&);
CommandResult handleCommandPermIdGetByName(Command&);
CommandResult handleCommandPermFind(Command&);
CommandResult handleCommandPermOverview(Command&);
command_result handleCommandPermGet(Command&);
command_result handleCommandPermIdGetByName(Command&);
command_result handleCommandPermFind(Command&);
command_result handleCommandPermOverview(Command&);
CommandResult handleCommandChannelFind(Command&); //TODO: Use cached permission values
CommandResult handleCommandChannelInfo(Command&); //TODO: Use cached permission values
command_result handleCommandChannelFind(Command&); //TODO: Use cached permission values
command_result handleCommandChannelInfo(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotCreate(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotDelete(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotSetSubscription(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotCreate(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotDelete(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotSetSubscription(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotPlayerInfo(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotPlayerAction(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotPlayerInfo(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotPlayerAction(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueList(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueAdd(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueRemove(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueReorder(Command&); //TODO: Use cached permission values
CommandResult handleCommandMusicBotPlaylistAssign(Command&);
command_result handleCommandMusicBotPlaylistAssign(Command&);
/* playlist management */
CommandResult handleCommandPlaylistList(Command&);
CommandResult handleCommandPlaylistCreate(Command&);
CommandResult handleCommandPlaylistDelete(Command&);
CommandResult handleCommandPlaylistPermList(Command&);
CommandResult handleCommandPlaylistAddPerm(Command&);
CommandResult handleCommandPlaylistDelPerm(Command&);
command_result handleCommandPlaylistList(Command&);
command_result handleCommandPlaylistCreate(Command&);
command_result handleCommandPlaylistDelete(Command&);
command_result handleCommandPlaylistPermList(Command&);
command_result handleCommandPlaylistAddPerm(Command&);
command_result handleCommandPlaylistDelPerm(Command&);
/* playlist properties */
CommandResult handleCommandPlaylistInfo(Command&);
CommandResult handleCommandPlaylistEdit(Command&);
command_result handleCommandPlaylistInfo(Command&);
command_result handleCommandPlaylistEdit(Command&);
CommandResult handleCommandPlaylistSongList(Command&);
CommandResult handleCommandPlaylistSongAdd(Command&);
CommandResult handleCommandPlaylistSongReorder(Command&);
CommandResult handleCommandPlaylistSongRemove(Command&);
command_result handleCommandPlaylistSongList(Command&);
command_result handleCommandPlaylistSongAdd(Command&);
command_result handleCommandPlaylistSongReorder(Command&);
command_result handleCommandPlaylistSongRemove(Command&);
CommandResult handleCommandPermReset(Command&); //TODO: Use cached permission values
command_result handleCommandPermReset(Command&); //TODO: Use cached permission values
CommandResult handleCommandHelp(Command&); //TODO: Use cached permission values
command_result handleCommandHelp(Command&); //TODO: Use cached permission values
CommandResult handleCommandUpdateMyTsId(Command&);
CommandResult handleCommandUpdateMyTsData(Command&);
command_result handleCommandUpdateMyTsId(Command&);
command_result handleCommandUpdateMyTsData(Command&);
/// <summary>
/// With a whisper list set a client can talk to the specified clients and channels bypassing the standard rule that voice is only transmitted to the current channel. Whisper lists can be defined for individual clients.
/// </summary>
@ -585,26 +582,26 @@ namespace ts {
//CMD_TODO handleCommandServerTempPasswordAdd -> servertemppasswordadd pw=PWD desc=DES duration=1200 (20 min) tcid=4 tcpw=asdasd (channel password)
//Legacy, for TeamSpeak 3
CommandResult handleCommandClientSetServerQueryLogin(Command&);
command_result handleCommandClientSetServerQueryLogin(Command&);
CommandResult handleCommandQueryList(Command&);
CommandResult handleCommandQueryRename(Command&);
CommandResult handleCommandQueryCreate(Command&);
CommandResult handleCommandQueryDelete(Command&);
CommandResult handleCommandQueryChangePassword(Command&);
command_result handleCommandQueryList(Command&);
command_result handleCommandQueryRename(Command&);
command_result handleCommandQueryCreate(Command&);
command_result handleCommandQueryDelete(Command&);
command_result handleCommandQueryChangePassword(Command&);
CommandResult handleCommandConversationHistory(Command&);
CommandResult handleCommandConversationFetch(Command&);
CommandResult handleCommandConversationMessageDelete(Command&);
command_result handleCommandConversationHistory(Command&);
command_result handleCommandConversationFetch(Command&);
command_result handleCommandConversationMessageDelete(Command&);
CommandResult handleCommandLogView(Command&);
command_result handleCommandLogView(Command&);
//CMD_TODO handleCommandLogAdd
//handleCommandClientSiteReport() -> return findError(0x00)
//handleCommandChannelCreatePrivate() -> return findError(0x02)
//handleCommandCustome_Unknown_Command() -> return findError(0x100)
CommandResult handleCommandDummy_IpChange(Command&);
command_result handleCommandDummy_IpChange(Command&);
//handleCommandDummy_NewIp
//handleCommandDummy_ConnectFailed
//handleCommandDummy_ConnectionLost

File diff suppressed because it is too large Load Diff

View File

@ -103,13 +103,17 @@ bool ConnectedClient::handleTextMessage(ChatMessageMode mode, std::string text,
return true; \
}
//TODO: Correct error message print!
#define HANDLE_CMD_ERROR(_message) \
send_message(serverInstance->musicRoot(), string(_message) + ": action failed");
/*
if(result.extraProperties.count("extra_msg") > 0) \
send_message(serverInstance->musicRoot(), string(_message) + ": " + result.extraProperties["extra_msg"]); \
else if(result.extraProperties.count("failed_permid") > 0) \
send_message(serverInstance->musicRoot(), string(_message) + ". (Missing permission " + permission::resolvePermissionData((permission::PermissionType) stoull(result.extraProperties["failed_permid"]))->name + ")"); \
else \
send_message(serverInstance->musicRoot(), string(_message) + ": " + result.error.message);
*/
#define JOIN_ARGS(variable, index) \
string variable; \
@ -153,7 +157,8 @@ bool ConnectedClient::handle_text_command(
if (TARG(0, "create")) {
Command cmd("");
auto result = this->handleCommandMusicBotCreate(cmd);
if(!result) {
if(result.error_code()) {
result.release_details();
HANDLE_CMD_ERROR("Failed to create music bot");
return true;
}
@ -212,8 +217,9 @@ bool ConnectedClient::handle_text_command(
Command cmd("");
cmd["client_nickname"] = ss.str();
auto result = this->handleCommandClientEdit(cmd, bot);
if(!result) {
if(result.error_code()) {
HANDLE_CMD_ERROR("Failed to rename bot");
result.release_details();
return true;
}
send_message(serverInstance->musicRoot(), "Name successfully changed!");
@ -499,8 +505,9 @@ bool ConnectedClient::handle_text_command(
JOIN_ARGS(value, 3);
cmd[arguments[2]] = value;
auto result = this->handleCommandClientEdit(cmd, bot);
if(!result) {
if(result.error_code()) {
HANDLE_CMD_ERROR("Failed to change bot property");
result.release_details();
return true;
}
send_message(serverInstance->musicRoot(), "Property successfully changed!");

View File

@ -343,22 +343,24 @@ HWID_REGEX(unix, "^[a-z0-9]{32}$");
HWID_REGEX(android, "^[a-z0-9]{16}$");
HWID_REGEX(ios, "^[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}$");
CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
TIMING_START(timings);
{
lock_guard<threads::Mutex> lock(this->server->join_attempts_lock);
auto inetAddr = this->getPeerIp();
if(config::voice::clientConnectLimit > 0 && this->server->join_attempts[inetAddr] + 1 > config::voice::clientConnectLimit)
return {findError("client_is_flooding"), "To many joins per second per ip"};
return command_result{error::client_join_rate_limit_reached};
if(config::voice::connectLimit > 0 && this->server->join_attempts["_"] + 1 > config::voice::connectLimit)
return {findError("client_is_flooding"), "To many joins per second"};
return command_result{error::server_join_rate_limit_reached};
this->server->join_attempts[inetAddr]++;
this->server->join_attempts["_"]++;
}
TIMING_STEP(timings, "join atmp c");
if(!DatabaseHelper::assignDatabaseId(this->server->getSql(), this->server->getServerId(), _this.lock())) return {findError("vs_critical"), "Could not assign database id!"};
if(!DatabaseHelper::assignDatabaseId(this->server->getSql(), this->server->getServerId(), _this.lock()))
return command_result{error::vs_critical, "Could not assign database id!"};
TIMING_STEP(timings, "db assign ");
this->server->getGroupManager()->enableCache(this->getClientDatabaseId());
TIMING_STEP(timings, "gr cache ");
@ -423,8 +425,10 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
else if(key == "pubSignCert") continue;
else if(key == "client_version" || key == "client_platform") {
for(auto& character : cmd[key].string())
if(!isascii(character))
return {findError("parameter_invalid"), "invalid version or platform"};
if(!isascii(character)) {
logWarning(this->getServerId(), "{} Tried to join within an invalid supplied '{}' ({})", CLIENT_STR_LOG_PREFIX, key,cmd[key].string());
return command_result{error::client_hacked};
}
}
const auto &info = property::info<property::ClientProperties>(key);
@ -433,7 +437,8 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
continue;
//return {findError("parameter_invalid"), "Unknown property " + key};
}
if(!info->validate_input(cmd[key].as<string>())) return {findError("parameter_invalid"), "Unknown value type for " + key};
if(!info->validate_input(cmd[key].as<string>()))
return command_result{error::parameter_invalid};
this->properties()[info] = cmd[key].as<std::string>();
}
@ -459,7 +464,7 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
if(geoloc::provider_vpn && permissions[permission::b_client_ignore_vpn] == permNotGranted) {
auto provider = this->isAddressV4() ? geoloc::provider_vpn->resolveInfoV4(this->getPeerIp(), true) : geoloc::provider_vpn->resolveInfoV6(this->getPeerIp(), true);
if(provider)
return {findError(0xD01), strvar::transform(ts::config::messages::kick_vpn, strvar::StringValue{"provider.name", provider->name}, strvar::StringValue{"provider.website", provider->side})};
return command_result{error::server_connect_banned, strvar::transform(ts::config::messages::kick_vpn, strvar::StringValue{"provider.name", provider->name}, strvar::StringValue{"provider.website", provider->side})};
}
if(this->getType() == ClientType::CLIENT_TEAMSPEAK && (permissions[permission::b_client_enforce_valid_hwid] == permNotGranted && permissions[permission::b_client_enforce_valid_hwid] == 0)) {
@ -470,14 +475,15 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
!std::regex_match(hwid, regex_hwid_android) &&
!std::regex_match(hwid, regex_hwid_ios)
) {
return {findError("parameter_invalid"), config::messages::kick_invalid_hardware_id};
return command_result{error::parameter_invalid, config::messages::kick_invalid_hardware_id};
}
}
TIMING_STEP(timings, "valid hw ip");
auto ignorePassword = permissions[permission::b_virtualserver_join_ignore_password] > 0 && permissions[permission::b_virtualserver_join_ignore_password] != permNotGranted;
if(!ignorePassword)
if(!this->server->verifyServerPassword(cmd["client_server_password"].string(), true)) return {findError("server_invalid_password"), "invalid server password"};
if(!this->server->verifyServerPassword(cmd["client_server_password"].string(), true))
return command_result{error::server_invalid_password};
size_t clones_uid = 0;
size_t clones_ip = 0;
@ -496,17 +502,17 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
if(permissions[permission::i_client_max_clones_uid] > 0 && clones_uid >= permissions[permission::i_client_max_clones_uid]) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} uid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_uid, permissions[permission::i_client_max_clones_uid]);
return {findError("client_too_many_clones_connected"), "too many clones connected (uid)"};
return command_result{error:: client_too_many_clones_connected, "too many clones connected (uid)"};
}
if(permissions[permission::i_client_max_clones_ip] > 0 && clones_ip >= permissions[permission::i_client_max_clones_ip]) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} ip clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_ip, permissions[permission::i_client_max_clones_ip]);
return {findError("client_too_many_clones_connected"), "too many clones connected (ip)"};
return command_result{error:: client_too_many_clones_connected, "too many clones connected (ip)"};
}
if(permissions[permission::i_client_max_clones_hwid] > 0 && clones_hwid >= permissions[permission::i_client_max_clones_hwid] && !_own_hwid.empty()) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} hwid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_hwid, permissions[permission::i_client_max_clones_hwid]);
return {findError("client_too_many_clones_connected"), "too many clones connected (hwid)"};
return command_result{error:: client_too_many_clones_connected, "too many clones connected (hwid)"};
}
TIMING_STEP(timings, "max clones ");
@ -560,7 +566,7 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
} else time = "never";
fullReason += time + "!";
return {findError(0xD01), fullReason};
return command_result{error::server_connect_banned, fullReason};
}
TIMING_STEP(timings, "ban resolve");
@ -577,9 +583,10 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
bool allowReserved = permissions[permission::b_client_use_reserved_slot] != permNotGranted && permissions[permission::b_client_use_reserved_slot] != 0;
if(reserved > maxClients){
if(!allowReserved) return {findError("server_maxclients_reached"), "server max clients reached"};
if(!allowReserved)
return command_result{error::server_maxclients_reached};
} else if(maxClients - (allowReserved ? 0 : reserved) <= count)
return {findError("server_maxclients_reached"), "server max clients reached"};
return command_result{error::server_maxclients_reached};
TIMING_STEP(timings, "max clients");
@ -613,7 +620,7 @@ CommandResult SpeakingClient::handleCommandClientInit(Command& cmd) {
});
debugMessage(this->getServerId(), "{} Client init timings: {}", CLIENT_STR_LOG_PREFIX, TIMING_FINISH(timings));
return CommandResult::Success;
return command_result{error::ok};
}
/* must be triggered while helding an execute lock */
@ -666,7 +673,9 @@ void SpeakingClient::processJoin() {
TIMING_STEP(timings, "notify sini");
if(!ref_server->assignDefaultChannel(this->ref(), false)) {
this->notifyError({findError("vs_critical"), "Could not assign default channel!"});
auto result = command_result{error::vs_critical, "Could not assign default channel!"};
this->notifyError(result);
result.release_details();
this->closeConnection(system_clock::now() + seconds(1));
return;
}
@ -776,19 +785,21 @@ void SpeakingClient::updateChannelClientProperties(bool channel_lock, bool notif
this->max_idle_time = this->permissionValueFlagged(permission::i_client_max_idletime, this->currentChannel);
}
CommandResult SpeakingClient::handleCommand(Command &command) {
command_result SpeakingClient::handleCommand(Command &command) {
if(this->connectionState() == ConnectionState::INIT_HIGH) {
if(this->handshake.state == HandshakeState::BEGIN || this->handshake.state == HandshakeState::IDENTITY_PROOF) {
CommandResult result;
command_result result;
if(command.command() == "handshakebegin")
result = this->handleCommandHandshakeBegin(command);
else if(command.command() == "handshakeindentityproof")
result = this->handleCommandHandshakeIdentityProof(command);
else
result = {findError("client_not_logged_in")};
result = command_result{error::client_not_logged_in};
if(!result)
if(result.error_code())
this->postCommandHandler.push_back([&]{
this->closeConnection(system_clock::now() + seconds(1));
});
return result;
}
}

View File

@ -59,7 +59,7 @@ namespace ts {
void updateChannelClientProperties(bool channel_lock, bool notify) override;
protected:
CommandResult handleCommand(Command &command) override;
command_result handleCommand(Command &command) override;
public:
void handlePacketVoice(const pipes::buffer_view&, bool head, bool fragmented);
@ -68,9 +68,9 @@ namespace ts {
void processJoin();
void processLeave();
virtual CommandResult handleCommandHandshakeBegin(Command&);
virtual CommandResult handleCommandHandshakeIdentityProof(Command &);
virtual CommandResult handleCommandClientInit(Command&);
virtual command_result handleCommandHandshakeBegin(Command&);
virtual command_result handleCommandHandshakeIdentityProof(Command &);
virtual command_result handleCommandClientInit(Command&);
void triggerVoiceEnd();
inline void updateSpeak(bool onlyUpdate, const std::chrono::system_clock::time_point &time);

View File

@ -23,13 +23,13 @@ void free_ecc(ecc_key* key) {
delete key;
}
CommandResult SpeakingClient::handleCommandHandshakeBegin(Command& cmd) { //If !result than the connection will be closed!
command_result SpeakingClient::handleCommandHandshakeBegin(Command& cmd) { //If !result than the connection will be closed!
if(this->handshake.state != HandshakeState::BEGIN)
return {findError("web_handshake_invalid"), "invalid connection state!"};
return command_result{error::web_handshake_invalid};
auto intention = cmd["intention"].as<int>();
if(intention != 0)
return {findError("web_handshake_unsupported"), ""};
return command_result{error::web_handshake_unsupported};
auto authenticationMethod = cmd["authentication_method"].as<int>();
if(authenticationMethod == IdentityType::TEAMSPEAK) {
@ -41,7 +41,8 @@ CommandResult SpeakingClient::handleCommandHandshakeBegin(Command& cmd) { //If !
this->handshake.identityKey = shared_ptr<ecc_key>(new ecc_key{}, free_ecc);
if(ecc_import((u_char*) identity.data(), identity.length(), this->handshake.identityKey.get()) != CRYPT_OK) {
this->handshake.identityKey = nullptr;
return {findError("web_handshake_invalid"), "invalid ecc key state!"};
logWarning(this->getServerId(), "{} Failed to import remote public key.", CLIENT_STR_LOG_PREFIX);
return command_result{error::web_handshake_invalid};
}
auto message = "TeaSpeak, made with love and coffee by WolverinDEV (#" + base64::encode(rnd_string(32)) + ")";
@ -65,26 +66,26 @@ CommandResult SpeakingClient::handleCommandHandshakeBegin(Command& cmd) { //If !
auto& json_str = this->handshake.proof_message;
if(!reader->parse(json_str.data(), json_str.data() + json_str.size(), &*this->handshake.identityData, &error)) {
debugMessage(this->getServerId(), "[{}] Failed to parse forum account data: {}", error);
return {findError("web_handshake_invalid"), "invalid json!"};
return command_result{error::web_handshake_invalid};
}
auto& json_data = *this->handshake.identityData;
if(json_data["user_id"].isNull())
return {findError("web_handshake_invalid"), "Missing json data (user_id)!"};
return command_result{error::web_handshake_invalid}; //{findError("web_handshake_invalid"), "Missing json data (user_id)!"};
if(json_data["user_name"].isNull())
return {findError("web_handshake_invalid"), "Missing json data (user_name)!"};
return command_result{error::web_handshake_invalid}; //{findError("web_handshake_invalid"), "Missing json data (user_name)!"};
if(json_data["user_group"].isNull())
return {findError("web_handshake_invalid"), "Missing json data (user_group)!"};
return command_result{error::web_handshake_invalid}; //{findError("web_handshake_invalid"), "Missing json data (user_group)!"};
if(json_data["user_groups"].isNull())
return {findError("web_handshake_invalid"), "Missing json data (user_groups)!"};
return command_result{error::web_handshake_invalid}; //{findError("web_handshake_invalid"), "Missing json data (user_groups)!"};
if(json_data["data_age"].isNull())
return {findError("web_handshake_invalid"), "Missing json data (data_age)!"};
return command_result{error::web_handshake_invalid}; //{findError("web_handshake_invalid"), "Missing json data (data_age)!"};
//Type test
json_data["user_id"].asInt64();
if(json_data["data_age"].asUInt64() < duration_cast<milliseconds>((system_clock::now() - hours(72)).time_since_epoch()).count())
return {findError("web_handshake_invalid"), "Provided data is too old!"};
return command_result{error::web_handshake_identity_outdated}; // {findError("web_handshake_invalid"), "Provided data is too old!"};
this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = base64::encode(digest::sha1("TeaSpeak-Forum#" + json_data["user_id"].asString()));
@ -107,34 +108,37 @@ CommandResult SpeakingClient::handleCommandHandshakeBegin(Command& cmd) { //If !
this->properties()[property::CLIENT_TEAFORO_FLAGS] = flags;
}
} catch (Json::Exception& exception) {
return {findError("web_handshake_invalid"), "invalid json!"};
debugMessage(this->getServerId(), "{} Failed to parse supplied json: {}", CLIENT_STR_LOG_PREFIX, exception.what());
return command_result{error::web_handshake_invalid};
}
this->sendCommand(Command("handshakeidentityproof"));
this->handshake.state = HandshakeState::IDENTITY_PROOF;
} else if(authenticationMethod == IdentityType::NICKNAME) {
if(!config::server::authentication::name)
return {findError("web_handshake_identity_unsupported"), "Name authentication has been disabled"};
return command_result{error::web_handshake_unsupported};
this->handshake.state = HandshakeState::SUCCEEDED;
this->handshake.identityType = IdentityType::NICKNAME;
this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = base64::encode(digest::sha1("UserName#" + cmd["client_nickname"].string()));
} else {
return {findError("web_handshake_identity_unsupported"), ""};
return command_result{error::web_handshake_unsupported};
}
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult SpeakingClient::handleCommandHandshakeIdentityProof(Command& cmd) {
command_result SpeakingClient::handleCommandHandshakeIdentityProof(Command& cmd) {
if(this->handshake.state != HandshakeState::IDENTITY_PROOF)
return {findError("web_handshake_invalid"), "invalid connection state!"};
return command_result{error::web_handshake_invalid};
if(this->handshake.identityType == IdentityType::TEASPEAK_FORUM) {
auto encodedProof = cmd["proof"].string();
auto proof = base64::decode(encodedProof);
auto key = serverInstance->sslManager()->getRsaKey("teaforo_sign");
if(!key) return {findError("web_handshake_identity_unsupported"), "Missing server public key!"};
if(!serverInstance->sslManager()->verifySign(key, this->handshake.proof_message, proof)) return {findError("web_handshake_identity_proof_failed"), ""};
if(!key)
return command_result{error::web_handshake_identity_unsupported};
if(!serverInstance->sslManager()->verifySign(key, this->handshake.proof_message, proof))
return command_result{error::web_handshake_identity_proof_failed};
this->properties()[property::CLIENT_TEAFORO_ID] = (int64_t) (*this->handshake.identityData)["user_id"].asInt64();
this->properties()[property::CLIENT_TEAFORO_NAME] = (*this->handshake.identityData)["user_name"].asString();
@ -143,11 +147,13 @@ CommandResult SpeakingClient::handleCommandHandshakeIdentityProof(Command& cmd)
auto proof = base64::decode(cmd["proof"]);
int result;
if(ecc_verify_hash((u_char*) proof.data(), proof.length(), (u_char*) this->handshake.proof_message.data(), this->handshake.proof_message.length(), &result, this->handshake.identityKey.get()) != CRYPT_OK) return {findError("web_handshake_identity_proof_failed"), ""};
if(!result) return {findError("web_handshake_identity_proof_failed"), ""};
if(ecc_verify_hash((u_char*) proof.data(), proof.length(), (u_char*) this->handshake.proof_message.data(), this->handshake.proof_message.length(), &result, this->handshake.identityKey.get()) != CRYPT_OK)
return command_result{error::web_handshake_identity_proof_failed};
if(!result)
return command_result{error::web_handshake_identity_proof_failed};
this->handshake.state = HandshakeState::SUCCEEDED;
} else
return {findError("web_handshake_invalid"), "identity isn't required to proof authentication"};
return command_result{error::web_handshake_invalid};
return CommandResult::Success;
return command_result{error::ok};
}

View File

@ -7,7 +7,6 @@
#include <misc/memtracker.h>
#include "src/InstanceHandler.h"
#include <pipes/errors.h>
#include <query/command2.h>
#include <misc/std_unique_ptr.h>
using namespace std;
@ -76,7 +75,9 @@ void QueryClient::postInitialize() {
this->properties()[property::CLIENT_LASTCONNECTED] = duration_cast<seconds>(this->connectTimestamp.time_since_epoch()).count();
if(ts::config::query::sslMode == 1 && this->connectionType != ConnectionType::SSL_ENCRIPTED) {
this->notifyError({findError("failed_connection_initialisation"), "Please use a SSL encryption!"});
command_result error{error::failed_connection_initialisation, "Please use a SSL encryption!"};
this->notifyError(error);
error.release_details();
this->disconnect("Please us a SSL encryption for more security.\nThe server denies also all other connections!");
return;
}
@ -495,28 +496,31 @@ bool QueryClient::handleMessage(const pipes::buffer_view& message) {
}
unique_ptr<Command> cmd;
command_result error{};
try {
cmd = make_unique<Command>(Command::parse(pipes::buffer_view{(void*) command.data(), command.length()}, true, !ts::config::server::strict_ut8_mode));
} catch(std::invalid_argument& ex) {
logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (invalid argument): {}", this->getLoggingPeerIp(), this->getPeerPort(), command);
this->notifyError(CommandResult{findError("parameter_convert"), ex.what()});
return false;
} catch(command_malformed_exception& ex) {
logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (malformed command at {}): {}", this->getLoggingPeerIp(), this->getPeerPort(), ex.index(), command);
this->notifyError(CommandResult{findError("parameter_convert"), "invalid character @" + to_string(ex.index())});
return false;
error = command_result{error::parameter_convert};
goto handle_error;
} catch(std::exception& ex) {
logTrace(LOG_QUERY, "[{}:{}] Failed to parse command (exception: {}): {}", this->getLoggingPeerIp(), this->getPeerPort(), ex.what(), command);
this->notifyError(CommandResult{ErrorType::VSError, ex.what()});
return false;
error = command_result{error::vs_critical, std::string{ex.what()}};
goto handle_error;
}
try {
this->handleCommandFull(*cmd);
} catch(std::exception& ex) {
this->notifyError(CommandResult{ErrorType::VSError, ex.what()});
error = command_result{error::vs_critical, std::string{ex.what()}};
goto handle_error;
}
return true;
handle_error:
this->notifyError(error);
error.release_details();
return false;
}
void QueryClient::sendCommand(const ts::Command &command, bool) {

View File

@ -86,7 +86,7 @@ namespace ts {
std::shared_ptr<QueryAccount> query_account;
protected:
CommandResult handleCommand(Command &command) override;
command_result handleCommand(Command &command) override;
public:
//Silent events
@ -144,41 +144,41 @@ namespace ts {
bool notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, const std::string &message, std::shared_ptr<ConnectedClient> invoker, size_t length, bool lock_channel_tree) override;
private:
CommandResult handleCommandExit(Command&);
CommandResult handleCommandLogin(Command&);
CommandResult handleCommandLogout(Command&);
CommandResult handleCommandServerSelect(Command &);
CommandResult handleCommandServerInfo(Command&);
CommandResult handleCommandChannelList(Command&);
CommandResult handleCommandJoin(Command&);
CommandResult handleCommandLeft(Command&);
command_result handleCommandExit(Command&);
command_result handleCommandLogin(Command&);
command_result handleCommandLogout(Command&);
command_result handleCommandServerSelect(Command &);
command_result handleCommandServerInfo(Command&);
command_result handleCommandChannelList(Command&);
command_result handleCommandJoin(Command&);
command_result handleCommandLeft(Command&);
CommandResult handleCommandServerList(Command&);
CommandResult handleCommandServerCreate(Command&);
CommandResult handleCommandServerDelete(Command&);
CommandResult handleCommandServerStart(Command&);
CommandResult handleCommandServerStop(Command&);
command_result handleCommandServerList(Command&);
command_result handleCommandServerCreate(Command&);
command_result handleCommandServerDelete(Command&);
command_result handleCommandServerStart(Command&);
command_result handleCommandServerStop(Command&);
CommandResult handleCommandInstanceInfo(Command&);
CommandResult handleCommandInstanceEdit(Command&);
command_result handleCommandInstanceInfo(Command&);
command_result handleCommandInstanceEdit(Command&);
CommandResult handleCommandBindingList(Command&);
command_result handleCommandBindingList(Command&);
CommandResult handleCommandHostInfo(Command&);
command_result handleCommandHostInfo(Command&);
CommandResult handleCommandGlobalMessage(Command&);
command_result handleCommandGlobalMessage(Command&);
CommandResult handleCommandServerIdGetByPort(Command&);
command_result handleCommandServerIdGetByPort(Command&);
CommandResult handleCommandServerSnapshotDeploy(Command&);
CommandResult handleCommandServerSnapshotCreate(Command&);
CommandResult handleCommandServerProcessStop(Command&);
command_result handleCommandServerSnapshotDeploy(Command&);
command_result handleCommandServerSnapshotCreate(Command&);
command_result handleCommandServerProcessStop(Command&);
CommandResult handleCommandServerNotifyRegister(Command&);
CommandResult handleCommandServerNotifyList(Command&);
CommandResult handleCommandServerNotifyUnregister(Command&);
command_result handleCommandServerNotifyRegister(Command&);
command_result handleCommandServerNotifyList(Command&);
command_result handleCommandServerNotifyUnregister(Command&);
CommandResult handleCommandSetCompressionMode(Command&);
command_result handleCommandSetCompressionMode(Command&);
};
}
}

View File

@ -20,7 +20,7 @@ constexpr unsigned int string_hash(const char* str, int h = 0) {
return !str[h] ? 5381 : (string_hash(str, h + 1U) * 33U) ^ str[h];
}
CommandResult QueryClient::handleCommand(Command& cmd) {
command_result QueryClient::handleCommand(Command& cmd) {
/*
if (cmd.command() == "exit" || cmd.command() == "quit") return this->handleCommandExit(cmd);
else if (cmd.command() == "use" || cmd.command() == "serverselect") return this->handleCommandServerSelect(cmd);
@ -117,14 +117,14 @@ CommandResult QueryClient::handleCommand(Command& cmd) {
return ConnectedClient::handleCommand(cmd);
}
CommandResult QueryClient::handleCommandExit(Command &) {
command_result QueryClient::handleCommandExit(Command &) {
logMessage(LOG_QUERY, "[Query] {}:{} disconnected. (Requested by client)", this->getLoggingPeerIp(), this->getPeerPort());
this->closeConnection(system_clock::now() + seconds(1));
return CommandResult::Success;
return command_result{error::ok};
}
//login client_login_name=andreas client_login_password=meinPW
CommandResult QueryClient::handleCommandLogin(Command& cmd) {
command_result QueryClient::handleCommandLogin(Command& cmd) {
CMD_RESET_IDLE;
std::string username, password;
@ -144,7 +144,7 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
threads::MutexLock lock(this->handle->loginLock);
if(!account)
return {findError("client_invalid_password"), "username or password dose not match"};
return command_result{error::client_invalid_password, "username or password dose not match"};
if (account->password != password) {
if(!this->whitelisted) {
@ -154,15 +154,20 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
this->postCommandHandler.emplace_back([&](){
this->closeConnection(system_clock::now() + seconds(1));
});
return {findError("ban_flooding"), ""};
return command_result{error::ban_flooding};
}
}
return {findError("client_invalid_password"), "username or password dose not match"};
return command_result{error::client_invalid_password, "username or password dose not match"};
}
}
if(!this->properties()[property::CLIENT_LOGIN_NAME].as<string>().empty()) {
Command log("logout");
if(!this->handleCommandLogout(log)) return {ErrorType::VSError, "Failed to logout!"};
auto result = this->handleCommandLogout(log);
if(result.error_code()) {
result.release_details();
logError(this->getServerId(), "Query client failed to login from old login.");
return command_result{error::vs_critical};
}
}
this->query_account = account;
@ -190,7 +195,7 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
if(target_server != this->server)
joined_channel = nullptr;
if(!target_server)
return {findError("server_invalid_id"), "server does not exists anymore"};
return command_result{error::server_invalid_id, "server does not exists anymore"};
}
this->server = target_server;
@ -226,12 +231,12 @@ CommandResult QueryClient::handleCommandLogin(Command& cmd) {
this->properties()[property::CLIENT_TOTALCONNECTIONS]++;
this->updateChannelClientProperties(true, true);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandLogout(Command &) {
command_result QueryClient::handleCommandLogout(Command &) {
CMD_RESET_IDLE;
if(this->properties()[property::CLIENT_LOGIN_NAME].as<string>().empty()) return {findError("client_not_logged_in"), "not logged in"};
if(this->properties()[property::CLIENT_LOGIN_NAME].as<string>().empty()) return command_result{error::client_not_logged_in, "not logged in"};
this->properties()[property::CLIENT_LOGIN_NAME] = "";
this->query_account = nullptr;
@ -278,10 +283,10 @@ CommandResult QueryClient::handleCommandLogout(Command &) {
this->updateChannelClientProperties(true, true);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
command_result QueryClient::handleCommandServerSelect(Command &cmd) {
CMD_RESET_IDLE;
shared_ptr<TSServer> target;
@ -295,18 +300,18 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
if(parm.find_first_not_of("0123456789") == string::npos)
target = serverInstance->getVoiceServerManager()->findServerById(static_cast<ServerId>(stol(parm)));
if(!target && (!cmd[0].has("0") && (!cmd[0].has("sid") || !cmd["sid"] == 0))) return {findError("server_invalid_id"), "Invalid server id"};
if(!target && (!cmd[0].has("0") && (!cmd[0].has("sid") || !cmd["sid"] == 0))) return command_result{error::server_invalid_id, "Invalid server id"};
if(target == this->server) return CommandResult::Success;
if(target == this->server) return command_result{error::ok};
if(target) {
if(this->query_account && this->query_account->bound_server > 0) {
if(target->getServerId() != this->query_account->bound_server)
return {findError("server_invalid_id"), "You're a server bound query, and the target server isn't your origin."};
return command_result{error::server_invalid_id, "You're a server bound query, and the target server isn't your origin."};
} else {
auto allowed = target->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_select, this->getType(), nullptr);
if(allowed != -1 && allowed <= 0) return CommandResultPermissionError{permission::b_virtualserver_select};
if(allowed != -1 && allowed <= 0) return command_result{permission::b_virtualserver_select};
}
}
@ -362,23 +367,23 @@ CommandResult QueryClient::handleCommandServerSelect(Command &cmd) {
}
this->updateChannelClientProperties(true, true);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandJoin(Command &) {
command_result QueryClient::handleCommandJoin(Command &) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
if(!this->server->running())
return {findError("server_is_not_running"), "server isnt started yet"};
return command_result{error::server_is_not_running, "server isnt started yet"};
if(this->currentChannel)
return {findError("server_already_joined"), "already joined!"};
return command_result{error::server_already_joined, "already joined!"};
this->server->assignDefaultChannel(this->ref(), true);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandLeft(Command&) {
command_result QueryClient::handleCommandLeft(Command&) {
CMD_REQ_SERVER;
CMD_REQ_CHANNEL;
CMD_RESET_IDLE;
@ -386,10 +391,10 @@ CommandResult QueryClient::handleCommandLeft(Command&) {
PERM_CHECK_CHANNELR(permission::b_virtualserver_select_godmode, 1, nullptr, 1);
unique_lock server_channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, nullptr, "leaving", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerInfo(Command &) {
command_result QueryClient::handleCommandServerInfo(Command &) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_info_view, 1, true);
@ -469,10 +474,10 @@ CommandResult QueryClient::handleCommandServerInfo(Command &) {
}
this->sendCommand(cmd);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandChannelList(Command& cmd) {
command_result QueryClient::handleCommandChannelList(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_channel_list, 1, true);
CMD_RESET_IDLE;
@ -530,10 +535,10 @@ CommandResult QueryClient::handleCommandChannelList(Command& cmd) {
}
this->sendCommand(result);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerList(Command& cmd) {
command_result QueryClient::handleCommandServerList(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_serverinstance_virtualserver_list, 1, true);
Command res("");
@ -563,15 +568,15 @@ CommandResult QueryClient::handleCommandServerList(Command& cmd) {
}
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerCreate(Command& cmd) {
command_result QueryClient::handleCommandServerCreate(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_create, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED) {
return {findError("vs_critical"), "Server manager isn't started yet or not finished starting"};
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
}
string startError;
@ -583,9 +588,9 @@ CommandResult QueryClient::handleCommandServerCreate(Command& cmd) {
threads::MutexLock lock(serverInstance->getVoiceServerManager()->server_create_lock);
auto instances = serverInstance->getVoiceServerManager()->serverInstances();
if(config::server::max_virtual_server != -1 && instances.size() > config::server::max_virtual_server)
return {findError("server_max_vs_reached"), "You reached the via config.yml enabled virtual server limit."};
return command_result{error::server_max_vs_reached, "You reached the via config.yml enabled virtual server limit."};
if(instances.size() >= 65535)
return {findError("server_max_vs_reached"), "You cant create anymore virtual servers. (Software limit reached)"};
return command_result{error::server_max_vs_reached, "You cant create anymore virtual servers. (Software limit reached)"};
{
auto end = system_clock::now();
time_wait = duration_cast<milliseconds>(end - start);
@ -601,7 +606,7 @@ CommandResult QueryClient::handleCommandServerCreate(Command& cmd) {
auto _end = system_clock::now();
time_create = duration_cast<milliseconds>(_end - _start);
}
if(!server) return {findError("vs_critical"), "could not create new server"};
if(!server) return command_result{error::vs_critical, "could not create new server"};
for(const auto& key : cmd[0].keys()){
if(key == "virtualserver_port") continue;
@ -640,64 +645,64 @@ CommandResult QueryClient::handleCommandServerCreate(Command& cmd) {
res["time_global"] = time_global.count();
res["time_wait"] = time_wait.count();
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerDelete(Command& cmd) {
command_result QueryClient::handleCommandServerDelete(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_delete, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return {findError("vs_critical"), "Server manager isn't started yet or not finished starting"};
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
auto server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]);
if(!server) return {findError("server_invalid_id"), "invalid bounded server"};
if(!serverInstance->getVoiceServerManager()->deleteServer(server)) return {ErrorType::VSError};
return CommandResult::Success;
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
if(!serverInstance->getVoiceServerManager()->deleteServer(server)) return command_result{error::vs_critical};
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerStart(Command& cmd) {
command_result QueryClient::handleCommandServerStart(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_start_any, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return {findError("vs_critical"), "Server manager isn't started yet or not finished starting"};
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
auto server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]);
if(!server) return {findError("server_invalid_id"), "invalid bounded server"};
if(server->running()) return {findError("server_running"), "server already running"};
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
if(server->running()) return command_result{error::server_running, "server already running"};
if(server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_start, ClientType::CLIENT_QUERY, nullptr) != 1) {
if(!this->permissionGranted(permission::PERMTEST_HIGHEST, permission::b_virtualserver_start_any, 1))
return CommandResultPermissionError{permission::b_virtualserver_start};
return command_result{permission::b_virtualserver_start};
}
string err;
if(!server->start(err)) return {findError("vs_critical"), err};
return CommandResult::Success;
if(!server->start(err)) return command_result{error::vs_critical, err};
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerStop(Command& cmd) {
command_result QueryClient::handleCommandServerStop(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_stop, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return {findError("vs_critical"), "Server manager isn't started yet or not finished starting"};
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
auto server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]);
if(!server) return {findError("server_invalid_id"), "invalid bounded server"};
if(!server->running()) return {findError("server_is_not_running"), "server is not running"};
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
if(!server->running()) return command_result{error::server_is_not_running, "server is not running"};
if(server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_stop, ClientType::CLIENT_QUERY, nullptr) != 1) {
if(!this->permissionGranted(permission::PERMTEST_HIGHEST, permission::b_virtualserver_stop_any, 1))
return CommandResultPermissionError{permission::b_virtualserver_stop};
return command_result{permission::b_virtualserver_stop};
}
server->stop("server stopped");
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandInstanceInfo(Command& cmd) {
command_result QueryClient::handleCommandInstanceInfo(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_info_view, 1, true);
Command res("");
@ -707,10 +712,10 @@ CommandResult QueryClient::handleCommandInstanceInfo(Command& cmd) {
res["serverinstance_teaspeak"] = true;
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandInstanceEdit(Command& cmd) {
command_result QueryClient::handleCommandInstanceEdit(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_modify_settings, 1, true);
for(const auto &key : cmd[0].keys()){
@ -730,10 +735,10 @@ CommandResult QueryClient::handleCommandInstanceEdit(Command& cmd) {
}
serverInstance->properties()[info] = cmd[key].string();
}
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandHostInfo(Command &) {
command_result QueryClient::handleCommandHostInfo(Command &) {
PERM_CHECKR(permission::b_serverinstance_info_view, 1, true);
Command res("");
@ -765,37 +770,37 @@ CommandResult QueryClient::handleCommandHostInfo(Command &) {
res["connection_filetransfer_bytes_received_total"] = (*stats)[property::CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL].as<string>();
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandGlobalMessage(Command& cmd) {
command_result QueryClient::handleCommandGlobalMessage(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_textmessage_send, 1, true);
for(const auto &server : serverInstance->getVoiceServerManager()->serverInstances())
if(server->running()) server->broadcastMessage(server->getServerRoot(), cmd["msg"]);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerIdGetByPort(Command& cmd) {
command_result QueryClient::handleCommandServerIdGetByPort(Command& cmd) {
uint16_t port = cmd["virtualserver_port"];
auto server = serverInstance->getVoiceServerManager()->findServerByPort(port);
if(!server) return {findError("databse_empty_result"), "Invalid port"};
if(!server) return command_result{error::server_invalid_id};
Command res("");
res["server_id"] = server->getServerId();
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandBindingList(Command& cmd) {
command_result QueryClient::handleCommandBindingList(Command& cmd) {
Command res("");
res["ip"] = "0.0.0.0 ";
this->sendCommand(res); //TODO maybe list here all bindings from voice & file and query server?
return CommandResult::Success;
return command_result{error::ok};
}
//TODO with mapping!
CommandResult QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_snapshot_deploy, 1, true);
CMD_RESET_IDLE;
@ -809,7 +814,7 @@ CommandResult QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
}
auto hash = cmd["hash"].string();
if(hash.empty()) return {findError("parameter_invalid"), "Invalid hash (not present)"};
if(hash.empty()) return command_result{error::parameter_invalid, "Invalid hash (not present)"};
debugMessage(this->getServerId(), "Serversnapshot calculated hash: {}", hash);
bool mapping = cmd.hasParm("mapping");
cmd.disableParm("mapping");
@ -821,7 +826,7 @@ CommandResult QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
auto str = cmd.build().substr(strlen("serversnapshotdeploy "));
if(!ignore_hash) {
auto buildHash = base64::encode(digest::sha1(str));
if(buildHash != hash) return {findError("parameter_invalid"), "Invalid hash (Expected: \"" + hash + "\", Got: \"" + buildHash + "\")"};
if(buildHash != hash) return command_result{error::parameter_invalid, "Invalid hash (Expected: \"" + hash + "\", Got: \"" + buildHash + "\")"};
}
unique_lock server_create_lock(serverInstance->getVoiceServerManager()->server_create_lock);
@ -853,10 +858,10 @@ CommandResult QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
res["time"] = duration_cast<milliseconds>(end - start).count();
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
CommandResult QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
command_result QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_snapshot_create, 1, true);
CMD_RESET_IDLE;
CMD_REQ_SERVER;
@ -868,7 +873,7 @@ CommandResult QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
if(version == -1 && (cmd.hasParm("lagacy") || cmd.hasParm("legacy")))
version = 0;
if(!serverInstance->getVoiceServerManager()->createServerSnapshot(result, this->server, version, error))
return {ErrorType::VSError, error};
return command_result{error::vs_critical, error};
string data = result.build();
auto buildHash = base64::encode(digest::sha1(data));
@ -877,23 +882,23 @@ CommandResult QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
result[0]["hash"] = buildHash;
this->sendCommand(result);
return CommandResult::Success;
return command_result{error::ok};
}
extern bool mainThreadActive;
CommandResult QueryClient::handleCommandServerProcessStop(Command& cmd) {
command_result QueryClient::handleCommandServerProcessStop(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_stop, 1, true);
if(cmd[0].has("type")) {
if(cmd["type"] == "cancel") {
auto task = ts::server::scheduledShutdown();
if(!task) return {findError("server_is_not_shutting_down"), "There isn't a shutdown scheduled"};
if(!task) return command_result{error::server_is_not_shutting_down, "There isn't a shutdown scheduled"};
ts::server::cancelShutdown(true);
return CommandResult::Success;
return command_result{error::ok};
} else if(cmd["type"] == "schedule") {
if(!cmd[0].has("time")) return {findError("parameter_missing"), "Missing time"};
if(!cmd[0].has("time")) return command_result{error::parameter_missing, "Missing time"};
ts::server::scheduleShutdown(system_clock::now() + seconds(cmd["time"].as<uint64_t>()), cmd[0].has("msg") ? cmd["msg"].string() : ts::config::messages::applicationStopped);
return CommandResult::Success;
return command_result{error::ok};
}
}
@ -904,18 +909,18 @@ CommandResult QueryClient::handleCommandServerProcessStop(Command& cmd) {
reason = cmd["reasonmsg"].string();
serverInstance->getVoiceServerManager()->shutdownAll(reason);
mainThreadActive = false;
return CommandResult::Success;
return command_result{error::ok};
}
#define XMACRO_EV(evName0, evSpec0, evName1, evSpec1) \
if(cmd["event"].value() == "all" || (cmd["event"].value() == (evName0) && (cmd["specifier"].value() == "all" || cmd["specifier"].value() == (evSpec0)))) \
events.push_back({QueryEventGroup::evName1, QueryEventSpecifier::evSpec1});
inline CommandResult parseEvent(ParameterBulk& cmd, vector<pair<QueryEventGroup, QueryEventSpecifier>>& events){
inline bool parseEvent(ParameterBulk& cmd, vector<pair<QueryEventGroup, QueryEventSpecifier>>& events){
auto start = events.size();
#include "XMacroEventTypes.h"
if(start == events.size()) return {findError("parameter_invalid"), "invalid group/specifier"};
return CommandResult::Success;
if(start == events.size()) return false;
return true;
}
#undef XMACRO_EV
@ -923,7 +928,7 @@ inline CommandResult parseEvent(ParameterBulk& cmd, vector<pair<QueryEventGroup,
#define XMACRO_LAGACY_EV(lagacyName, gr, spec) \
if(event == lagacyName) this->toggleEvent(QueryEventGroup::gr, QueryEventSpecifier::spec, true);
CommandResult QueryClient::handleCommandServerNotifyRegister(Command &cmd) {
command_result QueryClient::handleCommandServerNotifyRegister(Command &cmd) {
CMD_REQ_SERVER;
CMD_REQ_PARM("event");
CMD_RESET_IDLE;
@ -932,17 +937,17 @@ CommandResult QueryClient::handleCommandServerNotifyRegister(Command &cmd) {
string event = cmd["event"];
std::transform(event.begin(), event.end(), event.begin(), ::tolower);
#include "XMacroEventTypes.h"
return CommandResult::Success;
return command_result{error::ok};
}
//TODO implement bulk
vector<pair<QueryEventGroup, QueryEventSpecifier>> events;
//parameter_invalid
auto result = parseEvent(cmd[0], events);
if(!result) return result;
if(!result) return command_result{error::parameter_invalid};
for(const auto& ev : events)
this->toggleEvent(ev.first, ev.second, true);
return CommandResult::Success;
return command_result{error::ok};
}
#undef XMACRO_LAGACY_EV
@ -953,7 +958,7 @@ else if((evName1) == group && (evSpec1) == spec){ \
index++; \
}
CommandResult QueryClient::handleCommandServerNotifyList(Command& cmd) {
command_result QueryClient::handleCommandServerNotifyList(Command& cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
@ -970,16 +975,16 @@ CommandResult QueryClient::handleCommandServerNotifyList(Command& cmd) {
}
}
if(index == 0) return {findError("database_empty_result"), ""};
if(index == 0) return command_result{error::database_empty_result};
this->sendCommand(res);
return CommandResult::Success;
return command_result{error::ok};
}
#undef XMACRO_EV
#define XMACRO_LAGACY_EV(lagacyName, gr, spec) \
if(event == lagacyName) this->toggleEvent(QueryEventGroup::gr, QueryEventSpecifier::spec, false);
CommandResult QueryClient::handleCommandServerNotifyUnregister(Command &cmd) {
command_result QueryClient::handleCommandServerNotifyUnregister(Command &cmd) {
CMD_REQ_SERVER;
CMD_REQ_PARM("event");
CMD_RESET_IDLE;
@ -988,15 +993,15 @@ CommandResult QueryClient::handleCommandServerNotifyUnregister(Command &cmd) {
string event = cmd["event"];
std::transform(event.begin(), event.end(), event.begin(), ::tolower);
#include "XMacroEventTypes.h"
return CommandResult::Success;
return command_result{error::ok};
}
//TODO implemt bulk
vector<pair<QueryEventGroup, QueryEventSpecifier>> events;
auto result = parseEvent(cmd[0], events);
if(!result) return result;
if(!result) return command_result{error::parameter_invalid};
for(const auto& ev : events)
this->toggleEvent(ev.first, ev.second, false);
return CommandResult::Success;
return command_result{error::ok};
}
#undef XMACRO_LAGACY_EV

View File

@ -1,5 +1,5 @@
#ifndef XMACRO_EV
#define XMACRO_EV_UNDEF
#ifndef XMACRO_EV
#define XMACRO_EV(a, b, c, d)
#endif
#ifndef XMACRO_LAGACY_EV

View File

@ -85,7 +85,7 @@ namespace ts {
void send_voice_whisper_packet(const pipes::buffer_view &packet, const VoicePacketFlags &flags) override;
protected:
virtual CommandResult handleCommand(Command &command) override;
virtual command_result handleCommand(Command &command) override;
//Some helper method
void sendPingRequest();
@ -106,10 +106,10 @@ namespace ts {
bool final_disconnected = false;
//General TS3 manager commands
CommandResult handleCommandClientInitIv(Command&);
CommandResult handleCommandClientEk(const std::unique_ptr<protocol::ClientPacket>&, Command&);
CommandResult handleCommandClientInit(Command&) override;
CommandResult handleCommandClientDisconnect(Command&);
command_result handleCommandClientInitIv(Command&);
command_result handleCommandClientEk(const std::unique_ptr<protocol::ClientPacket>&, Command&);
command_result handleCommandClientInit(Command&) override;
command_result handleCommandClientDisconnect(Command&);
//Locked by finalDisconnect, disconnect and close connection
std::shared_ptr<threads::Thread> flushing_thread;

View File

@ -16,10 +16,10 @@ using namespace ts::protocol;
using namespace ts;
CommandResult VoiceClient::handleCommand(ts::Command &command) {
command_result 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::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")
@ -55,7 +55,7 @@ inline bool calculate_security_level(int& result, ecc_key* pubKey, size_t offset
return true;
}
CommandResult VoiceClient::handleCommandClientInit(Command &cmd) {
command_result VoiceClient::handleCommandClientInit(Command &cmd) {
this->crypto.client_init = true;
this->connection->acknowledge_handler.reset();
@ -63,22 +63,22 @@ CommandResult VoiceClient::handleCommandClientInit(Command &cmd) {
int securityLevel;
if(!calculate_security_level(securityLevel, this->crypto.remote_key.get(), cmd["client_key_offset"])) {
logError(this->getServerId(), "[{}] Failed to calculate security level. Error code: {}", CLIENT_STR_LOG_PREFIX, securityLevel);
return {ErrorType::VSError};
return command_result{error::vs_critical};
}
if(securityLevel < 8)
return {findError("channel_invalid_security_hash"), "cant calculate security level"};
return command_result{error::client_could_not_validate_identity};
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)};
if(securityLevel < requiredLevel) return command_result{error::client_could_not_validate_identity, to_string(requiredLevel)};
}
this->lastPingResponse = std::chrono::system_clock::now();
return SpeakingClient::handleCommandClientInit(cmd);
}
CommandResult VoiceClient::handleCommandClientDisconnect(Command& cmd) {
command_result 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;
return command_result{error::ok};
}

View File

@ -22,7 +22,7 @@ inline void generate_random(uint8_t *destination, size_t length) {
*(destination++) = (uint8_t) rand();
}
ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
this->last_packet_handshake = system_clock::now();
if(this->state == ConnectionState::CONNECTED) { /* we've a reconnect */
@ -31,13 +31,13 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
CLIENT_STR_LOG_PREFIX,
duration_cast<milliseconds>(system_clock::now() - this->lastPingResponse).count()
);
return CommandResult::Success;
return ts::command_result{error::ok};
} else if(!config::voice::allow_session_reinitialize) {
logMessage(this->getServerId(), "{} Client initialized session reconnect and last ping response is older then 5 seconds ({}). Dropping attempt because its not allowed due to config settings",
CLIENT_STR_LOG_PREFIX,
duration_cast<milliseconds>(system_clock::now() - this->lastPingResponse).count()
);
return CommandResult::Success;
return ts::command_result{error::ok};
}
logMessage(this->getServerId(), "{} Client initialized reconnect and last ping response is older then 5 seconds ({}). Allowing attempt",
CLIENT_STR_LOG_PREFIX,
@ -70,7 +70,7 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
/* normal TeamSpeak handling */
string clientAlpha = base64::decode(command["alpha"]); //random
if(clientAlpha.length() != 10) return {findError("parameter_invalid"), "Invalid alpha"};
if(clientAlpha.length() != 10) return ts::command_result{error::parameter_invalid};
string clientOmega = base64::decode(command["omega"]); //The identity public key
string ip = command["ip"];
@ -85,7 +85,7 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
auto state = ecc_import((const unsigned char *) clientOmega.data(), clientOmega.length(), this->crypto.remote_key.get());
if(state != CRYPT_OK) {
this->crypto.remote_key.reset();
return {ts::findError("client_could_not_validate_identity"), error_to_string(state)};
return ts::command_result{error::client_could_not_validate_identity};
}
this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = base64::encode(digest::sha1(command["omega"].string()));
@ -115,7 +115,10 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
char signBuffer[signBufferLength];
prng_state prngState{};
memset(&prngState, 0, sizeof(prngState));
if(ecc_sign_hash((u_char*) licenseHash.data(), licenseHash.length(), (u_char*) signBuffer, &signBufferLength, &prngState, find_prng("sprng"), this->getServer()->serverKey()) != CRYPT_OK) return {findError("vs_critical"), "Could not sign license!"};
if(ecc_sign_hash((u_char*) licenseHash.data(), licenseHash.length(), (u_char*) signBuffer, &signBufferLength, &prngState, find_prng("sprng"), this->getServer()->serverKey()) != CRYPT_OK) {
logError(this->getServerId(), "Failed to sign crypto chain!");
return ts::command_result{error::vs_critical};
}
auto proof = base64::encode(signBuffer, signBufferLength);
Command initivexpand2("initivexpand2");
@ -134,7 +137,10 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
debugMessage(this->getServerId(), "{} Got non client 3.1 protocol with build timestamp {}", CLIENT_STR_LOG_PREFIX, this->crypto.client_time);
auto serverOmega = this->getServer()->publicServerKey();
if(serverOmega.empty()) return {findError("vs_critical"), "Could not export public key!"};
if(serverOmega.empty()) {
logError(this->getServerId(), "Failed to export server public key!");
return ts::command_result{error::vs_critical};;
}
{
Command initivexpand("initivexpand");
@ -155,17 +161,17 @@ ts::CommandResult VoiceClient::handleCommandClientInitIv(Command& command) {
string error;
if(!this->connection->getCryptHandler()->setupSharedSecret(this->crypto.alpha, this->crypto.beta, this->crypto.remote_key.get(), this->server->serverKey(), error)){
this->connection->getCryptHandler()->unblock();
debugMessage(this->server->getServerId(), "Could not setup shared secret! (" + error + ")");
return {findError("vs_critical"), "Could not setup shared secret"};
logError(this->server->getServerId(), "Could not setup shared secret! (" + error + ")");
return ts::command_result{error::vs_critical};
}
this->connection->getCryptHandler()->unblock();
this->crypto.protocol_encrypted = true;
}
}
return CommandResult::Success;
return ts::command_result{error::ok};
}
ts::CommandResult VoiceClient::handleCommandClientEk(const std::unique_ptr<protocol::ClientPacket>& packet, Command& cmd) {
ts::command_result VoiceClient::handleCommandClientEk(const std::unique_ptr<protocol::ClientPacket>& packet, Command& cmd) {
this->last_packet_handshake = system_clock::now();
debugMessage(this->getServerId(), "{} Got client ek!", CLIENT_STR_LOG_PREFIX);
@ -176,5 +182,5 @@ ts::CommandResult VoiceClient::handleCommandClientEk(const std::unique_ptr<proto
this->connection->acknowledge_handler.reset();
this->crypto.protocol_encrypted = true;
this->sendAcknowledge(packet->packetId()); //Send the encrypted acknowledge
return CommandResult::Success;
return ts::command_result{error::ok};
}

View File

@ -3,7 +3,6 @@
#include <algorithm>
#include <log/LogUtils.h>
#include "../web/WebClient.h"
#include "query/command2.h"
#include "VoiceClient.h"
using namespace std;
@ -18,28 +17,29 @@ void VoiceClient::handlePacketInit(const unique_ptr<ts::protocol::ClientPacket>
//TODO Packet handlers -> move back to voice manager?
void VoiceClient::handlePacketCommand(const std::unique_ptr<protocol::ClientPacket>& packet) {
std::unique_ptr<Command> command;
command_result result{};
try {
command = make_unique<Command>(Command::parse(packet->data(), true, !ts::config::server::strict_ut8_mode));
} catch(std::invalid_argument& ex) {
this->notifyError({findError("parameter_convert"), ex.what()});
return;
} catch(command_malformed_exception& ex) {
this->notifyError({findError("parameter_convert"), ex.what()});
return;
result = command_result{error::parameter_convert, std::string{ex.what()}};
goto handle_error;
} catch(std::exception& ex) {
this->notifyError({findError("parameter_convert"), ex.what()});
return;
result = command_result{error::parameter_convert, std::string{ex.what()}};
goto handle_error;
}
if(command->command() == "clientek") {
auto result = this->handleCommandClientEk(packet, *command);
if(!result)
this->notifyError(result);
result = this->handleCommandClientEk(packet, *command);
if(result.error_code()) goto handle_error;
} else if(command->command() == "clientinitiv") {
auto result = this->handleCommandClientInitIv(*command);
if(!result)
this->notifyError(result);
result = this->handleCommandClientInitIv(*command);
if(result.error_code()) goto handle_error;
} else this->handleCommandFull(*command, true);
return;
handle_error:
this->notifyError(result);
result.release_details();
}
void VoiceClient::handlePacketPing(const std::unique_ptr<protocol::ClientPacket>& packet) {

View File

@ -232,11 +232,11 @@ bool WebClient::closeConnection(const std::chrono::system_clock::time_point& tim
return true;
}
CommandResult WebClient::handleCommand(Command &command) {
command_result WebClient::handleCommand(Command &command) {
if(this->connectionState() == ConnectionState::INIT_HIGH && this->handshake.state == HandshakeState::SUCCEEDED){
if(command.command() == "clientinit") {
auto result = this->handleCommandClientInit(command);
if(!result)
if(result.error_code())
this->closeConnection(system_clock::now() + seconds(1));
return result;
}
@ -624,7 +624,7 @@ bool WebClient::disconnect(const std::string &reason) {
return this->closeConnection(system_clock::now() + seconds(1));
}
CommandResult WebClient::handleCommandClientInit(Command &command) {
command_result WebClient::handleCommandClientInit(Command &command) {
return SpeakingClient::handleCommandClientInit(command);
}

View File

@ -109,8 +109,8 @@ namespace ts {
protected:
CommandResult handleCommand(Command &command) override;
CommandResult handleCommandClientInit(Command &command) override;
command_result handleCommand(Command &command) override;
command_result handleCommandClientInit(Command &command) override;
};
}
}

2
shared

@ -1 +1 @@
Subproject commit 664b73910c99558f9ba14dd2f06dabe67b5f2f2a
Subproject commit d42ec40a58892f4c7ff1da6dd4e69df94e2aa848