Using new permissions system consequently

This commit is contained in:
WolverinDEV
2020-01-26 14:21:34 +01:00
parent bb2e7699dc
commit c7b6c0a3ba
37 changed files with 8982 additions and 657 deletions
+69 -102
View File
@@ -85,20 +85,20 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
/* this->server may be null! */
shared_ptr<TSServer> server_ref = this->server;
auto permissions = this->permissionValues(permission::PERMTEST_ORDERED, {
auto permissions = this->calculate_permissions({
permission::i_client_talk_power,
permission::b_client_is_priority_speaker,
permission::b_client_ignore_antiflood,
permission::i_channel_view_power,
permission::b_channel_ignore_view_power
}, this->currentChannel);
}, this->currentChannel ? this->currentChannel->channelId() : 0);
permission::PermissionValue
permission_talk_power = permNotGranted,
permission_priority_speaker = permNotGranted,
permission_ignore_antiflood = permNotGranted,
permission_channel_view_power = permNotGranted,
permission_channel_ignore_view_power = permNotGranted;
permission::v2::PermissionFlaggedValue
permission_talk_power{0, false},
permission_priority_speaker{0, false},
permission_ignore_antiflood{0, false},
permission_channel_view_power{0, false},
permission_channel_ignore_view_power{0, false};
for(const auto& perm : permissions) {
if(perm.first == permission::i_client_talk_power)
permission_talk_power = perm.second;
@@ -113,18 +113,15 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
else sassert(false);
}
if(permission_talk_power < -2) permission_talk_power = -2;
else if(permission_talk_power == -2) permission_talk_power = 0;
deque<property::ClientProperties> notifyList;
debugMessage(this->getServerId(), "{} Got a channel talk power of {} Talk power set is {}", CLIENT_STR_LOG_PREFIX, permission_talk_power, this->properties()[property::CLIENT_TALK_POWER].as<uint64_t>());
if(permission_talk_power != this->properties()[property::CLIENT_TALK_POWER].as<uint64_t>()) { //We do not have to update tp if there's no channel
this->properties()[property::CLIENT_TALK_POWER] = permission_talk_power;
if((permission_talk_power.has_value ? permission_talk_power.value : 0) != this->properties()[property::CLIENT_TALK_POWER].as<uint64_t>()) { //We do not have to update tp if there's no channel
this->properties()[property::CLIENT_TALK_POWER] = (permission_talk_power.has_value ? permission_talk_power.value : 0);
notifyList.emplace_back(property::CLIENT_TALK_POWER);
auto update = this->properties()[property::CLIENT_IS_TALKER].as<bool>() || this->properties()[property::CLIENT_TALK_REQUEST].as<int64_t>() > 0;
if(update && this->currentChannel) {
if(this->currentChannel->talk_power_granted({permission_talk_power, permission_talk_power != permNotGranted})) {
if(this->currentChannel->talk_power_granted(permission_talk_power)) {
this->properties()[property::CLIENT_IS_TALKER] = 0;
this->properties()[property::CLIENT_TALK_REQUEST] = 0;
this->properties()[property::CLIENT_TALK_REQUEST_MSG] = "";
@@ -164,16 +161,16 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
}
}
auto pSpeaker = permission_priority_speaker > 0;
auto pSpeaker = permission_priority_speaker.has_value && permission_priority_speaker.value > 0;
if(properties()[property::CLIENT_IS_PRIORITY_SPEAKER].as<bool>() != pSpeaker){
properties()[property::CLIENT_IS_PRIORITY_SPEAKER] = pSpeaker;
notifyList.emplace_back(property::CLIENT_IS_PRIORITY_SPEAKER);
}
block_flood = permission_ignore_antiflood <= 0 || permission_ignore_antiflood == permNotGranted;
block_flood = !!permission_ignore_antiflood.has_value || permission_ignore_antiflood.value <= 0;
if(server_ref)
server_ref->notifyClientPropertyUpdates(_this.lock(), notifyList, notify_self);
this->updateTalkRights(permission_talk_power);
this->updateTalkRights(permission_talk_power.has_value ? permission_talk_power.value : 0);
if((this->channels_view_power != permission_channel_view_power || this->channels_ignore_view != permission_channel_ignore_view_power) && notify_self && this->currentChannel && server_ref) {
this->channels_view_power = permission_channel_view_power;
@@ -229,7 +226,7 @@ std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::subscribeChannel(cons
if(!ref_server)
return {};
auto general_granted = enforce || this->permission_granted(this->permissionValue(permission::b_channel_ignore_subscribe_power, nullptr), 1, true);
auto general_granted = enforce || permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_subscribe_power, 0));
{
shared_lock server_channel_lock(ref_server->channel_tree_lock, defer_lock);
unique_lock client_channel_lock(this->channel_lock, defer_lock);
@@ -245,10 +242,10 @@ std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::subscribeChannel(cons
if(local_channel->subscribed) continue; //Already subscribed
if(!general_granted && channel != this->currentChannel) {
auto granted_permission = this->calculate_permission_value(permission::i_channel_subscribe_power, channel->channelId());
auto granted_permission = this->calculate_permission(permission::i_channel_subscribe_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_subscribe_power, granted_permission, false)) {
auto ignore_power = this->calculate_permission_value(permission::b_channel_ignore_subscribe_power, channel->channelId());
auto ignore_power = this->calculate_permission(permission::b_channel_ignore_subscribe_power, channel->channelId());
if(!ignore_power.has_value || ignore_power.value < 1)
continue;
}
@@ -564,9 +561,9 @@ bool ConnectedClient::notifyClientNeededPermissions() {
cache_lock.unlock();
for(const auto& value : permissions) {
if(value.second != permNotGranted || value.first == permission::b_client_force_push_to_talk) {
if(value.second.has_value) {
cmd[index]["permid"] = value.first;
cmd[index++]["permvalue"] = value.second == permNotGranted ? 0 : value.second;
cmd[index++]["permvalue"] = value.second.value;
}
}
if(permissions.empty()) {
@@ -591,6 +588,8 @@ bool ConnectedClient::notifyError(const command_result& result, const std::strin
} else {
cmd["id"] = (int) result.error_code();
cmd["msg"] = findError(result.error_code()).message;
if(result.is_permission_error())
cmd["failed_permid"] = result.permission_id();
}
if(retCode.length() > 0)
@@ -616,7 +615,7 @@ inline void send_channels(ConnectedClient* client, ChannelIT begin, const Channe
if(begin == end)
return;
Command channellist("channellist");
ts::command_builder builder{"channellist", 512, 6};
size_t index = 0;
while(begin != end) {
@@ -625,9 +624,9 @@ inline void send_channels(ConnectedClient* client, ChannelIT begin, const Channe
for (const auto &elm : channel->properties().list_properties(property::FLAG_CHANNEL_VIEW, client->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
if(elm.type() == property::CHANNEL_ORDER)
channellist[index][elm.type().name] = override_orderid ? 0 : (*begin)->previous_channel;
builder.put_unchecked(index, elm.type().name, override_orderid ? 0 : (*begin)->previous_channel);
else
channellist[index][elm.type().name] = elm.as<string>();
builder.put_unchecked(index, elm.type().name, elm.as<string>());
}
begin++;
@@ -636,9 +635,9 @@ inline void send_channels(ConnectedClient* client, ChannelIT begin, const Channe
}
if(dynamic_cast<VoiceClient*>(client)) {
auto vc = dynamic_cast<VoiceClient*>(client);
vc->sendCommand0(channellist, false, true); /* we need to process this command directly so it will be processed before the channellistfinished stuff */
vc->sendCommand0(builder.build(), false, true); /* we need to process this command directly so it will be processed before the channellistfinished stuff */
} else {
client->sendCommand(channellist);
client->sendCommand(builder);
}
if(begin != end)
send_channels(client, begin, end, override_orderid);
@@ -785,7 +784,7 @@ void ConnectedClient::sendServerInit() {
command["acn"] = this->getDisplayName();
command["aclid"] = this->getClientId();
if(dynamic_cast<VoiceClient*>(this)) {
dynamic_cast<VoiceClient*>(this)->sendCommand0(command, false, true); /* process it directly so the order for the channellist entries is ensured. (First serverinit then everything else) */
dynamic_cast<VoiceClient*>(this)->sendCommand0(command.build(), false, true); /* process it directly so the order for the channellist entries is ensured. (First serverinit then everything else) */
} else {
this->sendCommand(command);
}
@@ -851,7 +850,7 @@ bool ConnectedClient::handleCommandFull(Command& cmd, bool disconnectOnFail) {
}
std::shared_ptr<BanRecord> ConnectedClient::resolveActiveBan(const std::string& ip_address) {
if(this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_ignore_bans, 1)) return nullptr;
if(permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ignore_bans, 0))) return nullptr;
//Check if manager banned
auto banManager = serverInstance->banManager();
@@ -901,44 +900,37 @@ std::shared_ptr<BanRecord> ConnectedClient::resolveActiveBan(const std::string&
}
bool ConnectedClient::update_cached_permissions() {
auto values = this->permissionValues(permission::PERMTEST_ORDERED, permission::neededPermissions, shared_ptr(this->currentChannel)); /* copy the channel here so it does not change */
auto values = this->calculate_permissions(permission::neededPermissions, this->currentChannel? this->currentChannel->channelId() : 0); /* copy the channel here so it does not change */
auto updated = false;
{
lock_guard cached_lock(this->cached_permissions_lock);
vector<permission::PermissionType> old_permissions;
old_permissions.reserve(this->cached_permissions.size());
auto old_cached_permissions{this->cached_permissions};
this->cached_permissions = values;
std::sort(this->cached_permissions.begin(), this->cached_permissions.end(), [](const auto& a, const auto& b) { return a.first < b.first; });
for(const auto& value : this->cached_permissions)
old_permissions.push_back(value.first);
for(const auto& value : values) {
auto value_it = cached_permissions.find(value.first);
if(value_it == cached_permissions.end()) { /* new entry */
updated = true;
this->cached_permissions[value.first] = value.second;
continue; /* no need to remove that from old_permissions because it isn't there */
} else if(value_it->second != value.second) { /* entry changed */
updated = true;
value_it->second = value.second;
}
{ /* we've updated the value or verified it */
auto old_it = find(old_permissions.begin(), old_permissions.end(), value.first);
if(old_it != old_permissions.end())
old_permissions.erase(old_it);
if(this->cached_permissions.size() != old_cached_permissions.size())
updated = true;
else {
for(auto oit = old_cached_permissions.begin(), nit = this->cached_permissions.begin(); oit != old_cached_permissions.end(); oit++, nit++) {
if(oit->first != nit->first || oit->second != nit->second) {
updated = true;
break;
}
}
}
}
for(const auto& left : old_permissions) {
auto value_it = cached_permissions.find(left);
if(value_it != cached_permissions.end()) {
cached_permissions.erase(value_it);
updated = true;
}
}
this->cpmerission_whisper_power = {0, false};
this->cpmerission_needed_whisper_power = {0, false};
for(const auto& entry : values) {
if(entry.first == permission::i_client_whisper_power)
this->cpmerission_whisper_power = entry.second;
else
if(entry.first == permission::i_client_needed_whisper_power)
this->cpmerission_needed_whisper_power = entry.second;
}
return updated;
@@ -954,72 +946,47 @@ void ConnectedClient::sendTSPermEditorWarning() {
}
}
permission::v2::PermissionFlaggedValue ConnectedClient::calculate_permission_value(const ts::permission::PermissionType &permission, ts::ChannelId channel_id) {
if(channel_id == (this->currentChannel ? this->currentChannel->channelId() : 0) || channel_id == -1) {
std::lock_guard lock(this->cached_permissions_lock);
auto index = this->cached_permissions.find(permission);
if(index != this->cached_permissions.end())
return {index->second, index->second != permNotGranted};
}
auto ref_server = this->server;
if(ref_server) {
auto result = this->server->calculatePermissions2(this->getClientDatabaseId(), {permission}, this->getType(), channel_id, false);
if(!result.empty()) /* it should never be empty! */
return result.back().second;
}
auto value = this->permissionValue(permission::PERMTEST_ORDERED, permission, nullptr);
return {value, value != permNotGranted};
}
#define RESULT(flag) \
#define RESULT(perm_) \
do { \
ventry->join_state_id = this->join_state_id; \
ventry->joinable = (flag); \
return flag; \
ventry->join_permission_error = (perm_); \
return perm_; \
} while(0)
bool ConnectedClient::calculate_and_get_join_state(const std::shared_ptr<BasicChannel>& channel) {
permission::PermissionType ConnectedClient::calculate_and_get_join_state(const std::shared_ptr<BasicChannel>& channel) {
shared_ptr<ViewEntry> ventry;
{
shared_lock view_lock(this->channel_lock);
ventry = this->channel_view()->find_channel(channel);
if(!ventry)
return false;
return permission::i_channel_view_power;
}
if(ventry->join_state_id == this->join_state_id)
return ventry->joinable;
return ventry->join_permission_error;
auto channel_id = channel->channelId();
auto permission_cache = make_shared<CalculateCache>();
switch(channel->channelType()) {
case ChannelType::permanent:
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_permanent, 1, channel, true, permission_cache))
RESULT(false);
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_permanent, channel_id)))
RESULT(permission::b_channel_join_permanent);
break;
case ChannelType::semipermanent:
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_semi_permanent, 1, channel, true, permission_cache))
RESULT(false);
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_semi_permanent, channel_id)))
RESULT(permission::b_channel_join_semi_permanent);
break;
case ChannelType::temporary:
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_temporary, 1, channel, true, permission_cache))
RESULT(false);
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_temporary, channel_id)))
RESULT(permission::b_channel_join_temporary);
break;
}
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true, permission_cache)) {
auto result = this->server->calculatePermissions2(this->getClientDatabaseId(), {permission::i_channel_join_power}, this->getType(), channel->channelId(), false, permission_cache);
if(result.empty())
RESULT(false);
if(!channel->permission_granted(permission::i_channel_needed_join_power, result.back().second, false))
RESULT(false);
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)))
RESULT(permission::i_channel_join_power);
}
auto val = this->permissionValue(permission::PERMTEST_ORDERED, permission::b_client_is_sticky, this->currentChannel, permission_cache);
if (val != permNotGranted && val > 0) {
auto st = this->permissionValue(permission::PERMTEST_ORDERED, permission::b_client_ignore_sticky, this->currentChannel, permission_cache);
if (st != 1)
RESULT(false);
}
RESULT(true);
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)))
RESULT(permission::b_client_is_sticky);
RESULT(permission::unknown);
}