Using proper permission inheritance

This commit is contained in:
WolverinDEV 2021-05-26 12:32:03 +02:00
parent f059e6b3c8
commit 03bad9e6f5
5 changed files with 53 additions and 47 deletions

View File

@ -24,35 +24,23 @@ ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, Chann
std::shared_ptr<BasicChannel> channel{};
try {
std::shared_lock channel_lock{server->get_channel_tree_lock()};
channel = server->getChannelTree()->findChannel(channel_id);
this->channel_ = server->getChannelTree()->findChannel(channel_id);
} catch (std::system_error& e) {
if(e.code() != std::errc::resource_deadlock_would_occur) {
throw;
}
/* tree already write locked, no need to lock it again */
channel = server->getChannelTree()->findChannel(channel_id);
}
if(channel) {
this->channel_permissions = channel->permissions();
this->channel_ = server->getChannelTree()->findChannel(channel_id);
}
}
this->channel_id_ = channel_id;
}
ClientPermissionCalculator::ClientPermissionCalculator(DataClient *client, const std::shared_ptr<BasicChannel> &channel) {
/* Note: Order matters! */
this->initialize_client(client);
this->initialize_default_groups(client->getServer());
if(channel) {
this->channel_id_ = channel->channelId();
this->channel_permissions = channel->permissions();
} else {
this->channel_id_ = 0;
this->channel_permissions = nullptr;
}
this->channel_ = channel;
}
ClientPermissionCalculator::ClientPermissionCalculator(
@ -63,26 +51,21 @@ ClientPermissionCalculator::ClientPermissionCalculator(
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();
std::shared_ptr<BasicChannel> channel{};
try {
std::shared_lock channel_lock{server->get_channel_tree_lock()};
channel = server->getChannelTree()->findChannel(channel_id);
this->channel_ = server->getChannelTree()->findChannel(channel_id);
} catch (std::system_error& e) {
if(e.code() != std::errc::resource_deadlock_would_occur) {
throw;
}
/* tree already write locked, no need to lock it again */
channel = server->getChannelTree()->findChannel(channel_id);
}
if(channel) {
this->channel_permissions = channel->permissions();
this->channel_ = server->getChannelTree()->findChannel(channel_id);
}
} else {
this->virtual_server_id = 0;
@ -216,8 +199,8 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
server_group_data_initialized = false; /* reset all group data */
auto client_permission_flags = 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 = client_permissions->channel_permission(permission, this->channel_id_);
if(this->channel_ && client_permission_flags.channel_specific) {
auto data = client_permissions->channel_permission(permission, this->channel_->channelId());
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);
@ -226,7 +209,7 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
}
bool skip_channel_permissions = this->channel_id_ == 0 || this->has_global_skip_permission();
bool skip_channel_permissions = !this->channel_ || this->has_global_skip_permission();
if(!skip_channel_permissions) {
/* We dont have a global skip flag. Lets see if the target permission has skip enabled */
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
@ -262,8 +245,9 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
}
/* 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(this->channel_) {
auto channel_permissions = this->channel_->permissions();
auto data = calculate_granted ? channel_permissions->permission_granted_flagged(permission) : 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);
@ -341,22 +325,38 @@ const std::shared_ptr<groups::ChannelGroup>& ClientPermissionCalculator::assigne
}
this->assigned_channel_group_.emplace();
if(this->channel_id_ == 0) {
if(!this->channel_) {
return *this->assigned_channel_group_;
}
auto channel_group_assignment = this->group_manager_->assignments().exact_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_;
std::shared_ptr<BasicChannel> inherited_channel{this->channel_};
auto channel_group_assignment = this->group_manager_->assignments().calculate_channel_group_of_client(
groups::GroupAssignmentCalculateMode::GLOBAL,
this->client_database_id,
inherited_channel
);
if(channel_group_assignment.has_value()) {
assert(inherited_channel);
auto channel_group = this->group_manager_->channel_groups()->find_group(groups::GroupCalculateMode::GLOBAL, *channel_group_assignment);
if(channel_group) {
this->assigned_channel_group_.emplace(std::move(channel_group));
logTrace(this->virtual_server_id, "[Permission] Using calculated channel group with id {} (Channel id: {}, Inherited channel id: {}).",
*channel_group_assignment, this->channel_->channelId(), inherited_channel->channelId());
} else {
logTrace(this->virtual_server_id, "[Permission] Missing calculated channel group with id {} (Channel id: {}, Inherited channel id: {}). Using default channel group.",
*channel_group_assignment, this->channel_->channelId(), inherited_channel->channelId());
}
} else {
logTrace(this->virtual_server_id, "[Permission] Using default 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();
if(!this->assigned_channel_group_.has_value()) {
assigned_channel_group_.emplace(
this->default_channel_group()
);
}
*this->assigned_channel_group_ = channel_group;
return *this->assigned_channel_group_;
}

View File

@ -89,9 +89,9 @@ namespace ts::server {
ServerId virtual_server_id;
ClientDbId client_database_id;
ClientType client_type;
ChannelId channel_id_;
std::shared_ptr<BasicChannel> channel_;
std::shared_ptr<groups::GroupManager> group_manager_{};
std::shared_ptr<permission::v2::PermissionManager> channel_permissions{};
std::function<std::shared_ptr<groups::ChannelGroup>()> default_channel_group{[]{ return nullptr; }};
std::function<std::shared_ptr<groups::ServerGroup>()> default_server_group{[]{ return nullptr; }};

View File

@ -551,7 +551,6 @@ void VirtualServer::client_move(
}
}
TIMING_STEP(timings, "notify view");
target_client->currentChannel = target_channel;
/* third step: update stuff for the client (remember: the client cant execute anything at the moment!) */

View File

@ -1169,32 +1169,36 @@ permission::PermissionType ConnectedClient::calculate_and_get_join_state(const s
return ventry->join_permission_error;
}
auto channel_id = channel->channelId();
ClientPermissionCalculator target_permissions{this, channel};
switch(channel->channelType()) {
case ChannelType::permanent:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_permanent, channel_id))) {
if(!target_permissions.permission_granted(permission::b_channel_join_permanent, 1)) {
RESULT(permission::b_channel_join_permanent);
}
break;
case ChannelType::semipermanent:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_semi_permanent, channel_id))) {
if(!target_permissions.permission_granted(permission::b_channel_join_semi_permanent, 1)) {
RESULT(permission::b_channel_join_semi_permanent);
}
break;
case ChannelType::temporary:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_temporary, channel_id))) {
if(!target_permissions.permission_granted(permission::b_channel_join_temporary, 1)) {
RESULT(permission::b_channel_join_temporary);
}
break;
}
if(!channel->permission_granted(permission::i_channel_needed_join_power, this->calculate_permission(permission::i_channel_join_power, channel_id), false)) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_join_power, channel_id))) {
auto required_join_power = channel->permissions()->permission_value_flagged(permission::i_channel_needed_join_power);
required_join_power.clear_flag_on_zero();
if(!target_permissions.permission_granted(permission::i_channel_join_power, required_join_power)) {
if(!target_permissions.permission_granted(permission::b_channel_ignore_join_power, 1)) {
RESULT(permission::i_channel_join_power);
}
}
if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_is_sticky, this->currentChannel ? this->currentChannel->channelId() : 0))) {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ignore_sticky, channel_id))) {
if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_is_sticky, this->getChannelId()))) {
if(!target_permissions.permission_granted(permission::b_client_ignore_sticky, 1)) {
RESULT(permission::b_client_is_sticky);
}
}

View File

@ -526,6 +526,9 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
for (const auto &targetClient : this->server->findClientsByCldbId(target_cldbid)) {
connected_client = targetClient;
/* Permissions might changed because of group inheritance */
targetClient->join_state_id++;
bool channel_group_changed, server_group_changed;
targetClient->update_displayed_client_groups(server_group_changed, channel_group_changed);