diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 40102cb..a8788df 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -96,6 +96,8 @@ set(SERVER_SOURCE_FILES src/music/PlayablePlaylist.cpp src/InstanceHandler.cpp src/InstanceHandlerSetup.cpp + src/InstanceHandlerPermissions.cpp + src/PermissionCalculator.cpp src/Configuration.cpp diff --git a/server/src/DatabaseHelper.cpp b/server/src/DatabaseHelper.cpp index 81a3fc0..855a6ba 100644 --- a/server/src/DatabaseHelper.cpp +++ b/server/src/DatabaseHelper.cpp @@ -251,8 +251,7 @@ std::shared_ptr DatabaseHelper::find_cached_p return nullptr; } -std::shared_ptr DatabaseHelper::loadClientPermissionManager(const std::shared_ptr& server, ClientDbId cldbid) { - auto server_id = server ? server->getServerId() : 0; +std::shared_ptr DatabaseHelper::loadClientPermissionManager(const ServerId& server_id, ClientDbId cldbid) { #ifndef DISABLE_CACHING { std::lock_guard lock{cached_permission_manager_lock}; @@ -264,12 +263,12 @@ std::shared_ptr DatabaseHelper::loadClientPermissionManag logTrace(server_id, "[Permission] Loading client permission manager for client {}", cldbid); auto permission_manager = std::make_shared(); bool loaded = false; - if(this->use_startup_cache && server) { + if(this->use_startup_cache && server_id > 0) { shared_ptr entry; { threads::MutexLock lock(this->startup_lock); for(const auto& entries : this->startup_entries) { - if(entries->sid == server->getServerId()) { + if(entries->sid == server_id) { entry = entries; break; } @@ -278,12 +277,11 @@ std::shared_ptr DatabaseHelper::loadClientPermissionManag if(entry) { for(const auto& perm : entry->permissions) { if(perm->type == permission::SQL_PERM_USER && perm->id == cldbid) { - auto channel = perm->channelId > 0 ? server->getChannelTree()->findChannel(perm->channelId) : nullptr; - - if(channel) - permission_manager->load_permission(perm->permission->type, {perm->value, perm->grant}, channel->channelId(), perm->flag_skip, perm->flag_negate, perm->value != permNotGranted, perm->grant != permNotGranted); - else + if(perm->channelId > 0) { + permission_manager->load_permission(perm->permission->type, {perm->value, perm->grant}, perm->channelId, perm->flag_skip, perm->flag_negate, perm->value != permNotGranted, perm->grant != permNotGranted); + } else { permission_manager->load_permission(perm->permission->type, {perm->value, perm->grant}, perm->flag_skip, perm->flag_negate, perm->value != permNotGranted, perm->grant != permNotGranted); + } } } loaded = true; @@ -292,7 +290,7 @@ std::shared_ptr DatabaseHelper::loadClientPermissionManag if(!loaded) { auto command = sql::command(this->sql, "SELECT `permId`, `value`, `channelId`, `grant`, `flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id", - variable{":serverId", server ? server->getServerId() : 0}, + variable{":serverId", server_id}, variable{":type", permission::SQL_PERM_USER}, variable{":id", cldbid}); LOG_SQL_CMD(load_permissions_v2(server_id, permission_manager.get(), command, true, false)); diff --git a/server/src/DatabaseHelper.h b/server/src/DatabaseHelper.h index 7c2d321..8dae742 100644 --- a/server/src/DatabaseHelper.h +++ b/server/src/DatabaseHelper.h @@ -92,7 +92,7 @@ namespace ts::server { std::deque> queryDatabaseInfo(const std::shared_ptr&, const std::deque&); std::deque> queryDatabaseInfoByUid(const std::shared_ptr &, std::deque); - std::shared_ptr loadClientPermissionManager(const std::shared_ptr&, ClientDbId); + std::shared_ptr loadClientPermissionManager(const ServerId&, ClientDbId); void saveClientPermissions(const std::shared_ptr&, ClientDbId , const std::shared_ptr& /* permission manager */); std::shared_ptr loadChannelPermissions(const std::shared_ptr&, ChannelId); diff --git a/server/src/Group.h b/server/src/Group.h index cffbc08..cd065b6 100644 --- a/server/src/Group.h +++ b/server/src/Group.h @@ -12,15 +12,6 @@ #include namespace ts { - namespace server { - class VirtualServer; - class ConnectedClient; - } - - struct CachedClient; - class GroupManager; - class Group; - enum GroupType { GROUP_TYPE_TEMPLATE, GROUP_TYPE_NORMAL, @@ -41,198 +32,4 @@ namespace ts { DEFINE_TRANSFORMS(ts::GroupType, uint8_t); DEFINE_TRANSFORMS(ts::GroupTarget, uint8_t); -DEFINE_TRANSFORMS(ts::GroupNameMode, uint8_t); - -namespace ts { - struct GroupMember { - std::string uid; - uint64_t cldbId; - uint64_t channelId; - std::string displayName; - std::chrono::time_point until; - }; - struct GroupAssignment { - GroupAssignment() {} - GroupAssignment(CachedClient *parent, ServerId server, uint64_t channelId, const std::shared_ptr &group, const std::chrono::time_point &until) : parent(parent), server(server), channelId(channelId), group(group), until(until) {} - - CachedClient* parent = nullptr; //Could be null! - - ServerId server = 0; - uint64_t channelId = 0; - std::shared_ptr group; - std::chrono::time_point until; - - inline bool isPermanent(){ return std::chrono::time_point_cast(until).time_since_epoch().count() == 0; } - }; - - struct CachedClient { - ClientDbId client_database_id; - - std::vector> server_groups; - std::map> channel_groups; - - size_t use_count = 0; - - std::mutex lock; /* never lock this lock before the general client cache! */ - }; - - class Group { - friend class GroupManager; - public: - Group(GroupManager* handle, GroupTarget target, GroupType type, GroupId groupId); - ~Group(); - - std::shared_ptr permissions(){ return this->_permissions; } - Properties& properties(){ return *this->_properties; } - - GroupNameMode nameMode(){ return (GroupNameMode) (uint8_t) properties()[property::GROUP_NAMEMODE]; } - - std::string name(){ return properties()[property::GROUP_NAME]; } - - GroupId groupId(){ return properties()[property::GROUP_ID]; } - - GroupTarget target() { return _target; } - GroupType type() { return _type; } - - void apply_properties_from_permissions(); - - inline permission::PermissionValue updateType() { - auto permission_manager = this->permissions(); /* copy the manager */ - assert(permission_manager); - const auto data = permission_manager->permission_value_flagged(permission::i_group_auto_update_type); - return data.has_value ? data.value : 0; - } - - inline bool permission_granted(const permission::PermissionType& permission, const permission::v2::PermissionFlaggedValue& granted_value, bool require_granted_value) { - auto permission_manager = this->permissions(); /* copy the manager */ - assert(permission_manager); - const auto data = permission_manager->permission_value_flagged(permission); - if(!data.has_value) { - return !require_granted_value || granted_value.has_value; - } - if(!granted_value.has_value) { - return false; - } - if(data.value == -1) { - return granted_value.value == -1; - } - return granted_value.value >= data.value; - } - - inline bool is_permanent() { - auto permission_manager = this->permissions(); /* copy the manager */ - assert(permission_manager); - const auto data = permission_manager->permission_value_flagged(permission::b_group_is_permanent); - return data.has_value ? data.value == 1 : false; - } - - inline IconId icon_id() { - auto permission_manager = this->permissions(); /* copy the manager */ - assert(permission_manager); - const auto data = permission_manager->permission_value_flagged(permission::i_icon_id); - return data.has_value ? data.value : 0; - } - private: - void setPermissionManager(const std::shared_ptr& manager); - - GroupManager* handle; - std::shared_ptr _permissions; - Properties* _properties; - GroupTarget _target; - GroupType _type; - }; - - class GroupManager { - friend class ServerChannelTree; - friend class Group; - friend class server::VirtualServer; - public: - static int64_t generateGroupId(sql::SqlManager* sql); - - GroupManager(const std::shared_ptr &, sql::SqlManager *, std::shared_ptr root = nullptr); - ~GroupManager(); - - bool loadGroupFormDatabase(GroupId id = 0); - - std::vector> availableGroups(bool root = true); - std::vector> availableServerGroups(bool root = true); - std::vector> availableChannelGroups(bool root = true); - - std::vector> getAssignedServerGroups(ClientDbId cldbid); - inline bool hasServerGroupAssigned(uint64_t cldbId, const std::shared_ptr& group){ - for(const auto& assign : this->getAssignedServerGroups(cldbId)) if(assign->group == group) return true; - return false; - } - - std::shared_ptr get_group_assignment(const ClientDbId& client_database_id, const std::shared_ptr& group) { - for(const auto& assign : this->getAssignedServerGroups(client_database_id)) - if(assign->group == group) return assign; - return nullptr; - } - - std::vector> getServerGroups(ClientDbId cldbid, server::ClientType type); - inline bool hasServerGroup(uint64_t cldbId, server::ClientType type, const std::shared_ptr& group){ - for(const auto& assign : this->getServerGroups(cldbId, type)) if(assign->group == group) return true; - return false; - } - - - //Gets the channel group (may inherited) - std::shared_ptr getChannelGroup(ClientDbId cldbId, const std::shared_ptr &, bool assign_default); - //Gets the channel group within the channel - std::shared_ptr getChannelGroupExact(ClientDbId cldbId, const std::shared_ptr&, bool assign_default); - - std::vector> defaultServerGroupGroupAssignments(ClientDbId, server::ClientType); - std::shared_ptr defaultChannelGroupAssignment(ClientDbId cldbId, const std::shared_ptr &); - - void addServerGroup(ClientDbId cldbId, std::shared_ptr, std::chrono::time_point until = std::chrono::time_point()); - void removeServerGroup(ClientDbId cldbId, std::shared_ptr); - void setChannelGroup(ClientDbId cldbId, std::shared_ptr, std::shared_ptr , std::chrono::time_point until = std::chrono::time_point()); - - std::shared_ptr createGroup(GroupTarget target, GroupType type, std::string name); - GroupId copyGroup(std::shared_ptr group, GroupType type, std::string name, ServerId targetServerId); - bool copyGroupPermissions(const std::shared_ptr& source, const std::shared_ptr& target); - - bool reloadGroupPermissions(std::shared_ptr); - - bool renameGroup(std::shared_ptr, std::string); - bool deleteGroup(std::shared_ptr); - bool deleteAllGroups(); - std::deque listGroupMembers(std::shared_ptr, bool names = false); - std::vector> listGroupAssignments(ClientDbId client); - - void cleanupAssignments(ClientDbId); - - std::shared_ptr findGroup(GroupId); - std::shared_ptr findGroupLocal(GroupId); - std::vector> findGroup(GroupTarget target, std::string); - - std::shared_ptr defaultGroup(GroupTarget type, bool enforce_property = false); - - std::deque update_server_group_property(const std::shared_ptr &client, bool channel_lock, const std::shared_ptr& channel); - void enableCache(const ClientDbId& /* client database id */); /* if this called disableCache(...) MUST be called to decrease the reference count */ - void disableCache(const ClientDbId& /* client database id */); - bool isClientCached(const ClientDbId& /* client database id */); - void clearCache(); - - bool isLocalGroup(std::shared_ptr); - protected: - void handleChannelDeleted(const ChannelId& /* channel id */); - private: - std::shared_ptr root = nullptr; - std::weak_ptr server; - ServerId getServerId(); - - sql::SqlManager* sql; - - std::mutex group_lock{}; - std::vector> groups; - - threads::Mutex cacheLock; - std::vector> cachedClients; - - int insertGroupFromDb(int count, char** values, char** column); - - inline std::shared_ptr resolve_cached_client(ClientDbId client_database_id); - }; -} \ No newline at end of file +DEFINE_TRANSFORMS(ts::GroupNameMode, uint8_t); \ No newline at end of file diff --git a/server/src/InstanceHandler.cpp b/server/src/InstanceHandler.cpp index 5d24268..16dba77 100644 --- a/server/src/InstanceHandler.cpp +++ b/server/src/InstanceHandler.cpp @@ -17,6 +17,7 @@ #include #include #include +#include "./groups/GroupManager.h" #ifndef _POSIX_SOURCE #define _POSIX_SOURCE @@ -32,10 +33,8 @@ using namespace std::chrono; using namespace ts; using namespace ts::server; -#define INSTANCE_TICK_NAME "instance" - extern bool mainThreadActive; -InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) { +InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql), permission_helper_{this} { serverInstance = this; this->general_task_executor_ = std::make_shared(ts::config::threads::ticking, "instance tick "); @@ -128,10 +127,49 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) { dynamic_pointer_cast(this->_musicRoot)->initialize_weak_reference(this->_musicRoot); { - this->__old__groupManager = std::make_shared(nullptr, this->getSql()); - this->__old__groupManager->loadGroupFormDatabase(); + using GroupLoadResult = groups::GroupLoadResult; - if (this->__old__groupManager->availableServerGroups(false).empty()) { + this->group_manager_ = std::make_shared(this->getSql(), 0, nullptr); + if(!this->group_manager_->initialize(this->group_manager_, error_message)) { + logCritical(LOG_INSTANCE, "Failed to initialize instance group manager: {}", error_message); + mainThreadActive = false; + return; + } + + bool initialize_groups{false}; + switch(this->group_manager_->server_groups()->load_data(true)) { + case GroupLoadResult::SUCCESS: + break; + case GroupLoadResult::NO_GROUPS: + initialize_groups = true; + break; + + case GroupLoadResult::DATABASE_ERROR: + logCritical(LOG_INSTANCE, "Failed to load instance server groups (Database error)"); + mainThreadActive = false; + return; + } + + switch(this->group_manager_->channel_groups()->load_data(true)) { + case GroupLoadResult::SUCCESS: + break; + case GroupLoadResult::NO_GROUPS: + initialize_groups = true; + break; + + case GroupLoadResult::DATABASE_ERROR: + logCritical(LOG_INSTANCE, "Failed to load instance channel groups (Database error)"); + mainThreadActive = false; + return; + } + + if(!this->group_manager_->assignments().load_data(error_message)) { + logCritical(LOG_INSTANCE, "Failed to load instance group assignments: {}", error_message); + mainThreadActive = false; + return; + } + + if (initialize_groups) { if(!this->setupDefaultGroups()){ logCritical(LOG_INSTANCE, "Could not setup server instance! Stopping..."); mainThreadActive = false; @@ -139,30 +177,7 @@ InstanceHandler::InstanceHandler(SqlDataManager *sql) : sql(sql) { } } - debugMessage(LOG_INSTANCE, "Instance admin group id " + to_string(this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP].as())); - auto instance_server_admin = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP].as()); - if (!instance_server_admin) { - instance_server_admin = this->__old__groupManager->availableServerGroups(false).front(); - logCritical(LOG_INSTANCE, "Missing instance server admin group! Using first available (" + (instance_server_admin ? instance_server_admin->name() : "nil") + ")"); - } - if(this->__old__groupManager->listGroupAssignments(this->globalServerAdmin->getClientDatabaseId()).empty()) - this->__old__groupManager->addServerGroup(this->globalServerAdmin->getClientDatabaseId(), instance_server_admin); - - debugMessage(LOG_INSTANCE, "Server guest group id " + to_string(this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as())); - auto instance_server_guest = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as_save()); - if (!instance_server_guest) { - instance_server_guest = this->__old__groupManager->availableServerGroups(false).front(); - logCritical(LOG_INSTANCE, "Missing instance server guest group! Using first available (" + (instance_server_guest ? instance_server_guest->name() : "nil") + ")"); - } - this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP] = instance_server_guest->groupId(); - - debugMessage(LOG_INSTANCE, "Server music group id " + to_string(this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as())); - auto instance_server_music = this->__old__groupManager->findGroup(this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as_save()); - if (!instance_server_music) { - instance_server_music = instance_server_guest; - logCritical(LOG_INSTANCE, "Missing instance server music group! Using serverguest (" + (instance_server_music ? instance_server_music->name() : "nil") + ")"); - } - this->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP] = instance_server_music->groupId(); + this->validate_default_groups(); } { @@ -214,7 +229,7 @@ InstanceHandler::~InstanceHandler() { delete this->banMgr; delete this->dbHelper; - __old__groupManager = nullptr; + group_manager_ = nullptr; globalServerAdmin = nullptr; _musicRoot = nullptr; @@ -547,23 +562,14 @@ void InstanceHandler::tickInstance() { this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_ALIVE] = this->calculateSpokenTime().count(); this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_TOTAL] = - this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_ALIVE].as() + - this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_DELETED].as() + - this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_VARIANZ].as(); + this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_ALIVE].as_save() + + this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_DELETED].as_save() + + this->properties()[property::SERVERINSTANCE_SPOKEN_TIME_VARIANZ].as_save(); } } void InstanceHandler::save_group_permissions() { - auto groups = this->getOldGroupManager()->availableGroups(false); - for(auto& group : groups) { - auto permissions = group->permissions(); - if(permissions->require_db_updates()) { - auto begin = system_clock::now(); - serverInstance->databaseHelper()->saveGroupPermissions(0, group->groupId(), 0, permissions); - auto end = system_clock::now(); - debugMessage(0, "Saved instance group permissions for group {} ({}) in {}ms", group->groupId(), group->name(), duration_cast(end - begin).count()); - } - } + this->group_manager()->save_permissions(); } void InstanceHandler::save_channel_permissions() { @@ -884,35 +890,58 @@ void InstanceHandler::loadWebCertificate() { this->web_cert_revision = revision; } +bool InstanceHandler::validate_default_groups() { + using groups::GroupCalculateMode; + using groups::GroupAssignmentCalculateMode; -permission::v2::PermissionFlaggedValue InstanceHandler::calculate_permission(permission::PermissionType permission, - ClientDbId cldbid, ClientType type, ChannelId channel, bool granted, std::shared_ptr cache) { - auto result = this->calculate_permissions({permission}, cldbid, type, channel, granted, cache); - if(result.empty()) return {0, false}; - return result.front().second; -} + { + auto property = this->properties()[property::SERVERINSTANCE_ADMIN_SERVERQUERY_GROUP]; + auto group_id = property.as_save(); + debugMessage(LOG_INSTANCE, "Instance admin query group id {}", group_id); -std::vector > InstanceHandler::calculate_permissions( - const std::deque &permissions, ClientDbId cldbid, ClientType type, ChannelId channel, bool granted, std::shared_ptr cache) { - std::vector> result{}; + auto group_instance = this->group_manager_->server_groups()->find_group(GroupCalculateMode::GLOBAL, group_id); + if(!group_instance) { + auto available_groups = this->group_manager_->server_groups()->available_groups(GroupCalculateMode::GLOBAL); + if(available_groups.empty()) { + logCritical(LOG_INSTANCE, "Missing instance server groups."); + return false; + } - //TODO: Negate? - //TODO: May move this part to the instance? - - auto server_groups = this->getOldGroupManager()->getServerGroups(cldbid, type); - for(const auto& permission : permissions) { - permission::v2::PermissionFlaggedValue value{0, false}; - - for(const auto &gr : server_groups){ - auto group_permissions = gr->group->permissions(); - auto flagged_permissions = granted ? group_permissions->permission_granted_flagged(permission) : group_permissions->permission_value_flagged(permission); - if(flagged_permissions.has_value) - if(!value.has_value || flagged_permissions.value > value.value || flagged_permissions.value == -1) - value = flagged_permissions; + group_instance = available_groups.front(); + logCritical(LOG_INSTANCE, "Missing instance server admin query group. Using first available ({})", group_instance->group_id()); } - result.emplace_back(permission, value); + property.update_value(group_instance->group_id()); + + { + auto& assignments = this->group_manager_->assignments(); + auto client_assignments = assignments.server_groups_of_client(GroupAssignmentCalculateMode::GLOBAL, this->globalServerAdmin->getClientDatabaseId()); + if(client_assignments.empty()) { + assignments.add_server_group(this->globalServerAdmin->getClientDatabaseId(), group_instance->group_id()); + } + } } - return result; -} \ No newline at end of file + { + auto property = this->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP]; + auto group_id = property.as_save(); + debugMessage(LOG_INSTANCE, "Instance guest query group id {}", group_id); + + auto group_instance = this->group_manager_->server_groups()->find_group(GroupCalculateMode::GLOBAL, group_id); + if(!group_instance) { + auto available_groups = this->group_manager_->server_groups()->available_groups(GroupCalculateMode::GLOBAL); + if(available_groups.empty()) { + logCritical(LOG_INSTANCE, "Missing instance server groups."); + return false; + } + + group_instance = available_groups.front(); + logCritical(LOG_INSTANCE, "Missing instance server guest query group. Using first available ({})", group_instance->group_id()); + } + + property.update_value(group_instance->group_id()); + } + return true; +} + +InstancePermissionHelper::InstancePermissionHelper(InstanceHandler *instance) : instance{instance} {} \ No newline at end of file diff --git a/server/src/InstanceHandler.h b/server/src/InstanceHandler.h index 69f530a..1cbc329 100644 --- a/server/src/InstanceHandler.h +++ b/server/src/InstanceHandler.h @@ -32,7 +32,38 @@ namespace ts { class ActionLogger; } + namespace groups { + class GroupManager; + } + class ServerCommandExecutor; + class InstanceHandler; + + struct InstancePermissionHelper { + public: + explicit InstancePermissionHelper(InstanceHandler*); + + permission::v2::PermissionFlaggedValue calculate_permission( + permission::PermissionType, + ClientDbId, + ClientType type, + ChannelId channel, + bool granted = false, + std::shared_ptr cache = nullptr + ) const; + + std::vector> calculate_permissions( + const std::deque&, + ClientDbId, + ClientType type, + ChannelId channel, + bool granted = false, + std::shared_ptr cache = nullptr + ) const; + + private: + InstanceHandler* instance; + }; class InstanceHandler { public: @@ -47,7 +78,7 @@ namespace ts { } std::shared_ptr getInitialServerAdmin(){ return globalServerAdmin; } - std::shared_ptr getOldGroupManager(){ return __old__groupManager; } + const auto& group_manager(){ return this->group_manager_; } std::shared_ptr getChannelTree() { return this->default_tree; } std::shared_mutex& getChannelTreeLock() { return this->default_tree_lock; } @@ -87,24 +118,7 @@ namespace ts { std::shared_ptr getConversationIo() { return this->conversation_io; } [[nodiscard]] inline const auto& server_command_executor() { return this->server_command_executor_; } - - permission::v2::PermissionFlaggedValue calculate_permission( - permission::PermissionType, - ClientDbId, - ClientType type, - ChannelId channel, - bool granted = false, - std::shared_ptr cache = nullptr - ); - - std::vector> calculate_permissions( - const std::deque&, - ClientDbId, - ClientType type, - ChannelId channel, - bool granted = false, - std::shared_ptr cache = nullptr - ); + [[nodiscard]] inline const auto& permission_helper() { return this->permission_helper_; } [[nodiscard]] inline std::shared_ptr license_service() { return this->license_service_; } private: @@ -141,9 +155,12 @@ namespace ts { std::shared_ptr web_list = nullptr; std::shared_ptr default_server_properties = nullptr; - std::shared_ptr default_tree = nullptr; std::shared_mutex default_tree_lock; - std::shared_ptr __old__groupManager = nullptr; + std::shared_ptr default_tree = nullptr; + + InstancePermissionHelper permission_helper_; + + std::shared_ptr group_manager_{nullptr}; std::shared_ptr globalServerAdmin = nullptr; std::shared_ptr _musicRoot = nullptr; @@ -167,6 +184,7 @@ namespace ts { void save_channel_permissions(); void loadWebCertificate(); + bool validate_default_groups(); }; } } diff --git a/server/src/InstanceHandlerPermissions.cpp b/server/src/InstanceHandlerPermissions.cpp new file mode 100644 index 0000000..cdbe902 --- /dev/null +++ b/server/src/InstanceHandlerPermissions.cpp @@ -0,0 +1,76 @@ +// +// Created by WolverinDEV on 26/02/2021. +// + +#include "./InstanceHandler.h" +#include "./groups/GroupManager.h" + +using namespace ts; +using namespace ts::server; + +permission::v2::PermissionFlaggedValue InstancePermissionHelper::calculate_permission( + permission::PermissionType permission, + ClientDbId cldbid, + ClientType type, + ChannelId channel, + bool granted, + std::shared_ptr cache +) const { + auto result = this->calculate_permissions({permission}, cldbid, type, channel, granted, cache); + if(result.empty()) return {0, false}; + return result.front().second; +} + +std::vector > InstancePermissionHelper::calculate_permissions( + const std::deque &permissions, + ClientDbId cldbid, + ClientType /* type */, + ChannelId /* channel */, + bool granted, + std::shared_ptr /* cache */ +) const { + std::vector> result{}; + + /* TODO: Use same algorithm as on normal servers */ + std::vector> assigned_groups{}; + { + using groups::GroupAssignmentCalculateMode; + using groups::GroupCalculateMode; + + auto group_manager = this->instance->group_manager(); + auto& assignment_manager = group_manager->assignments(); + + auto assignments = assignment_manager.server_groups_of_client(GroupAssignmentCalculateMode::GLOBAL, cldbid); + if(assignments.empty()) { + assignments.push_back(this->instance->properties()[property::SERVERINSTANCE_GUEST_SERVERQUERY_GROUP].as_save()); + } + + assigned_groups.reserve(assignments.size()); + for(const auto& group_id : assignments) { + auto group = group_manager->server_groups()->find_group(GroupCalculateMode::GLOBAL, group_id); + if(!group) { + continue; + } + + assigned_groups.push_back(std::move(group)); + } + } + + for(const auto& permission : permissions) { + permission::v2::PermissionFlaggedValue value{0, false}; + + for(const auto &gr : assigned_groups){ + auto group_permissions = gr->permissions(); + auto flagged_permissions = granted ? group_permissions->permission_granted_flagged(permission) : group_permissions->permission_value_flagged(permission); + if(flagged_permissions.has_value) { + if(!value.has_value || flagged_permissions.value > value.value || flagged_permissions.value == -1) { + value = flagged_permissions; + } + } + } + + result.emplace_back(permission, value); + } + + return result; +} \ No newline at end of file diff --git a/server/src/InstanceHandlerSetup.cpp b/server/src/InstanceHandlerSetup.cpp index 52b7af8..ad38650 100644 --- a/server/src/InstanceHandlerSetup.cpp +++ b/server/src/InstanceHandlerSetup.cpp @@ -123,7 +123,7 @@ bool InstanceHandler::setupDefaultGroups() { for(const auto& info : groups) { debugMessage(LOG_INSTANCE, "Creating default group {} with type {}", info->name, to_string(info->target)); //Query groups - auto group = this->__old__groupManager->createGroup( + auto group = this->group_manager_->createGroup( info->target != 2 ? GroupTarget::GROUPTARGET_SERVER : GroupTarget::GROUPTARGET_CHANNEL, info->target == 0 ? GroupType::GROUP_TYPE_QUERY : GroupType::GROUP_TYPE_TEMPLATE, info->name diff --git a/server/src/PermissionCalculator.cpp b/server/src/PermissionCalculator.cpp new file mode 100644 index 0000000..3e7a4bb --- /dev/null +++ b/server/src/PermissionCalculator.cpp @@ -0,0 +1,343 @@ +// +// Created by WolverinDEV on 27/02/2021. +// + +#include "./PermissionCalculator.h" +#include "./InstanceHandler.h" +#include "./groups/Group.h" +#include "./client/DataClient.h" +#include +#include +#include + +using namespace ts::server; +using ts::permission::PermissionType; +using ts::permission::v2::PermissionFlaggedValue; + +ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, ChannelId channel_id) { + this->initialize_client(client); + + auto server = client->getServer(); + if(server && channel_id > 0) { + std::shared_lock channel_lock{server->get_channel_tree_lock()}; + auto channel = server->getChannelTree()->findChannel(channel_id); + channel_lock.unlock(); + + if(channel) { + this->channel_permissions = channel->permissions(); + } + } + this->channel_id_ = channel_id; +} + +ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, const std::shared_ptr &channel) { + this->initialize_client(client); + if(channel) { + this->channel_id_ = channel->channelId(); + this->channel_permissions = channel->permissions(); + } else { + this->channel_id_ = 0; + this->channel_permissions = nullptr; + } +} + +ClientPermissionCalculator::ClientPermissionCalculator( + const std::shared_ptr &server, + ClientDbId client_database_id, + ClientType client_type, + ChannelId channel_id) { + + this->client_database_id = client_database_id; + this->client_type = client_type; + this->channel_id_ = channel_id; + + if(server) { + this->virtual_server_id = server->getServerId(); + this->group_manager_ = server->group_manager(); + this->default_channel_group = [server]{ return server->default_channel_group(); }; + + std::shared_lock channel_lock{server->get_channel_tree_lock()}; + auto channel = server->getChannelTree()->findChannel(channel_id); + channel_lock.unlock(); + + if(channel) { + this->channel_permissions = channel->permissions(); + } + } else { + this->virtual_server_id = 0; + this->group_manager_ = serverInstance->group_manager(); + } +} + +void ClientPermissionCalculator::initialize_client(DataClient* client) { + this->virtual_server_id = client->getServerId(); + this->client_database_id = client->getClientDatabaseId(); + this->client_type = client->getType(); + this->client_permissions = client->permissions(); + + auto server = client->getServer(); + if(server) { + this->group_manager_ = server->group_manager(); + this->default_channel_group = [server]{ return server->default_channel_group(); }; + } else { + this->group_manager_ = serverInstance->group_manager(); + } +} + +std::vector> ClientPermissionCalculator::calculate_permissions( + const std::deque &permissions, + bool calculate_granted +) { + if(permissions.empty()) { + return {}; + } + + std::vector> result; + result.reserve(permissions.size()); + + if(!this->client_permissions) { + this->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->virtual_server_id, this->client_database_id); + if(!this->client_permissions) { + logCritical(this->virtual_server_id, "Failed to load client permissions for client {}", this->client_database_id); + for(size_t index{0}; index < permissions.size(); index++) { + result.emplace_back(permissions[index], PermissionFlaggedValue{ 0, false }); + } + return result; + } + } + + bool have_skip_permission{false}; + int skip_permission_type{-1}; /* -1 := unset | 0 := skip, not explicit | 1 := skip, explicit */ + + /* + * server_group_data[0] := Server group id + * server_group_data[1] := Skip flag + * server_group_data[2] := Negate flag + * server_group_data[3] := Permission value + */ + typedef std::tuple GroupData; + bool server_group_data_initialized = false; + std::vector server_group_data; + GroupData* active_server_group; + + /* function to calculate skip permission */ + auto calculate_skip = [&]{ + skip_permission_type = 0; + /* test for skip permission within the client permission manager */ + { + auto skip_value = this->client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions); + if(skip_value.has_value) { + have_skip_permission = skip_value.value == 1; + skip_permission_type = 1; + logTrace(this->virtual_server_id, "[Permission] Found skip permission in client permissions. Value: {}", have_skip_permission); + } + } + /* test for skip permission within all server groups */ + if(skip_permission_type != 1) { + for(const auto& assignment : this->assigned_server_groups()) { + auto group_permissions = assignment->permissions(); + auto flagged_value = group_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions); + if(flagged_value.has_value) { + have_skip_permission |= flagged_value.value == 1; + if(have_skip_permission) { + logTrace(this->virtual_server_id, "[Permission] Found skip permission in client server group. Group: {} ({}), Value: {}", assignment->group_id(), assignment->display_name(), have_skip_permission); + break; + } + } + } + } + }; + + auto initialize_group_data = [&](const permission::PermissionType& permission_type) { + server_group_data_initialized = true; + active_server_group = nullptr; + + auto assigned_groups = this->assigned_server_groups(); + server_group_data.resize(assigned_groups.size()); + auto it = server_group_data.begin(); + for(auto& group : assigned_groups) { + auto group_permissions = group->permissions(); + auto permission_flags = group_permissions->permission_flags(permission_type); + + auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set; + if(!flag_set) { + continue; + } + + //TODO: Test if there is may a group channel permissions + auto value = group_permissions->permission_values(permission_type); + *it = std::make_tuple(group->group_id(), (bool) permission_flags.skip, (bool) permission_flags.negate, calculate_granted ? value.grant : value.value); + it++; + } + if(it == server_group_data.begin()) { + return; /* no server group has that permission */ + } + + server_group_data.erase(it, server_group_data.end()); /* remove unneeded */ + + auto found_negate = false; + for(auto& group : server_group_data) { + if(std::get<2>(group)) { + found_negate = true; + break; + } + } + + if(found_negate) { + server_group_data.erase(remove_if(server_group_data.begin(), server_group_data.end(), [](auto data) { return !std::get<2>(data); }), server_group_data.end()); + logTrace(this->virtual_server_id, "[Permission] Found negate flag within server groups. Groups left: {}", server_group_data.size()); + if(server_group_data.empty()) { + logTrace(this->virtual_server_id, "[Permission] After non negated groups have been kicked out the negated groups are empty! This should not happen! Permission: {}, Client ID: {}", permission_type, this->client_database_id); + } + permission::PermissionValue current_lowest = 0; + for(auto& group : server_group_data) { + if(!active_server_group || (std::get<3>(group) < current_lowest && std::get<3>(group) != -1)) { + current_lowest = std::get<3>(group); + active_server_group = &group; + } + } + } else { + permission::PermissionValue current_highest = 0; + for(auto& group : server_group_data) { + if(!active_server_group || (std::get<3>(group) > current_highest || std::get<3>(group) == -1)) { + current_highest = std::get<3>(group); + active_server_group = &group; + } + } + } + }; + + for(const auto& permission : permissions) { + server_group_data_initialized = false; /* reset all group data */ + auto client_permission_flags = this->client_permissions->permission_flags(permission); + /* lets try to resolve the channel specific permission */ + if(this->channel_id_ > 0 && client_permission_flags.channel_specific) { + auto data = this->client_permissions->channel_permission(permission, this->channel_id_); + if(calculate_granted ? data.flags.grant_set : data.flags.value_set) { + result.push_back({permission, {calculate_granted ? data.values.grant : data.values.value, true}}); + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Client channel permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, data.values.value); + continue; + } + } + + + bool skip_channel_permissions = this->channel_id_ == 0; + if(!skip_channel_permissions) { + /* look if somewhere is the skip permission flag set */ + if(skip_permission_type == -1) {/* initialize skip flag */ + calculate_skip(); + } + skip_channel_permissions = have_skip_permission; + } + if(!skip_channel_permissions) { + /* okey we've no global skip. Then now lookup the groups and the client permissions */ + if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) { + /* okey the client has the permission, this counts */ + skip_channel_permissions = client_permission_flags.skip; + } else { + if(!server_group_data_initialized) { + initialize_group_data(permission); + } + + if(active_server_group) { + skip_channel_permissions = std::get<1>(*active_server_group); + } + } + } + + if(!skip_channel_permissions) { + /* lookup the channel group */ + { + auto channel_assignment = this->assigned_channel_group(); + if(channel_assignment) { + auto group_permissions = channel_assignment->permissions(); + auto permission_flags = group_permissions->permission_flags(permission); + + auto flag_set = calculate_granted ? permission_flags.grant_set : permission_flags.value_set; + if(flag_set) { + auto value = group_permissions->permission_values(permission); + result.push_back({permission, {calculate_granted ? value.grant : value.value, true}}); + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Channel group permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, calculate_granted ? value.grant : value.value); + continue; + } + } + } + + /* lookup the channel permissions. Whyever? */ + if(this->channel_permissions) { + auto data = calculate_granted ? this->channel_permissions->permission_granted_flagged(permission) : this->channel_permissions->permission_value_flagged(permission); + if(data.has_value) { + result.push_back({permission, {data.value, true}}); + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Channel permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, data.value); + continue; + } + } + } + + if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) { + auto client_value = this->client_permissions->permission_values(permission); + result.push_back({permission, {calculate_granted ? client_value.grant : client_value.value, true}}); + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Client permission)", this->client_database_id, permission::resolvePermissionData(permission)->name, client_value.value); + continue; + } + + if(!server_group_data_initialized) { + initialize_group_data(permission); + } + + if(active_server_group) { + result.push_back({permission, {get<3>(*active_server_group), true}}); + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned {} (Server group permission of group {})", this->client_database_id, permission::resolvePermissionData(permission)->name, get<3>(*active_server_group), get<0>(*active_server_group)); + continue; + } + + logTrace(this->virtual_server_id, "[Permission] Calculation for client {} of permission {} returned in no permission.", this->client_database_id, permission::resolvePermissionData(permission)->name); + result.push_back({permission, {permNotGranted, false}}); + } + + return result; +} + +const std::vector>& ClientPermissionCalculator::assigned_server_groups() { + if(this->assigned_server_groups_.has_value()) { + return *this->assigned_server_groups_; + } + + auto assignments = this->group_manager_->assignments().server_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->client_database_id); + + this->assigned_server_groups_.emplace(); + this->assigned_server_groups_->reserve(assignments.size()); + + for(const auto& group_id : assignments) { + auto group = this->group_manager_->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id); + if(group) { + this->assigned_server_groups_->push_back(group); + } + } + + return *this->assigned_server_groups_; +} + +const std::shared_ptr& ClientPermissionCalculator::assigned_channel_group() { + if(this->assigned_channel_group_.has_value()) { + return *this->assigned_channel_group_; + } + + this->assigned_channel_group_.emplace(); + if(this->channel_id_ == 0) { + return *this->assigned_channel_group_; + } + + auto channel_group_assignment = this->group_manager_->assignments().channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->client_database_id, this->channel_id_); + if(!channel_group_assignment.has_value()) { + return *this->assigned_channel_group_; + } + + auto channel_group = this->group_manager_->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, channel_group_assignment->group_id); + if(!channel_group) { + channel_group = this->default_channel_group(); + } + + *this->assigned_channel_group_ = channel_group; + return *this->assigned_channel_group_; +} \ No newline at end of file diff --git a/server/src/PermissionCalculator.h b/server/src/PermissionCalculator.h new file mode 100644 index 0000000..a0d3dbb --- /dev/null +++ b/server/src/PermissionCalculator.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include + +namespace ts { + class BasicChannel; +} + +namespace ts::server { + class DataClient; + class VirtualServer; + + namespace groups { + class ChannelGroup; + class ServerGroup; + class GroupManager; + } + + /** + * Helper for calculating the client permissions for a certain channel. + * Note: All functions are not thread save! + */ + class ClientPermissionCalculator { + public: + explicit ClientPermissionCalculator(DataClient* /* client */, const std::shared_ptr& /* target channel */); + explicit ClientPermissionCalculator(DataClient* /* client */, ChannelId /* target channel id */); + explicit ClientPermissionCalculator( + const std::shared_ptr& /* server */, + ClientDbId /* client database id */, + ClientType /* client type */, + ChannelId /* target channel id */ + ); + + /** + * Calculate the given permissions. + * This method can be called from everywhere without any locking needed. + * @param granted + * @return + */ + permission::v2::PermissionFlaggedValue calculate_permission( + permission::PermissionType, + bool granted = false + ); + + /** + * Calculate the given permissions. + * This method can be called from everywhere without any locking needed. + * @param channel + * @param calculate_granted + * @return + */ + std::vector> calculate_permissions( + const std::deque&, + bool calculate_granted = false + ); + private: + /* given fields */ + ServerId virtual_server_id; + ClientDbId client_database_id; + ClientType client_type; + ChannelId channel_id_; + std::shared_ptr group_manager_{}; + std::shared_ptr channel_permissions{}; + std::function()> default_channel_group{[]{ return nullptr; }}; + + /* fields which will be set when calculating permissions */ + std::shared_ptr client_permissions{}; + + bool global_skip{false}; + bool global_skip_set{false}; + + std::optional> assigned_channel_group_{}; + std::optional>> assigned_server_groups_{}; + + void initialize_client(DataClient* /* client */); + + [[nodiscard]] const std::vector>& assigned_server_groups(); + [[nodiscard]] const std::shared_ptr& assigned_channel_group(); + }; +} \ No newline at end of file diff --git a/server/src/ServerManagerSnapshotDeploy.cpp b/server/src/ServerManagerSnapshotDeploy.cpp index b76efc3..4d76f87 100644 --- a/server/src/ServerManagerSnapshotDeploy.cpp +++ b/server/src/ServerManagerSnapshotDeploy.cpp @@ -978,7 +978,7 @@ bool VirtualServerManager::createServerSnapshot(Command &cmd, shared_ptrgetGroupManager()->availableServerGroups(false)) { + for(const auto& group : server->group_manager()->availableServerGroups(false)) { cmd[index]["id"] = group->groupId(); cmd[index]["name"] = group->name(); if(!writePermissions(group->permissions(), cmd, index, version, permission::teamspeak::SERVER, error)) break; @@ -1000,7 +1000,7 @@ bool VirtualServerManager::createServerSnapshot(Command &cmd, shared_ptrgetGroupManager()->availableChannelGroups(false)) { + for(const auto& group : server->group_manager()->availableChannelGroups(false)) { cmd[index]["id"] = group->groupId(); cmd[index]["name"] = group->name(); if(!writePermissions(group->permissions(), cmd, index, version, permission::teamspeak::SERVER, error)) break; diff --git a/server/src/TS3ServerClientManager.cpp b/server/src/TS3ServerClientManager.cpp index 9491af0..8259c9e 100644 --- a/server/src/TS3ServerClientManager.cpp +++ b/server/src/TS3ServerClientManager.cpp @@ -267,7 +267,7 @@ void VirtualServer::testBanStateChange(const std::shared_ptr& i bool VirtualServer::could_default_create_channel() { { - auto default_group = this->getGroupManager()->defaultGroup(GroupTarget::GROUPTARGET_SERVER); + auto default_group = this->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_SERVER); if(default_group) { auto flag = default_group->permissions()->permission_value_flagged(permission::b_channel_create_temporary).value == 1; flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_semi_permanent).value == 1; @@ -278,7 +278,7 @@ bool VirtualServer::could_default_create_channel() { } { - auto default_group = this->getGroupManager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); + auto default_group = this->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); if(default_group) { auto flag = default_group->permissions()->permission_value_flagged(permission::b_channel_create_temporary).value == 1; flag = flag ? flag : default_group->permissions()->permission_value_flagged(permission::b_channel_create_semi_permanent).value == 1; diff --git a/server/src/TS3ServerHeartbeat.cpp b/server/src/TS3ServerHeartbeat.cpp index 665bb23..4352f98 100644 --- a/server/src/TS3ServerHeartbeat.cpp +++ b/server/src/TS3ServerHeartbeat.cpp @@ -236,7 +236,7 @@ void VirtualServer::executeServerTick() { { BEGIN_TIMINGS(); - auto groups = this->getGroupManager()->availableGroups(false); + auto groups = this->group_manager()->availableGroups(false); for(auto& group : groups) { auto permissions = group->permissions(); if(permissions->require_db_updates()) { diff --git a/server/src/VirtualServer.cpp b/server/src/VirtualServer.cpp index fe89d6a..a07350f 100644 --- a/server/src/VirtualServer.cpp +++ b/server/src/VirtualServer.cpp @@ -27,6 +27,7 @@ #include "src/manager/ConversationManager.h" #include #include +#include "./groups/GroupManager.h" using namespace std; using namespace std::chrono; @@ -48,6 +49,7 @@ VirtualServer::VirtualServer(uint16_t serverId, sql::SqlManager* database) : ser bool VirtualServer::initialize(bool test_properties) { assert(self.lock()); + std::string error{}; this->rtc_server_ = std::make_unique(); this->_properties = serverInstance->databaseHelper()->loadServerProperties(self.lock()); @@ -187,9 +189,9 @@ bool VirtualServer::initialize(bool test_properties) { channelTree = new ServerChannelTree(self.lock(), this->sql); channelTree->loadChannelsFromDatabase(); - this->groups = new GroupManager(self.lock(), this->sql, serverInstance->getOldGroupManager()); - if(!this->groups->loadGroupFormDatabase()){ //TODO exception etc - logCritical(this->serverId, "Cant setup group manager!"); + this->groups_manager_ = std::make_shared(this->getSql(), this->getServerId(), serverInstance->group_manager()); + if(!this->groups_manager_->initialize(this->groups_manager_, error)) { + logCritical(this->getServerId(), "Failed to initialize group manager: {}", error); return false; } @@ -225,21 +227,57 @@ bool VirtualServer::initialize(bool test_properties) { this->complains = new ComplainManager(this); if(!this->complains->loadComplains()) logError(this->serverId, "Could not load complains"); - //Setup new server if needed - if(this->groups->availableServerGroups(false).empty() || this->groups->availableChannelGroups(false).empty()){ - if(!this->properties()[property::VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY].as().empty()) { - logCritical(this->getServerId(), "Missing default groups. Applying permission reset!"); + { + using groups::GroupLoadResult; + + bool initialize_groups{false}; + switch(this->groups_manager_->server_groups()->load_data(true)) { + case GroupLoadResult::SUCCESS: + break; + case GroupLoadResult::NO_GROUPS: + initialize_groups = true; + break; + + case GroupLoadResult::DATABASE_ERROR: + logError(this->getServerId(), "Failed to load server groups (Database error)"); + return false; + } + + switch(this->groups_manager_->channel_groups()->load_data(true)) { + case GroupLoadResult::SUCCESS: + break; + case GroupLoadResult::NO_GROUPS: + initialize_groups = true; + break; + + case GroupLoadResult::DATABASE_ERROR: + logError(this->getServerId(), "Failed to load channel groups (Database error)"); + return false; + } + + if(!this->groups_manager_->assignments().load_data(error)) { + logError(this->getServerId(), "Failed to load group assignments: {}", error); + return false; + } + + if (initialize_groups) { + if(!this->properties()[property::VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY].as().empty()) { + logCritical(this->getServerId(), "Missing default groups. Applying permission reset!"); + } + + string token; + if(!this->resetPermissions(token)) { + logCritical(this->serverId, "Failed to reset server permissions! This could be fatal!"); + } + logMessageFmt(true, this->serverId, "---------------------- Token ----------------------"); + logMessageFmt(true, this->serverId, "{:^51}", "The server's serveradmin token:"); + logMessageFmt(true, this->serverId, "{:^51}", token); + logMessageFmt(true, this->serverId, ""); + logMessageFmt(true, this->serverId, "{:^51}", "Note: This token could be used just once!"); + logMessageFmt(true, this->serverId, "---------------------- Token ----------------------"); } - string token; - if(!this->resetPermissions(token)) - logCritical(this->serverId, "Failed to reset server permissions! This could be fatal!"); - logMessageFmt(true, this->serverId, "---------------------- Token ----------------------"); - logMessageFmt(true, this->serverId, "{:^51}", "The server's serveradmin token:"); - logMessageFmt(true, this->serverId, "{:^51}", token); - logMessageFmt(true, this->serverId, ""); - logMessageFmt(true, this->serverId, "{:^51}", "Note: This token could be used just once!"); - logMessageFmt(true, this->serverId, "---------------------- Token ----------------------"); } + if(test_properties) this->ensureValidDefaultGroups(); @@ -839,7 +877,7 @@ void VirtualServer::broadcastMessage(std::shared_ptr invoker, s std::vector> CalculateCache::getGroupAssignments(VirtualServer* server, ClientDbId cldbid, ClientType type) { if(assignment_server_groups_set) return assignment_server_groups; - assignment_server_groups = server->getGroupManager()->getServerGroups(cldbid, type); + assignment_server_groups = server->group_manager()->getServerGroups(cldbid, type); assignment_server_groups_set = true; return assignment_server_groups; } @@ -848,7 +886,7 @@ std::shared_ptr CalculateCache::getChannelAssignment(VirtualSer if(this->assignment_channel_group_set && this->assignment_channel_group_channel == channel_id) return this->assignment_channel_group; auto channel = this->getServerChannel(server, channel_id); - assignment_channel_group = channel ? server->getGroupManager()->getChannelGroup(client_dbid, channel, true) : nullptr; + assignment_channel_group = channel ? server->group_manager()->getChannelGroup(client_dbid, channel, true) : nullptr; assignment_channel_group_set = true; assignment_channel_group_channel = channel_id; return assignment_channel_group; @@ -884,7 +922,7 @@ vectorclient_permissions) { - cache->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(self.lock(), client_dbid); + cache->client_permissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), client_dbid); } bool have_skip_permission = false; @@ -1134,44 +1172,44 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) { { - threads::MutexLock lock(this->getGroupManager()->cacheLock); - this->getGroupManager()->deleteAllGroups(); + threads::MutexLock lock(this->group_manager()->cacheLock); + this->group_manager()->deleteAllGroups(); deque> saved_groups; - for(const auto& group : serverInstance->getOldGroupManager()->availableGroups(false)){ + for(const auto& group : serverInstance->group_manager()->availableGroups(false)){ if(group->type() != GroupType::GROUP_TYPE_TEMPLATE) continue; debugMessage(this->serverId, "Copy default group {{Id: {}, Type: {}, Target: {}, Name: {}}} to server", group->groupId(), group->type(), group->target(), group->name()); - this->getGroupManager()->copyGroup(group, GroupType::GROUP_TYPE_NORMAL, group->name(), this->serverId); + this->group_manager()->copyGroup(group, GroupType::GROUP_TYPE_NORMAL, group->name(), this->serverId); } } //Server admin - auto default_server_admin = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as()); - auto default_server_music = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as()); - auto default_server_guest = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as()); + auto default_server_admin = serverInstance->group_manager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP].as()); + auto default_server_music = serverInstance->group_manager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_MUSICDEFAULT_GROUP].as()); + auto default_server_guest = serverInstance->group_manager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP].as()); - auto default_channel_admin = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as()); - auto default_channel_guest = serverInstance->getOldGroupManager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as()); + auto default_channel_admin = serverInstance->group_manager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP].as()); + auto default_channel_guest = serverInstance->group_manager()->findGroup(serverInstance->properties()[property::SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP].as()); if(!default_server_guest) { logCritical(0, "Missing default server guest template group!"); - assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty()); + assert(!serverInstance->group_manager()->availableChannelGroups().empty()); - default_server_guest = serverInstance->getOldGroupManager()->availableServerGroups().front(); + default_server_guest = serverInstance->group_manager()->availableServerGroups().front(); logCritical(0, "Using group {} as default server guest group for server {}.", default_server_guest->name(), this->serverId); } if(!default_channel_admin) { logCritical(0, "Missing default channel guest template group!"); - assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty()); + assert(!serverInstance->group_manager()->availableChannelGroups().empty()); - default_channel_admin = serverInstance->getOldGroupManager()->availableChannelGroups().front(); + default_channel_admin = serverInstance->group_manager()->availableChannelGroups().front(); logCritical(0, "Using group {} as channel server guest group for server {}.", default_channel_admin->name(), this->serverId); } if(!default_server_music) { logCritical(0, "Missing default channel guest template group!"); - assert(!serverInstance->getOldGroupManager()->availableChannelGroups().empty()); + assert(!serverInstance->group_manager()->availableChannelGroups().empty()); - default_server_music = serverInstance->getOldGroupManager()->availableChannelGroups().front(); + default_server_music = serverInstance->group_manager()->availableChannelGroups().front(); logCritical(0, "Using group {} as channel server guest group for server {}.", default_server_music->name(), this->serverId); } @@ -1185,12 +1223,12 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) { default_channel_admin = default_channel_guest; } - this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_guest->name()).front()->groupId(); - this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP] = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_music->name()).front()->groupId(); - this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_admin->name()).front()->groupId(); - this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_guest->name()).front()->groupId(); + this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_guest->name()).front()->groupId(); + this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_music->name()).front()->groupId(); + this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_admin->name()).front()->groupId(); + this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_CHANNEL, default_channel_guest->name()).front()->groupId(); - auto server_admin_group_id = this->getGroupManager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_admin->name()).front()->groupId(); + auto server_admin_group_id = this->group_manager()->findGroup(GroupTarget::GROUPTARGET_SERVER, default_server_admin->name()).front()->groupId(); auto token = this->tokenManager->create_token(0, "Default server admin token", 1, std::chrono::system_clock::time_point{}); if(!token) { logCritical(this->serverId, "Failed to register the default server admin token."); @@ -1217,7 +1255,7 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) { client->notifyServerGroupList(); client->notifyChannelGroupList(); } - if(this->notifyClientPropertyUpdates(client, this->getGroupManager()->update_server_group_property(client, true, client->getChannel()))) { + if(this->notifyClientPropertyUpdates(client, this->group_manager()->update_server_group_property(client, true, client->getChannel()))) { client->task_update_needed_permissions.enqueue(); } client->task_update_channel_client_properties.enqueue(); @@ -1226,16 +1264,16 @@ bool VirtualServer::resetPermissions(std::string& new_permission_token) { } void VirtualServer::ensureValidDefaultGroups() { - auto default_server_group = this->getGroupManager()->defaultGroup(GROUPTARGET_SERVER, true); + auto default_server_group = this->group_manager()->defaultGroup(GROUPTARGET_SERVER, true); if(!default_server_group) { logError(this->serverId, "Missing server's default server group! (Id: {})", this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP].value()); - default_server_group = this->getGroupManager()->availableServerGroups(false).front(); + default_server_group = this->group_manager()->availableServerGroups(false).front(); logError(this->serverId, "Using {} ({}) instead!", default_server_group->groupId(), default_server_group->name()); this->properties()[property::VIRTUALSERVER_DEFAULT_SERVER_GROUP] = default_server_group->groupId(); } - auto default_music_group = this->getGroupManager()->defaultGroup(GROUPTARGET_SERVER, true); + auto default_music_group = this->group_manager()->defaultGroup(GROUPTARGET_SERVER, true); if(!default_music_group) { logError(this->serverId, "Missing server's default music group! (Id: {})", this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP].value()); @@ -1244,20 +1282,20 @@ void VirtualServer::ensureValidDefaultGroups() { this->properties()[property::VIRTUALSERVER_DEFAULT_MUSIC_GROUP] = default_music_group->groupId(); } - auto default_channel_group = this->getGroupManager()->defaultGroup(GROUPTARGET_CHANNEL, true); + auto default_channel_group = this->group_manager()->defaultGroup(GROUPTARGET_CHANNEL, true); if(!default_channel_group) { logError(this->serverId, "Missing server's default channel group! (Id: {})", this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP].value()); - default_channel_group = this->getGroupManager()->availableChannelGroups(false).front(); + default_channel_group = this->group_manager()->availableChannelGroups(false).front(); logError(this->serverId, "Using {} ({}) instead!", default_channel_group->groupId(), default_channel_group->name()); this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP] = default_channel_group->groupId(); } - auto admin_channel_group = this->getGroupManager()->findGroupLocal(this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP].as_save()); + auto admin_channel_group = this->group_manager()->findGroupLocal(this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP].as_save()); if(!admin_channel_group) { logError(this->serverId, "Missing server's default channel admin group! (Id: {})", this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP].value()); - admin_channel_group = this->getGroupManager()->availableChannelGroups(false).front(); + admin_channel_group = this->group_manager()->availableChannelGroups(false).front(); logError(this->serverId, "Using {} ({}) instead!", admin_channel_group->groupId(), admin_channel_group->name()); this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP] = admin_channel_group->groupId(); } @@ -1347,4 +1385,16 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr VirtualServer::default_channel_group() { + auto group_id = this->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_GROUP].as_save(); + auto group = this->group_manager()->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id); + if(!group) { + auto groups = this->group_manager()->channel_groups()->available_groups(groups::GroupCalculateMode::GLOBAL); + /* TODO: Log warning? */ + group = groups.back(); + } + + return group; } \ No newline at end of file diff --git a/server/src/VirtualServer.h b/server/src/VirtualServer.h index 0ec9c9a..b3834e3 100644 --- a/server/src/VirtualServer.h +++ b/server/src/VirtualServer.h @@ -67,11 +67,15 @@ namespace ts { class WebControlServer; - namespace conversation { class ConversationManager; } + namespace groups { + class ChannelGroup; + class GroupManager; + } + struct ServerState { enum value { OFFLINE, @@ -188,13 +192,15 @@ namespace ts { inline ServerId getServerId(){ return this->serverId; } inline ServerChannelTree* getChannelTree(){ return this->channelTree; } - inline GroupManager* getGroupManager() { return this->groups; } inline rtc::Server& rtc_server() { return *this->rtc_server_; } [[nodiscard]] inline auto& getTokenManager() { return *this->tokenManager; } + [[nodiscard]] inline auto group_manager() { return this->groups_manager_; } + [[nodiscard]] std::shared_ptr default_channel_group(); + bool notifyServerEdited(std::shared_ptr, std::deque keys); bool notifyClientPropertyUpdates(std::shared_ptr, const std::deque& keys, bool selfNotify = true); /* execute only with at least channel tree read lock! */ inline bool notifyClientPropertyUpdates(const std::shared_ptr& client, const std::deque& keys, bool selfNotify = true) { @@ -343,7 +349,7 @@ namespace ts { ServerChannelTree* channelTree = nullptr; std::shared_mutex channel_tree_lock; /* lock if access channel tree! */ - GroupManager* groups = nullptr; + std::shared_ptr groups_manager_{}; std::shared_ptr serverRoot = nullptr; std::shared_ptr serverAdmin = nullptr; diff --git a/server/src/channel/ServerChannel.cpp b/server/src/channel/ServerChannel.cpp index 08c54f9..74ef71d 100644 --- a/server/src/channel/ServerChannel.cpp +++ b/server/src/channel/ServerChannel.cpp @@ -574,11 +574,11 @@ void ServerChannelTree::on_channel_entry_deleted(const shared_ptr auto server = this->server_ref.lock(); if(server) { - server->getGroupManager()->handleChannelDeleted(channel->channelId()); + server->group_manager()->handleChannelDeleted(channel->channelId()); server->conversation_manager()->delete_conversation(channel->channelId()); server->rtc_server().destroy_channel(server_channel->rtc_channel_id); } else { - serverInstance->getOldGroupManager()->handleChannelDeleted(channel->channelId()); + serverInstance->group_manager()->handleChannelDeleted(channel->channelId()); } diff --git a/server/src/client/ConnectedClient.cpp b/server/src/client/ConnectedClient.cpp index 74b5cc5..00e6277 100644 --- a/server/src/client/ConnectedClient.cpp +++ b/server/src/client/ConnectedClient.cpp @@ -11,6 +11,9 @@ #include "src/VirtualServer.h" #include "voice/VoiceClient.h" #include "../InstanceHandler.h" +#include "../PermissionCalculator.h" +#include "../groups/GroupManager.h" +#include "../groups/Group.h" #include using namespace std; @@ -119,8 +122,6 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool permission::b_client_ignore_antiflood, permission::i_channel_view_power, permission::b_channel_ignore_view_power, - permission::i_icon_id, - permission::b_client_is_priority_speaker, }, channel ? channel->channelId() : 0); permission::v2::PermissionFlaggedValue @@ -974,7 +975,9 @@ bool ConnectedClient::update_client_needed_permissions() { /* The server and/or the channel might change while we're executing this method */ auto currentChannel = this->currentChannel; - auto values = this->calculate_permissions(permission::neededPermissions, currentChannel ? currentChannel->channelId() : 0); + + ClientPermissionCalculator permission_helper{this, currentChannel}; + auto values = permission_helper.calculate_permissions(permission::neededPermissions); auto updated = false; { @@ -1072,6 +1075,9 @@ permission::PermissionType ConnectedClient::calculate_and_get_join_state(const s } void ConnectedClient::useToken(token::TokenId token_id) { + using groups::GroupCalculateMode; + using groups::GroupAssignmentResult; + auto server_ref = this->server; if(!server_ref) { return; @@ -1089,38 +1095,56 @@ void ConnectedClient::useToken(token::TokenId token_id) { bool tree_registered = !!this->currentChannel; bool server_groups_changed{false}, channel_group_changed{false}; - std::deque> added_server_groups{}; - std::deque> removed_server_groups{}; + std::deque> added_server_groups{}; + std::deque> removed_server_groups{}; for(const auto& action : actions) { switch(action.type) { case token::ActionType::AddServerGroup: case token::ActionType::RemoveServerGroup: { - auto group = server->getGroupManager()->findGroup(action.id1); - if(!group || group->target() != GroupTarget::GROUPTARGET_SERVER) { + auto group = server->group_manager()->server_groups()->find_group(GroupCalculateMode::GLOBAL, action.id1); + if(!group) { debugMessage(this->getServerId(), "{} Skipping token action add/remove server group for group {} because the group does not exists anymore.", CLIENT_STR_LOG_PREFIX, action.id1); break; } if(action.type == token::ActionType::AddServerGroup) { - if(this->server->groups->hasServerGroupAssigned(this->getClientDatabaseId(), group)) { - debugMessage(this->getServerId(), "{} Skipping token action add server group for group {} because client is already member of that group.", CLIENT_STR_LOG_PREFIX, action.id1); - } else { - debugMessage(this->getServerId(), "{} Executing token action add server group for group {}.", CLIENT_STR_LOG_PREFIX, action.id1); - this->server->groups->addServerGroup(this->getClientDatabaseId(), group); + auto result = this->server->group_manager()->assignments().add_server_group(this->getClientDatabaseId(), group->group_id()); + switch(result) { + case GroupAssignmentResult::SUCCESS: + debugMessage(this->getServerId(), "{} Executing token action add server group for group {}.", CLIENT_STR_LOG_PREFIX, action.id1); + added_server_groups.push_back(group); + server_groups_changed = true; + break; - added_server_groups.push_back(group); - server_groups_changed = true; + case GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP: + debugMessage(this->getServerId(), "{} Skipping token action add server group for group {} because client is already member of that group.", CLIENT_STR_LOG_PREFIX, action.id1); + break; + + case GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP: + case GroupAssignmentResult::SET_ALREADY_MEMBER_OF_GROUP: + default: + assert(false); + break; } } else { - if(!this->server->groups->hasServerGroupAssigned(this->getClientDatabaseId(), group)) { - debugMessage(this->getServerId(), "{} Skipping token action remove server group for group {} because client is not a member of that group.", CLIENT_STR_LOG_PREFIX, action.id1); - } else { - debugMessage(this->getServerId(), "{} Executing token action remove server group for group {}.", CLIENT_STR_LOG_PREFIX, action.id1); - this->server->groups->removeServerGroup(this->getClientDatabaseId(), group); + auto result = this->server->group_manager()->assignments().remove_server_group(this->getClientDatabaseId(), group->group_id()); + switch(result) { + case GroupAssignmentResult::SUCCESS: + debugMessage(this->getServerId(), "{} Executing token action remove server group for group {}.", CLIENT_STR_LOG_PREFIX, action.id1); + removed_server_groups.push_back(group); + server_groups_changed = true; + break; - removed_server_groups.push_back(group); - server_groups_changed = true; + case GroupAssignmentResult::REMOVE_NOT_MEMBER_OF_GROUP: + debugMessage(this->getServerId(), "{} Skipping token action remove server group for group {} because client is not a member of that group.", CLIENT_STR_LOG_PREFIX, action.id1); + break; + + case GroupAssignmentResult::ADD_ALREADY_MEMBER_OF_GROUP: + case GroupAssignmentResult::SET_ALREADY_MEMBER_OF_GROUP: + default: + assert(false); + break; } } @@ -1128,8 +1152,8 @@ void ConnectedClient::useToken(token::TokenId token_id) { } case token::ActionType::SetChannelGroup: { - auto group = server->getGroupManager()->findGroup(action.id1); - if(!group || group->target() != GroupTarget::GROUPTARGET_CHANNEL) { + auto group = server->group_manager()->channel_groups()->find_group(GroupCalculateMode::GLOBAL, action.id1); + if(!group) { debugMessage(this->getServerId(), "{} Skipping token action set channel group for group {} at channel {} because the group does not exists anymore.", CLIENT_STR_LOG_PREFIX, action.id1, action.id2); break; } @@ -1141,7 +1165,7 @@ void ConnectedClient::useToken(token::TokenId token_id) { } channel_group_changed = true; - this->server->groups->setChannelGroup(this->getClientDatabaseId(), group, channel); + this->server->group_manager()->assignments().set_channel_group(this->getClientDatabaseId(), group->group_id(), channel->channelId(), !group->is_permanent()); break; } @@ -1167,7 +1191,8 @@ void ConnectedClient::useToken(token::TokenId token_id) { } if(tree_registered && (server_groups_changed || channel_group_changed)) { - auto updated_properties = this->getServer()->getGroupManager()->update_server_group_property(this->ref(), true, this->currentChannel); + /* TODO: Set "Update server groups" as task */ + auto updated_properties = this->getServer()->group_manager()->update_server_group_property(this->ref(), true, this->currentChannel); if(!updated_properties.empty()) { this->getServer()->notifyClientPropertyUpdates(this->ref(), updated_properties); } diff --git a/server/src/client/ConnectedClient.h b/server/src/client/ConnectedClient.h index 8e7ddf6..ee5506b 100644 --- a/server/src/client/ConnectedClient.h +++ b/server/src/client/ConnectedClient.h @@ -47,7 +47,6 @@ do {\ if(cmd.bulkCount() != count) return command_result{error::parameter_invalid_count}; namespace ts { - class GroupManager; namespace connection { class VoiceClientConnection; } @@ -108,8 +107,6 @@ namespace ts { inline std::shared_ptr getChannel(){ return this->currentChannel; } inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; } - inline std::shared_ptr getServer(){ return this->server; } - inline ServerId getServerId(){ return this->server ? this->server->getServerId() : (ServerId) 0; } //bool channelSubscribed(const std::shared_ptr&); /* if lock_channel == false then channel_lock must be write locked! */ diff --git a/server/src/client/ConnectedClientNotifyHandler.cpp b/server/src/client/ConnectedClientNotifyHandler.cpp index e64b215..eeb7a1f 100644 --- a/server/src/client/ConnectedClientNotifyHandler.cpp +++ b/server/src/client/ConnectedClientNotifyHandler.cpp @@ -45,7 +45,7 @@ bool ConnectedClient::notifyServerGroupList(bool as_notify) { Command cmd(as_notify ? "notifyservergrouplist" : ""); int index = 0; - for (const auto& group : (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->availableServerGroups(true)) { + for (const auto& group : (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->availableServerGroups(true)) { if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) { cmd[index]["cgid"] = group->groupId(); } else { @@ -171,7 +171,7 @@ bool ConnectedClient::notifyClientPermList(ClientDbId cldbid, const std::shared_ bool ConnectedClient::notifyChannelGroupList(bool as_notify) { Command cmd(as_notify ? "notifychannelgrouplist" : ""); int index = 0; - for (const auto &group : (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->availableChannelGroups(true)) { + for (const auto &group : (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->availableChannelGroups(true)) { if(group->target() == GroupTarget::GROUPTARGET_CHANNEL) { cmd[index]["cgid"] = group->groupId(); } else { diff --git a/server/src/client/DataClient.cpp b/server/src/client/DataClient.cpp index 0373ff3..d6b7554 100644 --- a/server/src/client/DataClient.cpp +++ b/server/src/client/DataClient.cpp @@ -5,6 +5,7 @@ #include "./DataClient.h" #include "../InstanceHandler.h" +#include "../groups/GroupManager.h" using namespace std; using namespace ts; @@ -89,8 +90,9 @@ bool DataClient::loadDataForCurrentServer() { } }); - if(this->properties()[property::CLIENT_DATABASE_ID].as() == 0) + if(this->properties()[property::CLIENT_DATABASE_ID].as() == 0) { return false; + } //Load general properties std::deque copied; @@ -117,7 +119,7 @@ bool DataClient::loadDataForCurrentServer() { } this->_properties->toggleSave(true); - this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(ref_server, this->getClientDatabaseId()); + this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(ref_server->getServerId(), this->getClientDatabaseId()); //Setup / fix stuff #if 0 @@ -165,39 +167,81 @@ std::vectorcalculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache); } else { - return serverInstance->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache); + return serverInstance->permission_helper().calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache); } } permission::v2::PermissionFlaggedValue DataClient::calculate_permission( permission::PermissionType permission, ChannelId channel, bool granted, std::shared_ptr cache) { auto result = this->calculate_permissions({permission}, channel, granted, cache); - if(result.empty()) return {0, false}; + if(result.empty()) { + return {0, false}; + } return result.back().second; } -std::vector> DataClient::assignedServerGroups() { - if(!this->server) return serverInstance->getOldGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType()); - return this->server->groups->getServerGroups(this->getClientDatabaseId(), this->getType()); +std::vector> DataClient::assignedServerGroups() { + auto ref_server = this->server; + auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager(); + + auto assignments = group_manager->assignments().server_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId()); + + std::vector> result{}; + result.reserve(assignments.size()); + + for(const auto& group_id : assignments) { + auto group = group_manager->server_groups()->find_group(groups::GroupCalculateMode::GLOBAL, group_id); + if(group) { + result.push_back(group); + } + } + + return result; } -std::shared_ptr DataClient::assignedChannelGroup(const shared_ptr &channel) { - if(!this->server || !channel) return {}; - return this->server->groups->getChannelGroup(this->getClientDatabaseId(), channel, true); +std::shared_ptr DataClient::assignedChannelGroup(const shared_ptr &channel) { + auto ref_server = this->server; + assert(channel); + if(!channel || !ref_server) { + return nullptr; + } + + std::shared_ptr result{}; + + auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager(); + auto channel_group_assignment = group_manager->assignments().channel_group_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId(), channel->channelId()); + if(channel_group_assignment.has_value()) { + result = group_manager->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, channel_group_assignment->group_id); + } + + if(!result) { + result = ref_server->default_channel_group(); + } + + assert(result); + return result; } -bool DataClient::serverGroupAssigned(const shared_ptr &group) { - for(const auto &gr : this->assignedServerGroups()) - if(gr->group == group) return true; +bool DataClient::serverGroupAssigned(const shared_ptr &group) { + auto ref_server = this->server; + auto group_manager = ref_server ? ref_server->group_manager() : serverInstance->group_manager(); + + auto assignments = group_manager->assignments().server_groups_of_client(groups::GroupAssignmentCalculateMode::GLOBAL, this->getClientDatabaseId()); + for(const auto& assigned_group_id : assignments) { + if(assigned_group_id == group->group_id()) { + return true; + } + } + return false; } -bool DataClient::channelGroupAssigned(const shared_ptr &group, const shared_ptr &channel) { - if(!channel) return false; - auto gr = this->assignedChannelGroup(channel); - sassert(gr); - if(!gr) return false; - return gr->group == group; +bool DataClient::channelGroupAssigned(const shared_ptr &group, const shared_ptr &channel) { + if(!channel) { + return false; + } + + return this->assignedChannelGroup(channel) == group; } std::string DataClient::getAvatarId() { diff --git a/server/src/client/DataClient.h b/server/src/client/DataClient.h index f3e25d6..75c41ea 100644 --- a/server/src/client/DataClient.h +++ b/server/src/client/DataClient.h @@ -19,6 +19,11 @@ namespace ts { namespace server { class VirtualServer; + namespace groups { + class ServerGroup; + class ChannelGroup; + } + class DataClient { friend class VirtualServer; friend class QueryServer; @@ -63,6 +68,7 @@ namespace ts { PropertyWrapper properties(){ return { this->_properties }; } + [[nodiscard]] inline auto permissions(){ return this->clientPermissions; } /* main permission calculate function */ /** @@ -95,15 +101,20 @@ namespace ts { std::shared_ptr cache = nullptr ); - virtual std::vector> assignedServerGroups(); - virtual std::shared_ptr assignedChannelGroup(const std::shared_ptr &); - virtual bool serverGroupAssigned(const std::shared_ptr &); - virtual bool channelGroupAssigned(const std::shared_ptr &, const std::shared_ptr &); + virtual std::vector> assignedServerGroups(); + virtual std::shared_ptr assignedChannelGroup(const std::shared_ptr &); + virtual bool serverGroupAssigned(const std::shared_ptr &); + virtual bool channelGroupAssigned(const std::shared_ptr &, const std::shared_ptr &); virtual std::string getDisplayName() { return this->properties()[property::CLIENT_NICKNAME]; } virtual std::string getLoginName() { return this->properties()[property::CLIENT_LOGIN_NAME]; } virtual void setDisplayName(std::string displayName) { this->properties()[property::CLIENT_NICKNAME] = displayName; } + [[nodiscard]] inline std::shared_ptr getServer() { return this->server; } + [[nodiscard]] inline ServerId getServerId() { + auto server_ref = this->getServer(); + return server_ref ? server_ref->getServerId() : (ServerId) 0; + } virtual ClientType getExternalType(){ uint8_t type = this->properties()[property::CLIENT_TYPE]; diff --git a/server/src/client/SpeakingClient.cpp b/server/src/client/SpeakingClient.cpp index c1546a8..af4dfe7 100644 --- a/server/src/client/SpeakingClient.cpp +++ b/server/src/client/SpeakingClient.cpp @@ -122,7 +122,7 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) { } TIMING_STEP(timings, "db assign "); - this->server->getGroupManager()->enableCache(this->getClientDatabaseId()); + this->server->group_manager()->enableCache(this->getClientDatabaseId()); TIMING_STEP(timings, "gr cache "); const static vector available_parameters = { @@ -437,9 +437,9 @@ void SpeakingClient::processJoin() { } TIMING_STEP(timings, "server reg "); - ref_server->getGroupManager()->cleanupAssignments(this->getClientDatabaseId()); + ref_server->group_manager()->cleanupAssignments(this->getClientDatabaseId()); TIMING_STEP(timings, "grp cleanup"); - ref_server->getGroupManager()->update_server_group_property(this->ref(), true, nullptr); + ref_server->group_manager()->update_server_group_property(this->ref(), true, nullptr); TIMING_STEP(timings, "grp apply "); this->properties()[property::CLIENT_COUNTRY] = config::geo::countryFlag; @@ -568,7 +568,7 @@ void SpeakingClient::processLeave() { unique_lock server_channel_lock(this->server->channel_tree_lock); server->unregisterClient(ownLock, "disconnected", server_channel_lock); /* already moves client to void if needed */ } - server->groups->disableCache(ownLock->getClientDatabaseId()); + server->group_manager()->disableCache(ownLock->getClientDatabaseId()); server->music_manager_->cleanup_client_bots(this->getClientDatabaseId()); //ref_server = nullptr; Removed caused nullptr exceptions } diff --git a/server/src/client/command_handler/channel.cpp b/server/src/client/command_handler/channel.cpp index 7cd5735..0361f5e 100644 --- a/server/src/client/command_handler/channel.cpp +++ b/server/src/client/command_handler/channel.cpp @@ -136,7 +136,7 @@ command_result ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_create, 1); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); log::GroupType log_group_type; if (cmd["type"].as() == GroupType::GROUP_TYPE_QUERY) { @@ -203,7 +203,7 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) { auto ref_server = this->server; - auto group_manager = this->server ? this->server->groups : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto source_group_id = cmd["scgid"].as(); auto source_group = group_manager->findGroup(source_group_id); @@ -338,7 +338,7 @@ command_result ConnectedClient::handleCommandChannelGroupRename(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto channel_group = group_manager->findGroup(cmd["cgid"].as()); if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; @@ -373,7 +373,7 @@ command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_delete, 1); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto channel_group = group_manager->findGroup(cmd["cgid"].as()); if (!channel_group || channel_group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; @@ -409,7 +409,7 @@ command_result ConnectedClient::handleCommandChannelGroupDel(Command &cmd) { 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 cl) { - if (this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) { + if (this->server->notifyClientPropertyUpdates(cl, this->server->group_manager()->update_server_group_property(cl, true, cl->getChannel()))) { cl->task_update_needed_permissions.enqueue(); } cl->notifyChannelGroupList(); @@ -450,7 +450,7 @@ command_result ConnectedClient::handleCommandChannelGroupClientList(Command &cmd string query = "SELECT `groupId`, `cldbid`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid"; if (cmd[0].has("cgid") && cmd["cgid"].as() > 0) { - auto group = this->server->getGroupManager()->findGroup(cmd["cgid"]); + auto group = this->server->group_manager()->findGroup(cmd["cgid"]); if (!group || group->target() != GroupTarget::GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; query += " AND `groupId` = :groupId"; @@ -508,7 +508,7 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd) CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channelgroup_permission_list, 1); - auto channelGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["cgid"].as()); + auto channelGroup = (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->findGroup(cmd["cgid"].as()); if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; if (!this->notifyGroupPermList(channelGroup, cmd.hasParm("permsid"))) return command_result{error::database_empty_result}; @@ -522,7 +522,7 @@ command_result ConnectedClient::handleCommandChannelGroupPermList(Command &cmd) command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto channelGroup = group_manager->findGroup(cmd["cgid"].as()); if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true); @@ -574,7 +574,7 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) { command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto channelGroup = group_manager->findGroup(cmd["cgid"].as()); if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"}; ACTION_REQUIRES_GROUP_PERMISSION(channelGroup, permission::i_channel_group_needed_modify_power, permission::i_channel_group_modify_power, true); @@ -954,14 +954,14 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) { const auto self_lock = this->ref(); GroupId adminGroup = this->server->properties()[property::VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP]; - auto channel_admin_group = this->server->groups->findGroup(adminGroup); + auto channel_admin_group = this->server->group_manager()->findGroup(adminGroup); if (!channel_admin_group) { logError(this->getServerId(), "Missing server's default channel admin group! Using default channel group!"); - channel_admin_group = this->server->groups->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); + channel_admin_group = this->server->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); } /* FIXME: Log group assignment */ - this->server->groups->setChannelGroup(this->getClientDatabaseId(), channel_admin_group, created_channel); + this->server->group_manager()->setChannelGroup(this->getClientDatabaseId(), channel_admin_group, created_channel); if (created_channel->channelType() == ChannelType::temporary && (this->getType() == ClientType::CLIENT_TEAMSPEAK || this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEASPEAK)) { channel_tree_read_lock.unlock(); @@ -2264,7 +2264,7 @@ command_result ConnectedClient::handleCommandChannelClientPermList(Command &cmd) ACTION_REQUIRES_PERMISSION(permission::b_virtualserver_channelclient_permission_list, 1, channel_id); if (!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cmd["cldbid"])) return command_result{error::client_invalid_id}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cmd["cldbid"].as()); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cmd["cldbid"].as()); Command res(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifychannelclientpermlist" : ""); @@ -2324,7 +2324,7 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd) auto channel = dynamic_pointer_cast(l_channel->entry); if (!channel) return command_result{error::vs_critical}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cldbid); { auto required_permissions = this->server->calculate_permission(permission::i_client_needed_permission_modify_power, cmd["cldbid"], ClientType::CLIENT_TEAMSPEAK, channel_id); ACTION_REQUIRES_PERMISSION(permission::i_client_permission_modify_power, required_permissions, channel_id); @@ -2393,7 +2393,7 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd) auto channel = dynamic_pointer_cast(l_channel->entry); if (!channel) return command_result{error::vs_critical}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cldbid); auto required_permissions = this->server->calculate_permission(permission::i_client_needed_permission_modify_power, cmd["cldbid"], ClientType::CLIENT_TEAMSPEAK, channel_id); ACTION_REQUIRES_PERMISSION(permission::i_client_permission_modify_power, required_permissions, channel_id); diff --git a/server/src/client/command_handler/client.cpp b/server/src/client/command_handler/client.cpp index 4e42985..360058e 100644 --- a/server/src/client/command_handler/client.cpp +++ b/server/src/client/command_handler/client.cpp @@ -977,7 +977,7 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) { auto cldbid = cmd["cldbid"].as(); if(!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cldbid)) return command_result{error::client_invalid_id}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cldbid); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_permission_modify_power, this->server->calculate_permission(permission::i_client_needed_permission_modify_power, cldbid, ClientType::CLIENT_TEAMSPEAK, 0)); @@ -1021,7 +1021,7 @@ command_result ConnectedClient::handleCommandClientDelPerm(Command &cmd) { auto cldbid = cmd["cldbid"].as(); if(!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cldbid)) return command_result{error::client_invalid_id}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cldbid); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_permission_modify_power, this->server->calculate_permission(permission::i_client_needed_permission_modify_power, cldbid, ClientType::CLIENT_TEAMSPEAK, 0)); ts::command::bulk_parser::PermissionBulksParser pparser{cmd}; @@ -1062,7 +1062,7 @@ command_result ConnectedClient::handleCommandClientPermList(Command &cmd) { ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_client_permission_list, 1); if(!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cmd["cldbid"])) return command_result{error::client_invalid_id}; - auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cmd["cldbid"]); + auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), cmd["cldbid"]); if (!this->notifyClientPermList(cmd["cldbid"], mgr, cmd.hasParm("permsid"))) return command_result{error::database_empty_result}; return command_result{error::ok}; } diff --git a/server/src/client/command_handler/misc.cpp b/server/src/client/command_handler/misc.cpp index 484d8d2..3d7e25e 100644 --- a/server/src/client/command_handler/misc.cpp +++ b/server/src/client/command_handler/misc.cpp @@ -443,9 +443,9 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd) CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(25); - auto serverGroup = this->server->groups->findGroup(cmd["cgid"].as()); + auto serverGroup = this->server->group_manager()->findGroup(cmd["cgid"].as()); if (!serverGroup && cmd["cgid"].as() == 0) - serverGroup = this->server->groups->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); + serverGroup = this->server->group_manager()->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL); if (!serverGroup || serverGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::group_invalid_id}; @@ -481,7 +481,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd) std::shared_ptr old_group; { - old_group = this->server->groups->getChannelGroupExact(target_cldbid, channel, false); + old_group = this->server->group_manager()->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(!old_group->group->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) { @@ -495,14 +495,14 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd) } } - this->server->groups->setChannelGroup(target_cldbid, serverGroup, channel); + this->server->group_manager()->setChannelGroup(target_cldbid, serverGroup, channel); std::shared_ptr 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 */ + auto updates = this->server->group_manager()->update_server_group_property(targetClient, false, targetClient->getChannel()); /* needs a write lock */ client_channel_lock_w.unlock(); shared_lock client_channel_lock_r(targetClient->channel_lock); auto result = this->server->notifyClientPropertyUpdates(targetClient, updates); @@ -530,7 +530,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd) target_cldbid, connected_client ? connected_client->getDisplayName() : "" ); } - if(serverGroup != this->server->groups->defaultGroup(GroupTarget::GROUPTARGET_CHANNEL)) { + if(serverGroup != this->server->group_manager()->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(), @@ -1241,7 +1241,7 @@ void check_token_action_permissions(const std::shared_ptr& clie switch(action.type) { case ActionType::AddServerGroup: { - auto target_group = client->getServer()->getGroupManager()->findGroup(action.id1); + auto target_group = client->getServer()->group_manager()->findGroup(action.id1); if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_SERVER) { action.type = ActionType::ActionIgnore; result.set_result(index, ts::command_result{error::group_invalid_id}); @@ -1258,7 +1258,7 @@ void check_token_action_permissions(const std::shared_ptr& clie } case ActionType::RemoveServerGroup: { - auto target_group = client->getServer()->getGroupManager()->findGroup(action.id1); + auto target_group = client->getServer()->group_manager()->findGroup(action.id1); if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_SERVER) { action.type = ActionType::ActionIgnore; result.set_result(index, ts::command_result{error::group_invalid_id}); @@ -1275,7 +1275,7 @@ void check_token_action_permissions(const std::shared_ptr& clie } case ActionType::SetChannelGroup: { - auto target_group = client->getServer()->getGroupManager()->findGroup(action.id1); + auto target_group = client->getServer()->group_manager()->findGroup(action.id1); if(!target_group || target_group->type() == GroupType::GROUP_TYPE_TEMPLATE || target_group->target() != GroupTarget::GROUPTARGET_CHANNEL) { action.type = ActionType::ActionIgnore; result.set_result(index, ts::command_result{error::group_invalid_id}); @@ -2043,7 +2043,7 @@ command_result ConnectedClient::handleCommandPermFind(Command &cmd) { perms.resize(entries.size()); size_t index{0}; - auto all_groups = this->server->groups->availableGroups(true); + auto all_groups = this->server->group_manager()->availableGroups(true); for(const auto& entry : entries) { auto& perm = perms[index++]; @@ -2183,9 +2183,9 @@ command_result ConnectedClient::handleCommandPermOverview(Command &cmd) { auto channel = this->server ? this->server->channelTree->findChannel(cmd["cid"]) : serverInstance->getChannelTree()->findChannel(cmd["cid"]); if(!channel) return command_result{error::channel_invalid_id}; - auto server_groups = this->server->getGroupManager()->getServerGroups(client_dbid, ClientType::CLIENT_TEAMSPEAK); - auto channel_group = this->server->getGroupManager()->getChannelGroup(client_dbid, channel, true); - auto permission_manager = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServer(), client_dbid); + auto server_groups = this->server->group_manager()->getServerGroups(client_dbid, ClientType::CLIENT_TEAMSPEAK); + auto channel_group = this->server->group_manager()->getChannelGroup(client_dbid, channel, true); + auto permission_manager = serverInstance->databaseHelper()->loadClientPermissionManager(this->getServerId(), client_dbid); Command result(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifypermoverview" : ""); size_t index = 0; @@ -2796,11 +2796,11 @@ command_result ConnectedClient::handleCommandQueryList(ts::Command &cmd) { auto global_list = permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_list, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_list, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_list, this->getClientDatabaseId(), this->getType(), 0) ); auto own_list = global_list || permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_list_own, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_list_own, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_list_own, this->getClientDatabaseId(), this->getType(), 0) ); if(!own_list && !global_list) @@ -2861,7 +2861,7 @@ command_result ConnectedClient::handleCommandQueryCreate(ts::Command &cmd) { if(!permission::v2::permission_granted(1, server->calculate_permission(permission::b_client_query_create, this->getClientDatabaseId(), this->getType(), 0))) return command_result{permission::b_client_query_create}; } else { - if(!permission::v2::permission_granted(1, serverInstance->calculate_permission(permission::b_client_query_create, this->getClientDatabaseId(), this->getType(), 0))) + if(!permission::v2::permission_granted(1, serverInstance->permission_helper().calculate_permission(permission::b_client_query_create, this->getClientDatabaseId(), this->getType(), 0))) return command_result{permission::b_client_query_create}; } @@ -2874,7 +2874,7 @@ command_result ConnectedClient::handleCommandQueryCreate(ts::Command &cmd) { if(!permission::v2::permission_granted(1, server->calculate_permission(permission::b_client_query_create_own, this->getClientDatabaseId(), this->getType(), 0))) return command_result{permission::b_client_query_create_own}; } else { - if(!permission::v2::permission_granted(1, serverInstance->calculate_permission(permission::b_client_query_create_own, this->getClientDatabaseId(), this->getType(), 0))) + if(!permission::v2::permission_granted(1, serverInstance->permission_helper().calculate_permission(permission::b_client_query_create_own, this->getClientDatabaseId(), this->getType(), 0))) return command_result{permission::b_client_query_create_own}; } } @@ -2910,11 +2910,11 @@ command_result ConnectedClient::handleCommandQueryDelete(ts::Command &cmd) { auto delete_all = permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_delete, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_delete, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_delete, this->getClientDatabaseId(), this->getType(), 0) ); auto delete_own = delete_all || permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_delete_own, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_delete_own, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_delete_own, this->getClientDatabaseId(), this->getType(), 0) ); if(account->unique_id == this->getUid()) { @@ -2946,11 +2946,11 @@ command_result ConnectedClient::handleCommandQueryRename(ts::Command &cmd) { auto rename_all = permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_rename, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_rename, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_rename, this->getClientDatabaseId(), this->getType(), 0) ); auto rename_own = rename_all || permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_rename_own, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_rename_own, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_rename_own, this->getClientDatabaseId(), this->getType(), 0) ); if(account->unique_id == this->getUid()) { @@ -2985,11 +2985,11 @@ command_result ConnectedClient::handleCommandQueryChangePassword(ts::Command &cm auto change_all = permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_change_password, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_change_password_global, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_change_password_global, this->getClientDatabaseId(), this->getType(), 0) ); auto change_own = change_all || permission::v2::permission_granted(1, server ? server->calculate_permission(permission::b_client_query_change_own_password, this->getClientDatabaseId(), this->getType(), 0) : - serverInstance->calculate_permission(permission::b_client_query_change_own_password, this->getClientDatabaseId(), this->getType(), 0) + serverInstance->permission_helper().calculate_permission(permission::b_client_query_change_own_password, this->getClientDatabaseId(), this->getType(), 0) ); auto password = cmd[0].has("client_login_password") ? cmd["client_login_password"].as() : ""; diff --git a/server/src/client/command_handler/server.cpp b/server/src/client/command_handler/server.cpp index 0128a5c..3153f7c 100644 --- a/server/src/client/command_handler/server.cpp +++ b/server/src/client/command_handler/server.cpp @@ -87,22 +87,22 @@ command_result ConnectedClient::handleCommandServerEdit(Command &cmd) { SERVEREDIT_CHK_PROP_CACHED("virtualserver_codec_encryption_mode", permission::b_virtualserver_modify_codec_encryption_mode, int) } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_server_group", permission::b_virtualserver_modify_default_servergroup, GroupId) if(target_server) { - auto group = target_server->groups->findGroup(cmd["virtualserver_default_server_group"].as()); + auto group = target_server->group_manager()->findGroup(cmd["virtualserver_default_server_group"].as()); if (!group || group->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_group", permission::b_virtualserver_modify_default_channelgroup, GroupId) if(target_server) { - auto group = target_server->groups->findGroup(cmd["virtualserver_default_channel_group"].as()); + auto group = target_server->group_manager()->findGroup(cmd["virtualserver_default_channel_group"].as()); if (!group || group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_channel_admin_group", permission::b_virtualserver_modify_default_channeladmingroup, GroupId) if(target_server) { - auto group = target_server->groups->findGroup(cmd["virtualserver_default_channel_admin_group"].as()); + auto group = target_server->group_manager()->findGroup(cmd["virtualserver_default_channel_admin_group"].as()); if (!group || group->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid}; } } SERVEREDIT_CHK_PROP_CACHED("virtualserver_default_music_group", permission::b_virtualserver_modify_default_musicgroup, GroupId) if(target_server) { - auto group = target_server->groups->findGroup(cmd["virtualserver_default_music_group"].as()); + auto group = target_server->group_manager()->findGroup(cmd["virtualserver_default_music_group"].as()); if (!group || group->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; } } @@ -226,7 +226,7 @@ command_result ConnectedClient::handleCommandServerEdit(Command &cmd) { if(target_server) { if (group_update) target_server->forEachClient([&](const shared_ptr& client) { - if(target_server->notifyClientPropertyUpdates(client, target_server->groups->update_server_group_property(client, true, client->getChannel()))) { + if(target_server->notifyClientPropertyUpdates(client, target_server->group_manager()->update_server_group_property(client, true, client->getChannel()))) { client->task_update_needed_permissions.enqueue(); } }); @@ -314,7 +314,7 @@ command_result ConnectedClient::handleCommandServerGroupAdd(Command &cmd) { log_group_type = log::GroupType::NORMAL; } - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().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"}; @@ -360,7 +360,7 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) { auto ref_server = this->server; ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_create, 1); - auto group_manager = this->server ? this->server->groups : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto source_group_id = cmd["ssgid"].as(); auto source_group = group_manager->findGroup(source_group_id); @@ -494,7 +494,7 @@ command_result ConnectedClient::handleCommandServerGroupRename(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto serverGroup = group_manager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; @@ -529,7 +529,7 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_delete, 1); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getOldGroupManager().get(); + auto group_manager = this->server ? this->server->group_manager() : serverInstance->group_manager().get(); auto serverGroup = group_manager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, true); @@ -566,7 +566,7 @@ command_result ConnectedClient::handleCommandServerGroupDel(Command &cmd) { 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 cl) { - if(this->server->notifyClientPropertyUpdates(cl, this->server->groups->update_server_group_property(cl, true, cl->getChannel()))) { + if(this->server->notifyClientPropertyUpdates(cl, this->server->group_manager()->update_server_group_property(cl, true, cl->getChannel()))) { cl->task_update_needed_permissions.enqueue(); } cl->notifyServerGroupList(); @@ -589,7 +589,7 @@ command_result ConnectedClient::handleCommandServerGroupClientList(Command &cmd) ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_client_list, 1); auto server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; - auto groupManager = server ? this->server->groups : serverInstance->getOldGroupManager().get(); + auto groupManager = server ? this->server->group_manager() : serverInstance->group_manager().get(); auto serverGroup = groupManager->findGroup(cmd["sgid"].as()); if (!serverGroup || serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::group_invalid_id}; @@ -617,7 +617,7 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd) CMD_CHK_AND_INC_FLOOD_POINTS(25); auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; - auto group_manager = target_server ? this->server->groups : serverInstance->getOldGroupManager().get(); + auto group_manager = target_server ? this->server->group_manager() : serverInstance->group_manager().get(); auto target_cldbid = cmd["cldbid"].as(); if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"}; @@ -714,7 +714,7 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd) for(const auto& _server : target_server ? std::deque>{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()))) { + if (_server->notifyClientPropertyUpdates(targetClient, _server->group_manager()->update_server_group_property(targetClient, true, targetClient->getChannel()))) { for (const auto &client : _server->getClients()) { if(client->isClientVisible(targetClient, true) || client == targetClient) for(const auto& group : applied_groups) @@ -741,7 +741,7 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd) CMD_CHK_AND_INC_FLOOD_POINTS(25); auto target_server = cmd[0].has("sid") && cmd["sid"] == 0 ? nullptr : this->server; - auto group_manager = target_server ? this->server->groups : serverInstance->getOldGroupManager().get(); + auto group_manager = target_server ? this->server->group_manager() : serverInstance->group_manager().get(); auto target_cldbid = cmd["cldbid"].as(); if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"}; @@ -852,7 +852,7 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd) ConnectedLockedClient clock{targetClient}; if(!clock) continue; - if (_server->notifyClientPropertyUpdates(targetClient, _server->groups->update_server_group_property(targetClient, true, targetClient->getChannel()))) { + if (_server->notifyClientPropertyUpdates(targetClient, _server->group_manager()->update_server_group_property(targetClient, true, targetClient->getChannel()))) { for (const auto &client : _server->getClients()) { if(client->isClientVisible(targetClient, true) || client == targetClient) for(const auto& group : applied_groups) @@ -879,7 +879,7 @@ command_result ConnectedClient::handleCommandServerGroupPermList(Command &cmd) { CMD_CHK_AND_INC_FLOOD_POINTS(5); ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_servergroup_permission_list, 1); - auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as()); + auto serverGroup = (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if(this->getType() == ClientType::CLIENT_TEAMSPEAK && this->command_times.last_notify + this->command_times.notify_timeout < system_clock::now()) { @@ -894,7 +894,7 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as()); + auto serverGroup = (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1); @@ -959,7 +959,7 @@ command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5); - auto serverGroup = (this->server ? this->server->groups : serverInstance->getOldGroupManager().get())->findGroup(cmd["sgid"].as()); + auto serverGroup = (this->server ? this->server->group_manager() : serverInstance->group_manager().get())->findGroup(cmd["sgid"].as()); if (!serverGroup) return command_result{error::group_invalid_id}; if (serverGroup->target() != GROUPTARGET_SERVER) return command_result{error::parameter_invalid}; ACTION_REQUIRES_GROUP_PERMISSION(serverGroup, permission::i_server_group_needed_modify_power, permission::i_server_group_modify_power, 1); @@ -1024,7 +1024,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command& CMD_CHK_AND_INC_FLOOD_POINTS(25); auto ref_server = this->server; - auto group_manager = ref_server ? this->server->groups : &*serverInstance->getOldGroupManager(); + auto group_manager = ref_server ? this->server->group_manager() : &*serverInstance->group_manager(); deque> groups; for(const auto& group : group_manager->availableGroups(false)) { @@ -1102,7 +1102,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command& CMD_CHK_AND_INC_FLOOD_POINTS(25); auto ref_server = this->server; - auto group_manager = ref_server ? this->server->groups : &*serverInstance->getOldGroupManager(); + auto group_manager = ref_server ? this->server->group_manager() : &*serverInstance->group_manager(); deque> groups; for(const auto& group : group_manager->availableGroups(false)) { @@ -1184,14 +1184,14 @@ command_result ConnectedClient::handleCommandServerGroupsByClientId(Command &cmd int index = 0; if (this->server) { - for (const auto &group : this->server->groups->getAssignedServerGroups(cldbid)) { + for (const auto &group : this->server->group_manager()->getAssignedServerGroups(cldbid)) { result[index]["name"] = group->group->name(); result[index]["sgid"] = group->group->groupId(); result[index]["cldbid"] = cldbid; index++; } } else { - for (const auto &group : serverInstance->getOldGroupManager()->getAssignedServerGroups(cldbid)) { + for (const auto &group : serverInstance->group_manager()->getAssignedServerGroups(cldbid)) { result[index]["name"] = group->group->name(); result[index]["sgid"] = group->group->groupId(); result[index]["cldbid"] = cldbid; diff --git a/server/src/client/query/QueryClient.cpp b/server/src/client/query/QueryClient.cpp index 8c50ac3..b1f565e 100644 --- a/server/src/client/query/QueryClient.cpp +++ b/server/src/client/query/QueryClient.cpp @@ -631,9 +631,9 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) { this->currentChannel = nullptr; } - old_server->groups->disableCache(this->getClientDatabaseId()); + old_server->group_manager()->disableCache(this->getClientDatabaseId()); this->loadDataForCurrentServer(); } - serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId()); + serverInstance->group_manager()->enableCache(this->getClientDatabaseId()); } \ No newline at end of file diff --git a/server/src/client/query/QueryClientCommands.cpp b/server/src/client/query/QueryClientCommands.cpp index 136071b..23b95e8 100644 --- a/server/src/client/query/QueryClientCommands.cpp +++ b/server/src/client/query/QueryClientCommands.cpp @@ -247,8 +247,8 @@ command_result QueryClient::handleCommandLogin(Command& cmd) { this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->unregisterClient(this->ref(), "login", tree_lock); } - this->server->groups->disableCache(this->getClientDatabaseId()); - } else serverInstance->getOldGroupManager()->disableCache(this->getClientDatabaseId()); + this->server->group_manager()->disableCache(this->getClientDatabaseId()); + } else serverInstance->group_manager()->disableCache(this->getClientDatabaseId()); logMessage(LOG_QUERY, "Got new authenticated client. Username: {}, Unique-ID: {}, Bounded Server: {}", account->username, account->unique_id, account->bound_server); @@ -268,7 +268,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) { DatabaseHelper::assignDatabaseId(this->sql, static_cast(target_server ? target_server->getServerId() : 0), this->ref()); if(target_server) { - target_server->groups->enableCache(this->getClientDatabaseId()); + target_server->group_manager()->enableCache(this->getClientDatabaseId()); target_server->registerClient(this->ref()); { @@ -292,7 +292,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) { this->task_update_needed_permissions.enqueue(); } } else { - serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId()); + serverInstance->group_manager()->enableCache(this->getClientDatabaseId()); this->task_update_needed_permissions.enqueue(); } @@ -317,15 +317,15 @@ command_result QueryClient::handleCommandLogout(Command &) { this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock); this->server->unregisterClient(this->ref(), "logout", tree_lock); } - this->server->groups->disableCache(this->getClientDatabaseId()); - } else serverInstance->getOldGroupManager()->disableCache(this->getClientDatabaseId()); + this->server->group_manager()->disableCache(this->getClientDatabaseId()); + } else serverInstance->group_manager()->disableCache(this->getClientDatabaseId()); this->properties()[property::CLIENT_UNIQUE_IDENTIFIER] = "UnknownQuery"; //TODO load from table this->properties()[property::CLIENT_NICKNAME] = string() + "ServerQuery#" + this->getLoggingPeerIp() + "/" + to_string(ntohs(this->getPeerPort())); DatabaseHelper::assignDatabaseId(this->sql, static_cast(this->server ? this->server->getServerId() : 0), this->ref()); if(this->server){ - this->server->groups->enableCache(this->getClientDatabaseId()); + this->server->group_manager()->enableCache(this->getClientDatabaseId()); this->server->registerClient(this->ref()); { @@ -346,7 +346,7 @@ command_result QueryClient::handleCommandLogout(Command &) { this->task_update_needed_permissions.enqueue(); } } else { - serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId()); + serverInstance->group_manager()->enableCache(this->getClientDatabaseId()); this->task_update_needed_permissions.enqueue(); } @@ -400,7 +400,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) { DatabaseHelper::assignDatabaseId(this->sql, static_cast(this->server ? this->server->getServerId() : 0), this->ref()); if(this->server) { - this->server->groups->enableCache(this->getClientDatabaseId()); + this->server->group_manager()->enableCache(this->getClientDatabaseId()); this->server->registerClient(this->ref()); { @@ -419,7 +419,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) { this->task_update_needed_permissions.enqueue(); } } else { - serverInstance->getOldGroupManager()->enableCache(this->getClientDatabaseId()); + serverInstance->group_manager()->enableCache(this->getClientDatabaseId()); this->task_update_needed_permissions.enqueue(); } diff --git a/server/src/client/web/WebClient.cpp b/server/src/client/web/WebClient.cpp index 7f07c63..0f692cb 100644 --- a/server/src/client/web/WebClient.cpp +++ b/server/src/client/web/WebClient.cpp @@ -227,7 +227,7 @@ bool WebClient::close_connection(const std::chrono::system_clock::time_point& ti unique_lock server_channel_lock(this->server->channel_tree_lock); this->server->unregisterClient(this->ref(), "disconnected", server_channel_lock); } - this->server->groups->disableCache(this->getClientDatabaseId()); + this->server->group_manager()->disableCache(this->getClientDatabaseId()); //this->server = nullptr; } diff --git a/server/src/groups/Group.h b/server/src/groups/Group.h index f43f13c..1a97aee 100644 --- a/server/src/groups/Group.h +++ b/server/src/groups/Group.h @@ -61,6 +61,36 @@ namespace ts::server::groups { return value.has_value ? value.value : 0; } + [[nodiscard]] inline bool is_permanent() { + auto permission_manager = this->permissions_; + assert(permission_manager); + const auto data = permission_manager->permission_value_flagged(permission::b_group_is_permanent); + return data.has_value ? data.value == 1 : false; + } + + [[nodiscard]] inline permission::PermissionValue update_type() { + auto permission_manager = this->permissions_; + assert(permission_manager); + const auto data = permission_manager->permission_value_flagged(permission::i_group_auto_update_type); + return data.has_value ? data.value : 0; + } + + [[nodiscard]] inline bool permission_granted(const permission::PermissionType& permission, const permission::v2::PermissionFlaggedValue& granted_value, bool require_granted_value) { + auto permission_manager = this->permissions_;; + assert(permission_manager); + const auto data = permission_manager->permission_value_flagged(permission); + if(!data.has_value) { + return !require_granted_value || granted_value.has_value; + } + if(!granted_value.has_value) { + return false; + } + if(data.value == -1) { + return granted_value.value == -1; + } + return granted_value.value >= data.value; + } + private: const ServerId virtual_server_id_; const GroupId group_id_; diff --git a/server/src/groups/GroupAssignmentManager.cpp b/server/src/groups/GroupAssignmentManager.cpp index ea2a9f8..e71f889 100644 --- a/server/src/groups/GroupAssignmentManager.cpp +++ b/server/src/groups/GroupAssignmentManager.cpp @@ -217,7 +217,7 @@ std::vector GroupAssignmentManager::server_groups_of_client(ts::ser return result; } -std::vector GroupAssignmentManager::channel_group_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) { +std::vector GroupAssignmentManager::channel_groups_of_client(GroupAssignmentCalculateMode mode, ClientDbId cldbid) { std::vector result{}; bool cache_found{false}; { @@ -262,7 +262,7 @@ std::vector GroupAssignmentManager::channel_group_of_cli if(mode == GroupAssignmentCalculateMode::GLOBAL) { if(auto parent = this->manager_->parent_manager(); parent) { - auto parent_groups = parent->assignments().channel_group_of_client(mode, cldbid); + auto parent_groups = parent->assignments().channel_groups_of_client(mode, cldbid); result.reserve(result.size() + parent_groups.size()); result.insert(result.begin(), parent_groups.begin(), parent_groups.end()); } @@ -271,6 +271,21 @@ std::vector GroupAssignmentManager::channel_group_of_cli return result; } +std::optional GroupAssignmentManager::channel_group_of_client(GroupAssignmentCalculateMode mode, + ClientDbId client_database_id, ChannelId channel_id) { + /* TODO: Improve performance by not querying all groups */ + auto assignments = this->channel_groups_of_client(mode, client_database_id); + for(const auto& assignment : assignments) { + if(assignment.channel_id != channel_id) { + continue; + } + + return std::make_optional(assignment); + } + + return std::nullopt; +} + std::deque GroupAssignmentManager::server_group_clients(GroupId group_id) { std::deque result{}; if constexpr(kCacheAllClients) { @@ -279,8 +294,9 @@ std::deque GroupAssignmentManager::server_group_clients(GroupId auto it = std::find_if(client->server_group_assignments.begin(), client->server_group_assignments.end(), [&](const ServerGroupAssignment& assignment) { return assignment.group_id == group_id; }); - if(it == client->server_group_assignments.end()) + if(it == client->server_group_assignments.end()) { continue; + } result.push_back(client->client_database_id); } } else { @@ -436,8 +452,10 @@ GroupAssignmentResult GroupAssignmentManager::set_channel_group(ClientDbId clien } } } - if(temporary) + + if(temporary) { return GroupAssignmentResult::SUCCESS; + } sql::command(this->sql_manager(), "DELETE FROM `assignedGroups` WHERE `serverId` = :sid AND `cldbid` = :cldbid AND `channelId` = :chid", variable{":sid", this->server_id()}, diff --git a/server/src/groups/GroupAssignmentManager.h b/server/src/groups/GroupAssignmentManager.h index 087c97b..d438b5a 100644 --- a/server/src/groups/GroupAssignmentManager.h +++ b/server/src/groups/GroupAssignmentManager.h @@ -69,7 +69,8 @@ namespace ts::server { /* info/query methods */ [[nodiscard]] std::vector server_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */); - [[nodiscard]] std::vector channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */); + [[nodiscard]] std::vector channel_groups_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */); + [[nodiscard]] std::optional channel_group_of_client(GroupAssignmentCalculateMode /* mode */, ClientDbId /* client database id */, ChannelId /* channel id */); [[nodiscard]] std::deque server_group_clients(GroupId /* group id */); //[[nodiscard]] std::deque channel_group_clients(GroupId /* group id */, ChannelId /* channel id */); diff --git a/server/src/groups/GroupManager.cpp b/server/src/groups/GroupManager.cpp index 4131aac..386c050 100644 --- a/server/src/groups/GroupManager.cpp +++ b/server/src/groups/GroupManager.cpp @@ -38,6 +38,26 @@ bool GroupManager::initialize(const std::shared_ptr& self, std::st return true; } +void GroupManager::save_permissions() { + size_t total_groups_server, total_groups_channel; + size_t saved_groups_server, saved_groups_channel; + + auto timestamp_0 = std::chrono::system_clock::now(); + this->server_groups_->save_permissions(total_groups_server, saved_groups_server); + auto timestamp_1 = std::chrono::system_clock::now(); + this->channel_groups_->save_permissions(total_groups_channel, saved_groups_channel); + auto timestamp_2 = std::chrono::system_clock::now(); + + auto time_server_groups = std::chrono::duration_cast(timestamp_1 - timestamp_0).count(); + auto time_channel_groups = std::chrono::duration_cast(timestamp_2 - timestamp_1).count(); + + debugMessage(this->server_id(), "Saved {}/{} server and {}/{} channel group permissions in {}ms or {}ms", + saved_groups_server, total_groups_server, + saved_groups_channel, total_groups_channel, + time_server_groups, time_channel_groups + ); +} + /* Abstract group manager */ AbstractGroupManager::AbstractGroupManager( sql::SqlManager* database, @@ -149,6 +169,19 @@ int AbstractGroupManager::insert_group_from_sql(int length, std::string *values, return 0; } +void AbstractGroupManager::save_permissions() { + std::unique_lock group_lock{this->groups_}; + auto groups = this->groups_; + group_lock.unlock(); + + for(auto& group : groups) { + auto permissions = group->permissions(); + if(permissions->require_db_updates()) { + serverInstance->databaseHelper()->saveGroupPermissions(0, group->group_id(), (uint8_t) this->database_target_, permissions); + } + } +} + std::shared_ptr AbstractGroupManager::find_group_(GroupCalculateMode mode, GroupId group_id) { { std::lock_guard glock{this->group_mutex_}; diff --git a/server/src/groups/GroupManager.h b/server/src/groups/GroupManager.h index 92bdd2b..967d3f9 100644 --- a/server/src/groups/GroupManager.h +++ b/server/src/groups/GroupManager.h @@ -74,6 +74,8 @@ namespace ts::server::groups { GroupLoadResult load_data(bool /* initialize */ = false); void unload_data(); void reset_groups(bool /* cleanup database */); + + void save_permissions(size_t& /* total groups */, size_t& /* saved groups */); protected: std::shared_ptr parent_manager_; DatabaseGroupTarget database_target_; @@ -113,6 +115,25 @@ namespace ts::server::groups { public: ServerGroupManager(const std::shared_ptr& /* owner */, std::shared_ptr /* parent */); + [[nodiscard]] inline std::vector> available_groups(GroupCalculateMode mode) { + std::vector> result{}; + if(auto manager{std::dynamic_pointer_cast(this->parent_manager_)}; manager && mode != GroupCalculateMode::LOCAL) { + auto result_ = manager->available_groups(mode); + result.reserve(result_.size()); + result.insert(result.end(), result_.begin(), result_.end()); + } + + { + std::lock_guard group_lock{this->group_mutex_}; + result.reserve(this->groups_.size()); + for(const auto& group : this->groups_) { + result.push_back(this->cast_result(group)); + } + } + + return result; + } + [[nodiscard]] inline std::shared_ptr find_group(GroupCalculateMode mode, GroupId group_id) { return this->cast_result(this->find_group_(mode, group_id)); } @@ -166,6 +187,25 @@ namespace ts::server::groups { public: ChannelGroupManager(const std::shared_ptr& /* owner */, std::shared_ptr /* parent */); + [[nodiscard]] inline std::vector> available_groups(GroupCalculateMode mode) { + std::vector> result{}; + if(auto manager{std::dynamic_pointer_cast(this->parent_manager_)}; manager && mode != GroupCalculateMode::LOCAL) { + auto result_ = manager->available_groups(mode); + result.reserve(result_.size()); + result.insert(result.end(), result_.begin(), result_.end()); + } + + { + std::lock_guard group_lock{this->group_mutex_}; + result.reserve(this->groups_.size()); + for(const auto& group : this->groups_) { + result.push_back(this->cast_result(group)); + } + } + + return result; + } + [[nodiscard]] inline std::shared_ptr find_group(GroupCalculateMode mode, GroupId group_id) { return this->cast_result(this->find_group_(mode, group_id)); } @@ -226,6 +266,7 @@ namespace ts::server::groups { bool initialize(const std::shared_ptr& /* self ref, */, std::string& /* error */); [[nodiscard]] inline const std::shared_ptr& parent_manager() { return this->parent_manager_; } + void save_permissions(); [[nodiscard]] inline GroupAssignmentManager& assignments() { return this->assignment_manager_; } [[nodiscard]] inline const std::shared_ptr& server_groups() { return this->server_groups_; } diff --git a/server/src/music/MusicBotManager.cpp b/server/src/music/MusicBotManager.cpp index bdae634..77f6287 100644 --- a/server/src/music/MusicBotManager.cpp +++ b/server/src/music/MusicBotManager.cpp @@ -96,7 +96,7 @@ std::shared_ptr MusicBotManager::createBot(ClientDbId owner if(!config::music::enabled) return nullptr; - handle->groups->enableCache(musicBot->getClientDatabaseId()); + handle->group_manager()->enableCache(musicBot->getClientDatabaseId()); handle->registerClient(musicBot); { @@ -147,7 +147,7 @@ void MusicBotManager::deleteBot(std::shared_ptr musicBot) { handle->client_move(musicBot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock); handle->unregisterClient(musicBot, "bot deleted", server_channel_lock); } - handle->groups->disableCache(musicBot->getClientDatabaseId()); + handle->group_manager()->disableCache(musicBot->getClientDatabaseId()); serverInstance->databaseHelper()->deleteClient(handle, musicBot->getClientDatabaseId()); serverInstance->databaseHelper()->deleteClient(nullptr, musicBot->getClientDatabaseId()); @@ -241,7 +241,7 @@ int MusicBotManager::sqlCreateMusicBot(int length, std::string* values, std::str musicBot->properties()[property::CLIENT_LASTCONNECTED] = duration_cast(system_clock::now().time_since_epoch()).count(); } - handle->groups->enableCache(musicBot->getClientDatabaseId()); + handle->group_manager()->enableCache(musicBot->getClientDatabaseId()); if(musicBot->getClientDatabaseId() != botId) logCritical(handle->getServerId(),"Invalid music bot id mapping!"); { diff --git a/server/src/server/QueryServer.cpp b/server/src/server/QueryServer.cpp index dc62b6c..98a8a33 100644 --- a/server/src/server/QueryServer.cpp +++ b/server/src/server/QueryServer.cpp @@ -42,9 +42,9 @@ void QueryServer::unregisterConnection(const shared_ptr &client) { } if(client->server) { - client->server->getGroupManager()->disableCache(client->getClientDatabaseId()); + client->server->group_manager()->disableCache(client->getClientDatabaseId()); } else { - serverInstance->getOldGroupManager()->disableCache(client->getClientDatabaseId()); + serverInstance->group_manager()->disableCache(client->getClientDatabaseId()); } /* client->handle = nullptr; */ } diff --git a/server/src/terminal/CommandHandler.cpp b/server/src/terminal/CommandHandler.cpp index 3dcb05d..bc054a0 100644 --- a/server/src/terminal/CommandHandler.cpp +++ b/server/src/terminal/CommandHandler.cpp @@ -293,7 +293,7 @@ namespace terminal::chandler { return false; } - auto group = server->getGroupManager()->findGroup(groupId); + auto group = server->group_manager()->findGroup(groupId); if(!group) { handle.response.emplace_back("Could not resolve server group!"); return false; diff --git a/shared b/shared index 799bf8d..b26132f 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit 799bf8d26b5742e3e5df3c9ecbca233113d8f73d +Subproject commit b26132fa5498a1966bb11bbf9d1ee6bb32f39863