Added the action logging system
This commit is contained in:
parent
8e16309930
commit
68cfab1ac9
|
@ -141,6 +141,9 @@ set(SERVER_SOURCE_FILES
|
|||
src/snapshots/groups.cpp
|
||||
src/snapshots/deploy.cpp
|
||||
|
||||
src/manager/ActionLogger.cpp
|
||||
src/manager/ActionLoggerImpl.cpp
|
||||
|
||||
src/manager/ConversationManager.cpp
|
||||
src/client/SpeakingClientHandshake.cpp
|
||||
src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#endif
|
||||
#include <unistd.h>
|
||||
#include <files/FileServer.h>
|
||||
#include "./manager/ActionLogger.h"
|
||||
|
||||
#undef _POSIX_SOURCE
|
||||
|
||||
|
@ -49,6 +50,13 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) {
|
|||
}
|
||||
this->dbHelper = new DatabaseHelper(this->getSql());
|
||||
|
||||
this->action_logger_ = std::make_unique<log::ActionLogger>();
|
||||
if(!this->action_logger_->initialize(error_message)) {
|
||||
logCritical(LOG_INSTANCE, "Failed to initialize instance action logs: {}", error_message);
|
||||
logCritical(LOG_INSTANCE, "Action log has been disabled.");
|
||||
this->action_logger_->finalize();
|
||||
}
|
||||
|
||||
this->_properties = new Properties();
|
||||
this->_properties->register_property_type<property::InstanceProperties>();
|
||||
this->properties()[property::SERVERINSTANCE_FILETRANSFER_PORT] = ts::config::binding::DefaultFilePort;
|
||||
|
|
|
@ -27,6 +27,10 @@ namespace ts {
|
|||
class FileServerHandler;
|
||||
}
|
||||
|
||||
namespace log {
|
||||
class ActionLogger;
|
||||
}
|
||||
|
||||
class InstanceHandler {
|
||||
public:
|
||||
explicit InstanceHandler(SqlDataManager*);
|
||||
|
@ -51,6 +55,7 @@ namespace ts {
|
|||
BanManager* banManager(){ return this->banMgr; }
|
||||
ssl::SSLManager* sslManager(){ return this->sslMgr; }
|
||||
sql::SqlManager* getSql(){ return sql->sql(); }
|
||||
log::ActionLogger* action_logger() { return &*this->action_logger_; }
|
||||
file::FileServerHandler* getFileServerHandler() { return this->file_server_handler_; }
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> getStartTimestamp(){ return startTimestamp; }
|
||||
|
@ -120,7 +125,7 @@ namespace ts {
|
|||
BanManager* banMgr = nullptr;
|
||||
ssl::SSLManager* sslMgr = nullptr;
|
||||
file::FileServerHandler* file_server_handler_{nullptr};
|
||||
|
||||
std::unique_ptr<log::ActionLogger> action_logger_{nullptr};
|
||||
|
||||
ts::Properties* _properties = nullptr;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <misc/timer.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/sassert.h>
|
||||
#include <src/manager/ActionLogger.h>
|
||||
#include "InstanceHandler.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -323,7 +324,7 @@ void VirtualServer::notify_client_kick(
|
|||
*
|
||||
* Note: channel cant be a ref because the channel itself gets deleted!
|
||||
*/
|
||||
void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const shared_ptr<ConnectedClient> &invoker, const std::string& kick_message, unique_lock<std::shared_mutex> &tree_lock) {
|
||||
void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const shared_ptr<ConnectedClient> &invoker, const std::string& kick_message, unique_lock<std::shared_mutex> &tree_lock, bool temp_delete) {
|
||||
if(!tree_lock.owns_lock())
|
||||
tree_lock.lock();
|
||||
if(channel->deleted)
|
||||
|
@ -358,7 +359,12 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
|||
tree_lock.lock(); /* no clients left within that tree */
|
||||
command_locks.clear();
|
||||
|
||||
auto channel_ids = this->channelTree->delete_channel_root(channel);
|
||||
auto deleted_channels = this->channelTree->delete_channel_root(channel);
|
||||
log::ChannelDeleteReason delete_reason{temp_delete ? log::ChannelDeleteReason::EMPTY : log::ChannelDeleteReason::USER_ACTION};
|
||||
for(const auto& deleted_channel : deleted_channels) {
|
||||
serverInstance->action_logger()->channel_logger.log_channel_delete(this->serverId, invoker, deleted_channel->channelId(), channel == deleted_channel ? delete_reason : log::ChannelDeleteReason::PARENT_DELETED);
|
||||
}
|
||||
|
||||
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
client->notifyChannelDeleted(client->channels->delete_channel_root(channel), invoker);
|
||||
|
|
|
@ -187,7 +187,7 @@ void VirtualServer::executeServerTick() {
|
|||
if(system_clock::now() - last_left < deleteTimeout) continue; //One second stay
|
||||
if(system_clock::now() - channel_created < deleteTimeout + seconds(1)) continue; //One second stay
|
||||
|
||||
this->delete_channel(server_channel, this->serverRoot, "temporary autodelete", channel_lock);
|
||||
this->delete_channel(server_channel, this->serverRoot, "temporary auto delete", channel_lock, true);
|
||||
if(channel_lock.owns_lock())
|
||||
channel_lock.unlock();
|
||||
}
|
||||
|
|
|
@ -270,7 +270,8 @@ namespace ts {
|
|||
std::shared_ptr<ServerChannel> /* target channel */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
const std::string& /* kick message */,
|
||||
std::unique_lock<std::shared_mutex>& /* tree lock */
|
||||
std::unique_lock<std::shared_mutex>& /* tree lock */,
|
||||
bool temporary_auto_delete
|
||||
);
|
||||
|
||||
void send_text_message(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* sender */, const std::string& /* message */);
|
||||
|
|
|
@ -416,13 +416,13 @@ namespace ts {
|
|||
command_result handleCommandChannelDelPerm(Command&);
|
||||
|
||||
//Server group manager management
|
||||
command_result handleCommandServerGroupCopy(Command&);
|
||||
command_result handleCommandServerGroupAdd(Command&);
|
||||
command_result handleCommandServerGroupCopy(Command&);
|
||||
command_result handleCommandServerGroupRename(Command&);
|
||||
command_result handleCommandServerGroupDel(Command&);
|
||||
command_result handleCommandServerGroupClientList(Command&);
|
||||
command_result handleCommandServerGroupDelClient(Command&);
|
||||
command_result handleCommandServerGroupAddClient(Command&);
|
||||
command_result handleCommandServerGroupDelClient(Command&);
|
||||
command_result handleCommandServerGroupPermList(Command&);
|
||||
command_result handleCommandServerGroupAddPerm(Command&);
|
||||
command_result handleCommandServerGroupDelPerm(Command&);
|
||||
|
@ -598,6 +598,8 @@ namespace ts {
|
|||
|
||||
command_result handleCommandLogView(Command&);
|
||||
//CMD_TODO handleCommandLogAdd
|
||||
command_result handleCommandLogQuery(Command&);
|
||||
command_result handleCommandLogAdd(Command&);
|
||||
|
||||
command_result handleCommandListFeatureSupport(Command &cmd);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "src/InstanceHandler.h"
|
||||
#include "StringVariable.h"
|
||||
#include "misc/timer.h"
|
||||
#include "../manager/ActionLogger.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace ts;
|
||||
|
@ -800,11 +801,15 @@ void SpeakingClient::processJoin() {
|
|||
}
|
||||
}
|
||||
debugMessage(this->getServerId(), "{} Client join timings: {}", CLIENT_STR_LOG_PREFIX, TIMING_FINISH(timings));
|
||||
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_join(this->getServerId(), this->ref(), this->getChannelId(), this->currentChannel->name());
|
||||
}
|
||||
|
||||
void SpeakingClient::processLeave() {
|
||||
auto ownLock = _this.lock();
|
||||
auto server = this->getServer();
|
||||
|
||||
auto channel = this->currentChannel;
|
||||
if(server){
|
||||
logMessage(this->getServerId(), "Voice client {}/{} ({}) from {} left.", this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), this->getLoggingPeerIp() + ":" + to_string(this->getPeerPort()));
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <src/ShutdownHelper.h>
|
||||
#include <ThreadPool/Timer.h>
|
||||
#include <numeric>
|
||||
#include "src/manager/ActionLogger.h"
|
||||
|
||||
#include "src/client/command_handler/helpers.h"
|
||||
|
||||
|
@ -154,8 +155,10 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
|||
{
|
||||
threads::MutexLock lock(this->handle->loginLock);
|
||||
|
||||
if(!account)
|
||||
if(!account) {
|
||||
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), username, log::QueryAuthenticateResult::UNKNOWN_USER);
|
||||
return command_result{error::client_invalid_password, "username or password dose not match"};
|
||||
}
|
||||
|
||||
if (account->password != password) {
|
||||
if(!this->whitelisted) {
|
||||
|
@ -168,6 +171,8 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
|||
return command_result{error::ban_flooding};
|
||||
}
|
||||
}
|
||||
|
||||
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), username, log::QueryAuthenticateResult::INVALID_PASSWORD);
|
||||
return command_result{error::client_invalid_password, "username or password dose not match"};
|
||||
}
|
||||
}
|
||||
|
@ -242,12 +247,13 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
|||
this->properties()[property::CLIENT_TOTALCONNECTIONS]++;
|
||||
this->updateChannelClientProperties(true, true);
|
||||
|
||||
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), username, log::QueryAuthenticateResult::SUCCESS);
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
command_result QueryClient::handleCommandLogout(Command &) {
|
||||
CMD_RESET_IDLE;
|
||||
if(this->properties()[property::CLIENT_LOGIN_NAME].as<string>().empty()) return command_result{error::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};
|
||||
this->properties()[property::CLIENT_LOGIN_NAME] = "";
|
||||
this->query_account = nullptr;
|
||||
|
||||
|
@ -293,6 +299,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
|
|||
}
|
||||
|
||||
this->updateChannelClientProperties(true, true);
|
||||
serverInstance->action_logger()->query_authenticate_logger.log_query_authenticate(this->getServerId(), std::dynamic_pointer_cast<QueryClient>(this->ref()), "", log::QueryAuthenticateResult::SUCCESS);
|
||||
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
@ -315,6 +322,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
|
|||
if(target && target->getState() != ServerState::ONLINE && target->getState() != ServerState::OFFLINE) return command_result{error::server_is_not_running};
|
||||
if(target == this->server) return command_result{error::ok};
|
||||
|
||||
auto old_server_id = this->getServerId();
|
||||
if(target) {
|
||||
if(this->query_account && this->query_account->bound_server > 0) {
|
||||
if(target->getServerId() != this->query_account->bound_server)
|
||||
|
@ -362,7 +370,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
|
|||
this->update_cached_permissions();
|
||||
}
|
||||
this->updateChannelClientProperties(true, true);
|
||||
|
||||
serverInstance->action_logger()->query_logger.log_query_switch(std::dynamic_pointer_cast<QueryClient>(this->ref()), this->properties()[property::CLIENT_LOGIN_NAME].value(), old_server_id, this->getServerId());
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
|
@ -632,6 +640,7 @@ command_result QueryClient::handleCommandServerCreate(Command& cmd) {
|
|||
|
||||
time_global = duration_cast<milliseconds>(end - start);
|
||||
}
|
||||
serverInstance->action_logger()->server_logger.log_server_create(server->getServerId(), this->ref(), log::ServerCreateReason::USER_ACTION);
|
||||
|
||||
Command res("");
|
||||
res["sid"] = server->getServerId();
|
||||
|
@ -656,6 +665,7 @@ command_result QueryClient::handleCommandServerDelete(Command& cmd) {
|
|||
auto server = serverInstance->getVoiceServerManager()->findServerById(cmd["sid"]);
|
||||
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
|
||||
if(!serverInstance->getVoiceServerManager()->deleteServer(server)) return command_result{error::vs_critical};
|
||||
serverInstance->action_logger()->server_logger.log_server_delete(server->getServerId(), this->ref());
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
|
@ -684,7 +694,9 @@ command_result QueryClient::handleCommandServerStart(Command& cmd) {
|
|||
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_start_any, 1);
|
||||
|
||||
string err;
|
||||
if(!server->start(err)) return command_result{error::vs_critical, err};
|
||||
if(!server->start(err))
|
||||
return command_result{error::vs_critical, err};
|
||||
serverInstance->action_logger()->server_logger.log_server_start(server->getServerId(), this->ref());
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
|
@ -712,6 +724,7 @@ command_result QueryClient::handleCommandServerStop(Command& cmd) {
|
|||
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_stop_any, 1);
|
||||
|
||||
server->stop("server stopped", false);
|
||||
serverInstance->action_logger()->server_logger.log_server_stop(server->getServerId(), this->ref());
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
|
@ -846,7 +859,8 @@ command_result 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 command_result{error::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);
|
||||
|
@ -874,6 +888,7 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
|
|||
res["error_start"] = "";
|
||||
res["started"] = true;
|
||||
}
|
||||
serverInstance->action_logger()->server_logger.log_server_create(result->getServerId(), this->ref(), log::ServerCreateReason::SNAPSHOT_DEPLOY);
|
||||
}
|
||||
|
||||
res["time"] = duration_cast<milliseconds>(end - start).count();
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "VoiceClient.h"
|
||||
#include "src/VirtualServer.h"
|
||||
#include "../../server/VoiceServer.h"
|
||||
#include "src/InstanceHandler.h"
|
||||
#include "src/manager/ActionLogger.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
@ -146,6 +148,11 @@ bool VoiceClient::disconnect(ts::ViewReasonId reason_id, const std::string &reas
|
|||
cmd["invokeruid"] = invoker->getUid();
|
||||
}
|
||||
|
||||
auto old_channel = this->currentChannel;
|
||||
if(old_channel) {
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_leave(this->getServerId(), this->ref(), old_channel->channelId(), old_channel->name());
|
||||
}
|
||||
|
||||
if(notify_viewer && this->server) {
|
||||
unique_lock channel_lock(this->server->channel_tree_lock);
|
||||
this->server->client_move(this->ref(), nullptr, invoker, reason, reason_id, false, channel_lock);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <src/client/ConnectedClient.h>
|
||||
#include <misc/std_unique_ptr.h>
|
||||
#include <src/client/SpeakingClient.h>
|
||||
#include "../../manager/ActionLogger.h"
|
||||
|
||||
#if defined(TCP_CORK) && !defined(TCP_NOPUSH)
|
||||
#define TCP_NOPUSH TCP_CORK
|
||||
|
@ -637,6 +638,10 @@ void WebClient::handleMessage(const std::string &message) {
|
|||
//candidate:0 1 UDP 2122252543 192.168.43.141 34590 typ host
|
||||
|
||||
bool WebClient::disconnect(const std::string &reason) {
|
||||
auto old_channel = this->currentChannel;
|
||||
if(old_channel) {
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_leave(this->getServerId(), this->ref(), old_channel->channelId(), old_channel->name());
|
||||
}
|
||||
{
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
{
|
||||
|
|
|
@ -0,0 +1,449 @@
|
|||
//
|
||||
// Created by WolverinDEV on 26/06/2020.
|
||||
//
|
||||
|
||||
#include "ActionLogger.h"
|
||||
#include "../client/ConnectedClient.h"
|
||||
#include <sql/sqlite/SqliteSQL.h>
|
||||
#include <log/LogUtils.h>
|
||||
|
||||
using namespace ts::server;
|
||||
using namespace ts::server::log;
|
||||
|
||||
Invoker log::kInvokerSystem{"System", "system", 0};
|
||||
|
||||
void AbstractActionLogger::do_log(ServerId sid, Action action, sql::command &command) const {
|
||||
if(!this->enabled_) return;
|
||||
|
||||
command.executeLater().waitAndGetLater([sid, action](const sql::result& result) {
|
||||
if(!result) {
|
||||
logError(sid, "Failed to log action {}: {}", kActionName[(int) action], result.fmtStr());
|
||||
}
|
||||
}, sql::result{});
|
||||
}
|
||||
|
||||
template <>
|
||||
void TypedActionLogger<>::compile_model(sql::model &result, const std::string &command, const ActionLogger *logger) {
|
||||
std::exchange(result, sql::model{logger->sql_manager(), command});
|
||||
}
|
||||
|
||||
template <>
|
||||
void TypedActionLogger<>::register_invoker(ActionLogger *logger, const Invoker &invoker) {
|
||||
logger->register_invoker(invoker);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string TypedActionLogger<>::generate_insert(const std::string &table_name,
|
||||
const FixedHeaderKeys& header,
|
||||
DatabaseColumn *payload_columns,
|
||||
size_t payload_columns_length) {
|
||||
std::string result{"INSERT INTO `"};
|
||||
result.reserve(256);
|
||||
|
||||
result += table_name + "` (";
|
||||
result += "`" + header.timestamp.name + "`,";
|
||||
result += "`" + header.server_id.name + "`,";
|
||||
result += "`" + header.invoker_id.name + "`,";
|
||||
result += "`" + header.invoker_name.name + "`,";
|
||||
result += "`" + header.action.name + "`";
|
||||
|
||||
for(size_t index{0}; index < payload_columns_length; index++)
|
||||
result += ",`" + payload_columns[index].name + "`";
|
||||
|
||||
result += ") VALUES (:h0, :h1, :h2, :h3, :h4";
|
||||
|
||||
for(size_t index{0}; index < payload_columns_length; index++)
|
||||
result += ", " + TypedActionLogger::value_binding_name(index);
|
||||
result += ");";
|
||||
|
||||
debugMessage(0, "Insert query: {}", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
sql::command TypedActionLogger<>::compile_query(
|
||||
ActionLogger *logger,
|
||||
uint64_t server_id,
|
||||
const std::chrono::system_clock::time_point &begin_timestamp,
|
||||
const std::chrono::system_clock::time_point &end_timestamp, size_t limit,
|
||||
const std::string& table_name,
|
||||
const FixedHeaderKeys& header,
|
||||
DatabaseColumn *payload_columns,
|
||||
size_t payload_columns_length) {
|
||||
std::string command{"SELECT "};
|
||||
command.reserve(256);
|
||||
|
||||
command += "`" + header.timestamp.name + "`,";
|
||||
command += "`" + header.server_id.name + "`,";
|
||||
command += "`" + header.invoker_id.name + "`,";
|
||||
command += "`" + header.invoker_name.name + "`,";
|
||||
command += "`" + header.action.name + "`";
|
||||
|
||||
for(size_t index{0}; index < payload_columns_length; index++)
|
||||
command += ",`" + payload_columns[index].name + "`";
|
||||
|
||||
command += " FROM `" + table_name + "` WHERE `" + header.server_id.name + "` = " + std::to_string(server_id);
|
||||
|
||||
if(begin_timestamp.time_since_epoch().count() > 0)
|
||||
command += " AND `" + header.timestamp.name + "` <= " + std::to_string(std::chrono::ceil<std::chrono::milliseconds>(begin_timestamp.time_since_epoch()).count());
|
||||
|
||||
if(begin_timestamp.time_since_epoch().count() > 0)
|
||||
command += " AND `" + header.timestamp.name + "` >= " + std::to_string(std::chrono::floor<std::chrono::milliseconds>(end_timestamp.time_since_epoch()).count());
|
||||
|
||||
command += " ORDER BY `timestamp` DESC";
|
||||
if(limit > 0)
|
||||
command += " LIMIT " + std::to_string(limit);
|
||||
command += ";";
|
||||
|
||||
debugMessage(0, "Log query: {}", command);
|
||||
return sql::command{logger->sql_manager(), command};
|
||||
}
|
||||
|
||||
template <>
|
||||
bool TypedActionLogger<>::create_table(
|
||||
std::string& error,
|
||||
ActionLogger *logger,
|
||||
const std::string& table_name,
|
||||
const FixedHeaderKeys& header,
|
||||
DatabaseColumn *payload_columns,
|
||||
size_t payload_columns_length) {
|
||||
std::string command{};
|
||||
/* ATTENTION: If I implement MySQL add "CHARACTER SET=utf8" AT THE END! */
|
||||
if(logger->sql_manager()->getType() != sql::TYPE_SQLITE) {
|
||||
error = "unsupported database type";
|
||||
return false;
|
||||
}
|
||||
|
||||
command.reserve(256);
|
||||
command += "CREATE TABLE `" + table_name + "` (";
|
||||
command += "`id` INTEGER PRIMARY KEY NOT NULL,";
|
||||
command += "`" + header.timestamp.name + "` " + header.timestamp.type + ",";
|
||||
command += "`" + header.server_id.name + "` " + header.server_id.type + ",";
|
||||
command += "`" + header.invoker_id.name + "` " + header.invoker_id.type + ",";
|
||||
command += "`" + header.invoker_name.name + "` " + header.invoker_name.type + ",";
|
||||
command += "`" + header.action.name + "` " + header.action.type;
|
||||
|
||||
for(size_t index{0}; index < payload_columns_length; index++)
|
||||
command += ",`" + payload_columns[index].name + "` " + payload_columns[index].type;
|
||||
|
||||
command += ");";
|
||||
|
||||
auto result = sql::command{logger->sql_manager(), command}.execute();
|
||||
if(!result) {
|
||||
error = result.fmtStr();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool TypedActionLogger<>::parse_fixed_header(FixedHeaderValues &result, std::string *values, size_t values_length) {
|
||||
if(values_length< 5)
|
||||
return false;
|
||||
|
||||
int64_t timestamp;
|
||||
try {
|
||||
timestamp = std::stoll(values[0]);
|
||||
result.server_id = std::stoull(values[1]);
|
||||
result.invoker.database_id = std::stoull(values[2]);
|
||||
} catch (std::exception&) {
|
||||
return false;
|
||||
}
|
||||
result.timestamp = std::chrono::system_clock::time_point{} + std::chrono::milliseconds{timestamp};
|
||||
result.invoker.name = values[3];
|
||||
|
||||
result.action = Action::UNKNOWN;
|
||||
for(size_t index{0}; index < (size_t) Action::MAX; index++) {
|
||||
auto action = static_cast<Action>(index);
|
||||
if(kActionName[index] == values[4]) {
|
||||
result.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
return result.action != Action::UNKNOWN;
|
||||
}
|
||||
|
||||
template <>
|
||||
void TypedActionLogger<>::bind_fixed_header(sql::command &command, const FixedHeaderValues &fhvalues) {
|
||||
command.value(":h0", std::chrono::floor<std::chrono::milliseconds>(fhvalues.timestamp).time_since_epoch().count());
|
||||
command.value(":h1", fhvalues.server_id);
|
||||
command.value(":h2", fhvalues.invoker.database_id);
|
||||
command.value(":h3", fhvalues.invoker.name);
|
||||
command.value(":h4", kActionName[(int) fhvalues.action]);
|
||||
}
|
||||
|
||||
ActionLogger::ActionLogger() = default;
|
||||
ActionLogger::~ActionLogger() {
|
||||
this->finalize();
|
||||
}
|
||||
|
||||
#define CURRENT_VERSION 1
|
||||
bool ActionLogger::initialize(std::string &error) {
|
||||
int db_version{0};
|
||||
|
||||
this->sql_handle = new sql::sqlite::SqliteManager{};
|
||||
auto result = this->sql_handle->connect("sqlite://InstanceLogs.sqlite");
|
||||
if(!result) {
|
||||
error = result.fmtStr();
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
{
|
||||
if(sql_handle->getType() == sql::TYPE_MYSQL) {
|
||||
sql::command(this->sql_handle, "SET NAMES utf8").execute();
|
||||
//sql::command(this->manager, "DEFAULT CHARSET=utf8").execute();
|
||||
} else if(sql_handle->getType() == sql::TYPE_SQLITE) {
|
||||
sql::command(this->sql_handle, "PRAGMA locking_mode = EXCLUSIVE;").execute();
|
||||
sql::command(this->sql_handle, "PRAGMA synchronous = NORMAL;").execute();
|
||||
sql::command(this->sql_handle, "PRAGMA journal_mode = WAL;").execute();
|
||||
sql::command(this->sql_handle, "PRAGMA encoding = \"UTF-8\";").execute();
|
||||
}
|
||||
}
|
||||
|
||||
/* begin transaction, if available */
|
||||
if(this->sql_handle->getType() == sql::TYPE_SQLITE) {
|
||||
result = sql::command(this->sql_handle, "BEGIN TRANSACTION;").execute();
|
||||
if(!result) {
|
||||
error = "failed to begin transaction (" + result.fmtStr() + ")";
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
result = sql::command{this->sql_handle, "CREATE TABLE IF NOT EXISTS general(`key` VARCHAR(256), `value` TEXT);"}.execute();
|
||||
if(!result) {
|
||||
error = "failed to create if not exists the general table: " + result.fmtStr();
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
sql::command{this->sql_handle, "SELECT `value` FROM `general` WHERE `key` = 'version';"}.query([&](int, std::string* values, std::string*) {
|
||||
db_version = std::stoi(values[0]);
|
||||
});
|
||||
}
|
||||
|
||||
switch (db_version) {
|
||||
case 0:
|
||||
/* initial setup */
|
||||
case CURRENT_VERSION:
|
||||
/* current version */
|
||||
break;
|
||||
|
||||
default:
|
||||
error = CURRENT_VERSION < db_version ? "database version is newer than supported (supported: " + std::to_string(CURRENT_VERSION) + ", database: " + std::to_string(db_version) + ")" :
|
||||
"invalid database version (" + std::to_string(db_version) + ")";
|
||||
}
|
||||
|
||||
if(!this->server_logger.setup(db_version, error)) {
|
||||
error = "server logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->server_edit_logger.setup(db_version, error)) {
|
||||
error = "server edit logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->channel_logger.setup(db_version, error)) {
|
||||
error = "channel logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->permission_logger.setup(db_version, error)) {
|
||||
error = "permission logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->group_logger.setup(db_version, error)) {
|
||||
error = "group logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->group_assignment_logger.setup(db_version, error)) {
|
||||
error = "group assignment logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->client_channel_logger.setup(db_version, error)) {
|
||||
error = "client channel logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->client_edit_logger.setup(db_version, error)) {
|
||||
error = "client edit logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->file_logger.setup(db_version, error)) {
|
||||
error = "file logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->custom_logger.setup(db_version, error)) {
|
||||
error = "custom logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->query_logger.setup(db_version, error)) {
|
||||
error = "query logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(!this->query_authenticate_logger.setup(db_version, error)) {
|
||||
error = "query authenticate logger: " + error;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
|
||||
/* update the version */
|
||||
{
|
||||
std::string command{};
|
||||
if(db_version == 0)
|
||||
command = "INSERT INTO `general` (`key`, `value`) VALUES ('version', :version);";
|
||||
else
|
||||
command = "UPDATE `general` SET `value` = :version WHERE `key` = 'version';";
|
||||
|
||||
auto res = sql::command{this->sql_handle, command, variable{":version", CURRENT_VERSION}}.execute();
|
||||
if(!res) {
|
||||
logCritical(LOG_INSTANCE, "Failed to increment action log database version!");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if(this->sql_handle->getType() == sql::TYPE_SQLITE) {
|
||||
result = sql::command(this->sql_handle, "COMMIT;").execute();
|
||||
if(!result) {
|
||||
error = "failed to commit changes";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable all loggers */
|
||||
this->server_logger.set_enabled(true);
|
||||
this->server_edit_logger.set_enabled(true);
|
||||
this->channel_logger.set_enabled(true);
|
||||
this->permission_logger.set_enabled(true);
|
||||
this->group_logger.set_enabled(true);
|
||||
this->group_assignment_logger.set_enabled(true);
|
||||
this->client_channel_logger.set_enabled(true);
|
||||
this->client_edit_logger.set_enabled(true);
|
||||
this->file_logger.set_enabled(true);
|
||||
this->custom_logger.set_enabled(true);
|
||||
this->query_logger.set_enabled(true);
|
||||
this->query_authenticate_logger.set_enabled(true);
|
||||
return true;
|
||||
|
||||
error_exit:
|
||||
if(this->sql_handle && this->sql_handle->connected()) {
|
||||
result = sql::command(this->sql_handle, "ROLLBACK;").execute();
|
||||
if (!result) {
|
||||
logCritical(LOG_GENERAL, "Failed to rollback log database after transaction.");
|
||||
} else {
|
||||
debugMessage(LOG_GENERAL, "Rollbacked log database successfully.");
|
||||
}
|
||||
}
|
||||
this->finalize();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ActionLogger::finalize() {
|
||||
if(!this->sql_handle)
|
||||
return;
|
||||
|
||||
this->server_logger.finalize();
|
||||
this->server_edit_logger.finalize();
|
||||
this->channel_logger.finalize();
|
||||
this->permission_logger.finalize();
|
||||
this->group_logger.finalize();
|
||||
this->group_assignment_logger.finalize();
|
||||
this->client_channel_logger.finalize();
|
||||
this->client_edit_logger.finalize();
|
||||
this->custom_logger.finalize();
|
||||
this->file_logger.finalize();
|
||||
this->query_logger.finalize();
|
||||
this->query_authenticate_logger.finalize();
|
||||
|
||||
this->sql_handle->pool->threads()->wait_for(std::chrono::seconds{1});
|
||||
this->sql_handle->disconnect();
|
||||
delete this->sql_handle;
|
||||
this->sql_handle = nullptr;
|
||||
}
|
||||
|
||||
void ActionLogger::register_invoker(const Invoker &) {}
|
||||
|
||||
std::vector<LogEntryInfo> ActionLogger::query(
|
||||
std::vector<LoggerGroup> groups,
|
||||
uint64_t server,
|
||||
const std::chrono::system_clock::time_point &begin,
|
||||
const std::chrono::system_clock::time_point &end,
|
||||
size_t limit) {
|
||||
|
||||
std::vector<LogEntryInfo> result{};
|
||||
result.reserve(limit == 0 ? 1024 * 8 : limit * 2);
|
||||
|
||||
std::vector<std::deque<LogEntryInfo>> intresult{};
|
||||
intresult.reserve(8);
|
||||
|
||||
for(size_t index{0}; index < (size_t) LoggerGroup::MAX; index++) {
|
||||
auto group = static_cast<LoggerGroup>(index);
|
||||
if(!groups.empty() && std::find(groups.begin(), groups.end(), group) == groups.end())
|
||||
continue;
|
||||
|
||||
intresult.clear();
|
||||
switch (group) {
|
||||
case LoggerGroup::SERVER:
|
||||
std::exchange(intresult.emplace_back(), this->server_logger.query(server, begin, end, limit));
|
||||
std::exchange(intresult.emplace_back(), this->server_edit_logger.query(server, begin, end, limit));
|
||||
std::exchange(intresult.emplace_back(), this->group_logger.query(server, begin, end, limit));
|
||||
std::exchange(intresult.emplace_back(), this->group_assignment_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::CHANNEL:
|
||||
std::exchange(intresult.emplace_back(), this->channel_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::CLIENT:
|
||||
std::exchange(intresult.emplace_back(), this->client_channel_logger.query(server, begin, end, limit));
|
||||
std::exchange(intresult.emplace_back(), this->client_edit_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::FILES:
|
||||
std::exchange(intresult.emplace_back(), this->file_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::PERMISSION:
|
||||
std::exchange(intresult.emplace_back(), this->permission_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::CUSTOM:
|
||||
std::exchange(intresult.emplace_back(), this->custom_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::QUERY:
|
||||
std::exchange(intresult.emplace_back(), this->query_logger.query(server, begin, end, limit));
|
||||
std::exchange(intresult.emplace_back(), this->query_authenticate_logger.query(server, begin, end, limit));
|
||||
break;
|
||||
|
||||
case LoggerGroup::MAX:
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
for(auto& qresult : intresult) {
|
||||
if(qresult.empty())
|
||||
continue;
|
||||
/* qresult is already sorted */
|
||||
result.insert(result.begin(), qresult.begin(), qresult.begin() + std::min(qresult.size(), limit));
|
||||
|
||||
std::sort(result.begin(), result.end(), [](const LogEntryInfo& a, const LogEntryInfo& b){
|
||||
if(a.timestamp == b.timestamp)
|
||||
return &a > &b;
|
||||
return a.timestamp > b.timestamp;
|
||||
});
|
||||
if(limit > 0 && result.size() > limit)
|
||||
result.erase(result.begin() + limit, result.end());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,843 @@
|
|||
#pragma once
|
||||
|
||||
#include <Definitions.h>
|
||||
#include <optional>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <sql/SqlQuery.h>
|
||||
#include <Properties.h>
|
||||
#include <PermissionManager.h>
|
||||
#include <query/command3.h>
|
||||
|
||||
namespace ts::server {
|
||||
class ConnectedClient;
|
||||
class QueryClient;
|
||||
}
|
||||
|
||||
namespace ts::server::log {
|
||||
struct Invoker {
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
ClientDbId database_id{0};
|
||||
};
|
||||
extern Invoker kInvokerSystem;
|
||||
|
||||
enum struct LoggerGroup {
|
||||
CUSTOM,
|
||||
SERVER,
|
||||
CHANNEL,
|
||||
PERMISSION,
|
||||
CLIENT,
|
||||
FILES,
|
||||
QUERY,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) LoggerGroup::MAX> kLoggerGroupName{
|
||||
"custom",
|
||||
"server",
|
||||
"channel",
|
||||
"permission",
|
||||
"client",
|
||||
"files",
|
||||
"query"
|
||||
};
|
||||
|
||||
|
||||
enum struct Action {
|
||||
UNKNOWN,
|
||||
|
||||
SERVER_CREATE,
|
||||
SERVER_START,
|
||||
SERVER_EDIT,
|
||||
SERVER_STOP,
|
||||
SERVER_DELETE,
|
||||
|
||||
CHANNEL_CREATE,
|
||||
CHANNEL_EDIT,
|
||||
CHANNEL_DELETE,
|
||||
|
||||
PERMISSION_ADD_VALUE,
|
||||
PERMISSION_ADD_GRANT,
|
||||
|
||||
PERMISSION_EDIT_VALUE,
|
||||
PERMISSION_EDIT_GRANT,
|
||||
|
||||
PERMISSION_REMOVE_VALUE,
|
||||
PERMISSION_REMOVE_GRANT,
|
||||
|
||||
GROUP_CREATE,
|
||||
GROUP_RENAME,
|
||||
GROUP_PERMISSION_COPY,
|
||||
GROUP_DELETE,
|
||||
|
||||
GROUP_ASSIGNMENT_ADD,
|
||||
GROUP_ASSIGNMENT_REMOVE,
|
||||
|
||||
CLIENT_JOIN,
|
||||
CLIENT_EDIT,
|
||||
CLIENT_MOVE,
|
||||
CLIENT_KICK,
|
||||
CLIENT_LEAVE,
|
||||
|
||||
FILE_UPLOAD,
|
||||
FILE_DOWNLOAD,
|
||||
FILE_RENAME,
|
||||
FILE_DELETE,
|
||||
FILE_DIRECTORY_CREATE,
|
||||
|
||||
CUSTOM_LOG,
|
||||
|
||||
QUERY_AUTHENTICATE,
|
||||
QUERY_JOIN,
|
||||
QUERY_LEAVE,
|
||||
|
||||
MAX
|
||||
};
|
||||
|
||||
constexpr static std::array<std::string_view, (int) Action::MAX> kActionName{
|
||||
"unknown",
|
||||
"server-create",
|
||||
"server-start",
|
||||
"server-edit",
|
||||
"server-stop",
|
||||
"server-delete",
|
||||
|
||||
"channel-create",
|
||||
"channel-edit",
|
||||
"channel-delete",
|
||||
|
||||
"permission-add-value",
|
||||
"permission-add-grant",
|
||||
|
||||
"permission-edit-value",
|
||||
"permission-edit-grant",
|
||||
|
||||
"permission-remove-value",
|
||||
"permission-remove-grant",
|
||||
|
||||
"group-create",
|
||||
"group-rename",
|
||||
"group-permission-copy",
|
||||
"group-delete",
|
||||
|
||||
"group-assignment-add",
|
||||
"group-assignment-remove",
|
||||
|
||||
"client-join",
|
||||
"client-edit",
|
||||
"client-move",
|
||||
"client-kick",
|
||||
"client-leave",
|
||||
|
||||
"file-upload",
|
||||
"file-download",
|
||||
"file-rename",
|
||||
"file-delete",
|
||||
"file-directory-create",
|
||||
|
||||
"custom-log",
|
||||
|
||||
"query-authenticate",
|
||||
"query-join",
|
||||
"query-leave"
|
||||
};
|
||||
|
||||
struct LogEntryInfo {
|
||||
std::chrono::system_clock::time_point timestamp{};
|
||||
Action action{Action::UNKNOWN};
|
||||
|
||||
standalone_command_builder_bulk info{};
|
||||
};
|
||||
|
||||
class ActionLogger;
|
||||
|
||||
class AbstractActionLogger {
|
||||
public:
|
||||
explicit AbstractActionLogger(ActionLogger* impl) : logger_{impl} {}
|
||||
|
||||
[[nodiscard]] virtual bool setup(int /* database version */, std::string& /* error */) = 0;
|
||||
virtual void finalize() { this->enabled_ = false; }
|
||||
|
||||
[[nodiscard]] inline ActionLogger* logger() const { return this->logger_; }
|
||||
|
||||
[[nodiscard]] inline bool enabled() const { return this->enabled_; }
|
||||
inline void set_enabled(bool flag) { this->enabled_ = flag; }
|
||||
|
||||
[[nodiscard]] virtual std::deque<LogEntryInfo> query(
|
||||
uint64_t /* server id */,
|
||||
const std::chrono::system_clock::time_point& /* begin timestamp */,
|
||||
const std::chrono::system_clock::time_point& /* end timestamp */,
|
||||
size_t /* limit */
|
||||
) = 0;
|
||||
protected:
|
||||
ActionLogger* logger_;
|
||||
bool enabled_{false};
|
||||
|
||||
void do_log(ServerId /* server id */, Action /* action */, sql::command& /* command */) const;
|
||||
};
|
||||
|
||||
struct DatabaseColumn {
|
||||
std::string name{};
|
||||
std::string type{};
|
||||
};
|
||||
|
||||
struct FixedHeaderKeys {
|
||||
DatabaseColumn timestamp{};
|
||||
DatabaseColumn server_id{};
|
||||
DatabaseColumn invoker_id{};
|
||||
DatabaseColumn invoker_name{};
|
||||
DatabaseColumn action{};
|
||||
};
|
||||
|
||||
template <typename>
|
||||
using T2DatabaseColumn = DatabaseColumn;
|
||||
|
||||
struct FixedHeaderValues {
|
||||
std::chrono::system_clock::time_point timestamp{};
|
||||
ServerId server_id{0};
|
||||
Invoker invoker{};
|
||||
Action action{};
|
||||
};
|
||||
|
||||
template <typename... LoggingArguments>
|
||||
class TypedActionLogger : public AbstractActionLogger {
|
||||
public:
|
||||
constexpr static auto kFixedHeaderColumnCount = 5;
|
||||
static inline std::string value_binding_name(size_t index) {
|
||||
return ":v" + std::to_string(index);
|
||||
}
|
||||
|
||||
static void compile_model(sql::model& result, const std::string& command, const ActionLogger* logger);
|
||||
static void register_invoker(ActionLogger* logger, const Invoker& invoker);
|
||||
static std::string generate_insert(
|
||||
const std::string& /* table name */,
|
||||
const FixedHeaderKeys& /* headers */,
|
||||
DatabaseColumn* /* payload columns */,
|
||||
size_t /* payload column count */
|
||||
);
|
||||
static sql::command compile_query(
|
||||
ActionLogger* /* logger */,
|
||||
uint64_t /* server id */,
|
||||
const std::chrono::system_clock::time_point& /* begin timestamp */,
|
||||
const std::chrono::system_clock::time_point& /* end timestamp */,
|
||||
size_t /* limit */,
|
||||
const std::string& /* table name */,
|
||||
const FixedHeaderKeys& /* headers */,
|
||||
DatabaseColumn* /* payload columns */,
|
||||
size_t /* payload column count */
|
||||
);
|
||||
static bool create_table(
|
||||
std::string& /* error */,
|
||||
ActionLogger* /* logger */,
|
||||
const std::string& /* table name */,
|
||||
const FixedHeaderKeys& /* headers */,
|
||||
DatabaseColumn* /* payload columns */,
|
||||
size_t /* payload column count */
|
||||
);
|
||||
static void bind_fixed_header(sql::command& /* command */, const FixedHeaderValues& /* values */);
|
||||
static bool parse_fixed_header(FixedHeaderValues& /* result */, std::string* /* values */, size_t /* values length */);
|
||||
|
||||
explicit TypedActionLogger(ActionLogger* impl, std::string table_name, FixedHeaderKeys fh_keys, const T2DatabaseColumn<LoggingArguments>&... keys)
|
||||
: AbstractActionLogger{impl}, fh_keys{std::move(fh_keys)}, table_name{std::move(table_name)} {
|
||||
this->bind_key(0, keys...);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::deque<LogEntryInfo> query(
|
||||
uint64_t server_id,
|
||||
const std::chrono::system_clock::time_point& begin_timestamp,
|
||||
const std::chrono::system_clock::time_point& end_timestamp,
|
||||
size_t limit
|
||||
) override {
|
||||
std::deque<LogEntryInfo> result{};
|
||||
|
||||
auto sql_command = TypedActionLogger<>::compile_query(this->logger_, server_id, begin_timestamp, end_timestamp, limit, this->table_name, this->fh_keys, this->payload_column_names.data(), this->payload_column_names.size());
|
||||
|
||||
FixedHeaderValues header{};
|
||||
auto sql_result = sql_command.query([&](int length, std::string* values, std::string* names) {
|
||||
if(length < kFixedHeaderColumnCount + sizeof...(LoggingArguments))
|
||||
return;
|
||||
|
||||
if(!TypedActionLogger<>::parse_fixed_header(header, values, length))
|
||||
return;
|
||||
|
||||
auto& entry = result.emplace_back();
|
||||
entry.action = header.action;
|
||||
entry.timestamp = header.timestamp;
|
||||
|
||||
auto& info = entry.info;
|
||||
info.reserve(160);
|
||||
info.put_unchecked("timestamp", std::chrono::floor<std::chrono::milliseconds>(header.timestamp.time_since_epoch()).count());
|
||||
info.put_unchecked("invoker_database_id", header.invoker.database_id);
|
||||
info.put_unchecked("invoker_nickname", header.invoker.name);
|
||||
info.put_unchecked("action", kActionName[(int) header.action]);
|
||||
|
||||
for(size_t index{0}; index < sizeof...(LoggingArguments); index++)
|
||||
info.put_unchecked(this->payload_column_names[index].name, values[index + kFixedHeaderColumnCount]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
protected:
|
||||
void do_log(const FixedHeaderValues& fhvalues, const LoggingArguments&... vvalues) {
|
||||
if(!this->enabled_)
|
||||
return;
|
||||
|
||||
sql::command command = this->sql_model.command();
|
||||
|
||||
TypedActionLogger<>::bind_fixed_header(command, fhvalues);
|
||||
TypedActionLogger::bind_value(command, 0, vvalues...);
|
||||
|
||||
AbstractActionLogger::do_log(fhvalues.server_id, fhvalues.action, command);
|
||||
TypedActionLogger<>::register_invoker(this->logger_, fhvalues.invoker);
|
||||
}
|
||||
|
||||
bool setup(int db_version, std::string &error) override {
|
||||
TypedActionLogger<>::compile_model(
|
||||
this->sql_model,
|
||||
TypedActionLogger<>::generate_insert(this->table_name, this->fh_keys, this->payload_column_names.data(), this->payload_column_names.size()),
|
||||
this->logger_);
|
||||
if(db_version == 0) {
|
||||
if(!TypedActionLogger<>::create_table(error, this->logger_, this->table_name, this->fh_keys, this->payload_column_names.data(), this->payload_column_names.size()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, typename... Rest>
|
||||
static void bind_value(sql::command& result, int index, const T& value, const Rest&... vvalues) {
|
||||
result.value(TypedActionLogger::value_binding_name(index), value);
|
||||
TypedActionLogger::bind_value(result, index + 1, vvalues...);
|
||||
}
|
||||
|
||||
static void bind_value(sql::command&, int) {}
|
||||
|
||||
FixedHeaderKeys fh_keys;
|
||||
sql::model sql_model{nullptr};
|
||||
std::string table_name;
|
||||
std::array<DatabaseColumn, sizeof...(LoggingArguments)> payload_column_names{};
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
void bind_key(int index, const T& value, const Rest&... vkeys) {
|
||||
this->payload_column_names[index] = value;
|
||||
this->bind_key(index + 1, vkeys...);
|
||||
}
|
||||
|
||||
void bind_key(int) {}
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `property`, `value_old`, `value_new`
|
||||
class ServerEditActionLogger : public TypedActionLogger<std::string_view, std::string, std::string> {
|
||||
public:
|
||||
explicit ServerEditActionLogger(ActionLogger* impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
void log_server_edit(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
const property::PropertyDescription& /* property */,
|
||||
const std::string& /* old value */,
|
||||
const std::string& /* new value */);
|
||||
};
|
||||
|
||||
enum struct ServerCreateReason {
|
||||
USER_ACTION,
|
||||
SNAPSHOT_DEPLOY,
|
||||
INITIAL_SERVER,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) ServerCreateReason::MAX> kServerCreateReasonName {
|
||||
"user-action",
|
||||
"snapshot-deploy",
|
||||
"initial-server"
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `reason`
|
||||
class ServerActionLogger : public TypedActionLogger<std::string_view> {
|
||||
public:
|
||||
explicit ServerActionLogger(ActionLogger* impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_server_create(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
ServerCreateReason /* create reason */);
|
||||
|
||||
void log_server_delete(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */);
|
||||
|
||||
void log_server_start(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */);
|
||||
|
||||
void log_server_stop(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */);
|
||||
};
|
||||
|
||||
enum struct ChannelDeleteReason {
|
||||
PARENT_DELETED,
|
||||
USER_ACTION,
|
||||
SERVER_STOP,
|
||||
EMPTY,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) ChannelDeleteReason::MAX> kChannelDeleteReasonName {
|
||||
"parent-deleted",
|
||||
"user-action",
|
||||
"server-stop",
|
||||
"empty"
|
||||
};
|
||||
|
||||
enum struct ChannelType {
|
||||
TEMPORARY,
|
||||
SEMI_PERMANENT,
|
||||
PERMANENT,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) ChannelType::MAX> kChannelTypeName {
|
||||
"temporary",
|
||||
"semi-permanent",
|
||||
"permanent"
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `property` (may be the delete reason), `value_old`, `value_new`
|
||||
class ChannelActionLogger : public TypedActionLogger<ChannelId, std::string_view, std::string, std::string> {
|
||||
public:
|
||||
explicit ChannelActionLogger(ActionLogger* impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_channel_create(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
ChannelId /* channel id */,
|
||||
ChannelType /* type */);
|
||||
|
||||
void log_channel_move(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
ChannelId /* channel id */,
|
||||
ChannelId /* old parent channel */,
|
||||
ChannelId /* new parent channel */,
|
||||
ChannelId /* old channel order */,
|
||||
ChannelId /* new channel order */);
|
||||
|
||||
void log_channel_edit(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
ChannelId /* channel id */,
|
||||
const property::PropertyDescription& /* property */,
|
||||
const std::string& /* old value */,
|
||||
const std::string& /* new value */);
|
||||
|
||||
void log_channel_delete(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
ChannelId /* channel id */,
|
||||
ChannelDeleteReason /* reason */);
|
||||
};
|
||||
|
||||
enum struct PermissionTarget {
|
||||
SERVER_GROUP,
|
||||
CHANNEL_GROUP,
|
||||
CHANNEL,
|
||||
CLIENT,
|
||||
CLIENT_CHANNEL,
|
||||
PLAYLIST,
|
||||
PLAYLIST_CLIENT,
|
||||
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) PermissionTarget::MAX> kPermissionTargetName {
|
||||
"server-group",
|
||||
"channel-group",
|
||||
"channel",
|
||||
"client",
|
||||
"client-channel",
|
||||
"playlist",
|
||||
"playlist-client"
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `target`, `id1`, `id1_name`, `id2`, `id2_name`, `permission`, `old_value`, `old_negated`, `old_skipped`, `new_value`, `new_negated`, `new_skipped`
|
||||
class PermissionActionLogger : public TypedActionLogger<std::string_view, uint64_t, std::string, uint64_t, std::string, std::string, int32_t, bool, bool, int32_t, bool, bool> {
|
||||
public:
|
||||
explicit PermissionActionLogger(ActionLogger* impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_permission_add_value(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* value */,
|
||||
bool /* negated */,
|
||||
bool /* skipped */);
|
||||
|
||||
void log_permission_add_grant(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* value */);
|
||||
|
||||
void log_permission_edit_value(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* old value */,
|
||||
bool /* old negated */,
|
||||
bool /* old skipped */,
|
||||
int32_t /* new value */,
|
||||
bool /* new negated */,
|
||||
bool /* new skipped */);
|
||||
|
||||
void log_permission_edit_grant(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* old value */,
|
||||
int32_t /* new value */);
|
||||
|
||||
void log_permission_remove_value(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* old value */,
|
||||
bool /* old negate */,
|
||||
bool /* old skip */);
|
||||
|
||||
void log_permission_remove_grant(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
server::log::PermissionTarget /* target */,
|
||||
uint64_t /* id1 */, const std::string& /* id1 name */,
|
||||
uint64_t /* id2 */, const std::string& /* id2 name */,
|
||||
const permission::PermissionTypeEntry& /* permission */,
|
||||
int32_t /* old value */);
|
||||
};
|
||||
|
||||
enum struct GroupType {
|
||||
NORMAL,
|
||||
TEMPLATE,
|
||||
QUERY,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) GroupType::MAX> kGroupTypeName {
|
||||
"normal",
|
||||
"template",
|
||||
"query"
|
||||
};
|
||||
|
||||
enum struct GroupTarget {
|
||||
SERVER,
|
||||
CHANNEL,
|
||||
MAX
|
||||
};
|
||||
constexpr static std::array<std::string_view, (int) GroupTarget::MAX> kGroupTargetName {
|
||||
"server",
|
||||
"channel"
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `type`, `target`, `group`, `group_name`, `source`, `source_name`
|
||||
class GroupActionLogger : public TypedActionLogger<std::string_view, std::string_view, uint64_t, std::string, uint64_t, std::string> {
|
||||
public:
|
||||
explicit GroupActionLogger(ActionLogger* impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_group_create(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
GroupType /* type */,
|
||||
uint64_t /* group */,
|
||||
const std::string& /* group name */,
|
||||
uint64_t /* source */,
|
||||
const std::string& /* source name */
|
||||
);
|
||||
|
||||
void log_group_rename(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
GroupType /* type */,
|
||||
uint64_t /* group */,
|
||||
const std::string& /* target name */,
|
||||
const std::string& /* source name */
|
||||
);
|
||||
|
||||
void log_group_permission_copy(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
GroupType /* type */,
|
||||
uint64_t /* target group */,
|
||||
const std::string& /* target group name */,
|
||||
uint64_t /* source */,
|
||||
const std::string& /* source name */
|
||||
);
|
||||
|
||||
void log_group_delete(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
GroupType /* type */,
|
||||
uint64_t /* group */,
|
||||
const std::string& /* group name */
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `target`, `group`, `group_name`, `client`, `client_name`
|
||||
class GroupAssignmentActionLogger : public TypedActionLogger<std::string_view, uint64_t, std::string, uint64_t, std::string> {
|
||||
public:
|
||||
explicit GroupAssignmentActionLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_group_assignment_add(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
uint64_t /* group */,
|
||||
const std::string& /* group name */,
|
||||
uint64_t /* client */,
|
||||
const std::string& /* client name */
|
||||
);
|
||||
|
||||
void log_group_assignment_remove(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* editor (may be null) */,
|
||||
GroupTarget /* target */,
|
||||
uint64_t /* group */,
|
||||
const std::string& /* group name */,
|
||||
uint64_t /* client */,
|
||||
const std::string& /* client name */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `target_client`, `target_client_name`, `source_channel`, `source_channel_name`, `target_channel`, `target_channel_name`
|
||||
class ClientChannelActionLogger : public TypedActionLogger<uint64_t, std::string, uint64_t, std::string, uint64_t, std::string> {
|
||||
public:
|
||||
explicit ClientChannelActionLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
|
||||
void log_client_join(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* subject */,
|
||||
uint64_t /* target channel */,
|
||||
const std::string& /* target channel name */
|
||||
);
|
||||
|
||||
void log_client_move(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* issuer (may be null) */,
|
||||
const std::shared_ptr<ConnectedClient>& /* subject */,
|
||||
uint64_t /* target channel */,
|
||||
const std::string& /* target channel name */,
|
||||
uint64_t /* source channel */,
|
||||
const std::string& /* source channel name */
|
||||
);
|
||||
|
||||
void log_client_kick(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* issuer (may be null) */,
|
||||
const std::shared_ptr<ConnectedClient>& /* subject */,
|
||||
uint64_t /* target channel */,
|
||||
const std::string& /* target channel name */,
|
||||
uint64_t /* source channel */,
|
||||
const std::string& /* source channel name */
|
||||
);
|
||||
|
||||
void log_client_leave(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* subject */,
|
||||
uint64_t /* source channel */,
|
||||
const std::string& /* source channel name */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `target_client`, `target_client_name`, `property`, `old_value`, `new_value`
|
||||
class ClientEditActionLogger : public TypedActionLogger<uint64_t, std::string, std::string_view, std::string, std::string> {
|
||||
public:
|
||||
explicit ClientEditActionLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_client_edit(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* issuer (may be null) */,
|
||||
const std::shared_ptr<ConnectedClient>& /* subject */,
|
||||
const property::PropertyDescription& /* property */,
|
||||
const std::string& /* old value */,
|
||||
const std::string& /* new value */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `source_channel_id`, `source_path`, `target_channel_id`, `target_path`
|
||||
class FilesActionLogger : public TypedActionLogger<uint64_t, std::string, uint64_t, std::string> {
|
||||
public:
|
||||
explicit FilesActionLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_file_upload(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
uint64_t /* channel id */,
|
||||
const std::string& /* path */
|
||||
);
|
||||
|
||||
void log_file_download(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
uint64_t /* channel id */,
|
||||
const std::string& /* path */
|
||||
);
|
||||
|
||||
void log_file_rename(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
uint64_t /* source channel id */,
|
||||
const std::string& /* source name */,
|
||||
uint64_t /* target channel id */,
|
||||
const std::string& /* target name */
|
||||
);
|
||||
|
||||
void log_file_delete(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
uint64_t /* channel id */,
|
||||
const std::string& /* source name */
|
||||
);
|
||||
|
||||
void log_file_directory_create(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* invoker */,
|
||||
uint64_t /* channel id */,
|
||||
const std::string& /* path */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `message`
|
||||
class CustomLogger : public TypedActionLogger<std::string> {
|
||||
public:
|
||||
explicit CustomLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
|
||||
void add_log_message(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* issuer (may be null) */,
|
||||
const std::string& /* message */
|
||||
);
|
||||
};
|
||||
|
||||
enum struct QueryAuthenticateResult {
|
||||
SUCCESS,
|
||||
UNKNOWN_USER,
|
||||
INVALID_PASSWORD,
|
||||
MAX
|
||||
};
|
||||
|
||||
constexpr static std::array<std::string_view, (int) QueryAuthenticateResult::MAX> kQueryAuthenticateResultName {
|
||||
"success",
|
||||
"unknown-user",
|
||||
"invalid-password"
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `ip`, `username`, `result`
|
||||
class QueryAuthenticateLogger : public TypedActionLogger<std::string, std::string, std::string_view> {
|
||||
public:
|
||||
explicit QueryAuthenticateLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_query_authenticate(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<QueryClient>& /* query */,
|
||||
const std::string& /* username (if empty he logs out) */,
|
||||
QueryAuthenticateResult /* result */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `ip`, `username`, `source_server`
|
||||
class QueryServerLogger : public TypedActionLogger<std::string, std::string, bool> {
|
||||
public:
|
||||
explicit QueryServerLogger(ActionLogger *impl);
|
||||
|
||||
bool setup(int, std::string &) override;
|
||||
|
||||
void log_query_switch(
|
||||
const std::shared_ptr<QueryClient>& /* query */,
|
||||
const std::string& /* authenticated username */,
|
||||
ServerId /* source */,
|
||||
ServerId /* target */
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
VIRTUALSERVER_LOG_CLIENT, (Bans: TODO!, Updates: Done, Channel Tree: Done)
|
||||
VIRTUALSERVER_LOG_QUERY, (Check))
|
||||
VIRTUALSERVER_LOG_CHANNEL, (Check)
|
||||
VIRTUALSERVER_LOG_PERMISSIONS, (Check)
|
||||
VIRTUALSERVER_LOG_SERVER, (Check; Groups: Check; Assignments: Check; Administrate: Check)
|
||||
VIRTUALSERVER_LOG_FILETRANSFER (Check)
|
||||
*/
|
||||
class ActionLogger {
|
||||
public:
|
||||
explicit ActionLogger();
|
||||
~ActionLogger();
|
||||
|
||||
[[nodiscard]] bool initialize(std::string& /* error */);
|
||||
void finalize();
|
||||
|
||||
[[nodiscard]] inline sql::SqlManager* sql_manager() const { return this->sql_handle; }
|
||||
|
||||
void register_invoker(const Invoker&);
|
||||
|
||||
[[nodiscard]] virtual std::vector<LogEntryInfo> query(
|
||||
std::vector<LoggerGroup> /* groups */,
|
||||
uint64_t /* server id */,
|
||||
const std::chrono::system_clock::time_point& /* begin timestamp */,
|
||||
const std::chrono::system_clock::time_point& /* end timestamp */,
|
||||
size_t /* limit */
|
||||
);
|
||||
|
||||
ServerActionLogger server_logger{this};
|
||||
ServerEditActionLogger server_edit_logger{this};
|
||||
ChannelActionLogger channel_logger{this};
|
||||
PermissionActionLogger permission_logger{this};
|
||||
GroupActionLogger group_logger{this};
|
||||
GroupAssignmentActionLogger group_assignment_logger{this};
|
||||
ClientChannelActionLogger client_channel_logger{this};
|
||||
ClientEditActionLogger client_edit_logger{this};
|
||||
FilesActionLogger file_logger{this};
|
||||
CustomLogger custom_logger{this};
|
||||
QueryServerLogger query_logger{this};
|
||||
QueryAuthenticateLogger query_authenticate_logger{this};
|
||||
private:
|
||||
sql::SqlManager* sql_handle{nullptr};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,898 @@
|
|||
//
|
||||
// Created by WolverinDEV on 26/06/2020.
|
||||
//
|
||||
|
||||
#include "ActionLogger.h"
|
||||
#include "../client/ConnectedClient.h"
|
||||
#include "../client/query/QueryClient.h"
|
||||
|
||||
using namespace ts::server;
|
||||
using namespace ts::server::log;
|
||||
|
||||
static FixedHeaderKeys kDefaultHeaderFields{
|
||||
.timestamp = {"timestamp", "BIGINT"},
|
||||
.server_id = {"server_id", "INT"},
|
||||
.invoker_id = {"invoker_database_id", "BIGINT"},
|
||||
.invoker_name = {"invoker_name", "VARCHAR(128)"},
|
||||
.action = {"action", "VARCHAR(64)"}
|
||||
};
|
||||
|
||||
inline Invoker client_to_invoker(const std::shared_ptr<ConnectedClient>& client) {
|
||||
return client ? Invoker{
|
||||
.name = client->getDisplayName(),
|
||||
.unique_id = client->getUid(),
|
||||
.database_id = client->getClientDatabaseId()
|
||||
} : kInvokerSystem;
|
||||
}
|
||||
|
||||
/* server action logger */
|
||||
bool ServerActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ServerActionLogger::ServerActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_server",
|
||||
kDefaultHeaderFields,
|
||||
{"reason", "VARCHAR(64)"}
|
||||
} { }
|
||||
|
||||
void ServerActionLogger::log_server_create(ServerId sid, const std::shared_ptr<ConnectedClient> &invoker, ServerCreateReason reason) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(invoker),
|
||||
.action = Action::SERVER_CREATE,
|
||||
}, kServerCreateReasonName[(int) reason]);
|
||||
}
|
||||
|
||||
void ServerActionLogger::log_server_delete(ServerId sid, const std::shared_ptr<ConnectedClient> &invoker) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(invoker),
|
||||
.action = Action::SERVER_DELETE,
|
||||
}, "");
|
||||
}
|
||||
|
||||
void ServerActionLogger::log_server_start(ServerId sid, const std::shared_ptr<ConnectedClient> &invoker) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(invoker),
|
||||
.action = Action::SERVER_START,
|
||||
}, "");
|
||||
}
|
||||
|
||||
void ServerActionLogger::log_server_stop(ServerId sid, const std::shared_ptr<ConnectedClient> &invoker) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(invoker),
|
||||
.action = Action::SERVER_STOP,
|
||||
}, "");
|
||||
}
|
||||
|
||||
/* -------------------------- server edit logger -------------------------- */
|
||||
bool ServerEditActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ServerEditActionLogger::ServerEditActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_server_edit",
|
||||
kDefaultHeaderFields,
|
||||
{"property", "VARCHAR(128)"},
|
||||
{"value_old", "TEXT"},
|
||||
{"value_new", "TEXT"}
|
||||
} { }
|
||||
|
||||
void ServerEditActionLogger::log_server_edit(ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
const property::PropertyDescription &property,
|
||||
const std::string &old_value,
|
||||
const std::string &new_value) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::SERVER_EDIT,
|
||||
}, property.name, old_value, new_value);
|
||||
}
|
||||
|
||||
/* -------------------------- channel logger -------------------------- */
|
||||
bool ChannelActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelActionLogger::ChannelActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_channel",
|
||||
kDefaultHeaderFields,
|
||||
{"channel_id", "BIGINT"},
|
||||
{"property", "VARCHAR(128)"},
|
||||
{"value_old", "TEXT"},
|
||||
{"value_new", "TEXT"}
|
||||
} { }
|
||||
|
||||
void ChannelActionLogger::log_channel_create(ServerId sid, const std::shared_ptr<ConnectedClient> &client, ChannelId cid, ChannelType type) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::CHANNEL_CREATE,
|
||||
}, cid, kChannelTypeName[(int) type], "", "");
|
||||
}
|
||||
|
||||
void ChannelActionLogger::log_channel_edit(ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
ChannelId cid,
|
||||
const property::PropertyDescription &property,
|
||||
const std::string &old_value,
|
||||
const std::string &new_value) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::CHANNEL_EDIT,
|
||||
}, cid, property.name, old_value, new_value);
|
||||
}
|
||||
|
||||
void ChannelActionLogger::log_channel_move(ServerId sid, const std::shared_ptr<ConnectedClient> &client, ChannelId cid, ChannelId opcid, ChannelId npcid, ChannelId oco, ChannelId nco) {
|
||||
auto timestamp = std::chrono::system_clock::now();
|
||||
if(opcid != npcid) {
|
||||
this->do_log({
|
||||
.timestamp = timestamp,
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::CHANNEL_EDIT,
|
||||
}, cid, "channel_parent_id", std::to_string(opcid), std::to_string(npcid));
|
||||
}
|
||||
|
||||
if(oco != nco) {
|
||||
this->do_log({
|
||||
.timestamp = timestamp,
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::CHANNEL_EDIT,
|
||||
}, cid, "channel_order", std::to_string(oco), std::to_string(nco));
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelActionLogger::log_channel_delete(ServerId sid, const std::shared_ptr<ConnectedClient> &client, ChannelId cid, ChannelDeleteReason reason) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::CHANNEL_DELETE,
|
||||
}, cid, kChannelDeleteReasonName[(int) reason], "", "");
|
||||
}
|
||||
|
||||
/* -------------------------- permission logger -------------------------- */
|
||||
bool PermissionActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PermissionActionLogger::PermissionActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_permission",
|
||||
kDefaultHeaderFields,
|
||||
{"target", "VARCHAR(64)"},
|
||||
{"id1", "BIGINT"},
|
||||
{"id1_name", "VARCHAR(128)"},
|
||||
{"id2", "BIGINT"},
|
||||
{"id2_name", "VARCHAR(128)"},
|
||||
{"permission", "VARCHAR(64)"},
|
||||
{"old_value", "BIGINT"},
|
||||
{"old_negated", "INT(1)"},
|
||||
{"old_skipped", "INT(1)"},
|
||||
{"new_value", "BIGINT"},
|
||||
{"new_negated", "INT(1)"},
|
||||
{"new_skipped", "INT(1)"}
|
||||
} { }
|
||||
|
||||
void PermissionActionLogger::log_permission_add_value(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t new_value,
|
||||
bool new_negated,
|
||||
bool new_skipped) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_ADD_VALUE,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, 0, false, false, new_value, new_negated, new_skipped);
|
||||
}
|
||||
|
||||
void PermissionActionLogger::log_permission_add_grant(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t new_value) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_ADD_GRANT,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, 0, false, false, new_value, false, false);
|
||||
}
|
||||
|
||||
void PermissionActionLogger::log_permission_edit_value(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t old_value,
|
||||
bool old_negated,
|
||||
bool old_skipped,
|
||||
int32_t new_value,
|
||||
bool new_negated,
|
||||
bool new_skipped) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_EDIT_VALUE,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, old_value, old_negated, old_skipped, new_value, new_negated, new_skipped);
|
||||
}
|
||||
|
||||
void PermissionActionLogger::log_permission_edit_grant(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t old_value,
|
||||
int32_t new_value) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_EDIT_GRANT,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, old_value, false, false, new_value, false, false);
|
||||
}
|
||||
|
||||
void PermissionActionLogger::log_permission_remove_value(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t old_value,
|
||||
bool old_negated,
|
||||
bool old_skipped) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_REMOVE_VALUE,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, old_value, old_negated, old_skipped, 0, false, false);
|
||||
}
|
||||
|
||||
void PermissionActionLogger::log_permission_remove_grant(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& client,
|
||||
PermissionTarget target,
|
||||
uint64_t id1, const std::string& id1_name,
|
||||
uint64_t id2, const std::string& id2_name,
|
||||
const permission::PermissionTypeEntry& permission,
|
||||
int32_t old_value) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::PERMISSION_REMOVE_GRANT,
|
||||
}, kPermissionTargetName[(int) target], id1, id1_name, id2, id2_name, permission.name, old_value, false, false, 0, false, false);
|
||||
}
|
||||
|
||||
/* -------------------------- group logger -------------------------- */
|
||||
constexpr auto kTableLogsGroupCreateSqlite = R"(
|
||||
CREATE TABLE `logs_groups` (
|
||||
`id` INTEGER PRIMARY KEY NOT NULL,
|
||||
`timestamp` BIGINT,
|
||||
`server_id` INTEGER,
|
||||
`invoker_database_id` BIGINT,
|
||||
`invoker_name` VARCHAR(128),
|
||||
`action` VARCHAR(64),
|
||||
`type` VARCHAR(64),
|
||||
`target` VARCHAR(64),
|
||||
`group` BIGINT,
|
||||
`group_name` VARCHAR(128),
|
||||
`source` BIGINT,
|
||||
`source_name` VARCHAR(128)
|
||||
);
|
||||
)";
|
||||
|
||||
bool GroupActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GroupActionLogger::GroupActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_groups",
|
||||
kDefaultHeaderFields,
|
||||
{"type", "VARCHAR(64)"},
|
||||
{"target", "VARCHAR(64)"},
|
||||
{"group", "BIGINT"},
|
||||
{"group_name", "VARCHAR(128)"},
|
||||
{"source", "BIGINT"},
|
||||
{"source_name", "VARCHAR(128)"}
|
||||
} { }
|
||||
|
||||
void GroupActionLogger::log_group_create(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
GroupType type,
|
||||
uint64_t gid,
|
||||
const std::string &name,
|
||||
uint64_t sgid,
|
||||
const std::string &sname) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_CREATE,
|
||||
}, kGroupTargetName[(int) target], kGroupTypeName[(int) type], gid, name, sgid, sname);
|
||||
}
|
||||
|
||||
void GroupActionLogger::log_group_permission_copy(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
GroupType type,
|
||||
uint64_t gid,
|
||||
const std::string &name,
|
||||
uint64_t sgid,
|
||||
const std::string &sname) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_PERMISSION_COPY,
|
||||
}, kGroupTargetName[(int) target], kGroupTypeName[(int) type], gid, name, sgid, sname);
|
||||
}
|
||||
|
||||
void GroupActionLogger::log_group_rename(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
GroupType type,
|
||||
uint64_t gid,
|
||||
const std::string &name,
|
||||
const std::string &sname) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_RENAME,
|
||||
}, kGroupTargetName[(int) target], kGroupTypeName[(int) type], gid, name, 0, sname);
|
||||
}
|
||||
|
||||
void GroupActionLogger::log_group_delete(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
GroupType type,
|
||||
uint64_t gid,
|
||||
const std::string &name) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_DELETE,
|
||||
}, kGroupTargetName[(int) target], kGroupTypeName[(int) type], gid, name, 0, "");
|
||||
}
|
||||
|
||||
/* -------------------------- group assignment logger -------------------------- */
|
||||
bool GroupAssignmentActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GroupAssignmentActionLogger::GroupAssignmentActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_group_assignments",
|
||||
kDefaultHeaderFields,
|
||||
{"target", "VARCHAR(64)"},
|
||||
{"group", "BIGINT"},
|
||||
{"group_name", "VARCHAR(128)"},
|
||||
{"client", "BIGINT"},
|
||||
{"client_name", "VARCHAR(128)"}
|
||||
} { }
|
||||
|
||||
void GroupAssignmentActionLogger::log_group_assignment_add(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
uint64_t gid,
|
||||
const std::string &gname,
|
||||
uint64_t tclient,
|
||||
const std::string &client_name) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_ASSIGNMENT_ADD,
|
||||
}, kGroupTargetName[(int) target], gid, gname, tclient, client_name);
|
||||
}
|
||||
|
||||
void GroupAssignmentActionLogger::log_group_assignment_remove(
|
||||
ts::ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &client,
|
||||
GroupTarget target,
|
||||
uint64_t gid,
|
||||
const std::string &gname,
|
||||
uint64_t tclient,
|
||||
const std::string &client_name) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(client),
|
||||
.action = Action::GROUP_ASSIGNMENT_REMOVE,
|
||||
}, kGroupTargetName[(int) target], gid, gname, tclient, client_name);
|
||||
}
|
||||
|
||||
/* -------------------------- group assignment logger -------------------------- */
|
||||
bool ClientChannelActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ClientChannelActionLogger::ClientChannelActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_client_channel",
|
||||
kDefaultHeaderFields,
|
||||
{"target_client", "BIGINT"},
|
||||
{"target_client_name", "VARCHAR(128)"},
|
||||
{"source_channel", "BIGINT"},
|
||||
{"source_channel_name", "VARCHAR(128)"},
|
||||
{"target_channel", "BIGINT"},
|
||||
{"target_channel_name", "VARCHAR(128)"}
|
||||
} { }
|
||||
|
||||
void ClientChannelActionLogger::log_client_join(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& subject,
|
||||
uint64_t target_channel,
|
||||
const std::string& target_channel_name) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = kInvokerSystem,
|
||||
.action = Action::CLIENT_JOIN,
|
||||
}, subject->getClientDatabaseId(), subject->getDisplayName(), 0, "", target_channel, target_channel_name);
|
||||
}
|
||||
|
||||
void ClientChannelActionLogger::log_client_leave(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& subject,
|
||||
uint64_t source_channel,
|
||||
const std::string& source_channel_name) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = kInvokerSystem,
|
||||
.action = Action::CLIENT_LEAVE,
|
||||
}, subject->getClientDatabaseId(), subject->getDisplayName(), source_channel, source_channel_name, 0, "");
|
||||
}
|
||||
|
||||
void ClientChannelActionLogger::log_client_move(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
const std::shared_ptr<ConnectedClient> &subject,
|
||||
uint64_t target_channel, const std::string &target_channel_name, uint64_t source_channel, const std::string &source_channel_name) {
|
||||
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::CLIENT_MOVE,
|
||||
}, subject->getClientId(), subject->getDisplayName(), source_channel, source_channel_name, target_channel, target_channel_name);
|
||||
}
|
||||
|
||||
void ClientChannelActionLogger::log_client_kick(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
const std::shared_ptr<ConnectedClient> &subject,
|
||||
uint64_t target_channel, const std::string &target_channel_name, uint64_t source_channel, const std::string &source_channel_name) {
|
||||
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::CLIENT_KICK,
|
||||
}, subject->getClientId(), subject->getDisplayName(), source_channel, source_channel_name, target_channel, target_channel_name);
|
||||
}
|
||||
|
||||
/* -------------------------- group assignment logger -------------------------- */
|
||||
bool ClientEditActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ClientEditActionLogger::ClientEditActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_client_edit",
|
||||
kDefaultHeaderFields,
|
||||
{"target_client", "BIGINT"},
|
||||
{"target_client_name", "VARCHAR(128)"},
|
||||
{"property", "VARCHAR(128)"},
|
||||
{"old_value", "TEXT"},
|
||||
{"new_value", "TEXT"}
|
||||
} { }
|
||||
|
||||
void ClientEditActionLogger::log_client_edit(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient>& issuer,
|
||||
const std::shared_ptr<ConnectedClient>& subject,
|
||||
const property::PropertyDescription& property,
|
||||
const std::string& old_value,
|
||||
const std::string& new_value
|
||||
) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::CLIENT_EDIT,
|
||||
}, subject->getClientId(), subject->getDisplayName(), property.name, old_value, new_value);
|
||||
}
|
||||
|
||||
/* -------------------------- file transfer logger -------------------------- */
|
||||
bool FilesActionLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FilesActionLogger::FilesActionLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_files",
|
||||
kDefaultHeaderFields,
|
||||
{"source_channel_id", "BIGINT"},
|
||||
{"source_path", "VARCHAR(256)"},
|
||||
{"target_channel_id", "BIGINT"},
|
||||
{"target_path", "VARCHAR(256)"}
|
||||
} { }
|
||||
|
||||
void FilesActionLogger::log_file_upload(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
uint64_t channel_id,
|
||||
const std::string &path) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::FILE_UPLOAD,
|
||||
}, 0, "", channel_id, path);
|
||||
}
|
||||
|
||||
void FilesActionLogger::log_file_download(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
uint64_t channel_id,
|
||||
const std::string &path) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::FILE_DOWNLOAD,
|
||||
}, channel_id, path, 0, "");
|
||||
}
|
||||
|
||||
void FilesActionLogger::log_file_rename(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
uint64_t old_channel_id,
|
||||
const std::string &old_name,
|
||||
uint64_t mew_channel_id,
|
||||
const std::string &new_name) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::FILE_RENAME,
|
||||
}, old_channel_id, old_name, mew_channel_id, new_name);
|
||||
}
|
||||
|
||||
void FilesActionLogger::log_file_directory_create(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
uint64_t channel_id,
|
||||
const std::string &path) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::FILE_DIRECTORY_CREATE,
|
||||
}, 0, "", channel_id, path);
|
||||
}
|
||||
|
||||
void FilesActionLogger::log_file_delete(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
uint64_t channel_id,
|
||||
const std::string &path) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::FILE_DELETE,
|
||||
}, channel_id, path, 0, "");
|
||||
}
|
||||
|
||||
/* -------------------------- custom logger -------------------------- */
|
||||
bool CustomLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CustomLogger::CustomLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_custom",
|
||||
kDefaultHeaderFields,
|
||||
{"message", "TEXT"},
|
||||
} { }
|
||||
|
||||
void CustomLogger::add_log_message(
|
||||
ServerId sid,
|
||||
const std::shared_ptr<ConnectedClient> &issuer,
|
||||
const std::string &message) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = sid,
|
||||
.invoker = client_to_invoker(issuer),
|
||||
.action = Action::CUSTOM_LOG,
|
||||
}, message);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `ip`, `username`, `result`
|
||||
class QueryAuthenticateLogger : public TypedActionLogger<std::string, std::string, bool> {
|
||||
public:
|
||||
void log_query_authenticate(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* query */,
|
||||
const std::string& /* username (if empty he logs out) */,
|
||||
bool /* success */
|
||||
);
|
||||
};
|
||||
|
||||
//Table: `id`, `timestamp`, `server_id`, `invoker_database_id`, `invoker_name`, `action`, `ip`, `username`, `source_server`
|
||||
class QueryServerLogger : public TypedActionLogger<std::string, std::string, bool> {
|
||||
public:
|
||||
void log_query_switch(
|
||||
ServerId /* server id */,
|
||||
const std::shared_ptr<ConnectedClient>& /* query */,
|
||||
const std::string& /* authenticateed username */,
|
||||
ServerId /* source */
|
||||
);
|
||||
};
|
||||
#endif
|
||||
|
||||
/* -------------------------- query authenticate logger -------------------------- */
|
||||
bool QueryAuthenticateLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QueryAuthenticateLogger::QueryAuthenticateLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_query_authenticate",
|
||||
kDefaultHeaderFields,
|
||||
{"ip", "VARCHAR(64)"},
|
||||
{"username", "VARCHAR(128)"},
|
||||
{"result", "INT(1)"}
|
||||
} { }
|
||||
|
||||
void QueryAuthenticateLogger::log_query_authenticate(
|
||||
ServerId server,
|
||||
const std::shared_ptr<QueryClient> &query,
|
||||
const std::string &username,
|
||||
QueryAuthenticateResult result) {
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = server,
|
||||
.invoker = client_to_invoker(query),
|
||||
.action = Action::QUERY_AUTHENTICATE,
|
||||
}, query->getLoggingPeerIp(), username, kQueryAuthenticateResultName[(int) result]);
|
||||
}
|
||||
|
||||
/* -------------------------- query server logger -------------------------- */
|
||||
bool QueryServerLogger::setup(int version, std::string &error) {
|
||||
if(!TypedActionLogger::setup(version, error))
|
||||
return false;
|
||||
|
||||
switch (version) {
|
||||
case 0:
|
||||
case 1:
|
||||
/* up to date, nothing to do */
|
||||
return true;
|
||||
|
||||
default:
|
||||
error = "invalid database source version";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QueryServerLogger::QueryServerLogger(ActionLogger* impl) : TypedActionLogger{
|
||||
impl,
|
||||
"logs_query_server",
|
||||
kDefaultHeaderFields,
|
||||
{"ip", "VARCHAR(64)"},
|
||||
{"username", "VARCHAR(128)"},
|
||||
{"other_server", "INT"}
|
||||
} { }
|
||||
|
||||
void QueryServerLogger::log_query_switch(const std::shared_ptr<QueryClient> &query, const std::string &username, ServerId source, ServerId target) {
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = source,
|
||||
.invoker = client_to_invoker(query),
|
||||
.action = Action::QUERY_LEAVE,
|
||||
}, query->getLoggingPeerIp(), username, target);
|
||||
|
||||
this->do_log({
|
||||
.timestamp = std::chrono::system_clock::now(),
|
||||
.server_id = target,
|
||||
.invoker = client_to_invoker(query),
|
||||
.action = Action::QUERY_JOIN,
|
||||
}, query->getLoggingPeerIp(), username, source);
|
||||
}
|
2
shared
2
shared
|
@ -1 +1 @@
|
|||
Subproject commit f11bee75c19b437513154a9dc1c9167c72e94427
|
||||
Subproject commit 809fa82b3158c78ad9604ec576fe779688de13fa
|
Loading…
Reference in New Issue