Added the action logging system

This commit is contained in:
WolverinDEV
2020-06-28 14:01:14 +02:00
parent 8e16309930
commit 68cfab1ac9
22 changed files with 2988 additions and 86 deletions
@@ -6,10 +6,12 @@
#include <PermissionManager.h>
#include <src/client/ConnectedClient.h>
#include "./helpers.h"
#include "../../manager/ActionLogger.h"
namespace ts::command::bulk_parser {
template <bool kParseValue>
class PermissionBulkParser {
friend class PermissionBulkParser<false>;
public:
explicit PermissionBulkParser(ts::ParameterBulk& bulk) {
if(bulk.has("permid")) {
@@ -45,7 +47,7 @@ namespace ts::command::bulk_parser {
}
}
PermissionBulkParser(const PermissionBulkParser&) = delete;
PermissionBulkParser(PermissionBulkParser&&) = default;
PermissionBulkParser(PermissionBulkParser&&) noexcept = default;
~PermissionBulkParser() {
this->error_.release_data();
@@ -78,9 +80,9 @@ namespace ts::command::bulk_parser {
inline void apply_to(const std::shared_ptr<permission::v2::PermissionManager>& manager, permission::v2::PermissionUpdateType mode) const {
if(this->is_grant_permission()) {
manager->set_permission(this->permission_type(), { 0, this->value() }, permission::v2::PermissionUpdateType::do_nothing, mode);
this->old_value = manager->set_permission(this->permission_type(), { 0, this->value() }, permission::v2::PermissionUpdateType::do_nothing, mode);
} else {
manager->set_permission(
this->old_value = manager->set_permission(
this->permission_type(),
{ this->value(), 0 },
mode,
@@ -91,11 +93,61 @@ namespace ts::command::bulk_parser {
}
}
inline void log_update(
server::log::PermissionActionLogger& logger,
ServerId sid,
const std::shared_ptr<server::ConnectedClient>& issuer,
server::log::PermissionTarget target,
permission::v2::PermissionUpdateType mode,
uint64_t id1, const std::string& id1_name,
uint64_t id2, const std::string& id2_name
) const {
if(this->is_grant_permission()) {
switch (mode) {
case permission::v2::delete_value:
if(!this->old_value.flags.grant_set)
return;
logger.log_permission_remove_grant(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->old_value.values.grant);
break;
case permission::v2::set_value:
if(this->old_value.flags.grant_set) {
logger.log_permission_edit_grant(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->old_value.values.grant, this->value_);
} else {
logger.log_permission_add_grant(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->value_);
}
break;
case permission::v2::do_nothing:
break;
}
} else {
switch (mode) {
case permission::v2::delete_value:
if(!this->old_value.flags.value_set)
return;
logger.log_permission_remove_value(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->old_value.values.value, this->old_value.flags.negate, this->old_value.flags.skip);
break;
case permission::v2::set_value:
if(this->old_value.flags.value_set) {
logger.log_permission_edit_value(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->old_value.values.value, this->old_value.flags.negate, this->old_value.flags.skip, this->value_, this->flag_negated_, this->flag_skip_);
} else {
logger.log_permission_add_value(sid, issuer, target, id1, id1_name, id2, id2_name, *this->permission_, this->old_value.values.value, this->old_value.flags.negate, this->old_value.flags.skip);
}
break;
case permission::v2::do_nothing:
break;
}
}
}
inline void apply_to_channel(const std::shared_ptr<permission::v2::PermissionManager>& manager, permission::v2::PermissionUpdateType mode, ChannelId channel_id) const {
if(this->is_grant_permission()) {
manager->set_channel_permission(this->permission_type(), channel_id, { this->value(), true }, permission::v2::PermissionUpdateType::do_nothing, mode);
this->old_value = manager->set_channel_permission(this->permission_type(), channel_id, { this->value(), true }, permission::v2::PermissionUpdateType::do_nothing, mode);
} else {
manager->set_channel_permission(
this->old_value = manager->set_channel_permission(
this->permission_type(),
channel_id,
{ this->value(), true },
@@ -122,6 +174,7 @@ namespace ts::command::bulk_parser {
permission::PermissionValue value_{0};
ts::command_result error_{error::ok};
mutable permission::v2::PermissionContainer old_value{};
#ifndef NDEBUG
bool error_released_{false};
#endif
@@ -131,7 +184,7 @@ namespace ts::command::bulk_parser {
class PermissionBulksParser {
public:
PermissionBulksParser(const PermissionBulksParser&) = delete;
PermissionBulksParser(PermissionBulksParser&&) = default;
PermissionBulksParser(PermissionBulksParser&&) noexcept = default;
template <typename base_iterator>
struct FilteredPermissionIterator : public base_iterator {
+247 -29
View File
@@ -15,6 +15,7 @@
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include <cstdint>
#include "helpers.h"
@@ -138,11 +139,30 @@ command_result ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1);
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
if(cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_NORMAL && !this->server) return command_result{error::parameter_invalid, "You cant create normal channel groups on the template server"};
if(cmd["name"].string().empty()) return command_result{error::parameter_invalid, "invalid group name"};
log::GroupType log_group_type;
if(cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
log_group_type = log::GroupType::TEMPLATE;
} else {
if(!this->server)
return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"};
log_group_type = log::GroupType::NORMAL;
}
if(cmd["name"].string().empty())
return command_result{error::parameter_invalid, "invalid group name"};
for(const auto& gr : group_manager->availableServerGroups(true))
if(gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "Group already exists"};
if(gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_CHANNEL)
return command_result{error::parameter_invalid, "Group already exists"};
auto group = group_manager->createGroup(GroupTarget::GROUPTARGET_CHANNEL, cmd["type"].as<GroupType>(), cmd["name"].string());
serverInstance->action_logger()->group_logger.log_group_create(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, group->groupId(), group->name(), 0, "");
if (group) {
group->permissions()->set_permission(permission::b_group_is_permanent, {1, 0}, permission::v2::set_value, permission::v2::do_nothing);
if(this->server)
@@ -212,6 +232,28 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
if(!group_manager->copyGroupPermissions(source_group, target_group))
return command_result{error::vs_critical, "failed to copy group permissions"};
log::GroupType log_group_type;
switch (target_group->type()) {
case GroupType::GROUP_TYPE_QUERY:
log_group_type = log::GroupType::QUERY;
break;
case GroupType::GROUP_TYPE_TEMPLATE:
log_group_type = log::GroupType::TEMPLATE;
break;
case GroupType::GROUP_TYPE_NORMAL:
log_group_type = log::GroupType::NORMAL;
break;
default:
return command_result{error::parameter_invalid, "type"};
}
serverInstance->action_logger()->group_logger.log_group_permission_copy(target_group->type() != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
this->ref(), log::GroupTarget::CHANNEL, log_group_type, target_group->groupId(), target_group->name(), source_group->groupId(), source_group->name());
global_update = !this->server || !group_manager->isLocalGroup(target_group);
} else {
//Copy a new group
@@ -223,6 +265,24 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
return command_result{result};
}
log::GroupType log_group_type;
switch (target_type) {
case GroupType::GROUP_TYPE_QUERY:
log_group_type = log::GroupType::QUERY;
break;
case GroupType::GROUP_TYPE_TEMPLATE:
log_group_type = log::GroupType::TEMPLATE;
break;
case GroupType::GROUP_TYPE_NORMAL:
log_group_type = log::GroupType::NORMAL;
break;
default:
return command_result{error::parameter_invalid, "type"};
}
if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL)
return command_result{error::parameter_invalid, "You cant create normal groups on the template server!"};
@@ -232,6 +292,8 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
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 command_result{error::vs_critical, "failed to copy group"};
serverInstance->action_logger()->group_logger.log_group_create(target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
this->ref(), log::GroupTarget::CHANNEL, log_group_type, target_group_id, cmd["name"], source_group->groupId(), source_group->name());
if(this->getType() == ClientType::CLIENT_QUERY) {
Command notify("");
@@ -256,10 +318,26 @@ command_result ConnectedClient::handleCommandChannelGroupRename(Command &cmd) {
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
auto channel_group = group_manager->findGroup(cmd["cgid"].as<GroupId>());
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL)
return command_result{error::parameter_invalid, "invalid channel group id"};
ACTION_REQUIRES_GROUP_PERMISSION(channel_group, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true);
auto type = channel_group->type();
log::GroupType log_group_type;
if(type == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
log_group_type = log::GroupType::TEMPLATE;
} else {
log_group_type = log::GroupType::NORMAL;
}
auto old_name = channel_group->name();
group_manager->renameGroup(channel_group, cmd["name"].string());
serverInstance->action_logger()->group_logger.log_group_rename(this->getServerId(), this->ref(), log::GroupTarget::CHANNEL, log_group_type, channel_group->groupId(), channel_group->name(), old_name);
if(this->server)
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyChannelGroupList();
@@ -285,21 +363,37 @@ command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) {
}
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP] == channel_group->groupId())
return command_result{error::parameter_invalid, "Could not delete instance default channel group!"};
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP] == channel_group->groupId())
return command_result{error::parameter_invalid, "Could not delete instance default channel admin group!"};
auto type = channel_group->type();
log::GroupType log_group_type;
if(type == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
log_group_type = log::GroupType::TEMPLATE;
} else {
log_group_type = log::GroupType::NORMAL;
}
if (!cmd["force"].as<bool>())
if (!group_manager->listGroupMembers(channel_group, false).empty())
return command_result{error::database_empty_result, "group not empty!"};
if (group_manager->deleteGroup(channel_group) && this->server) {
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) {
if(cl->update_cached_permissions()) /* update cached calculated permissions */
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
}
cl->notifyChannelGroupList();
});
if (group_manager->deleteGroup(channel_group)) {
serverInstance->action_logger()->group_logger.log_group_delete(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, channel_group->groupId(), channel_group->name());
if(this->server) {
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) {
if(cl->update_cached_permissions()) /* update cached calculated permissions */
cl->sendNeededPermissions(false); /* cached permissions had changed, notify the client */
}
cl->notifyChannelGroupList();
});
}
}
return command_result{error::ok};
@@ -414,6 +508,15 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
bool updateList{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(channelGroup->permissions(), permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CHANNEL_GROUP,
permission::v2::PermissionUpdateType::set_value,
0, "",
channelGroup->groupId(), channelGroup->name()
);
updateList |= ppermission.is_group_property();
}
@@ -453,6 +556,14 @@ command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
bool updateList{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(channelGroup->permissions(), permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CHANNEL_GROUP,
permission::v2::PermissionUpdateType::delete_value,
0, "",
channelGroup->groupId(), channelGroup->name()
);
updateList |= ppermission.is_group_property();
}
@@ -685,24 +796,50 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
);
}
for (auto &prop : cmd[0].keys()) {
if (prop == "channel_flag_default") continue;
if (prop == "channel_order") continue;
if (prop == "channel_name") continue;
if (prop == "cpid") continue;
if (prop == "cid") continue;
/* log channel create */
{
log::ChannelType log_channel_type;
switch (created_channel->channelType()) {
case ChannelType::permanent:
log_channel_type = log::ChannelType::PERMANENT;
break;
const auto &property = property::find<property::ChannelProperties>(prop);
case ChannelType::semipermanent:
log_channel_type = log::ChannelType::SEMI_PERMANENT;
break;
case ChannelType::temporary:
log_channel_type = log::ChannelType::TEMPORARY;
break;
}
serverInstance->action_logger()->channel_logger.log_channel_create(this->getServerId(), this->ref(), created_channel->channelId(), log_channel_type);
}
for (auto &property_name : cmd[0].keys()) {
if (property_name == "channel_flag_default") continue;
if (property_name == "channel_order") continue;
if (property_name == "channel_name") continue;
if (property_name == "cpid") continue;
if (property_name == "cid") continue;
const auto &property = property::find<property::ChannelProperties>(property_name);
if(property == property::CHANNEL_UNDEFINED) {
logError(this->getServerId(), "Client " + this->getDisplayName() + " tried to change a not existing channel property " + prop);
logError(this->getServerId(), "Client " + this->getDisplayName() + " tried to change a not existing channel property " + property_name);
continue;
}
if(!property.validate_input(cmd[prop].as<string>())) {
logError(this->getServerId(), "Client " + this->getDisplayName() + " tried to change a property to an invalid value. (Value: '" + cmd[prop].as<string>() + "', Property: '" + std::string{property.name} + "')");
if(!property.validate_input(cmd[property_name].as<string>())) {
logError(this->getServerId(), "Client " + this->getDisplayName() + " tried to change a property to an invalid value. (Value: '" + cmd[property_name].as<string>() + "', Property: '" + std::string{property.name} + "')");
continue;
}
created_channel->properties()[property] = cmd[prop].as<std::string>();
auto prop = created_channel->properties()[property];
auto old_value = prop.value();
auto new_value = cmd[property_name].as<std::string>();
if(old_value == new_value)
continue;
prop = new_value;
serverInstance->action_logger()->channel_logger.log_channel_edit(this->getServerId(), this->ref(), created_channel->channelId(), property, old_value, new_value);
}
if(created_channel->parent()) {
if(created_channel->parent()->channelType() > created_channel->channelType())
@@ -738,6 +875,8 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
logError(this->getServerId(), "Missing server's default channel admin group! Using default channel group!");
channel_admin_group = this->server->groups->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL);
}
/* FIXME: Log group assignment */
this->server->groups->setChannelGroup(this->getClientDatabaseId(), channel_admin_group, created_channel);
if (created_channel->channelType() == ChannelType::temporary && (this->getType() == ClientType::CLIENT_TEAMSPEAK || this->getType() == ClientType::CLIENT_WEB))
@@ -776,11 +915,15 @@ command_result ConnectedClient::handleCommandChannelDelete(Command &cmd) {
if(!clients.empty())
ACTION_REQUIRES_PERMISSION(permission::b_channel_delete_flag_force, 1, channel->channelId());
this->server->delete_channel(channel, this->ref(), "channel deleted", channel_tree_write_lock);
this->server->delete_channel(channel, this->ref(), "channel deleted", channel_tree_write_lock, false);
} else {
auto channel_ids = channel_tree->deleteChannelRoot(channel);
this->notifyChannelDeleted(channel_ids, this->ref());
auto deleted_channel_ids = channel_tree->deleteChannelRoot(channel);
for(const auto& channelId : deleted_channel_ids) {
serverInstance->action_logger()->channel_logger.log_channel_delete(0, this->ref(), channelId, channel->channelId() == channelId ? log::ChannelDeleteReason::USER_ACTION : log::ChannelDeleteReason::PARENT_DELETED);
}
this->notifyChannelDeleted(deleted_channel_ids, this->ref());
}
return command_result{error::ok};
}
@@ -1108,9 +1251,15 @@ command_result ConnectedClient::handleCommandChannelEdit(Command &cmd) {
for(const property::PropertyDescription* key : keys) {
if(*key == property::CHANNEL_ORDER) {
/* TODO: May move that up because if it fails may some other props have already be applied */
auto old_channel_order = channel->channelOrder();
if (!channel_tree->change_order(channel, cmd[std::string{key->name}]))
return command_result{error::channel_invalid_order, "Can't change order id"};
auto channel_parent = channel->parent() ? channel->parent()->channelId() : 0;
serverInstance->action_logger()->channel_logger.log_channel_move(this->getServerId(), this->ref(), channel->channelId(),
channel_parent, channel_parent,
old_channel_order, channel->channelOrder());
if(this->server) {
auto parent = channel->hasParent() ? channel_tree->findLinkedChannel(channel->parent()->channelId()) : nullptr;
auto previous = channel_tree->findLinkedChannel(channel->previousChannelId());
@@ -1144,6 +1293,9 @@ command_result ConnectedClient::handleCommandChannelEdit(Command &cmd) {
}
});
}
/* property has already been updated as well the log has also been written */
continue;
} else if(*key == property::CHANNEL_FLAG_DEFAULT) {
old_default_channel = channel_tree->getDefaultChannel();
if(old_default_channel == channel) {
@@ -1216,7 +1368,14 @@ command_result ConnectedClient::handleCommandChannelEdit(Command &cmd) {
channel->permissions()->set_permission(permission::i_client_needed_talk_power, {cmd[key->name].as<int>(), 0}, permission::v2::set_value, permission::v2::do_nothing);
}
channel->properties()[*key] = cmd[std::string{key->name}].string();
auto prop = channel->properties()[*key];
auto old_value = prop.value();
auto new_value = cmd[std::string{key->name}].string();
if(old_value == new_value)
continue;
prop = new_value;
serverInstance->action_logger()->channel_logger.log_channel_edit(this->getServerId(), this->ref(), channel->channelId(), *key, old_value, new_value);
}
if(this->server) {
vector<property::ChannelProperties> key_vector;
@@ -1283,9 +1442,16 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
if(channel->parent() == parent && channel->channelOrder() == (order ? order->channelId() : 0))
return command_result{error::ok};
if (channel->parent() != parent)
auto old_parent_channel_id = channel->parent() ? channel->parent()->channelId() : 0;
auto old_channel_order = channel->channelOrder();
bool change_parent{channel->parent() != parent};
bool change_order{(order ? order->channelId() : 0) != channel->channelOrder()};
if (change_parent)
ACTION_REQUIRES_PERMISSION(permission::b_channel_modify_parent, 1, channel_id);
if ((order ? order->channelId() : 0) != channel->channelOrder())
if (change_order)
ACTION_REQUIRES_PERMISSION(permission::b_channel_modify_sortorder, 1, channel_id);
{
@@ -1331,6 +1497,24 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
} while ((current_channel = dynamic_pointer_cast<ServerChannel>(current_channel->parent())));
}
/* log all the updates */
serverInstance->action_logger()->channel_logger.log_channel_move(this->getServerId(), this->ref(), channel->channelId(),
old_parent_channel_id, channel->parent() ? channel->parent()->channelId() : 0,
old_channel_order, channel->channelOrder());
for(const auto& type_update : channel_type_updates) {
serverInstance->action_logger()->channel_logger.log_channel_edit(this->getServerId(), this->ref(), type_update->channelId(),
property::describe(property::CHANNEL_FLAG_PERMANENT),
"",
type_update->properties()[property::CHANNEL_FLAG_PERMANENT].value()
);
serverInstance->action_logger()->channel_logger.log_channel_edit(this->getServerId(), this->ref(), type_update->channelId(),
property::describe(property::CHANNEL_FLAG_SEMI_PERMANENT),
"",
type_update->properties()[property::CHANNEL_FLAG_SEMI_PERMANENT].value()
);
}
if(this->server) {
auto self_rev = this->ref();
this->server->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
@@ -1442,8 +1626,17 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
auto permission_manager = channel->permissions();
auto updateClients = false, update_join_permissions = false, update_channel_properties = false;
auto channelId = channel->channelId();
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(permission_manager, permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CHANNEL,
permission::v2::PermissionUpdateType::set_value,
channelId, channel->name(),
0, ""
);
updateClients |= ppermission.is_client_view_property();
update_join_permissions = ppermission.permission_type() == permission::i_channel_needed_join_power;
@@ -1480,8 +1673,17 @@ command_result ConnectedClient::handleCommandChannelDelPerm(Command &cmd) {
auto permission_manager = channel->permissions();
auto updateClients = false, update_join_permissions = false, update_channel_properties = false;
auto channelId = channel->channelId();
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(permission_manager, permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CHANNEL,
permission::v2::PermissionUpdateType::delete_value,
channelId, channel->name(),
0, ""
);
updateClients |= ppermission.is_client_view_property();
update_join_permissions = ppermission.permission_type() == permission::i_channel_needed_join_power;
@@ -1586,6 +1788,14 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd)
bool update_view{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to_channel(mgr, permission::v2::PermissionUpdateType::delete_value, channel->channelId());
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CLIENT_CHANNEL,
permission::v2::PermissionUpdateType::delete_value,
cldbid, "",
channel->channelId(), channel->name()
);
update_view |= ppermission.is_client_view_property();
}
@@ -1646,6 +1856,14 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
bool update_view{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to_channel(mgr, permission::v2::PermissionUpdateType::set_value, channel->channelId());
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CLIENT_CHANNEL,
permission::v2::PermissionUpdateType::set_value,
cldbid, "",
channel->channelId(), channel->name()
);
update_view |= ppermission.is_client_view_property();
}
+45 -2
View File
@@ -15,6 +15,7 @@
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include <cstdint>
#include "helpers.h"
@@ -77,6 +78,7 @@ command_result ConnectedClient::handleCommandClientKick(Command &cmd) {
result.emplace_result(error::client_invalid_id);
continue;
}
if (client->getType() == CLIENT_MUSIC) {
result.emplace_result(error::client_invalid_type);
continue;
@@ -101,11 +103,16 @@ command_result ConnectedClient::handleCommandClientKick(Command &cmd) {
}
for(auto& client : clients) {
auto old_channel = client->getChannel();
if(!old_channel) continue;
if (target_channel) {
this->server->notify_client_kick(client.client, this->ref(), cmd["reasonmsg"].as<std::string>(), target_channel);
serverInstance->action_logger()->client_channel_logger.log_client_kick(this->getServerId(), this->ref(), client->ref(), target_channel->channelId(), target_channel->name(), old_channel->channelId(), old_channel->name());
} else {
this->server->notify_client_kick(client.client, this->ref(), cmd["reasonmsg"].as<std::string>(), nullptr);
client->close_connection(system_clock::now() + seconds(1));
serverInstance->action_logger()->client_channel_logger.log_client_kick(this->getServerId(), this->ref(), client->ref(), 0, "", old_channel->channelId(), old_channel->name());
}
}
@@ -257,6 +264,9 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
true,
server_channel_w_lock
);
serverInstance->action_logger()->client_channel_logger.log_client_move(this->getServerId(), this->ref(), client->ref(), channel->channelId(), channel->name(), oldChannel->channelId(), oldChannel->name());
if(std::find_if(channels.begin(), channels.end(), [&](const std::shared_ptr<BasicChannel>& channel) { return &*channel == &*oldChannel; }) == channels.end())
channels.push_back(oldChannel);
}
@@ -266,7 +276,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
server_channel_w_lock.lock();
if(oldChannel->channelType() == ChannelType::temporary && oldChannel->properties()[property::CHANNEL_DELETE_DELAY].as<int64_t>() == 0)
if(this->server->getClientsByChannelRoot(oldChannel, false).empty())
this->server->delete_channel(dynamic_pointer_cast<ServerChannel>(oldChannel), this->ref(), "temporary auto delete", server_channel_w_lock);
this->server->delete_channel(dynamic_pointer_cast<ServerChannel>(oldChannel), this->ref(), "temporary auto delete", server_channel_w_lock, true);
if(server_channel_w_lock.owns_lock())
server_channel_w_lock.unlock();
}
@@ -701,8 +711,24 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
if(*key.first == property::CLIENT_IS_PRIORITY_SPEAKER) {
client->clientPermissions->set_permission(permission::b_client_is_priority_speaker, {1, 0}, cmd["client_is_priority_speaker"].as<bool>() ? permission::v2::PermissionUpdateType::set_value : permission::v2::PermissionUpdateType::delete_value, permission::v2::PermissionUpdateType::do_nothing);
}
client->properties()[key.first] = cmd[0][key.second].value();
auto property = client->properties()[key.first];
auto old_value = property.value();
auto new_value = cmd[0][key.second].value();
if(old_value == new_value)
continue;
property = new_value;
updates.push_back(key.first);
serverInstance->action_logger()->client_edit_logger.log_client_edit(
this->getServerId(),
this->ref(),
client,
*key.first,
old_value,
new_value
);
}
if(update_talk_rights)
client->updateTalkRights(client->properties()[property::CLIENT_TALK_POWER]);
@@ -954,6 +980,15 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) {
bool update_channels{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(mgr, permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CLIENT,
permission::v2::PermissionUpdateType::set_value,
cldbid, "",
0, ""
);
update_channels |= ppermission.is_client_view_property();
}
@@ -989,6 +1024,14 @@ command_result ConnectedClient::handleCommandClientDelPerm(Command &cmd) {
bool update_channels{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(mgr, permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::CLIENT,
permission::v2::PermissionUpdateType::delete_value,
cldbid, "",
0, ""
);
update_channels |= ppermission.is_client_view_property();
}
+35 -5
View File
@@ -19,6 +19,7 @@
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include "helpers.h"
#include <files/FileServer.h>
@@ -185,6 +186,7 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
if(!virtual_file_server) return command_result{error::file_virtual_server_not_registered};
auto& file_system = file::server()->file_system();
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
@@ -194,6 +196,7 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
if(!channel->permission_granted(permission::i_ft_needed_directory_create_power, this->calculate_permission(permission::i_ft_directory_create_power, channel->channelId()), true))
return command_result{permission::i_ft_directory_create_power};
channel_tree_lock.unlock();
auto create_result = file_system.create_channel_directory(virtual_file_server, channel->channelId(), cmd["dirname"].string());
if(!create_result->wait_for(kFileAPITimeout))
@@ -217,6 +220,8 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
}
}
serverInstance->action_logger()->file_logger.log_file_directory_create(this->getServerId(), this->ref(), channel->channelId(), cmd["dirname"].string());
return command_result{error::ok};
}
@@ -234,9 +239,12 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
ts::command_result_bulk response{};
response.emplace_result_n(cmd.bulkCount(), error::ok);
std::vector<std::tuple<uint64_t, std::string>> file_log_info{};
auto file_path = cmd["path"].string();
std::shared_ptr<file::ExecuteResponse<file::filesystem::FileDeleteError, file::filesystem::FileDeleteResponse>> delete_response{};
if (cmd[0].has("cid") && cmd["cid"] != 0) {
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
@@ -249,8 +257,11 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
std::vector<std::string> delete_files{};
delete_files.reserve(cmd.bulkCount());
for(size_t index{0}; index < cmd.bulkCount(); index++)
file_log_info.reserve(cmd.bulkCount());
for(size_t index{0}; index < cmd.bulkCount(); index++) {
delete_files.push_back(file_path + "/" + cmd[index]["name"].string());
file_log_info.emplace_back(channel->channelId(), file_path + "/" + cmd[index]["name"].string());
}
delete_response = file_system.delete_channel_files(virtual_file_server, channel->channelId(), delete_files);
} else {
@@ -261,6 +272,7 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
std::vector<std::string> delete_files{};
delete_files.reserve(cmd.bulkCount());
file_log_info.reserve(cmd.bulkCount());
for(size_t index{0}; index < cmd.bulkCount(); index++) {
auto file_name = cmd[index]["name"].string();
if(!file_name.starts_with("/icon_")) {
@@ -269,6 +281,7 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
}
delete_files.push_back(file_name);
file_log_info.emplace_back(0, file_name);
}
delete_response = file_system.delete_icons(virtual_file_server, delete_files);
@@ -281,6 +294,7 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
std::vector<std::string> delete_files{};
delete_files.reserve(cmd.bulkCount());
file_log_info.reserve(cmd.bulkCount());
for(size_t index{0}; index < cmd.bulkCount(); index++) {
auto file_name = cmd[index]["name"].string();
if(!file_name.starts_with("/avatar_")) {
@@ -311,9 +325,12 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
}
delete_files.push_back("/avatar_" + avId);
file_log_info.emplace_back(0, "/avatar_" + avId);
} else {
this->properties()[property::CLIENT_FLAG_AVATAR] = "";
this->server->notifyClientPropertyUpdates(_this.lock(), deque<property::ClientProperties>{property::CLIENT_FLAG_AVATAR});
delete_files.push_back("/avatar_" + this->getAvatarId());
file_log_info.emplace_back(0, "/avatar_" + this->getAvatarId());
}
}
@@ -341,13 +358,17 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
const auto& file_status = delete_response->response();
size_t bulk_index{0};
for(const auto& file : file_status.delete_results) {
for(size_t index{0}; index < file_status.delete_results.size(); index++) {
const auto& file = file_status.delete_results[index];
const auto& log_file_info = file_log_info[index];
while(response.response(bulk_index).error_code() != error::ok)
bulk_index++;
using Status = file::filesystem::FileDeleteResponse::StatusType;
switch (file.status) {
case Status::SUCCESS:
serverInstance->action_logger()->file_logger.log_file_delete(this->getServerId(), this->ref(), std::get<0>(log_file_info), std::get<1>(log_file_info));
/* we already emplaced success */
break;
@@ -491,8 +512,7 @@ command_result ConnectedClient::handleCommandFTGetFileInfo(ts::Command &cmd) {
auto avId = hex::hex(base64::decode(uid), 'a', 'q');
delete_files.push_back("/avatar_" + avId);
} else {
this->properties()[property::CLIENT_FLAG_AVATAR] = "";
this->server->notifyClientPropertyUpdates(_this.lock(), deque<property::ClientProperties>{property::CLIENT_FLAG_AVATAR});
delete_files.push_back("/avatar_" + this->getAvatarId());
}
}
@@ -641,8 +661,9 @@ command_result ConnectedClient::handleCommandFTInitUpload(ts::Command &cmd) {
return command_result{error::file_transfer_client_quota_exceeded};
}
ChannelId log_channel_id{0};
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id, "Cant resolve channel"};
@@ -652,6 +673,7 @@ command_result ConnectedClient::handleCommandFTInitUpload(ts::Command &cmd) {
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_upload_power, permission::i_ft_file_upload_power, true);
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_UPLOAD, virtual_file_server, channel->channelId(), info);
log_channel_id = channel->channelId();
} else {
if (cmd["path"].string().empty() && cmd["name"].string().starts_with("/icon_")) {
auto max_size = this->calculate_permission(permission::i_max_icon_filesize, 0);
@@ -727,6 +749,7 @@ command_result ConnectedClient::handleCommandFTInitUpload(ts::Command &cmd) {
result.put_unchecked(0, "proto", "1");
this->sendCommand(result);
serverInstance->action_logger()->file_logger.log_file_upload(this->getServerId(), this->ref(), log_channel_id, info.file_path);
return command_result{error::ok};
}
@@ -781,7 +804,9 @@ command_result ConnectedClient::handleCommandFTInitDownload(ts::Command &cmd) {
info.client_id = this->getClientId();
info.max_concurrent_transfers = kMaxClientTransfers;
ChannelId log_channel_id{0};
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
if (!channel)
return command_result{error::channel_invalid_id};
@@ -791,6 +816,7 @@ command_result ConnectedClient::handleCommandFTInitDownload(ts::Command &cmd) {
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_download_power, permission::i_ft_file_download_power, true);
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_DOWNLOAD, virtual_file_server, channel->channelId(), info);
log_channel_id = channel->channelId();
} else {
if (cmd["path"].as<std::string>().empty() && cmd["name"].string().starts_with("/icon_")) {
transfer_response = file::server()->file_transfer().initialize_icon_transfer(file::transfer::Transfer::DIRECTION_DOWNLOAD, virtual_file_server, info);
@@ -859,6 +885,7 @@ command_result ConnectedClient::handleCommandFTInitDownload(ts::Command &cmd) {
result.put_unchecked(0, "seekpos", transfer->file_offset);
this->sendCommand(result);
serverInstance->action_logger()->file_logger.log_file_download(this->getServerId(), this->ref(), log_channel_id, info.file_path);
return command_result{error::ok};
}
@@ -881,6 +908,7 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
auto channel_id = cmd["cid"].as<ChannelId>();
auto target_channel_id = cmd[0].has("tcid") ? cmd["tcid"].as<ChannelId>() : channel_id;
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
auto channel = this->server->channelTree->findChannel(channel_id);
if (!channel)
return command_result{error::channel_invalid_id};
@@ -900,6 +928,7 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
ACTION_REQUIRES_CHANNEL_PERMISSION(targetChannel, permission::i_ft_needed_file_rename_power, permission::i_ft_file_rename_power, true);
}
channel_tree_lock.unlock();
auto rename_response = file::server()->file_system().rename_channel_file(virtual_file_server, channel_id, cmd["oldname"].string(), target_channel_id, cmd["newname"].string());
@@ -933,6 +962,7 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
}
}
serverInstance->action_logger()->file_logger.log_file_rename(this->getServerId(), this->ref(), channel_id, cmd["oldname"].string(), target_channel_id, cmd["newname"].string());
return command_result{error::ok};
}
+162 -13
View File
@@ -23,6 +23,7 @@
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include <experimental/filesystem>
#include <cstdint>
#include <StringVariable.h>
@@ -211,6 +212,9 @@ command_result ConnectedClient::handleCommand(Command &cmd) {
else if (command == "help") return this->handleCommandHelp(cmd);
else if (command == "logview") return this->handleCommandLogView(cmd);
else if (command == "logquery") return this->handleCommandLogQuery(cmd);
else if (command == "logadd") return this->handleCommandLogAdd(cmd);
else if (command == "servergroupautoaddperm") return this->handleCommandServerGroupAutoAddPerm(cmd);
else if (command == "servergroupautodelperm") return this->handleCommandServerGroupAutoDelPerm(cmd);
@@ -448,23 +452,28 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
}
}
std::shared_ptr<GroupAssignment> old_group;
{
auto old_group = this->server->groups->getChannelGroupExact(target_cldbid, channel, false);
old_group = this->server->groups->getChannelGroupExact(target_cldbid, channel, false);
if(old_group) {
auto channel_group_member_remove_power = this->calculate_permission(permission::i_channel_group_member_remove_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) {
if(!old_group->group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) {
if(target_cldbid != this->getClientDatabaseId())
return command_result{permission::i_channel_group_member_remove_power};
auto channel_group_self_remove_power = this->calculate_permission(permission::i_channel_group_self_remove_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_self_remove_power, true))
if(!old_group->group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_self_remove_power, true))
return command_result{permission::i_channel_group_self_remove_power};
}
}
}
this->server->groups->setChannelGroup(target_cldbid, serverGroup, channel);
std::shared_ptr<ConnectedClient> connected_client{};
for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) {
connected_client = targetClient;
unique_lock client_channel_lock_w(targetClient->channel_lock);
auto updates = this->server->groups->update_server_group_property(targetClient, false, targetClient->getChannel()); /* needs a write lock */
client_channel_lock_w.unlock();
@@ -487,6 +496,21 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
targetClient->updateChannelClientProperties(false, true);
}
if(old_group) {
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_remove(this->getServerId(),
this->ref(), log::GroupTarget::CHANNEL,
old_group->group->groupId(), old_group->group->name(),
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
);
}
if(serverGroup != this->server->groups->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL)) {
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_add(this->getServerId(),
this->ref(), log::GroupTarget::CHANNEL,
serverGroup->groupId(), serverGroup->name(),
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
);
}
return command_result{error::ok};
}
@@ -684,8 +708,9 @@ command_result ConnectedClient::handleCommandBanAdd(Command &cmd) {
bool banned = false;
if(existing) {
if(existing->invokerDbId == this->getClientDatabaseId()) {
if(existing->until == until) return command_result{error::database_duplicate_entry};
else {
if(existing->until == until) {
return command_result{error::database_duplicate_entry};
} else {
existing->until = until;
serverInstance->banManager()->updateBan(existing);
banned = true;
@@ -694,7 +719,9 @@ command_result ConnectedClient::handleCommandBanAdd(Command &cmd) {
serverInstance->banManager()->unban(existing);
}
}
if(!banned) serverInstance->banManager()->registerBan(sid, this->getClientDatabaseId(), banreason, uid, ip, name, hwid, until);
if(!banned) {
serverInstance->banManager()->registerBan(sid, this->getClientDatabaseId(), banreason, uid, ip, name, hwid, until);
}
for(auto server : (this->server ? std::deque<shared_ptr<VirtualServer>>{this->server} : serverInstance->getVoiceServerManager()->serverInstances()))
server->testBanStateChange(_this.lock());
@@ -1934,19 +1961,21 @@ command_result ConnectedClient::handleCommandPermReset(ts::Command& cmd) {
command_result ConnectedClient::handleCommandLogView(ts::Command& cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(50);
auto lagacy = this->getType() == CLIENT_TEAMSPEAK || cmd.hasParm("lagacy") || cmd.hasParm("legacy");
string log_path;
ServerId target_server = cmd[0].has("instance") && cmd["instance"].as<bool>() ? (ServerId) 0 : this->getServerId();
string server_identifier;
if(target_server > 0)
server_identifier = to_string(target_server);
else server_identifier = "[A-Z]{0,7}";
if(target_server == 0)
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_log_view, 1);
else
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_log_view, 1);
auto lagacy = this->getType() == CLIENT_TEAMSPEAK || cmd.hasParm("lagacy") || cmd.hasParm("legacy");
#if 0
string log_path;
string server_identifier;
if(target_server > 0)
server_identifier = to_string(target_server);
else
server_identifier = "[A-Z]{0,7}";
for(const auto& sink : logger::logger(target_server)->sinks()) {
if(dynamic_pointer_cast<spdlog::sinks::rotating_file_sink_mt>(sink)) {
log_path = dynamic_pointer_cast<spdlog::sinks::rotating_file_sink_mt>(sink)->filename();
@@ -2077,7 +2106,127 @@ command_result ConnectedClient::handleCommandLogView(ts::Command& cmd) {
}
}
this->sendCommand(result);
#else
constexpr static std::array<std::string_view, 5> log_output{
"The command 'logview' is not supported anymore.",
"In order to lookup the server actions use 'logquery'.",
"",
"If you need to lookup the TeaSpeak - Server logs, please visit the 'logs/' folder,",
"located at your TeaSpeak installation folder. All logs could be found there."
};
command_builder result{this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifyserverlog" : ""};
size_t index{0};
if(lagacy) {
for(const auto& message : log_output) {
std::string line{"2020-06-27 00:00.0000|CRITICAL|Server Instance | |"};
line += message;
result.put_unchecked(index++, "l", line);
}
} else {
for(const auto& message : log_output) {
std::string line{"[2020-06-27 00:00:00][ERROR] "};
line += message;
result.put_unchecked(index++, "l", line);
}
}
this->sendCommand(result);
#endif
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandLogQuery(ts::Command &cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(50);
uint64_t target_server = (cmd[0].has("instance") && cmd["instance"].as<bool>()) || cmd.hasParm("instance") ? (ServerId) 0 : this->getServerId();
if(target_server == 0) {
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_log_view, 1);
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_log_view, 1);
}
std::chrono::system_clock::time_point timestamp_begin{}, timestamp_end{};
if(cmd[0].has("begin"))
timestamp_begin += std::chrono::milliseconds{cmd["begin"].as<uint64_t>()};
if(cmd[0].has("end"))
timestamp_end += std::chrono::milliseconds{cmd["end"].as<uint64_t>()};
if(timestamp_begin <= timestamp_end && timestamp_begin.time_since_epoch().count() != 0)
return command_result{error::parameter_constraint_violation, "begin > end"};
size_t limit{100};
if(cmd[0].has("limit"))
limit = std::min((size_t) 2000, cmd["limit"].as<size_t>());
std::vector<log::LoggerGroup> groups{};
if(cmd[0].has("groups")) {
auto groups_string = cmd["groups"].string();
size_t offset{0}, findex;
do {
findex = groups_string.find(',', offset);
auto group_name = groups_string.substr(offset, findex - offset);
offset = findex + 1;
size_t index{0};
for(; index < (size_t) log::LoggerGroup::MAX; index++) {
auto group = static_cast<log::LoggerGroup>(index);
if(log::kLoggerGroupName[(int) group] == group_name) {
if(std::find(groups.begin(), groups.end(), group) != groups.end())
return command_result{error::parameter_invalid, "groups"};
groups.push_back(group);
}
}
if(index == (size_t) log::LoggerGroup::MAX)
return command_result{error::parameter_invalid, "groups"};
} while(offset != 0);
}
auto result = serverInstance->action_logger()->query(groups, target_server, timestamp_begin, timestamp_end, limit);
if(result.empty())
return command_result{error::database_empty_result};
command_builder notify{this->notify_response_command("notifylogquery")};
size_t index{0};
size_t threshold = this->getType() == ClientType::CLIENT_QUERY ? (size_t) -1 : 4096; /* limit each command to 4096 bytes */
for(log::LogEntryInfo& entry : result) {
notify.set_bulk(index, std::move(entry.info));
if(index == 0)
notify.put_unchecked(0, "sid", this->getServerId());
if(notify.current_size() > threshold) {
this->sendCommand(notify);
notify.reset();
index = 0;
}
index++;
}
if(index> 0)
this->sendCommand(notify);
if(this->getType() != ClientType::CLIENT_QUERY)
this->sendCommand(command_builder{"notifylogqueryfinished"});
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandLogAdd(ts::Command& cmd) {
CMD_CHK_AND_INC_FLOOD_POINTS(50);
uint64_t target_server = cmd[0].has("instance") && cmd["instance"].as<bool>() ? (ServerId) 0 : this->getServerId();
if(target_server == 0) {
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_log_add, 1);
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_log_add, 1);
}
serverInstance->action_logger()->custom_logger.add_log_message(target_server, this->ref(), cmd["msg"]);
return command_result{error::ok};
}
+40 -4
View File
@@ -561,8 +561,17 @@ command_result ConnectedClient::handleCommandPlaylistAddPerm(ts::Command &cmd) {
if(!pparser.validate(this->ref(), 0))
return pparser.build_command_result();
for(const auto& ppermission : pparser.iterate_valid_permissions())
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(playlist->permission_manager(), permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::PLAYLIST,
permission::v2::PermissionUpdateType::set_value,
playlist->playlist_id(), "",
0, ""
);
}
return pparser.build_command_result();
}
@@ -582,8 +591,17 @@ command_result ConnectedClient::handleCommandPlaylistDelPerm(ts::Command &cmd) {
if(!pparser.validate(this->ref(), 0))
return pparser.build_command_result();
for(const auto& ppermission : pparser.iterate_valid_permissions())
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(playlist->permission_manager(), permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::PLAYLIST,
permission::v2::PermissionUpdateType::delete_value,
playlist->playlist_id(), "",
0, ""
);
}
return pparser.build_command_result();
}
@@ -705,8 +723,17 @@ command_result ConnectedClient::handleCommandPlaylistClientAddPerm(ts::Command &
if(!pparser.validate(this->ref(), this->getClientDatabaseId()))
return pparser.build_command_result();
for(const auto& ppermission : pparser.iterate_valid_permissions())
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to_channel(playlist->permission_manager(), permission::v2::PermissionUpdateType::set_value, client_id);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::PLAYLIST_CLIENT,
permission::v2::PermissionUpdateType::set_value,
playlist->playlist_id(), "",
client_id, ""
);
}
return pparser.build_command_result();
}
@@ -730,8 +757,17 @@ command_result ConnectedClient::handleCommandPlaylistClientDelPerm(ts::Command &
if(!pparser.validate(this->ref(), this->getClientDatabaseId()))
return pparser.build_command_result();
for(const auto& ppermission : pparser.iterate_valid_permissions())
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to_channel(playlist->permission_manager(), permission::v2::PermissionUpdateType::delete_value, client_id);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::PLAYLIST_CLIENT,
permission::v2::PermissionUpdateType::delete_value,
playlist->playlist_id(), "",
client_id, ""
);
}
return pparser.build_command_result();
}
+140 -14
View File
@@ -19,6 +19,7 @@
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include "../../manager/ActionLogger.h"
#include "helpers.h"
#include "./bulk_parsers.h"
@@ -67,6 +68,7 @@ command_result ConnectedClient::handleCommandServerEdit(Command &cmd) {
target_server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]);
if(!target_server && cmd["sid"].as<ServerId>() != 0) return command_result{error::server_invalid_id};
}
ServerId serverId = target_server ? target_server->serverId : 0;
auto cache = make_shared<CalculateCache>();
map<string, string> toApplay;
@@ -220,10 +222,13 @@ command_result ConnectedClient::handleCommandServerEdit(Command &cmd) {
logError(target_server ? target_server->getServerId() : 0, "Client " + this->getDisplayName() + " tried to change a property to an invalid value. (Value: '" + elm.second + "', Property: '" + std::string{info.name} + "')");
continue;
}
if(target_server)
target_server->properties()[info] = elm.second;
else
(*serverInstance->getDefaultServerProperties())[info] = elm.second;
auto property = target_server ? target_server->properties()[info] : (*serverInstance->getDefaultServerProperties())[info];
if(property.value() == elm.second)
continue;
auto old_value = property.value();
property = elm.second;
serverInstance->action_logger()->server_edit_logger.log_server_edit(serverId, this->ref(), info, old_value, elm.second);
keys.push_back(elm.first);
group_update |= info == property::VIRTUALSERVER_DEFAULT_SERVER_GROUP || info == property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP || info == property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP;
@@ -301,23 +306,33 @@ command_result ConnectedClient::handleCommandServerGroupAdd(Command &cmd) {
if(cmd["name"].string().empty()) return command_result{error::parameter_invalid};
log::GroupType log_group_type;
if(cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(cmd["type"].as<GroupType>() == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
} else if(!this->server) return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"};
log_group_type = log::GroupType::TEMPLATE;
} else {
if(!this->server)
return command_result{error::parameter_invalid, "you cant create normal groups on the template server!"};
log_group_type = log::GroupType::NORMAL;
}
auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get();
for(const auto& gr : group_manager->availableServerGroups(true))
if(gr->name() == cmd["name"].string() && gr->target() == GroupTarget::GROUPTARGET_SERVER) return command_result{error::parameter_invalid, "Group already exists"};
auto group = group_manager->createGroup(GroupTarget::GROUPTARGET_SERVER, cmd["type"].as<GroupType>(), cmd["name"].string());
if (group) {
group->permissions()->set_permission(permission::b_group_is_permanent, {1,0}, permission::v2::set_value, permission::v2::do_nothing);
if(this->server)
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyServerGroupList();
});
} else return command_result{error::vs_critical};
if(!group)
return command_result{error::vs_critical};
group->permissions()->set_permission(permission::b_group_is_permanent, {1,0}, permission::v2::set_value, permission::v2::do_nothing);
if(this->server) {
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyServerGroupList();
});
}
serverInstance->action_logger()->group_logger.log_group_create(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, group->groupId(), group->name(), 0, "");
return command_result{error::ok};
}
@@ -379,6 +394,28 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
if(!group_manager->copyGroupPermissions(source_group, target_group))
return command_result{error::vs_critical, "failed to copy group permissions"};
log::GroupType log_group_type;
switch (target_group->type()) {
case GroupType::GROUP_TYPE_QUERY:
log_group_type = log::GroupType::QUERY;
break;
case GroupType::GROUP_TYPE_TEMPLATE:
log_group_type = log::GroupType::TEMPLATE;
break;
case GroupType::GROUP_TYPE_NORMAL:
log_group_type = log::GroupType::NORMAL;
break;
default:
return command_result{error::parameter_invalid, "type"};
}
serverInstance->action_logger()->group_logger.log_group_permission_copy(target_group->type() != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
this->ref(), log::GroupTarget::SERVER, log_group_type, target_group->groupId(), target_group->name(), source_group->groupId(), source_group->name());
global_update = !this->server || !group_manager->isLocalGroup(target_group);
} else {
//Copy a new group
@@ -389,6 +426,23 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
if(result != permission::undefined)
return command_result{result};
}
log::GroupType log_group_type;
switch (target_type) {
case GroupType::GROUP_TYPE_QUERY:
log_group_type = log::GroupType::QUERY;
break;
case GroupType::GROUP_TYPE_TEMPLATE:
log_group_type = log::GroupType::TEMPLATE;
break;
case GroupType::GROUP_TYPE_NORMAL:
log_group_type = log::GroupType::NORMAL;
break;
default:
return command_result{error::parameter_invalid, "type"};
}
if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL)
return command_result{error::parameter_invalid, "You cant create normal groups on the template server!"};
@@ -400,6 +454,8 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
if(target_group_id == 0)
return command_result{error::vs_critical, "failed to copy group"};
serverInstance->action_logger()->group_logger.log_group_create(target_type != GroupType::GROUP_TYPE_NORMAL ? 0 : this->getServerId(),
this->ref(), log::GroupTarget::SERVER, log_group_type, target_group_id, cmd["name"].string(), source_group->groupId(), source_group->name());
if(this->getType() == ClientType::CLIENT_QUERY) {
Command notify("");
notify["sgid"] = target_group_id;
@@ -428,13 +484,20 @@ command_result ConnectedClient::handleCommandServerGroupRename(Command &cmd) {
ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true);
auto type = serverGroup->type();
log::GroupType log_group_type;
if(type == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
log_group_type = log::GroupType::TEMPLATE;
} else {
log_group_type = log::GroupType::NORMAL;
}
auto old_name = serverGroup->name();
group_manager->renameGroup(serverGroup, cmd["name"].string());
serverInstance->action_logger()->group_logger.log_group_rename(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, serverGroup->groupId(), serverGroup->name(), old_name);
if(this->server)
this->server->forEachClient([](shared_ptr<ConnectedClient> cl) {
cl->notifyServerGroupList();
@@ -456,18 +519,26 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) {
if(this->server && this->server->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] == serverGroup->groupId())
return command_result{error::parameter_invalid, "Could not delete default server group!"};
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP] == serverGroup->groupId())
return command_result{error::parameter_invalid, "Could not delete instance default server admin group!"};
if(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP] == serverGroup->groupId())
return command_result{error::parameter_invalid, "Could not delete instance default server group!"};
if(serverInstance->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP] == serverGroup->groupId())
return command_result{error::parameter_invalid, "Could not delete instance default guest server query group!"};
auto type = serverGroup->type();
log::GroupType log_group_type;
if(type == GroupType::GROUP_TYPE_QUERY) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_querygroup, 1);
log_group_type = log::GroupType::QUERY;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_serverinstance_modify_templates, 1);
log_group_type = log::GroupType::TEMPLATE;
} else {
log_group_type = log::GroupType::NORMAL;
}
if (!cmd["force"].as<bool>())
@@ -475,6 +546,7 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) {
return command_result{error::database_empty_result, "group not empty!"};
if (group_manager->deleteGroup(serverGroup)) {
serverInstance->action_logger()->group_logger.log_group_delete(this->getServerId(), this->ref(), log::GroupTarget::SERVER, log_group_type, serverGroup->groupId(), serverGroup->name());
if(this->server)
this->server->forEachClient([&](shared_ptr<ConnectedClient> cl) {
if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) {
@@ -613,8 +685,10 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
}
}
std::shared_ptr<ConnectedClient> connected_client{};
for(const auto& _server : target_server ? std::deque<shared_ptr<VirtualServer>>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) {
for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) {
connected_client = targetClient;
if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true, targetClient->getChannel()))) {
for (const auto &client : _server->getClients()) {
if(client->isClientVisible(targetClient, true) || client == targetClient)
@@ -627,6 +701,13 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
}
}
}
for(const auto& group : applied_groups) {
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_add(target_server ? target_server->getServerId() : 0,
this->ref(), log::GroupTarget::SERVER,
group->groupId(), group->name(),
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
);
}
return command_result{error::ok};
}
@@ -740,8 +821,10 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
}
}
std::shared_ptr<ConnectedClient> connected_client{};
for(const auto& _server : target_server ? std::deque<shared_ptr<VirtualServer>>{target_server} : serverInstance->getVoiceServerManager()->serverInstances()) {
for (const auto &targetClient : _server->findClientsByCldbId(target_cldbid)) {
connected_client = targetClient;
ConnectedLockedClient clock{targetClient};
if(!clock) continue;
@@ -757,6 +840,13 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
}
}
}
for(const auto& group : applied_groups) {
serverInstance->action_logger()->group_assignment_logger.log_group_assignment_remove(target_server ? target_server->getServerId() : 0,
this->ref(), log::GroupTarget::SERVER,
group->groupId(), group->name(),
target_cldbid, connected_client ? connected_client->getDisplayName() : ""
);
}
return command_result{error::ok};
}
@@ -803,6 +893,15 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
auto permissions = serverGroup->permissions();
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(serverGroup->permissions(), permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::SERVER_GROUP,
permission::v2::PermissionUpdateType::set_value,
serverGroup->groupId(), serverGroup->name(),
0, ""
);
update_server_group_list |= ppermission.is_group_property();
update_talk_power |= ppermission.is_client_view_property();
}
@@ -859,6 +958,15 @@ command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) {
bool update_talk_power{false}, update_server_group_list{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
ppermission.apply_to(serverGroup->permissions(), permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::SERVER_GROUP,
permission::v2::PermissionUpdateType::delete_value,
serverGroup->groupId(), serverGroup->name(),
0, ""
);
update_server_group_list |= ppermission.is_group_property();
update_talk_power |= ppermission.is_client_view_property();
}
@@ -923,8 +1031,17 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
bool update_clients{false}, update_server_group_list{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
for(const auto& serverGroup : groups)
for(const auto& serverGroup : groups) {
ppermission.apply_to(serverGroup->permissions(), permission::v2::PermissionUpdateType::set_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::SERVER_GROUP,
permission::v2::PermissionUpdateType::set_value,
serverGroup->groupId(), serverGroup->name(),
0, ""
);
}
update_server_group_list |= ppermission.is_group_property();
update_clients |= ppermission.is_client_view_property();
@@ -993,8 +1110,17 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
bool update_clients{false}, update_server_group_list{false};
for(const auto& ppermission : pparser.iterate_valid_permissions()) {
for(const auto& serverGroup : groups)
for(const auto& serverGroup : groups) {
ppermission.apply_to(serverGroup->permissions(), permission::v2::PermissionUpdateType::delete_value);
ppermission.log_update(serverInstance->action_logger()->permission_logger,
this->getServerId(),
this->ref(),
log::PermissionTarget::SERVER_GROUP,
permission::v2::PermissionUpdateType::delete_value,
serverGroup->groupId(), serverGroup->name(),
0, ""
);
}
update_server_group_list |= ppermission.is_group_property();
update_clients |= ppermission.is_client_view_property();