diff --git a/git-teaspeak b/git-teaspeak index 965281a..819ba6d 160000 --- a/git-teaspeak +++ b/git-teaspeak @@ -1 +1 @@ -Subproject commit 965281a51a1f8fbaebbfc9cfeaa51dd25ce49385 +Subproject commit 819ba6d0903e1d102fff5921669d223ed72982c4 diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index c35841c..0ae7687 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -267,7 +267,6 @@ target_link_libraries(TeaSpeakServer sqlite3 ${LIBRARY_PATH_BREAKPAD} - ${LIBRARY_PATH_JDBC} ${LIBRARY_PATH_PROTOBUF} #${LIBWEBRTC_LIBRARIES} #ATTENTIAN! WebRTC does not work with crypto! (Already contains a crypto version) diff --git a/server/src/Group.cpp b/server/src/Group.cpp index 5134922..b19efd0 100644 --- a/server/src/Group.cpp +++ b/server/src/Group.cpp @@ -309,7 +309,7 @@ std::shared_ptr GroupManager::createGroup(GroupTarget target, GroupType t return group; } -bool GroupManager::copyGroup(std::shared_ptr group, GroupType type, std::string name, ServerId targetServerId) { +GroupId GroupManager::copyGroup(std::shared_ptr group, GroupType type, std::string name, ServerId targetServerId) { auto group_server = group->handle->getServerId(); auto groupId = generateGroupId(this->sql); @@ -331,14 +331,14 @@ bool GroupManager::copyGroup(std::shared_ptr group, GroupType type, std:: this->loadGroupFormDatabase(groupId); else if(this->root) this->root->loadGroupFormDatabase(groupId); - return true; + return groupId; } bool GroupManager::copyGroupPermissions(const shared_ptr &source, const shared_ptr &target) { auto targetServer = target->handle->getServerId(); auto sourceServer = source->handle->getServerId(); - auto res = sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type AND `id` = :id", variable{":sid", this->getServerId()}, variable{":type", SQL_PERM_GROUP}, variable{":id", target->groupId()}).execute(); + auto res = sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :sid AND `type` = :type AND `id` = :id", variable{":sid", targetServer}, variable{":type", SQL_PERM_GROUP}, variable{":id", target->groupId()}).execute(); LOG_SQL_CMD(res); res = sql::command(this->sql, "INSERT INTO `permissions` (`serverId`, `type`, `id`, `channelId`, `permId`, `value`, `grant`) SELECT :tsid AS `serverId`, `type`, :target AS `id`, 0 AS `channelId`, `permId`, `value`,`grant` FROM `permissions` WHERE `serverId` = :ssid AND `type` = :type AND `id` = :source", diff --git a/server/src/Group.h b/server/src/Group.h index 99b5a4c..0c8d418 100644 --- a/server/src/Group.h +++ b/server/src/Group.h @@ -190,7 +190,7 @@ namespace ts { void setChannelGroup(ClientDbId cldbId, std::shared_ptr, std::shared_ptr , std::chrono::time_point until = std::chrono::time_point()); std::shared_ptr createGroup(GroupTarget target, GroupType type, std::string name); - bool copyGroup(std::shared_ptr group, GroupType type, std::string name, ServerId targetServerId); + GroupId copyGroup(std::shared_ptr group, GroupType type, std::string name, ServerId targetServerId); bool copyGroupPermissions(const std::shared_ptr& source, const std::shared_ptr& target); bool reloadGroupPermissions(std::shared_ptr); diff --git a/server/src/client/ConnectedClientCommandHandler.cpp b/server/src/client/ConnectedClientCommandHandler.cpp index a43c9e2..f9b90df 100644 --- a/server/src/client/ConnectedClientCommandHandler.cpp +++ b/server/src/client/ConnectedClientCommandHandler.cpp @@ -981,46 +981,98 @@ CommandResult ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) { //name=Channel\sAdmin scgid=5 tcgid=4 type=1 CommandResult ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) { - CMD_RESET_IDLE; - CMD_CHK_AND_INC_FLOOD_POINTS(5); + CMD_RESET_IDLE; + CMD_CHK_AND_INC_FLOOD_POINTS(5); + + auto ref_server = this->server; CACHED_PERM_CHECK(permission::b_virtualserver_channelgroup_create, 1, true); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get(); - auto src = group_manager->findGroup(cmd["scgid"].as()); - if (!src || src->target() != GROUPTARGET_CHANNEL) return {findError("parameter_invalid"), "invalid channel group id"}; + auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get(); - bool global = false; - if(cmd[0].has("tcgid")&& cmd["tcgid"].as() != 0) { - auto target = group_manager->findGroup(cmd["tcgid"].as()); - if (!target || target->target() != GROUPTARGET_CHANNEL) return {findError("parameter_invalid"), "invalid target channel group id"}; - auto result = group_manager->copyGroupPermissions(src, target); - if(!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || group_manager->isLocalGroup(target); - } else { - auto type = cmd["type"].as(); - if(type == GroupType::GROUP_TYPE_QUERY) - CACHED_PERM_CHECK(permission::b_serverinstance_modify_querygroup, 1, true); - if(type == GroupType::GROUP_TYPE_TEMPLATE) - CACHED_PERM_CHECK(permission::b_serverinstance_modify_templates, 1, true); + auto source_group_id = cmd["scgid"].as(); + auto source_group = group_manager->findGroup(source_group_id); - if(type == GroupType::GROUP_TYPE_NORMAL && !this->server) return {findError("parameter_invalid"), "You cant create normal channel groups on the template server"}; - auto result = group_manager->copyGroup(src, cmd["type"], cmd["name"], type == GROUP_TYPE_NORMAL ? this->getServerId() : 0); //TODO maybe check by name? No duplicated groups? - if (!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || type != GroupType::GROUP_TYPE_NORMAL; + if(!source_group || source_group->target() != GROUPTARGET_CHANNEL) + return {findError("group_invalid_id"), "invalid source group"}; - if(this->getType() == ClientType::CLIENT_QUERY) { - Command notify(""); - notify["cgid"] = group_manager->availableChannelGroups(false).back()->groupId(); - this->sendCommand(notify); - } - } + const auto group_type_modificable = [&](GroupType type) { + switch(type) { + case GroupType::GROUP_TYPE_TEMPLATE: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_templates, 0), 1, true)) + return permission::b_serverinstance_modify_templates; + break; + case GroupType::GROUP_TYPE_QUERY: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_querygroup, 0), 1, true)) + return permission::b_serverinstance_modify_querygroup; + break; - for(const auto& server : (global ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) - if(server) - server->forEachClient([](shared_ptr cl) { - cl->notifyChannelGroupList(); - }); - return CommandResult::Success; + default: + break; + } + return permission::undefined; + }; + + { + auto result = group_type_modificable(source_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + auto global_update = false; + if(cmd[0].has("tcgid") && cmd["tcgid"].as() != 0) { + //Copy an existing group + auto target_group = group_manager->findGroup(cmd["tcgid"]); + if(!target_group || target_group->target() != GROUPTARGET_CHANNEL) + return {findError("group_invalid_id"), "invalid target group"}; + + { + auto result = group_type_modificable(target_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission_value(permission::i_channel_group_modify_power, 0), true)) + return CommandResultPermissionError{permission::i_channel_group_modify_power}; + + if(!group_manager->copyGroupPermissions(source_group, target_group)) + return {findError("vs_critical"), "failed to copy group permissions"}; + + global_update = !this->server || !group_manager->isLocalGroup(target_group); + } else { + //Copy a new group + auto target_type = cmd["type"].as(); + + { + auto result = group_type_modificable(target_type); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL) + return {findError("parameter_invalid"), "You cant create normal groups on the template server!"}; + + if(!group_manager->findGroup(GroupTarget::GROUPTARGET_CHANNEL, cmd["name"].string()).empty()) + return {findError("group_name_used"), "You cant create normal groups on the template server!"}; + + auto target_group_id = group_manager->copyGroup(source_group, target_type, cmd["name"], target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId()); + if(target_group_id == 0) + return {findError("vs_critical"), "failed to copy group"}; + + if(this->getType() == ClientType::CLIENT_QUERY) { + Command notify(""); + notify["cgid"] = target_group_id; + this->sendCommand(notify); + } + + global_update = !this->server || !group_manager->isLocalGroup(group_manager->findGroup(target_group_id)); + } + + for(const auto& server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) + if(server) + server->forEachClient([](shared_ptr cl) { + cl->notifyChannelGroupList(); + }); + return CommandResult::Success; } CommandResult ConnectedClient::handleCommandChannelGroupRename(Command &cmd) { @@ -2578,48 +2630,94 @@ CommandResult ConnectedClient::handleCommandServerGroupAdd(Command &cmd) { return CommandResult::Success; } -//name=Server\sAdmin\s(Copy) ssgid=1 tsgid=0 type=1 CommandResult ConnectedClient::handleCommandServerGroupCopy(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); + auto ref_server = this->server; CACHED_PERM_CHECK(permission::b_virtualserver_servergroup_create, 1, true); auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get(); - bool global = false; - auto src = group_manager->findGroup(cmd["ssgid"].as()); - if (!src || src->target() != GROUPTARGET_SERVER) return {findError("parameter_invalid"), "invalid server group id"}; - if(cmd[0].has("tsgid") && cmd["tsgid"].as() != 0) { - auto target = group_manager->findGroup(cmd["tsgid"].as()); - if (!target || target->target() != GROUPTARGET_SERVER) return {findError("parameter_invalid"), "invalid target server group id"}; - auto result = group_manager->copyGroupPermissions(src, target); - if(!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || group_manager->isLocalGroup(target); - } else { - //GroupType - auto type = cmd["type"].as(); - if(type == GroupType::GROUP_TYPE_NORMAL && !this->server) return {findError("parameter_invalid"), "You cant create normal groups on the template server!"}; - if(type == GroupType::GROUP_TYPE_QUERY) { - if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_querygroup), 1, true)) - return CommandResultPermissionError{permission::b_serverinstance_modify_querygroup}; - } else if(type == GroupType::GROUP_TYPE_TEMPLATE) { - if(!this->permission_granted(this->cached_permission_value(permission::b_serverinstance_modify_templates), 1, true)) - return CommandResultPermissionError{permission::b_serverinstance_modify_templates}; - } + auto source_group_id = cmd["ssgid"].as(); + auto source_group = group_manager->findGroup(source_group_id); - auto result = group_manager->copyGroup(src, type, cmd["name"], type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId()); //TODO maybe check by name? No duplicated groups? - if (!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || type != GroupType::GROUP_TYPE_NORMAL; + if(!source_group || source_group->target() != GROUPTARGET_SERVER) + return {findError("group_invalid_id"), "invalid source group"}; - if(this->getType() == ClientType::CLIENT_QUERY) { - Command notify(""); - notify["sgid"] = group_manager->availableServerGroups(false).back()->groupId(); - this->sendCommand(notify); - } + const auto group_type_modificable = [&](GroupType type) { + switch(type) { + case GroupType::GROUP_TYPE_TEMPLATE: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_templates, 0), 1, true)) + return permission::b_serverinstance_modify_templates; + break; + case GroupType::GROUP_TYPE_QUERY: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_querygroup, 0), 1, true)) + return permission::b_serverinstance_modify_querygroup; + break; + + default: + break; + } + return permission::undefined; + }; + + { + auto result = group_type_modificable(source_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; } - for(const auto& server : (global ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) + auto global_update = false; + if(cmd[0].has("tsgid") && cmd["tsgid"].as() != 0) { + //Copy an existing group + auto target_group = group_manager->findGroup(cmd["tsgid"]); + if(!target_group || target_group->target() != GROUPTARGET_SERVER) + return {findError("group_invalid_id"), "invalid target group"}; + + { + auto result = group_type_modificable(target_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!target_group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) + return CommandResultPermissionError{permission::i_server_group_modify_power}; + + if(!group_manager->copyGroupPermissions(source_group, target_group)) + return {findError("vs_critical"), "failed to copy group permissions"}; + + global_update = !this->server || !group_manager->isLocalGroup(target_group); + } else { + //Copy a new group + auto target_type = cmd["type"].as(); + + { + auto result = group_type_modificable(target_type); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL) + return {findError("parameter_invalid"), "You cant create normal groups on the template server!"}; + + if(!group_manager->findGroup(GroupTarget::GROUPTARGET_SERVER, cmd["name"].string()).empty()) + return {findError("group_name_used"), "You cant create normal groups on the template server!"}; + + auto target_group_id = group_manager->copyGroup(source_group, target_type, cmd["name"], target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId()); + if(target_group_id == 0) + return {findError("vs_critical"), "failed to copy group"}; + + if(this->getType() == ClientType::CLIENT_QUERY) { + Command notify(""); + notify["sgid"] = target_group_id; + this->sendCommand(notify); + } + + global_update = !this->server || !group_manager->isLocalGroup(group_manager->findGroup(target_group_id)); + } + + for(const auto& server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) if(server) server->forEachClient([](shared_ptr cl) { cl->notifyServerGroupList(); diff --git a/shared b/shared index a3c5bcb..c532266 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit a3c5bcb9f2f36598675da74dfb118b76eeff99fa +Subproject commit c532266cb8b1ba577e063c6ed14a810374c8c84f