Some code refactoring
This commit is contained in:
parent
bf643b4797
commit
6b774d3a80
@ -56,7 +56,7 @@ find_package(CXXTerminal REQUIRED)
|
||||
find_package(StringVariable REQUIRED)
|
||||
find_package(yaml-cpp REQUIRED)
|
||||
find_package(jsoncpp REQUIRED)
|
||||
find_package(Ed25519 REQUIRED)
|
||||
find_package(ed25519 REQUIRED)
|
||||
find_package(DataPipes REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
find_package(spdlog REQUIRED)
|
||||
|
@ -267,7 +267,7 @@ target_link_libraries(TeaSpeakServer
|
||||
tommath::static
|
||||
|
||||
jsoncpp_lib
|
||||
${ed25519_LIBRARIES_STATIC}
|
||||
${Ed25519_LIBRARIES_STATIC}
|
||||
zstd::libzstd_static
|
||||
)
|
||||
|
||||
|
@ -96,7 +96,7 @@ 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();
|
||||
this->client_permissions_ = client->permissions();
|
||||
|
||||
auto server = client->getServer();
|
||||
if(server) {
|
||||
@ -139,19 +139,8 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
std::vector<std::pair<PermissionType, PermissionFlaggedValue>> 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 */
|
||||
auto client_permissions = this->client_permissions();
|
||||
assert(client_permissions);
|
||||
|
||||
/*
|
||||
* server_group_data[0] := Server group id
|
||||
@ -164,34 +153,6 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
std::vector<GroupData> 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;
|
||||
@ -253,10 +214,10 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
|
||||
for(const auto& permission : permissions) {
|
||||
server_group_data_initialized = false; /* reset all group data */
|
||||
auto client_permission_flags = this->client_permissions->permission_flags(permission);
|
||||
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 = this->client_permissions->channel_permission(permission, this->channel_id_);
|
||||
auto data = 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);
|
||||
@ -265,16 +226,9 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
}
|
||||
|
||||
|
||||
bool skip_channel_permissions = this->channel_id_ == 0;
|
||||
bool skip_channel_permissions = this->channel_id_ == 0 || this->has_global_skip_permission();
|
||||
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 */
|
||||
/* 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) {
|
||||
/* okey the client has the permission, this counts */
|
||||
skip_channel_permissions = client_permission_flags.skip;
|
||||
@ -319,7 +273,7 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
}
|
||||
|
||||
if(calculate_granted ? client_permission_flags.grant_set : client_permission_flags.value_set) {
|
||||
auto client_value = this->client_permissions->permission_values(permission);
|
||||
auto client_value = 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;
|
||||
@ -336,12 +290,25 @@ std::vector<std::pair<PermissionType, PermissionFlaggedValue>> ClientPermissionC
|
||||
}
|
||||
|
||||
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}});
|
||||
result.push_back({permission, { permNotGranted, false }});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::shared_ptr<ts::permission::v2::PermissionManager> & ClientPermissionCalculator::client_permissions() {
|
||||
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 {}. Using empty permission set.", this->client_database_id);
|
||||
this->client_permissions_ = std::make_shared<permission::v2::PermissionManager>();
|
||||
}
|
||||
}
|
||||
|
||||
return this->client_permissions_;
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<groups::ServerGroup>>& ClientPermissionCalculator::assigned_server_groups() {
|
||||
if(this->assigned_server_groups_.has_value()) {
|
||||
return *this->assigned_server_groups_;
|
||||
@ -391,4 +358,47 @@ const std::shared_ptr<groups::ChannelGroup>& ClientPermissionCalculator::assigne
|
||||
|
||||
*this->assigned_channel_group_ = channel_group;
|
||||
return *this->assigned_channel_group_;
|
||||
}
|
||||
|
||||
bool ClientPermissionCalculator::has_global_skip_permission() {
|
||||
/* test for skip permission within the client permission manager */
|
||||
{
|
||||
auto client_permissions = this->client_permissions();
|
||||
auto skip_value = client_permissions->permission_value_flagged(permission::b_client_skip_channelgroup_permissions);
|
||||
if(skip_value.has_value) {
|
||||
this->skip_enabled = std::make_optional(permission::v2::permission_granted(1, skip_value));
|
||||
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client permissions. Value: {}", *this->skip_enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/* test for skip permission within all server groups */
|
||||
if(!this->skip_enabled.has_value()) {
|
||||
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) {
|
||||
this->skip_enabled = std::make_optional(permission::v2::permission_granted(1, flagged_value));
|
||||
if(*this->skip_enabled) {
|
||||
logTrace(this->virtual_server_id, "[Permission] Found skip permission in client server group. Group: {} ({})", assignment->group_id(), assignment->display_name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!this->skip_enabled.has_value()) {
|
||||
this->skip_enabled = std::make_optional(false);
|
||||
}
|
||||
|
||||
return *this->skip_enabled;
|
||||
}
|
||||
|
||||
bool ClientPermissionCalculator::permission_granted(const permission::PermissionType &permission,
|
||||
const permission::PermissionValue &required_value, bool granted) {
|
||||
return this->permission_granted(permission, { required_value, true }, granted);
|
||||
}
|
||||
|
||||
bool ClientPermissionCalculator::permission_granted(const permission::PermissionType &permission,
|
||||
const permission::v2::PermissionFlaggedValue &required_value, bool granted) {
|
||||
return permission::v2::permission_granted(required_value, this->calculate_permission(permission, granted));
|
||||
}
|
@ -40,7 +40,7 @@ namespace ts::server {
|
||||
* @param granted
|
||||
* @return
|
||||
*/
|
||||
permission::v2::PermissionFlaggedValue calculate_permission(
|
||||
[[nodiscard]] permission::v2::PermissionFlaggedValue calculate_permission(
|
||||
permission::PermissionType,
|
||||
bool granted = false
|
||||
);
|
||||
@ -52,10 +52,37 @@ namespace ts::server {
|
||||
* @param calculate_granted
|
||||
* @return
|
||||
*/
|
||||
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
|
||||
[[nodiscard]] std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
|
||||
const std::deque<permission::PermissionType>&,
|
||||
bool calculate_granted = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Test if the target has the target permission granted.
|
||||
* If the client does not have any value assigned for the permission `false` will be returned.
|
||||
*/
|
||||
[[nodiscard]] bool permission_granted(
|
||||
const permission::PermissionType& /* target permission */,
|
||||
const permission::PermissionValue& /* required value */,
|
||||
bool /* granted permission */ = false
|
||||
);
|
||||
|
||||
/**
|
||||
* Test if the target has the target permission granted.
|
||||
* If the client does not have any value assigned for the permission,
|
||||
* `true` will be returned if the `required value` contains no value
|
||||
* otherwise false will be returned.
|
||||
*
|
||||
* This method should be used when testing permissions which are allowed by default except if they're
|
||||
* specified otherwise. An example permission would be if we're testing against the channel needed join power.
|
||||
*/
|
||||
[[nodiscard]] bool permission_granted(
|
||||
const permission::PermissionType& /* target permission */,
|
||||
const permission::v2::PermissionFlaggedValue& /* required value */,
|
||||
bool /* granted permission */ = false
|
||||
);
|
||||
|
||||
//const PermissionValue& required, const PermissionFlaggedValue& given, bool requires_given = true
|
||||
private:
|
||||
/* given fields */
|
||||
ServerId virtual_server_id;
|
||||
@ -68,10 +95,9 @@ namespace ts::server {
|
||||
std::function<std::shared_ptr<groups::ServerGroup>()> default_server_group{[]{ return nullptr; }};
|
||||
|
||||
/* fields which will be set when calculating permissions */
|
||||
std::shared_ptr<permission::v2::PermissionManager> client_permissions{};
|
||||
std::shared_ptr<permission::v2::PermissionManager> client_permissions_{};
|
||||
|
||||
bool global_skip{false};
|
||||
bool global_skip_set{false};
|
||||
std::optional<bool> skip_enabled{};
|
||||
|
||||
std::optional<std::shared_ptr<groups::ChannelGroup>> assigned_channel_group_{};
|
||||
std::optional<std::vector<std::shared_ptr<groups::ServerGroup>>> assigned_server_groups_{};
|
||||
@ -81,5 +107,7 @@ namespace ts::server {
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<groups::ServerGroup>>& assigned_server_groups();
|
||||
[[nodiscard]] const std::shared_ptr<groups::ChannelGroup>& assigned_channel_group();
|
||||
[[nodiscard]] const std::shared_ptr<permission::v2::PermissionManager>& client_permissions();
|
||||
[[nodiscard]] bool has_global_skip_permission();
|
||||
};
|
||||
}
|
@ -175,7 +175,7 @@ void VirtualServer::unregisterInternalClient(std::shared_ptr<ConnectedClient> cl
|
||||
}
|
||||
|
||||
bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& client, bool join) {
|
||||
std::shared_lock server_channel_lock{this->channel_tree_lock};
|
||||
std::shared_lock server_channel_lock{this->channel_tree_mutex};
|
||||
std::shared_ptr<BasicChannel> channel{};
|
||||
|
||||
auto requested_channel_path = client->properties()[property::CLIENT_DEFAULT_CHANNEL].value();
|
||||
@ -206,7 +206,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
|
||||
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used explicitly allowed it.", client->getLoggingPrefix(), channel->channelId());
|
||||
|
||||
if(whitelist_entry->second != "ignore") {
|
||||
if (!channel->passwordMatch(client_channel_password, true)) {
|
||||
if (!channel->verify_password(std::make_optional(client_channel_password), true)) {
|
||||
if (!permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
|
||||
channel = nullptr;
|
||||
goto skip_permissions;
|
||||
@ -222,7 +222,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
|
||||
goto skip_permissions;
|
||||
}
|
||||
|
||||
if (!channel->passwordMatch(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD], true)) {
|
||||
if (!channel->verify_password(std::make_optional(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD].value()), true)) {
|
||||
if(!permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
|
||||
debugMessage(this->getServerId(), "{} Tried to join channel {} but hasn't given the right channel password.", client->getLoggingPrefix(), channel->channelId());
|
||||
channel = nullptr;
|
||||
@ -245,7 +245,7 @@ bool VirtualServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& clie
|
||||
debugMessage(this->getServerId(), "{} Using channel {} as default client channel.", client->getLoggingPrefix(), channel->channelId());
|
||||
if(join) {
|
||||
server_channel_lock.unlock();
|
||||
unique_lock server_channel_w_lock(this->channel_tree_lock);
|
||||
unique_lock server_channel_w_lock(this->channel_tree_mutex);
|
||||
this->client_move(client, channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
|
||||
} else {
|
||||
client->currentChannel = channel;
|
||||
@ -268,14 +268,14 @@ void VirtualServer::testBanStateChange(const std::shared_ptr<ConnectedClient>& i
|
||||
void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target, const std::shared_ptr<ts::server::ConnectedClient> &invoker, const std::string &reason, size_t time) {
|
||||
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
|
||||
lock_guard command_lock(target->command_lock);
|
||||
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
|
||||
unique_lock server_channel_lock(this->channel_tree_mutex); /* we're "moving" a client! */
|
||||
|
||||
if(target->currentChannel) {
|
||||
for(const auto& client : this->getClients()) {
|
||||
if(!client || client == target)
|
||||
continue;
|
||||
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
if(client->isClientVisible(target, false))
|
||||
client->notifyClientLeftViewBanned(target, reason, invoker, time, false);
|
||||
}
|
||||
@ -285,7 +285,7 @@ void VirtualServer::notify_client_ban(const shared_ptr<ConnectedClient> &target,
|
||||
}
|
||||
|
||||
/* now disconnect the target itself */
|
||||
unique_lock client_channel_lock(target->channel_lock);
|
||||
unique_lock client_channel_lock(target->channel_tree_mutex);
|
||||
target->notifyClientLeftViewBanned(target, reason, invoker, time, false);
|
||||
target->currentChannel = nullptr;
|
||||
}
|
||||
@ -298,19 +298,19 @@ void VirtualServer::notify_client_kick(
|
||||
|
||||
if(target_channel) {
|
||||
/* use the move! */
|
||||
unique_lock server_channel_lock(this->channel_tree_lock, defer_lock);
|
||||
unique_lock server_channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
this->client_move(target, target_channel, invoker, reason, ViewReasonId::VREASON_CHANNEL_KICK, true, server_channel_lock);
|
||||
} else {
|
||||
/* the target is not allowed to execute anything; Must before channel tree lock because the target may waits for us to finish the channel stuff */
|
||||
lock_guard command_lock(target->command_lock);
|
||||
unique_lock server_channel_lock(this->channel_tree_lock); /* we're "moving" a client! */
|
||||
unique_lock server_channel_lock(this->channel_tree_mutex); /* we're "moving" a client! */
|
||||
|
||||
if(target->currentChannel) {
|
||||
for(const auto& client : this->getClients()) {
|
||||
if(!client || client == target)
|
||||
continue;
|
||||
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
if(client->isClientVisible(target, false))
|
||||
client->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
|
||||
}
|
||||
@ -323,7 +323,7 @@ void VirtualServer::notify_client_kick(
|
||||
}
|
||||
|
||||
/* now disconnect the target itself */
|
||||
unique_lock client_channel_lock(target->channel_lock);
|
||||
unique_lock client_channel_lock(target->channel_tree_mutex);
|
||||
target->notifyClientLeftViewKicked(target, nullptr, reason, invoker, false);
|
||||
target->currentChannel = nullptr;
|
||||
}
|
||||
@ -361,7 +361,6 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
||||
channel->deleted = true;
|
||||
}
|
||||
auto default_channel = this->channelTree->getDefaultChannel();
|
||||
tree_lock.unlock();
|
||||
|
||||
deque<unique_lock<threads::Mutex>> command_locks;
|
||||
for(const auto& client : clients) {
|
||||
@ -373,7 +372,8 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
||||
}
|
||||
|
||||
if(!tree_lock.owns_lock()) {
|
||||
tree_lock.lock(); /* no clients left within that tree */
|
||||
/* This case should never happen. client_move should never unlock the tree lock! */
|
||||
tree_lock.lock();
|
||||
}
|
||||
command_locks.clear();
|
||||
|
||||
@ -384,8 +384,8 @@ void VirtualServer::delete_channel(shared_ptr<ts::ServerChannel> channel, const
|
||||
}
|
||||
|
||||
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
client->notifyChannelDeleted(client->channels->delete_channel_root(channel), invoker);
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
client->notifyChannelDeleted(client->channel_tree->delete_channel_root(channel), invoker);
|
||||
});
|
||||
|
||||
{
|
||||
@ -451,11 +451,11 @@ void VirtualServer::client_move(
|
||||
|
||||
/* second step: show the target channel to the client if its not shown and let him subscibe to the channel */
|
||||
if(target_channel && notify_client) {
|
||||
unique_lock client_channel_lock(target->channel_lock);
|
||||
unique_lock client_channel_lock(target->channel_tree_mutex);
|
||||
|
||||
bool success = false;
|
||||
/* TODO: Use a bunk here and not a notify for every single */
|
||||
for(const auto& channel : target->channels->show_channel(l_target_channel, success))
|
||||
for(const auto& channel : target->channel_tree->show_channel(l_target_channel, success))
|
||||
target->notifyChannelShow(channel->channel(), channel->previous_channel);
|
||||
sassert(success);
|
||||
if(!success)
|
||||
@ -469,11 +469,11 @@ void VirtualServer::client_move(
|
||||
this->forEachClient([&](const shared_ptr<ConnectedClient>& client) {
|
||||
if (!notify_client && client == target) return;
|
||||
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
auto chan_target = client->channels->find_channel(target_channel);
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
auto chan_target = client->channel_tree->find_channel(target_channel);
|
||||
|
||||
if(chan_target) {
|
||||
auto chan_source = client->channels->find_channel(s_source_channel);
|
||||
auto chan_source = client->channel_tree->find_channel(s_source_channel);
|
||||
if(chan_source) {
|
||||
if (chan_target->subscribed || client == target) {
|
||||
if (client == target || client->isClientVisible(target, false)) {
|
||||
@ -527,7 +527,7 @@ void VirtualServer::client_move(
|
||||
if(!client || client == target)
|
||||
continue;
|
||||
|
||||
unique_lock client_channel_lock(client->channel_lock);
|
||||
unique_lock client_channel_lock(client->channel_tree_mutex);
|
||||
if(client->isClientVisible(target, false))
|
||||
client->notifyClientLeftView(target, nullptr, reason_id, reason_message, invoker, false);
|
||||
}
|
||||
@ -541,11 +541,9 @@ void VirtualServer::client_move(
|
||||
TIMING_STEP(timings, "notify view");
|
||||
|
||||
target->currentChannel = target_channel;
|
||||
server_channel_write_lock.unlock();
|
||||
|
||||
/* third step: update stuff for the client (remember: the client cant execute anything at the moment!) */
|
||||
shared_lock server_channel_read_lock(this->channel_tree_lock);
|
||||
unique_lock client_channel_lock(target->channel_lock);
|
||||
unique_lock client_channel_lock{target->channel_tree_mutex};
|
||||
TIMING_STEP(timings, "lock own tr");
|
||||
|
||||
if (s_source_channel) {
|
||||
@ -573,7 +571,7 @@ void VirtualServer::client_move(
|
||||
|
||||
if(s_source_channel) {
|
||||
deque<ChannelId> deleted;
|
||||
for(const auto& channel : target->channels->test_channel(l_source_channel, l_target_channel)) {
|
||||
for(const auto& channel : target->channel_tree->test_channel(l_source_channel, l_target_channel)) {
|
||||
deleted.push_back(channel->channelId());
|
||||
}
|
||||
|
||||
@ -586,7 +584,7 @@ void VirtualServer::client_move(
|
||||
auto source_channel_sub_power = target->calculate_permission(permission::i_channel_subscribe_power, i_source_channel);
|
||||
if(!s_source_channel->permission_granted(permission::i_channel_needed_subscribe_power, source_channel_sub_power, false)) {
|
||||
auto source_channel_sub_power_ignore = target->calculate_permission(permission::b_channel_ignore_subscribe_power, i_source_channel);
|
||||
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore, true)) {
|
||||
if(!permission::v2::permission_granted(1, source_channel_sub_power_ignore)) {
|
||||
logTrace(this->serverId, "Force unsubscribing of client {} for channel {}/{}. (Channel switch and no permissions)",
|
||||
CLIENT_STR_LOG_PREFIX_(target), s_source_channel->name(),
|
||||
i_source_channel
|
||||
|
@ -173,7 +173,7 @@ void VirtualServer::executeServerTick() {
|
||||
{
|
||||
BEGIN_TIMINGS();
|
||||
|
||||
unique_lock channel_lock(this->channel_tree_lock);
|
||||
unique_lock channel_lock(this->channel_tree_mutex);
|
||||
auto channels = this->channelTree->channels();
|
||||
channel_lock.unlock();
|
||||
|
||||
|
@ -616,7 +616,7 @@ void VirtualServer::preStop(const std::string& reason) {
|
||||
}
|
||||
|
||||
for(const auto& cl : this->getClients()) {
|
||||
unique_lock channel_lock(cl->channel_lock);
|
||||
unique_lock channel_lock(cl->channel_tree_mutex);
|
||||
if (cl->currentChannel) {
|
||||
auto vc = dynamic_pointer_cast<VoiceClient>(cl);
|
||||
if(vc) {
|
||||
@ -822,22 +822,36 @@ std::vector<std::shared_ptr<ConnectedClient>> VirtualServer::getClients() {
|
||||
return clients;
|
||||
}
|
||||
|
||||
/* Note: This method **should** not lock the channel tree else we've a lot to do! */
|
||||
deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannel(std::shared_ptr<BasicChannel> channel) {
|
||||
assert(this);
|
||||
|
||||
auto s_channel = dynamic_pointer_cast<ServerChannel>(channel);
|
||||
if(!s_channel) return {}; /* what had we done wrong here... :D */
|
||||
assert(s_channel);
|
||||
|
||||
shared_lock client_lock(s_channel->client_lock);
|
||||
if(!s_channel) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_lock client_lock{s_channel->client_lock};
|
||||
auto weak_clients = s_channel->clients;
|
||||
client_lock.unlock();
|
||||
|
||||
std::deque<std::shared_ptr<ConnectedClient>> result;
|
||||
for(const auto& weak_client : weak_clients) {
|
||||
auto client = weak_client.lock();
|
||||
if(!client) continue;
|
||||
if(client->connectionState() != ConnectionState::CONNECTED) continue;
|
||||
if(client->getChannel() != channel) continue; /* to be sure */
|
||||
if(!client) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(client->connectionState() != ConnectionState::CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(client->getChannel() != channel) {
|
||||
/* This should not happen! */
|
||||
continue;
|
||||
}
|
||||
|
||||
result.push_back(move(client));
|
||||
}
|
||||
@ -847,7 +861,7 @@ deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannel(std::share
|
||||
deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannelRoot(const std::shared_ptr<BasicChannel> &root, bool lock) {
|
||||
assert(this);
|
||||
|
||||
shared_lock channel_lock(this->channel_tree_lock, defer_lock);
|
||||
shared_lock channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
if(lock)
|
||||
channel_lock.lock();
|
||||
|
||||
@ -860,6 +874,41 @@ deque<shared_ptr<ConnectedClient>> VirtualServer::getClientsByChannelRoot(const
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t VirtualServer::countChannelRootClients(const std::shared_ptr<BasicChannel> &root, size_t limit, bool lock_channel_tree) {
|
||||
std::shared_lock channel_lock{this->channel_tree_mutex, defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
channel_lock.lock();
|
||||
}
|
||||
|
||||
size_t result{0};
|
||||
for(const auto& channel : this->channelTree->channels(root)) {
|
||||
auto channel_clients = this->getClientsByChannel(channel);
|
||||
result += channel_clients.size();
|
||||
|
||||
if(result >= limit) {
|
||||
return limit;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VirtualServer::isChannelRootEmpty(const std::shared_ptr<BasicChannel> &root, bool lock_channel_tree) {
|
||||
std::shared_lock channel_lock{this->channel_tree_mutex, defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
channel_lock.lock();
|
||||
}
|
||||
|
||||
for(const auto& channel : this->channelTree->channels(root)) {
|
||||
auto channel_clients = this->getClientsByChannel(channel);
|
||||
if(!channel_clients.empty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VirtualServer::notifyServerEdited(std::shared_ptr<ConnectedClient> invoker, deque<string> keys) {
|
||||
if(!invoker) return false;
|
||||
|
||||
@ -886,7 +935,7 @@ bool VirtualServer::notifyServerEdited(std::shared_ptr<ConnectedClient> invoker,
|
||||
bool VirtualServer::notifyClientPropertyUpdates(std::shared_ptr<ConnectedClient> client, const deque<const property::PropertyDescription*>& keys, bool selfNotify) {
|
||||
if(keys.empty() || !client) return false;
|
||||
this->forEachClient([&](const shared_ptr<ConnectedClient>& cl) {
|
||||
shared_lock client_channel_lock(cl->channel_lock);
|
||||
shared_lock client_channel_lock(cl->channel_tree_mutex);
|
||||
if(cl->isClientVisible(client, false) || (cl == client && selfNotify))
|
||||
cl->notifyClientUpdated(client, keys, false);
|
||||
});
|
||||
@ -1137,7 +1186,7 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr<BasicC
|
||||
|
||||
if(!property_updates.empty()) {
|
||||
this->forEachClient([&](const std::shared_ptr<ConnectedClient>& cl) {
|
||||
shared_lock client_channel_lock(cl->channel_lock);
|
||||
shared_lock client_channel_lock(cl->channel_tree_mutex);
|
||||
cl->notifyChannelEdited(channel, property_updates, issuer, false);
|
||||
});
|
||||
}
|
||||
@ -1151,10 +1200,10 @@ void VirtualServer::update_channel_from_permissions(const std::shared_ptr<BasicC
|
||||
if(cl->currentChannel) sassert(l_target);
|
||||
|
||||
{
|
||||
unique_lock client_channel_lock(cl->channel_lock);
|
||||
unique_lock client_channel_lock(cl->channel_tree_mutex);
|
||||
|
||||
deque<ChannelId> deleted;
|
||||
for(const auto& [flag_visible, channel] : cl->channels->update_channel(l_source, l_target)) {
|
||||
for(const auto& [flag_visible, channel] : cl->channel_tree->update_channel(l_source, l_target)) {
|
||||
if(flag_visible) {
|
||||
cl->notifyChannelShow(channel->channel(), channel->previous_channel);
|
||||
} else {
|
||||
|
@ -155,6 +155,8 @@ namespace ts {
|
||||
std::vector<std::shared_ptr<ConnectedClient>> getClients();
|
||||
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannel(std::shared_ptr<BasicChannel>);
|
||||
std::deque<std::shared_ptr<ConnectedClient>> getClientsByChannelRoot(const std::shared_ptr<BasicChannel> &, bool lock_channel_tree);
|
||||
[[nodiscard]] size_t countChannelRootClients(const std::shared_ptr<BasicChannel> &, size_t /* limit */, bool /* lock the channel tree */);
|
||||
[[nodiscard]] bool isChannelRootEmpty(const std::shared_ptr<BasicChannel> &, bool lock_channel_tree);
|
||||
|
||||
template <typename ClType>
|
||||
std::vector<std::shared_ptr<ClType>> getClientsByChannel(const std::shared_ptr<BasicChannel>& ch) {
|
||||
@ -278,7 +280,7 @@ namespace ts {
|
||||
inline int voice_encryption_mode() { return this->_voice_encryption_mode; }
|
||||
inline std::shared_ptr<conversation::ConversationManager> conversation_manager() { return this->conversation_manager_; }
|
||||
|
||||
inline auto& get_channel_tree_lock() { return this->channel_tree_lock; }
|
||||
inline auto& get_channel_tree_lock() { return this->channel_tree_mutex; }
|
||||
|
||||
void update_channel_from_permissions(const std::shared_ptr<BasicChannel>& /* channel */, const std::shared_ptr<ConnectedClient>& /* issuer */);
|
||||
|
||||
@ -333,7 +335,7 @@ namespace ts {
|
||||
int _voice_encryption_mode = 2; /* */
|
||||
|
||||
ServerChannelTree* channelTree = nullptr;
|
||||
std::shared_mutex channel_tree_lock; /* lock if access channel tree! */
|
||||
std::shared_mutex channel_tree_mutex; /* lock if access channel tree! */
|
||||
|
||||
std::shared_ptr<groups::GroupManager> groups_manager_{};
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "../InstanceHandler.h"
|
||||
#include "../PermissionCalculator.h"
|
||||
#include "../groups/GroupManager.h"
|
||||
#include "../groups/Group.h"
|
||||
#include <event.h>
|
||||
|
||||
using namespace std;
|
||||
@ -28,7 +27,7 @@ ConnectedClient::ConnectedClient(sql::SqlManager* db, const std::shared_ptr<Virt
|
||||
memset(&this->remote_address, 0, sizeof(this->remote_address));
|
||||
|
||||
connectionStatistics = make_shared<stats::ConnectionStatistics>(server ? server->getServerStatistics() : nullptr);
|
||||
channels = make_shared<ClientChannelView>(this);
|
||||
channel_tree = make_shared<ClientChannelView>(this);
|
||||
}
|
||||
|
||||
ConnectedClient::~ConnectedClient() {
|
||||
@ -234,8 +233,8 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
|
||||
this->channels_view_power = permission_channel_view_power;
|
||||
this->channels_ignore_view = permission_channel_ignore_view_power;
|
||||
|
||||
shared_lock server_channel_lock(server_ref->channel_tree_lock, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock, defer_lock);
|
||||
shared_lock server_channel_lock(server_ref->channel_tree_mutex, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
|
||||
if(lock_channel_tree) {
|
||||
/* first read lock server channel tree */
|
||||
@ -246,7 +245,7 @@ void ConnectedClient::updateChannelClientProperties(bool lock_channel_tree, bool
|
||||
/* might have been changed since we locked the tree */
|
||||
if(channel) {
|
||||
deque<ChannelId> deleted;
|
||||
for(const auto& update_entry : this->channels->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(channel->channelId()))) {
|
||||
for(const auto& update_entry : this->channel_tree->update_channel_path(server_ref->channelTree->tree_head(), server_ref->channelTree->find_linked_entry(channel->channelId()))) {
|
||||
if(update_entry.first) {
|
||||
this->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
|
||||
} else {
|
||||
@ -272,7 +271,7 @@ void ConnectedClient::updateTalkRights(permission::v2::PermissionFlaggedValue ta
|
||||
}
|
||||
|
||||
void ConnectedClient::resetIdleTime() {
|
||||
this->idleTimestamp = chrono::system_clock::now();
|
||||
this->idleTimestamp = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
void ConnectedClient::increaseFloodPoints(uint16_t num) {
|
||||
@ -286,108 +285,129 @@ bool ConnectedClient::shouldFloodBlock() {
|
||||
this->server->properties()[property::VIRTUALSERVER_ANTIFLOOD_POINTS_NEEDED_COMMAND_BLOCK].as_or<uint16_t>(150);
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel, bool enforce) {
|
||||
deque<std::shared_ptr<BasicChannel>> subscribed_channels;
|
||||
void ConnectedClient::subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel, bool enforce) {
|
||||
std::deque<std::shared_ptr<BasicChannel>> subscribed_channels;
|
||||
|
||||
auto ref_server = this->server;
|
||||
if(!ref_server)
|
||||
return {};
|
||||
if(!ref_server) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
std::shared_lock server_channel_lock{ref_server->channel_tree_mutex, defer_lock};
|
||||
std::unique_lock client_channel_lock{this->channel_tree_mutex, defer_lock};
|
||||
if(lock_channel) {
|
||||
server_channel_lock.lock();
|
||||
client_channel_lock.lock();
|
||||
}
|
||||
|
||||
auto cache = make_shared<CalculateCache>();
|
||||
for (const auto& channel : targets) {
|
||||
auto local_channel = this->channels->find_channel(channel);
|
||||
if(!local_channel) continue; //Not visible
|
||||
if(local_channel->subscribed) continue; //Already subscribed
|
||||
for (const auto& targetChannel : targets) {
|
||||
auto local_channel = this->channel_tree->find_channel(targetChannel);
|
||||
if(!local_channel) {
|
||||
/* The target channel isn't visible. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!general_granted && channel != this->currentChannel) {
|
||||
auto granted_permission = this->calculate_permission(permission::i_channel_subscribe_power, channel->channelId());
|
||||
if(local_channel->subscribed) {
|
||||
/* We've already subscribed to that channel. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!channel->permission_granted(permission::i_channel_needed_subscribe_power, granted_permission, false)) {
|
||||
auto ignore_power = this->calculate_permission(permission::b_channel_ignore_subscribe_power, channel->channelId());
|
||||
if(!ignore_power.has_value || ignore_power.value < 1)
|
||||
if(!general_granted && targetChannel != this->currentChannel) {
|
||||
auto required_subscribe_power = targetChannel->permissions()->permission_value_flagged(permission::i_channel_needed_subscribe_power);
|
||||
required_subscribe_power.clear_flag_on_zero();
|
||||
|
||||
ClientPermissionCalculator permissionCalculator{this, targetChannel};
|
||||
if(!permissionCalculator.permission_granted(permission::i_channel_subscribe_power, required_subscribe_power)) {
|
||||
if(!permissionCalculator.permission_granted(permission::b_channel_ignore_subscribe_power, 1)) {
|
||||
/* The target client hasn't permissions to view the channel nor ignore the subscribe power */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local_channel->subscribed = true;
|
||||
subscribed_channels.push_back(channel);
|
||||
subscribed_channels.push_back(targetChannel);
|
||||
}
|
||||
|
||||
deque<shared_ptr<ConnectedClient>> visible_clients;
|
||||
std::deque<shared_ptr<ConnectedClient>> visible_clients{};
|
||||
for(const auto& target_channel : subscribed_channels) {
|
||||
/* ref_server->getClientsByChannel only acquires channel client lock */
|
||||
for(const auto& client : ref_server->getClientsByChannel(target_channel)) {
|
||||
visible_clients.push_back(client);
|
||||
}
|
||||
/* getClientsByChannel() does not acquire the server channel tree mutex */
|
||||
auto channel_clients = ref_server->getClientsByChannel(target_channel);
|
||||
visible_clients.insert(visible_clients.end(), channel_clients.begin(), channel_clients.end());
|
||||
}
|
||||
|
||||
this->notifyClientEnterView(visible_clients, ViewReasonSystem);
|
||||
if(!visible_clients.empty()) {
|
||||
this->notifyClientEnterView(visible_clients, ViewReasonSystem);
|
||||
}
|
||||
|
||||
if (!subscribed_channels.empty())
|
||||
if (!subscribed_channels.empty()) {
|
||||
this->notifyChannelSubscribed(subscribed_channels);
|
||||
}
|
||||
}
|
||||
|
||||
return subscribed_channels;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<BasicChannel>> ConnectedClient::unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel) {
|
||||
void ConnectedClient::unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& targets, bool lock_channel) {
|
||||
auto ref_server = this->server;
|
||||
if(!ref_server)
|
||||
return {};
|
||||
|
||||
deque<std::shared_ptr<BasicChannel> > unsubscribed_channels;
|
||||
if(!ref_server) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<BasicChannel> > unsubscribed_channels;
|
||||
{
|
||||
shared_lock server_channel_lock(ref_server->channel_tree_lock, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock, defer_lock);
|
||||
std::shared_lock server_channel_lock{ref_server->channel_tree_mutex, defer_lock};
|
||||
std::unique_lock client_channel_lock{this->channel_tree_mutex, defer_lock};
|
||||
if(lock_channel) {
|
||||
server_channel_lock.lock();
|
||||
client_channel_lock.lock();
|
||||
}
|
||||
|
||||
for (const auto& channel : targets) {
|
||||
if(this->currentChannel == channel) continue;
|
||||
if(this->currentChannel == channel) {
|
||||
/* Do not unsubscribe from our own channel. */
|
||||
continue;
|
||||
}
|
||||
|
||||
auto chan = this->channels->find_channel(channel);
|
||||
if(!chan || !chan->subscribed) continue;
|
||||
chan->subscribed = false;
|
||||
auto local_channel = this->channel_tree->find_channel(channel);
|
||||
if(!local_channel || !local_channel->subscribed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ref_server->getClientsByChannel only acquires channel client lock */
|
||||
local_channel->subscribed = false;
|
||||
|
||||
/* getClientsByChannel() does not acquire the server channel tree mutex */
|
||||
auto clients = this->server->getClientsByChannel(channel);
|
||||
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, clients](const weak_ptr<ConnectedClient>& weak) {
|
||||
auto c = weak.lock();
|
||||
if(!c) {
|
||||
logError(this->getServerId(), "{} Got \"dead\" client in visible client list! This can cause a remote client disconnect within the future!", CLIENT_STR_LOG_PREFIX);
|
||||
this->visibleClients.erase(std::remove_if(this->visibleClients.begin(), this->visibleClients.end(), [&, clients](const std::weak_ptr<ConnectedClient>& weak) {
|
||||
auto visible_client = weak.lock();
|
||||
if(!visible_client) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return std::find(clients.begin(), clients.end(), c) != clients.end();
|
||||
return std::find(clients.begin(), clients.end(), visible_client) != clients.end();
|
||||
}), this->visibleClients.end());
|
||||
|
||||
unsubscribed_channels.push_back(channel);
|
||||
}
|
||||
|
||||
if (!unsubscribed_channels.empty())
|
||||
if (!unsubscribed_channels.empty()) {
|
||||
this->notifyChannelUnsubscribed(unsubscribed_channels);
|
||||
}
|
||||
}
|
||||
|
||||
return unsubscribed_channels;
|
||||
}
|
||||
|
||||
bool ConnectedClient::isClientVisible(const std::shared_ptr<ts::server::ConnectedClient>& client, bool lock) {
|
||||
auto client_list = this->getVisibleClients(lock);
|
||||
for(const auto& entry : client_list)
|
||||
if(entry.lock() == client)
|
||||
std::shared_lock tree_lock(this->channel_tree_mutex, std::defer_lock);
|
||||
if(lock) {
|
||||
tree_lock.lock();
|
||||
}
|
||||
|
||||
for(const auto& entry : this->visibleClients) {
|
||||
if(entry.lock() == client) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -714,18 +734,18 @@ inline void send_channels(ConnectedClient* client, ChannelIT begin, const Channe
|
||||
}
|
||||
|
||||
void ConnectedClient::sendChannelList(bool lock_channel_tree) {
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock, defer_lock);
|
||||
shared_lock server_channel_lock(this->server->channel_tree_mutex, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
if(lock_channel_tree) {
|
||||
server_channel_lock.lock();
|
||||
client_channel_lock.lock();
|
||||
}
|
||||
|
||||
auto channels = this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
auto channels = this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
|
||||
if(this->currentChannel) {
|
||||
bool send_success;
|
||||
for(const auto& channel : this->channels->show_channel(this->server->channelTree->find_linked_entry(this->currentChannel->channelId()), send_success))
|
||||
for(const auto& channel : this->channel_tree->show_channel(this->server->channelTree->find_linked_entry(this->currentChannel->channelId()), send_success))
|
||||
channels.push_back(channel);
|
||||
if(!send_success)
|
||||
logCritical(this->getServerId(), "ConnectedClient::sendChannelList => failed to insert default channel!");
|
||||
@ -768,23 +788,6 @@ void ConnectedClient::sendChannelList(bool lock_channel_tree) {
|
||||
this->sendCommand(Command("channellistfinished"));
|
||||
}
|
||||
|
||||
void ConnectedClient::sendChannelDescription(const std::shared_ptr<BasicChannel>& channel, bool lock) {
|
||||
shared_lock tree_lock(this->channel_lock, defer_lock);
|
||||
if(lock)
|
||||
tree_lock.lock();
|
||||
|
||||
if(!this->channels->channel_visible(channel)) return;
|
||||
|
||||
auto limit = this->getType() == CLIENT_TEAMSPEAK ? 8192 : 131130;
|
||||
|
||||
auto description = channel->properties()[property::CHANNEL_DESCRIPTION].value();
|
||||
Command cmd("notifychanneledited");
|
||||
cmd["cid"] = channel->channelId();
|
||||
cmd["reasonid"] = 9;
|
||||
cmd["channel_description"] = description.size() > limit ? description.substr(0, limit) : description;
|
||||
this->sendCommand(cmd, true);
|
||||
}
|
||||
|
||||
void ConnectedClient::tick_server(const std::chrono::system_clock::time_point &time) {
|
||||
ALARM_TIMER(A1, "ConnectedClient::tick", milliseconds(2));
|
||||
if(this->state == ConnectionState::CONNECTED) {
|
||||
@ -1067,7 +1070,7 @@ void ConnectedClient::update_displayed_client_groups(bool& server_groups_changed
|
||||
server_group_assignments = "0";
|
||||
}
|
||||
|
||||
std::unique_lock view_lock{this->channel_lock};
|
||||
std::unique_lock view_lock{this->channel_tree_mutex};
|
||||
this->cached_server_groups = server_groups;
|
||||
}
|
||||
|
||||
@ -1134,7 +1137,7 @@ do { \
|
||||
permission::PermissionType ConnectedClient::calculate_and_get_join_state(const std::shared_ptr<BasicChannel>& channel) {
|
||||
std::shared_ptr<ViewEntry> ventry;
|
||||
{
|
||||
shared_lock view_lock(this->channel_lock);
|
||||
shared_lock view_lock(this->channel_tree_mutex);
|
||||
ventry = this->channel_view()->find_channel(channel);
|
||||
if(!ventry) {
|
||||
return permission::i_channel_view_power;
|
||||
|
@ -114,19 +114,18 @@ namespace ts {
|
||||
inline std::shared_ptr<BasicChannel> getChannel(){ return this->currentChannel; }
|
||||
inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; }
|
||||
|
||||
//bool channelSubscribed(const std::shared_ptr<BasicChannel>&);
|
||||
/* if lock_channel == false then channel_lock must be write locked! */
|
||||
std::deque<std::shared_ptr<BasicChannel>> subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool lock_channel, bool /* enforce */);
|
||||
/* if lock_channel == false then channel_lock must be write locked! */
|
||||
std::deque<std::shared_ptr<BasicChannel>> unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool lock_channel);
|
||||
/* If called without locking the client channel tree **must** be write locked */
|
||||
void subscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool /* lock server and client channel tree */, bool /* enforce */);
|
||||
/* If called without locking the client channel tree **must** be write locked */
|
||||
void unsubscribeChannel(const std::deque<std::shared_ptr<BasicChannel>>& target, bool /* lock server and client channel tree */);
|
||||
|
||||
bool isClientVisible(const std::shared_ptr<ConnectedClient>&, bool /* lock channel lock */);
|
||||
inline std::deque<std::weak_ptr<ConnectedClient>> getVisibleClients(bool lock_channel) {
|
||||
std::shared_lock lock(this->channel_lock, std::defer_lock);
|
||||
std::shared_lock lock(this->channel_tree_mutex, std::defer_lock);
|
||||
if(lock_channel) {
|
||||
lock.lock();
|
||||
}
|
||||
assert(mutex_shared_locked(this->channel_lock));
|
||||
assert(mutex_shared_locked(this->channel_tree_mutex));
|
||||
return this->visibleClients;
|
||||
}
|
||||
|
||||
@ -305,12 +304,12 @@ namespace ts {
|
||||
return this->connectionStatistics;
|
||||
}
|
||||
|
||||
inline std::shared_ptr<ClientChannelView> channel_view() { return this->channels; }
|
||||
inline std::shared_ptr<ClientChannelView> channel_view() { return this->channel_tree; }
|
||||
|
||||
[[nodiscard]] inline std::shared_ptr<ConnectedClient> ref() { return this->_this.lock(); }
|
||||
[[nodiscard]] inline std::weak_ptr<ConnectedClient> weak_ref() { return this->_this; }
|
||||
|
||||
std::shared_mutex& get_channel_lock() { return this->channel_lock; }
|
||||
std::shared_mutex& get_channel_lock() { return this->channel_tree_mutex; }
|
||||
|
||||
/* Attention: Ensure that channel_lock has been locked */
|
||||
[[nodiscard]] inline std::vector<GroupId>& current_server_groups() { return this->cached_server_groups; }
|
||||
@ -414,8 +413,8 @@ namespace ts {
|
||||
bool block_flood = true;
|
||||
FloodPoints floodPoints = 0;
|
||||
|
||||
std::shared_ptr<ClientChannelView> channels;
|
||||
std::shared_mutex channel_lock;
|
||||
std::shared_ptr<ClientChannelView> channel_tree{};
|
||||
std::shared_mutex channel_tree_mutex{};
|
||||
|
||||
/* The permission overview which the client itself has (for basic client actions ) */
|
||||
std::mutex client_needed_permissions_lock;
|
||||
@ -690,7 +689,6 @@ namespace ts {
|
||||
void sendChannelList(bool lock_channel_tree);
|
||||
void sendServerInit();
|
||||
void sendTSPermEditorWarning();
|
||||
void sendChannelDescription(const std::shared_ptr<BasicChannel>&, bool lock_tree);
|
||||
|
||||
bool handleTextMessage(ChatMessageMode, std::string, const std::shared_ptr<ConnectedClient>& /* sender target */);
|
||||
|
||||
|
@ -234,7 +234,7 @@ bool ConnectedClient::notifyServerGroupClientAdd(
|
||||
/* Deny any client moves 'till we've send the notify */
|
||||
std::shared_lock<std::shared_mutex> channel_tree_lock{};
|
||||
if(this->server) {
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
|
||||
}
|
||||
|
||||
if(!this->isClientVisible(target_client, true)) {
|
||||
@ -264,7 +264,7 @@ bool ConnectedClient::notifyServerGroupClientRemove(
|
||||
/* Deny any client moves 'till we've send the notify */
|
||||
std::shared_lock<std::shared_mutex> channel_tree_lock{};
|
||||
if(this->server) {
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
|
||||
}
|
||||
|
||||
if(!this->isClientVisible(target_client, true)) {
|
||||
@ -294,7 +294,7 @@ bool ConnectedClient::notifyClientChannelGroupChanged(std::optional<ts::command_
|
||||
/* Deny any client moves 'till we've send the notify */
|
||||
std::shared_lock<std::shared_mutex> channel_tree_lock{};
|
||||
if(this->server) {
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_lock};
|
||||
channel_tree_lock = std::shared_lock{this->server->channel_tree_mutex};
|
||||
}
|
||||
|
||||
/* No need to check if the channel is visible since if this is the case the client would not be visible as well. */
|
||||
@ -442,8 +442,8 @@ bool ConnectedClient::notifyClientMoved(const shared_ptr<ConnectedClient> &clien
|
||||
assert(client->getClientId() > 0);
|
||||
assert(client->currentChannel);
|
||||
assert(target_channel);
|
||||
sassert(mutex_shared_locked(this->channel_lock));
|
||||
sassert(mutex_shared_locked(client->channel_lock));
|
||||
sassert(mutex_shared_locked(this->channel_tree_mutex));
|
||||
sassert(mutex_shared_locked(client->channel_tree_mutex));
|
||||
assert(this->isClientVisible(client, false) || &*client == this);
|
||||
|
||||
Command mv("notifyclientmoved");
|
||||
@ -462,12 +462,12 @@ bool ConnectedClient::notifyClientMoved(const shared_ptr<ConnectedClient> &clien
|
||||
}
|
||||
|
||||
bool ConnectedClient::notifyClientUpdated(const std::shared_ptr<ConnectedClient> &client, const deque<const property::PropertyDescription*> &props, bool lock) {
|
||||
std::shared_lock channel_lock(this->channel_lock, defer_lock);
|
||||
std::shared_lock channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
if(lock) {
|
||||
channel_lock.lock();
|
||||
}
|
||||
|
||||
sassert(mutex_shared_locked(this->channel_lock));
|
||||
sassert(mutex_shared_locked(this->channel_tree_mutex));
|
||||
if(!this->isClientVisible(client, false) && client != this)
|
||||
return false;
|
||||
|
||||
@ -515,7 +515,7 @@ bool ConnectedClient::notifyClientChatClosed(const shared_ptr<ConnectedClient> &
|
||||
}
|
||||
|
||||
bool ConnectedClient::notifyChannelMoved(const std::shared_ptr<BasicChannel> &channel, ChannelId order, const std::shared_ptr<ConnectedClient> &invoker) {
|
||||
if(!channel || !this->channels->channel_visible(channel)) return false;
|
||||
if(!channel || !this->channel_tree->channel_visible(channel)) return false;
|
||||
|
||||
Command notify("notifychannelmoved");
|
||||
INVOKER(notify, invoker);
|
||||
@ -546,13 +546,13 @@ bool ConnectedClient::notifyChannelHide(const std::deque<ChannelId> &channel_ids
|
||||
if(channel_ids.empty()) return true;
|
||||
|
||||
if(this->getType() == ClientType::CLIENT_TEAMSPEAK) { //Voice hasnt that event
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock, defer_lock);
|
||||
shared_lock server_channel_lock(this->server->channel_tree_mutex, defer_lock);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex, defer_lock);
|
||||
if(lock_channel_tree) {
|
||||
server_channel_lock.lock();
|
||||
client_channel_lock.lock();
|
||||
} else {
|
||||
assert(mutex_locked(this->channel_lock));
|
||||
assert(mutex_locked(this->channel_tree_mutex));
|
||||
}
|
||||
|
||||
deque<shared_ptr<ConnectedClient>> clients_to_remove;
|
||||
@ -611,7 +611,7 @@ bool ConnectedClient::notifyChannelShow(const std::shared_ptr<ts::BasicChannel>
|
||||
}
|
||||
|
||||
bool ConnectedClient::notifyChannelDescriptionChanged(std::shared_ptr<BasicChannel> channel) {
|
||||
if(!this->channels->channel_visible(channel)) return false;
|
||||
if(!this->channel_tree->channel_visible(channel)) return false;
|
||||
Command notifyDesChanges("notifychanneldescriptionchanged");
|
||||
notifyDesChanges["cid"] = channel->channelId();
|
||||
this->sendCommand(notifyDesChanges);
|
||||
@ -619,7 +619,7 @@ bool ConnectedClient::notifyChannelDescriptionChanged(std::shared_ptr<BasicChann
|
||||
}
|
||||
|
||||
bool ConnectedClient::notifyChannelPasswordChanged(std::shared_ptr<BasicChannel> channel) {
|
||||
if(!this->channels->channel_visible(channel)) return false;
|
||||
if(!this->channel_tree->channel_visible(channel)) return false;
|
||||
Command notifyDesChanges("notifychannelpasswordchanged");
|
||||
notifyDesChanges["cid"] = channel->channelId();
|
||||
this->sendCommand(notifyDesChanges);
|
||||
@ -630,7 +630,7 @@ bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClien
|
||||
sassert(client && client->getClientId() > 0);
|
||||
sassert(to);
|
||||
sassert(!lock_channel_tree); /* we don't support locking */
|
||||
sassert(mutex_locked(this->channel_lock));
|
||||
sassert(mutex_locked(this->channel_tree_mutex));
|
||||
sassert(!this->isClientVisible(client, false) || &*client == this);
|
||||
|
||||
switch (reasonId) {
|
||||
@ -676,9 +676,11 @@ bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClien
|
||||
}
|
||||
|
||||
bool ConnectedClient::notifyClientEnterView(const std::deque<std::shared_ptr<ConnectedClient>> &clients, const ts::ViewReasonSystemT &_vrs) {
|
||||
if(clients.empty())
|
||||
if(clients.empty()) {
|
||||
return true;
|
||||
assert(mutex_locked(this->channel_lock));
|
||||
}
|
||||
|
||||
assert(mutex_locked(this->channel_tree_mutex));
|
||||
|
||||
Command cmd("notifycliententerview");
|
||||
|
||||
@ -691,8 +693,9 @@ bool ConnectedClient::notifyClientEnterView(const std::deque<std::shared_ptr<Con
|
||||
while(it != clients.end()) {
|
||||
auto client = *(it++);
|
||||
|
||||
if(this->isClientVisible(client, false))
|
||||
if(this->isClientVisible(client, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto channel = client->getChannel();
|
||||
sassert(!channel || channel->channelId() != 0);
|
||||
@ -731,7 +734,7 @@ bool ConnectedClient::notifyChannelEdited(
|
||||
const std::vector<property::ChannelProperties> &properties,
|
||||
const std::shared_ptr<ConnectedClient> &invoker,
|
||||
bool) {
|
||||
auto v_channel = this->channels->find_channel(channel->channelId());
|
||||
auto v_channel = this->channel_tree->find_channel(channel->channelId());
|
||||
if(!v_channel) return false; //Not visible? Important do not remove!
|
||||
|
||||
bool send_description_change{false};
|
||||
|
@ -43,7 +43,7 @@ bool SpeakingClient::shouldReceiveVoice(const std::shared_ptr<ConnectedClient> &
|
||||
if(this->properties()[property::CLIENT_OUTPUT_MUTED].as_or<bool>(false)) return false;
|
||||
|
||||
{
|
||||
shared_lock client_lock(this->channel_lock);
|
||||
shared_lock client_lock(this->channel_tree_mutex);
|
||||
for(const auto& entry : this->mutedClients)
|
||||
if(entry.lock() == sender)
|
||||
return false;
|
||||
@ -55,7 +55,7 @@ bool SpeakingClient::shouldReceiveVoiceWhisper(const std::shared_ptr<ConnectedCl
|
||||
if(!this->shouldReceiveVoice(sender))
|
||||
return false;
|
||||
|
||||
return permission::v2::permission_granted(this->cpmerission_needed_whisper_power, sender->cpmerission_whisper_power, false);
|
||||
return permission::v2::permission_granted(this->cpmerission_needed_whisper_power, sender->cpmerission_whisper_power);
|
||||
}
|
||||
|
||||
bool SpeakingClient::should_handle_voice_packet(size_t) {
|
||||
@ -396,16 +396,14 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
|
||||
}
|
||||
|
||||
/* must be triggered while helding an execute lock */
|
||||
//Note: Client permissions are may not really
|
||||
void SpeakingClient::processJoin() {
|
||||
TIMING_START(timings);
|
||||
auto ref_server = this->server;
|
||||
assert(ref_server);
|
||||
|
||||
this->resetIdleTime();
|
||||
|
||||
/* don't process any commands */
|
||||
std::lock_guard command_lock_{this->command_lock};
|
||||
auto ref_server = this->server;
|
||||
assert(ref_server);
|
||||
|
||||
if(this->state != ConnectionState::INIT_HIGH) {
|
||||
logError(this->getServerId(), "{} Invalid processJoin() connection state!", CLIENT_STR_LOG_PREFIX);
|
||||
@ -507,10 +505,10 @@ void SpeakingClient::processJoin() {
|
||||
this->properties()[property::CLIENT_CHANNEL_GROUP_ID] = "0";
|
||||
this->properties()[property::CLIENT_TALK_POWER] = "0";
|
||||
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_lock);
|
||||
if(this->getType() != ClientType::CLIENT_TEAMSPEAK) {
|
||||
std::lock_guard own_channel_lock{this->channel_lock};
|
||||
std::lock_guard own_channel_lock{this->channel_tree_mutex};
|
||||
this->subscribeChannel({this->currentChannel}, false, true); /* su "improve" the TS3 clients join speed we send the channel clients a bit later, when the TS3 client gets his own client variables */
|
||||
}
|
||||
}
|
||||
@ -571,7 +569,7 @@ void SpeakingClient::processLeave() {
|
||||
if(server){
|
||||
logMessage(this->getServerId(), "Voice client {}/{} ({}) from {} left.", this->getClientDatabaseId(), this->getUid(), this->getDisplayName(), this->getLoggingPeerIp() + ":" + to_string(this->getPeerPort()));
|
||||
{
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
server->unregisterClient(ownLock, "disconnected", server_channel_lock); /* already moves client to void if needed */
|
||||
}
|
||||
server->music_manager_->cleanup_client_bots(this->getClientDatabaseId());
|
||||
@ -822,7 +820,7 @@ command_result SpeakingClient::handleCommandBroadcastVideo(Command &command) {
|
||||
|
||||
switch(type) {
|
||||
case rtc::VideoBroadcastType::Screen:
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()), false)) {
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()))) {
|
||||
return ts::command_result{permission::b_video_screen};
|
||||
}
|
||||
|
||||
@ -830,7 +828,7 @@ command_result SpeakingClient::handleCommandBroadcastVideo(Command &command) {
|
||||
|
||||
|
||||
case rtc::VideoBroadcastType::Camera:
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()), false)) {
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()))) {
|
||||
return ts::command_result{permission::b_video_camera};
|
||||
}
|
||||
|
||||
@ -934,7 +932,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
|
||||
|
||||
auto permission_max_streams = this->calculate_permission(permission::i_video_max_streams, this->getChannelId());
|
||||
if(permission_max_streams.has_value) {
|
||||
if(!permission::v2::permission_granted(camera_streams + screen_streams, permission_max_streams, false)) {
|
||||
if(!permission::v2::permission_granted(camera_streams + screen_streams, permission_max_streams)) {
|
||||
return ts::command_result{permission::i_video_max_streams};
|
||||
}
|
||||
}
|
||||
@ -943,7 +941,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
|
||||
case rtc::VideoBroadcastType::Camera: {
|
||||
const auto permission_max_camera_streams = this->calculate_permission(permission::i_video_max_camera_streams, this->getChannelId());
|
||||
if(permission_max_camera_streams.has_value) {
|
||||
if(!permission::v2::permission_granted(camera_streams, permission_max_camera_streams, false)) {
|
||||
if(!permission::v2::permission_granted(camera_streams, permission_max_camera_streams)) {
|
||||
return ts::command_result{permission::i_video_max_camera_streams};
|
||||
}
|
||||
}
|
||||
@ -953,7 +951,7 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
|
||||
case rtc::VideoBroadcastType::Screen: {
|
||||
const auto permission_max_screen_streams = this->calculate_permission(permission::i_video_max_camera_streams, this->getChannelId());
|
||||
if(permission_max_screen_streams.has_value) {
|
||||
if(!permission::v2::permission_granted(screen_streams, permission_max_screen_streams, false)) {
|
||||
if(!permission::v2::permission_granted(screen_streams, permission_max_screen_streams)) {
|
||||
return ts::command_result{permission::i_video_max_screen_streams};
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "../../InstanceHandler.h"
|
||||
#include "../../build.h"
|
||||
#include "../../PermissionCalculator.h"
|
||||
#include "../../manager/ActionLogger.h"
|
||||
#include "../../manager/ConversationManager.h"
|
||||
#include "../../manager/PermissionNameMapper.h"
|
||||
@ -19,37 +19,53 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "./bulk_parsers.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <Properties.h>
|
||||
#include <bbcode/bbcodes.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/digest.h>
|
||||
#include <misc/sassert.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace std;
|
||||
using namespace ts;
|
||||
using namespace ts::server;
|
||||
|
||||
/*
|
||||
TODO: Log missing permissions?
|
||||
{findError("parameter_invalid"), "could not resolve permission " + (cmd[index].has("permid") ? cmd[index]["permid"].as<string>() : cmd[index]["permsid"].as<string>())};
|
||||
*/
|
||||
command_result ConnectedClient::handleCommandChannelGetDescription(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(0);
|
||||
RESOLVE_CHANNEL_R(cmd["cid"], true);
|
||||
auto channel = dynamic_pointer_cast<BasicChannel>(l_channel->entry);
|
||||
assert(channel);
|
||||
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_ignore_description_view_power, channel->channelId()))) {
|
||||
auto view_power = this->calculate_permission(permission::i_channel_description_view_power, channel->channelId());
|
||||
if (!channel->permission_granted(permission::i_channel_needed_description_view_power, view_power, false))
|
||||
return command_result{permission::i_channel_description_view_power};
|
||||
std::shared_lock channel_lock{this->channel_tree_mutex};
|
||||
if(!this->channel_tree->channel_visible(channel)) {
|
||||
return ts::command_result{error::channel_invalid_id};
|
||||
}
|
||||
|
||||
this->sendChannelDescription(channel, true);
|
||||
ClientPermissionCalculator permission_calculator{this, channel};
|
||||
if(!permission_calculator.permission_granted(permission::b_channel_ignore_description_view_power, 1)) {
|
||||
auto required_view_power = channel->permissions()->permission_value_flagged(permission::i_channel_needed_description_view_power);
|
||||
required_view_power.clear_flag_on_zero();
|
||||
|
||||
if(!permission_calculator.permission_granted(permission::i_channel_description_view_power, required_view_power)) {
|
||||
return command_result{permission::i_channel_description_view_power};
|
||||
}
|
||||
}
|
||||
|
||||
auto channel_description = channel->properties()[property::CHANNEL_DESCRIPTION].value();
|
||||
auto channel_description_limit = this->getType() == CLIENT_TEAMSPEAK ? 8192 : 131130;
|
||||
|
||||
if(channel_description.length() > channel_description_limit) {
|
||||
channel_description = channel_description.substr(0, channel_description_limit - 3);
|
||||
channel_description.append("...");
|
||||
}
|
||||
|
||||
ts::command_builder notify{this->notify_response_command("notifychanneledited")};
|
||||
notify.put_unchecked(0, "cid", channel->channelId());
|
||||
notify.put_unchecked(0, "reasonid", "9");
|
||||
notify.put_unchecked(0, "channel_description", channel_description);
|
||||
this->sendCommand(notify);
|
||||
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
@ -57,31 +73,46 @@ command_result ConnectedClient::handleCommandChannelSubscribe(Command &cmd) {
|
||||
CMD_REF_SERVER(ref_server);
|
||||
CMD_RESET_IDLE;
|
||||
|
||||
bool flood_points = false;
|
||||
deque<shared_ptr<BasicChannel>> channels;
|
||||
bool flood_points{false};
|
||||
std::deque<std::shared_ptr<BasicChannel>> target_channels{};
|
||||
//target_channels.reserve(cmd.bulkCount());
|
||||
|
||||
ts::command_result_bulk result{};
|
||||
result.emplace_result_n(cmd.bulkCount(), error::ok);
|
||||
|
||||
{
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
|
||||
std::lock_guard client_channel_lock{this->channel_tree_mutex};
|
||||
|
||||
for (int index = 0; index < cmd.bulkCount(); index++) {
|
||||
auto local_channel = this->channel_view()->find_channel(cmd[index]["cid"].as<ChannelId>());
|
||||
if (!local_channel)
|
||||
return command_result{error::channel_invalid_id, "Cant resolve channel"};
|
||||
for (int index{0}; index < cmd.bulkCount(); index++) {
|
||||
auto target_channel_id = cmd[index]["cid"].as<ChannelId>();
|
||||
auto local_channel = this->channel_view()->find_channel(target_channel_id);
|
||||
if (!local_channel) {
|
||||
result.set_result(index, ts::command_result{error::channel_invalid_id});
|
||||
continue;
|
||||
}
|
||||
|
||||
auto channel = this->server->channelTree->findChannel(cmd[index]["cid"].as<ChannelId>());
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id, "Cant resolve channel"};
|
||||
auto channel = this->server->channelTree->findChannel(target_channel_id);
|
||||
if (!channel) {
|
||||
result.set_result(index, ts::command_result{error::channel_invalid_id});
|
||||
continue;
|
||||
}
|
||||
|
||||
channels.push_back(channel);
|
||||
if (!flood_points && system_clock::now() - local_channel->view_timestamp > seconds(5)) {
|
||||
target_channels.push_back(channel);
|
||||
if (!flood_points && std::chrono::system_clock::now() - local_channel->view_timestamp > seconds(5)) {
|
||||
flood_points = true;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(15);
|
||||
|
||||
this->increaseFloodPoints(15);
|
||||
if(this->shouldFloodBlock()) {
|
||||
result.set_result(index, ts::command_result{error::ban_flooding});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!channels.empty())
|
||||
this->subscribeChannel(channels, false, false);
|
||||
if (!target_channels.empty()) {
|
||||
this->subscribeChannel(target_channels, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
return command_result{error::ok};
|
||||
@ -92,8 +123,8 @@ command_result ConnectedClient::handleCommandChannelSubscribeAll(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(20);
|
||||
|
||||
{
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
|
||||
std::lock_guard client_channel_lock{this->channel_tree_mutex};
|
||||
this->subscribeChannel(this->server->channelTree->channels(), false, false);
|
||||
this->subscribeToAll = true;
|
||||
}
|
||||
@ -104,20 +135,28 @@ command_result ConnectedClient::handleCommandChannelUnsubscribe(Command &cmd) {
|
||||
CMD_REQ_SERVER;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
{
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
ts::command_result_bulk result{};
|
||||
result.emplace_result_n(cmd.bulkCount(), error::ok);
|
||||
|
||||
deque<shared_ptr<BasicChannel>> channels;
|
||||
{
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
|
||||
std::lock_guard client_channel_lock{this->channel_tree_mutex};
|
||||
|
||||
std::deque<shared_ptr<BasicChannel>> channels{};
|
||||
for (int index = 0; index < cmd.bulkCount(); index++) {
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel) continue;
|
||||
if (!channel) {
|
||||
result.set_result(index, ts::command_result{error::channel_invalid_id});
|
||||
continue;
|
||||
}
|
||||
|
||||
channels.push_front(channel);
|
||||
}
|
||||
|
||||
this->unsubscribeChannel(channels, false);
|
||||
}
|
||||
return command_result{error::ok};
|
||||
|
||||
return command_result{std::move(result)};
|
||||
}
|
||||
|
||||
command_result ConnectedClient::handleCommandChannelUnsubscribeAll(Command &cmd) {
|
||||
@ -125,11 +164,12 @@ command_result ConnectedClient::handleCommandChannelUnsubscribeAll(Command &cmd)
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(25);
|
||||
|
||||
{
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_mutex};
|
||||
std::lock_guard client_channel_lock{this->channel_tree_mutex};
|
||||
this->unsubscribeChannel(this->server->channelTree->channels(), false);
|
||||
this->subscribeToAll = false;
|
||||
}
|
||||
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
@ -257,7 +297,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
||||
CMD_CHK_PARM_COUNT(1);
|
||||
|
||||
auto target_tree = this->server ? this->server->channelTree : &*serverInstance->getChannelTree();
|
||||
std::shared_lock channel_tree_read_lock{this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock()};
|
||||
std::shared_lock channel_tree_read_lock{this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock()};
|
||||
ChannelId parent_channel_id = cmd[0].has("cpid") ? cmd["cpid"].as<ChannelId>() : 0;
|
||||
|
||||
#define test_permission(required, permission_type) \
|
||||
@ -610,7 +650,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
|
||||
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();
|
||||
|
||||
std::unique_lock channel_tree_write_lock{this->server->channel_tree_lock};
|
||||
std::unique_lock channel_tree_write_lock{this->server->channel_tree_mutex};
|
||||
this->server->client_move(
|
||||
this->ref(),
|
||||
created_channel,
|
||||
@ -990,8 +1030,8 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
}
|
||||
}
|
||||
|
||||
auto channel_tree = server ? server->getChannelTree() : &*serverInstance->getChannelTree();
|
||||
std::unique_lock channel_tree_lock{server ? server->channel_tree_lock : serverInstance->getChannelTreeLock()};
|
||||
auto target_channel_tree = server ? server->getChannelTree() : &*serverInstance->getChannelTree();
|
||||
std::unique_lock channel_tree_lock{server ? server->channel_tree_mutex : serverInstance->getChannelTreeLock()};
|
||||
|
||||
struct TemporaryCreatedChannel {
|
||||
ServerChannelTree* channel_tree;
|
||||
@ -1002,7 +1042,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
|
||||
channel_tree->deleteChannelRoot(this->channel);
|
||||
}
|
||||
} temporary_created_channel{channel_tree, nullptr};
|
||||
} temporary_created_channel{target_channel_tree, nullptr};
|
||||
|
||||
std::shared_ptr<TreeView::LinkedTreeEntry> linked_channel;
|
||||
std::shared_ptr<ServerChannel> channel;
|
||||
@ -1019,31 +1059,31 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
{
|
||||
std::shared_ptr<BasicChannel> parent_channel{};
|
||||
if(parent_id > 0) {
|
||||
parent_channel = channel_tree->findChannel(parent_id);
|
||||
parent_channel = target_channel_tree->findChannel(parent_id);
|
||||
if(!parent_channel) {
|
||||
return command_result{error::channel_invalid_id};
|
||||
}
|
||||
}
|
||||
|
||||
if(channel_tree->findChannel(channel_name, parent_channel)) {
|
||||
if(target_channel_tree->findChannel(channel_name, parent_channel)) {
|
||||
return ts::command_result{error::channel_name_inuse};
|
||||
}
|
||||
}
|
||||
|
||||
channel = dynamic_pointer_cast<ServerChannel>(channel_tree->createChannel(parent_id, order_id, channel_name));
|
||||
channel = dynamic_pointer_cast<ServerChannel>(target_channel_tree->createChannel(parent_id, order_id, channel_name));
|
||||
if(!channel) {
|
||||
return command_result{error::vs_critical, "channel create failed"};
|
||||
}
|
||||
temporary_created_channel.channel = channel;
|
||||
|
||||
linked_channel = channel_tree->findLinkedChannel(channel->channelId());
|
||||
linked_channel = target_channel_tree->findLinkedChannel(channel->channelId());
|
||||
if(!linked_channel) {
|
||||
return command_result{error::vs_critical, "missing linked channel"};
|
||||
}
|
||||
|
||||
channel_id = channel->channelId();
|
||||
} else {
|
||||
linked_channel = channel_tree->findLinkedChannel(channel_id);
|
||||
linked_channel = target_channel_tree->findLinkedChannel(channel_id);
|
||||
channel = dynamic_pointer_cast<ServerChannel>(linked_channel->entry);
|
||||
}
|
||||
|
||||
@ -1173,7 +1213,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
|
||||
if(updating_name) {
|
||||
auto new_name = changed_values[property::CHANNEL_NAME];
|
||||
if(channel_tree->findChannel(new_name, channel->parent())) {
|
||||
if(target_channel_tree->findChannel(new_name, channel->parent())) {
|
||||
return ts::command_result{error::channel_name_inuse};
|
||||
}
|
||||
}
|
||||
@ -1375,12 +1415,12 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
ChannelId previous_channel_id{0};
|
||||
if(updating_sort_order) {
|
||||
previous_channel_id = converter<ChannelId>::from_string_view(changed_values[property::CHANNEL_ORDER]);
|
||||
auto previous_channel = channel_tree->findChannel(previous_channel_id);
|
||||
auto previous_channel = target_channel_tree->findChannel(previous_channel_id);
|
||||
if(!previous_channel && previous_channel_id != 0) {
|
||||
return command_result{error::channel_invalid_id};
|
||||
}
|
||||
|
||||
if(!channel_tree->move_channel(channel, channel->parent(), previous_channel)) {
|
||||
if(!target_channel_tree->move_channel(channel, channel->parent(), previous_channel)) {
|
||||
return ts::command_result{error::vs_critical, "failed to move channel"};
|
||||
}
|
||||
}
|
||||
@ -1395,7 +1435,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
auto current_channel = children_left.front();
|
||||
children_left.pop_front();
|
||||
|
||||
for (const auto &child : channel_tree->channels(current_channel, 1)) {
|
||||
for (const auto &child : target_channel_tree->channels(current_channel, 1)) {
|
||||
if (child == current_channel) {
|
||||
continue;
|
||||
}
|
||||
@ -1415,7 +1455,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
|
||||
std::shared_ptr<BasicChannel> old_default_channel{};
|
||||
if(updating_default) {
|
||||
old_default_channel = channel_tree->getDefaultChannel();
|
||||
old_default_channel = target_channel_tree->getDefaultChannel();
|
||||
if(old_default_channel) {
|
||||
old_default_channel->properties()[property::CHANNEL_FLAG_DEFAULT] = false;
|
||||
}
|
||||
@ -1472,8 +1512,8 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
if(updating_sort_order) {
|
||||
auto parent = channel->parent();
|
||||
|
||||
linked_parent_channel = parent ? channel_tree->findLinkedChannel(parent->channelId()) : nullptr;
|
||||
linked_previous_channel = channel_tree->findLinkedChannel(channel->previousChannelId());
|
||||
linked_parent_channel = parent ? target_channel_tree->findLinkedChannel(parent->channelId()) : nullptr;
|
||||
linked_previous_channel = target_channel_tree->findLinkedChannel(channel->previousChannelId());
|
||||
|
||||
assert(!parent || linked_parent_channel);
|
||||
assert(linked_previous_channel || channel->previousChannelId() == 0);
|
||||
@ -1505,7 +1545,7 @@ ts::command_result ConnectedClient::execute_channel_edit(ChannelId& channel_id,
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unique_lock client_tree_lock{client->channel_lock};
|
||||
std::unique_lock client_tree_lock{client->channel_tree_mutex};
|
||||
for(const auto& child_channel : child_channel_type_updates) {
|
||||
client->notifyChannelEdited(child_channel, child_channel_type_property_updates, self_ref, false);
|
||||
}
|
||||
@ -1681,11 +1721,12 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
|
||||
if (this->server) {
|
||||
auto self_rev = this->ref();
|
||||
this->server->forEachClient([&](const shared_ptr<ConnectedClient> &client) {
|
||||
unique_lock channel_lock(client->channel_lock);
|
||||
for (const auto &type_update : channel_type_updates)
|
||||
unique_lock channel_lock(client->channel_tree_mutex);
|
||||
for (const auto &type_update : channel_type_updates) {
|
||||
client->notifyChannelEdited(type_update, {property::CHANNEL_FLAG_PERMANENT, property::CHANNEL_FLAG_SEMI_PERMANENT}, self_rev, false);
|
||||
}
|
||||
|
||||
auto actions = client->channels->change_order(l_channel, l_parent, l_order);
|
||||
auto actions = client->channel_tree->change_order(l_channel, l_parent, l_order);
|
||||
std::deque<ChannelId> deletions;
|
||||
for (const auto &action : actions) {
|
||||
switch (action.first) {
|
||||
@ -1705,8 +1746,10 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!deletions.empty())
|
||||
|
||||
if (!deletions.empty()) {
|
||||
client->notifyChannelHide(deletions, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -2002,12 +2045,12 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd)
|
||||
if (elm->currentChannel == channel) {
|
||||
elm->task_update_channel_client_properties.enqueue();
|
||||
} else if (update_view) {
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex);
|
||||
|
||||
auto elm_channel = elm->currentChannel;
|
||||
if (elm_channel) {
|
||||
deque<ChannelId> deleted;
|
||||
for (const auto &update_entry : elm->channels->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
|
||||
for (const auto &update_entry : elm->channel_tree->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
|
||||
if (update_entry.first)
|
||||
elm->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
|
||||
else
|
||||
@ -2070,12 +2113,12 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
|
||||
if (elm->currentChannel == channel) {
|
||||
elm->task_update_channel_client_properties.enqueue();
|
||||
} else if (update_view) {
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex);
|
||||
|
||||
auto elm_channel = elm->currentChannel;
|
||||
if (elm_channel) {
|
||||
deque<ChannelId> deleted;
|
||||
for (const auto &update_entry : elm->channels->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
|
||||
for (const auto &update_entry : elm->channel_tree->update_channel_path(l_channel, this->server->channelTree->findLinkedChannel(elm->currentChannel->channelId()))) {
|
||||
if (update_entry.first)
|
||||
elm->notifyChannelShow(update_entry.second->channel(), update_entry.second->previous_channel);
|
||||
else
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <vector>
|
||||
#include <bitset>
|
||||
#include <algorithm>
|
||||
#include "../../build.h"
|
||||
#include "../ConnectedClient.h"
|
||||
#include "../InternalClient.h"
|
||||
#include "../voice/VoiceClient.h"
|
||||
@ -15,6 +14,7 @@
|
||||
#include "../../manager/ConversationManager.h"
|
||||
#include "../../manager/PermissionNameMapper.h"
|
||||
#include "../../manager/ActionLogger.h"
|
||||
#include "../../PermissionCalculator.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "helpers.h"
|
||||
@ -22,7 +22,6 @@
|
||||
|
||||
#include <Properties.h>
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/sassert.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/hex.h>
|
||||
#include <misc/rnd.h>
|
||||
@ -39,7 +38,7 @@ command_result ConnectedClient::handleCommandClientGetVariables(Command &cmd) {
|
||||
CMD_REQ_SERVER;
|
||||
ConnectedLockedClient client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
|
||||
{
|
||||
shared_lock tree_lock(this->channel_lock);
|
||||
shared_lock tree_lock(this->channel_tree_mutex);
|
||||
|
||||
if (!client || (client.client != this && !this->isClientVisible(client.client, false)))
|
||||
return command_result{error::client_invalid_id, ""};
|
||||
@ -131,7 +130,7 @@ command_result ConnectedClient::handleCommandClientGetIds(Command &cmd) {
|
||||
auto unique_id = cmd[index]["cluid"].as<string>();
|
||||
for(const auto& entry : client_list) {
|
||||
if(entry->getUid() == unique_id) {
|
||||
if(!config::server::show_invisible_clients_as_online && !this->channels->channel_visible(entry->currentChannel, nullptr))
|
||||
if(!config::server::show_invisible_clients_as_online && !this->channel_tree->channel_visible(entry->currentChannel, nullptr))
|
||||
continue;
|
||||
|
||||
notify[result_index]["name"] = entry->getDisplayName();
|
||||
@ -160,22 +159,20 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
|
||||
CMD_RESET_IDLE;
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(10);
|
||||
|
||||
shared_lock server_channel_r_lock(this->server->channel_tree_lock);
|
||||
std::unique_lock server_channel_lock{this->server->channel_tree_mutex};
|
||||
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel) {
|
||||
auto target_channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!target_channel) {
|
||||
return command_result{error::channel_invalid_id};
|
||||
}
|
||||
|
||||
auto permission_cache = make_shared<CalculateCache>();
|
||||
|
||||
auto& channel_whitelist = this->join_whitelisted_channel;
|
||||
auto whitelist_entry = std::find_if(channel_whitelist.begin(), channel_whitelist.end(), [&](const auto& entry) { return entry.first == channel->channelId(); });
|
||||
auto whitelist_entry = std::find_if(channel_whitelist.begin(), channel_whitelist.end(), [&](const auto& entry) { return entry.first == target_channel->channelId(); });
|
||||
if(whitelist_entry != channel_whitelist.end()) {
|
||||
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used earlier explicitly allowed it.", this->getLoggingPrefix(), channel->channelId());
|
||||
debugMessage(this->getServerId(), "{} Allowing client to join channel {} because the token he used earlier explicitly allowed it.", this->getLoggingPrefix(), target_channel->channelId());
|
||||
if(whitelist_entry->second != "ignore") {
|
||||
if (!channel->passwordMatch(cmd["cpw"], true)) {
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
|
||||
if (!target_channel->verify_password(cmd["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
|
||||
return command_result{error::channel_invalid_password};
|
||||
}
|
||||
}
|
||||
@ -185,13 +182,13 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
|
||||
cmd["cpw"] = "";
|
||||
}
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"], true)) {
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
|
||||
if (!target_channel->verify_password(cmd["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
|
||||
return command_result{error::channel_invalid_password};
|
||||
}
|
||||
}
|
||||
|
||||
auto permission_error = this->calculate_and_get_join_state(channel);
|
||||
auto permission_error = this->calculate_and_get_join_state(target_channel);
|
||||
if(permission_error != permission::unknown) {
|
||||
return command_result{permission_error};
|
||||
}
|
||||
@ -201,7 +198,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
|
||||
command_result_bulk result{};
|
||||
result.reserve(cmd.bulkCount());
|
||||
|
||||
std::vector<ConnectedLockedClient<ConnectedClient>> clients{};
|
||||
std::vector<ConnectedLockedClient<ConnectedClient>> target_clients{};
|
||||
|
||||
for(size_t index{0}; index < cmd.bulkCount(); index++) {
|
||||
auto target_client_id = cmd[index]["clid"].as<ClientId>();
|
||||
@ -217,7 +214,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(target_client->getChannel() == channel) {
|
||||
if(target_client->getChannel() == target_channel) {
|
||||
result.emplace_result(error::ok);
|
||||
continue;
|
||||
}
|
||||
@ -227,96 +224,90 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
|
||||
result.emplace_result(permission::i_client_move_power);
|
||||
continue;
|
||||
}
|
||||
if(!permission::v2::permission_granted(target_client->calculate_permission(permission::i_client_needed_move_power, channel->channelId()), this->calculate_permission(permission::i_client_move_power, channel->channelId()))) {
|
||||
if(!permission::v2::permission_granted(target_client->calculate_permission(permission::i_client_needed_move_power, target_channel->channelId()), this->calculate_permission(permission::i_client_move_power, target_channel->channelId()))) {
|
||||
result.emplace_result(permission::i_client_move_power);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
clients.emplace_back(std::move(target_client));
|
||||
target_clients.emplace_back(std::move(target_client));
|
||||
result.emplace_result(error::ok);
|
||||
}
|
||||
|
||||
ClientPermissionCalculator own_permission_calculator{this, target_channel};
|
||||
|
||||
/* FIXME: Some kind of invite key frags to prevent limit checking! */
|
||||
if (!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_unchecked<bool>() || !channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_unchecked<bool>()) {
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_maxclients, channel->channelId()))) {
|
||||
if(!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_unchecked<bool>()) {
|
||||
auto maxClients = channel->properties()[property::CHANNEL_MAXCLIENTS].as_unchecked<int32_t>();
|
||||
if (maxClients >= 0 && maxClients < this->server->getClientsByChannel(channel).size() + clients.size()) {
|
||||
return command_result{error::channel_maxclients_reached};
|
||||
}
|
||||
}
|
||||
if(!channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_unchecked<bool>()) {
|
||||
shared_ptr<BasicChannel> family_root;
|
||||
|
||||
if(channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_unchecked<bool>()) {
|
||||
family_root = channel;
|
||||
while(family_root &&
|
||||
family_root->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_unchecked<bool>()) {
|
||||
family_root = family_root->parent();
|
||||
}
|
||||
}
|
||||
if(family_root && !family_root->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED]) { //Could not be CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED
|
||||
auto maxClients = family_root->properties()[property::CHANNEL_MAXFAMILYCLIENTS].as_unchecked<int32_t>();
|
||||
auto client_count = 0;
|
||||
for(const auto& entry : this->server->getClientsByChannelRoot(channel, false)) {
|
||||
if(entry.get() != this) {
|
||||
client_count++; //Dont count the client itself
|
||||
}
|
||||
}
|
||||
|
||||
if (maxClients >= 0 && maxClients < client_count + clients.size()) {
|
||||
return command_result{error::channel_maxfamily_reached};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!target_channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as_or<bool>(true)) {
|
||||
auto max_clients = target_channel->properties()[property::CHANNEL_MAXCLIENTS].as_or<uint32_t>(0);
|
||||
auto channel_clients = this->server->getClientsByChannel(target_channel);
|
||||
if(channel_clients.size() >= max_clients && !own_permission_calculator.permission_granted(permission::b_channel_join_ignore_maxclients, 1)) {
|
||||
return command_result{error::channel_maxclients_reached};
|
||||
}
|
||||
}
|
||||
|
||||
server_channel_r_lock.unlock();
|
||||
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
|
||||
std::vector<std::shared_ptr<BasicChannel>> channels{};
|
||||
channels.reserve(clients.size());
|
||||
if(!target_channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as_or<bool>(true)) {
|
||||
auto base_channel{target_channel};
|
||||
while(base_channel && base_channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED].as_or<bool>(false)) {
|
||||
base_channel = base_channel->parent();
|
||||
}
|
||||
|
||||
for(auto& client : clients) {
|
||||
auto oldChannel = client->getChannel();
|
||||
if(!oldChannel) {
|
||||
if(base_channel) {
|
||||
auto max_clients = target_channel->properties()[property::CHANNEL_MAXFAMILYCLIENTS].as_or<uint32_t>(0);
|
||||
auto current_client_count = this->server->countChannelRootClients(target_channel, max_clients, false);
|
||||
if(current_client_count >= max_clients && !own_permission_calculator.permission_granted(permission::b_channel_join_ignore_maxclients, 1)) {
|
||||
return command_result{error::channel_maxfamily_reached};
|
||||
}
|
||||
} else {
|
||||
/* This is kinda odd, I guess we've moved the channel and haven't cleared the inherited flag */
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ServerChannel>> channels{};
|
||||
channels.reserve(target_clients.size());
|
||||
|
||||
for(auto& client : target_clients) {
|
||||
auto client_old_channel = dynamic_pointer_cast<ServerChannel>(client->getChannel());
|
||||
if(!client_old_channel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->server->client_move(
|
||||
client.client,
|
||||
channel,
|
||||
target_channel,
|
||||
client.client == this ? nullptr : this->ref(),
|
||||
"",
|
||||
client.client == this ? ViewReasonId::VREASON_USER_ACTION : ViewReasonId::VREASON_MOVED,
|
||||
true,
|
||||
server_channel_w_lock
|
||||
server_channel_lock
|
||||
);
|
||||
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_move(this->getServerId(), this->ref(), client->ref(), channel->channelId(), channel->name(), oldChannel->channelId(), oldChannel->name());
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_move(this->getServerId(), this->ref(), client->ref(), target_channel->channelId(), target_channel->name(), client_old_channel->channelId(), client_old_channel->name());
|
||||
|
||||
if(std::find_if(channels.begin(), channels.end(), [&](const std::shared_ptr<BasicChannel>& channel) { return &*channel == &*oldChannel; }) == channels.end()) {
|
||||
channels.push_back(oldChannel);
|
||||
if(std::find_if(channels.begin(), channels.end(), [&](const std::shared_ptr<ServerChannel>& channel) { return &*channel == &*client_old_channel; }) == channels.end()) {
|
||||
channels.push_back(client_old_channel);
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto& oldChannel : channels) {
|
||||
if(!server_channel_w_lock.owns_lock()) {
|
||||
server_channel_w_lock.lock();
|
||||
if(!server_channel_lock.owns_lock()) {
|
||||
server_channel_lock.lock();
|
||||
}
|
||||
|
||||
if(oldChannel->channelType() == ChannelType::temporary &&
|
||||
oldChannel->properties()[property::CHANNEL_DELETE_DELAY].as_unchecked<int64_t>() == 0) {
|
||||
if(this->server->getClientsByChannelRoot(oldChannel, false).empty()) {
|
||||
this->server->delete_channel(dynamic_pointer_cast<ServerChannel>(oldChannel), this->ref(), "temporary auto delete", server_channel_w_lock, true);
|
||||
}
|
||||
if(oldChannel->channelType() != ChannelType::temporary) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(server_channel_w_lock.owns_lock()) {
|
||||
server_channel_w_lock.unlock();
|
||||
if(oldChannel->properties()[property::CHANNEL_DELETE_DELAY].as_unchecked<int64_t>() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!this->server->isChannelRootEmpty(oldChannel, false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->server->delete_channel(oldChannel, this->ref(), "temporary auto delete", server_channel_lock, true);
|
||||
}
|
||||
return command_result{std::forward<command_result_bulk>(result)};
|
||||
|
||||
return command_result{std::move(result)};
|
||||
}
|
||||
|
||||
command_result ConnectedClient::handleCommandClientPoke(Command &cmd) {
|
||||
@ -388,7 +379,7 @@ command_result ConnectedClient::handleCommandClientChatClosed(Command &cmd) {
|
||||
ConnectedLockedClient<ConnectedClient> client{this->server->find_client_by_id(cmd["clid"].as<ClientId>())};
|
||||
if (!client) return command_result{error::client_invalid_id};
|
||||
{
|
||||
unique_lock channel_lock(this->channel_lock);
|
||||
unique_lock channel_lock(this->channel_tree_mutex);
|
||||
this->open_private_conversations.erase(remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [&](const weak_ptr<ConnectedClient>& weak) {
|
||||
return weak.lock() == client;
|
||||
}), this->open_private_conversations.end());
|
||||
@ -760,7 +751,7 @@ command_result ConnectedClient::handleCommandClientMute(Command &cmd) {
|
||||
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
|
||||
|
||||
{
|
||||
unique_lock channel_lock(this->channel_lock);
|
||||
unique_lock channel_lock(this->channel_tree_mutex);
|
||||
for(const auto& weak : this->mutedClients)
|
||||
if(weak.lock() == client) return command_result{error::ok};
|
||||
this->mutedClients.push_back(client.client);
|
||||
@ -780,7 +771,7 @@ command_result ConnectedClient::handleCommandClientUnmute(Command &cmd) {
|
||||
if (!client || client->getClientId() == this->getClientId()) return command_result{error::client_invalid_id};
|
||||
|
||||
{
|
||||
unique_lock channel_lock(this->channel_lock);
|
||||
unique_lock channel_lock(this->channel_tree_mutex);
|
||||
this->mutedClients.erase(std::remove_if(this->mutedClients.begin(), this->mutedClients.end(), [&](const weak_ptr<ConnectedClient>& weak) {
|
||||
auto c = weak.lock();
|
||||
return !c || c == client;
|
||||
|
@ -61,8 +61,10 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
if(!channel->permission_granted(permission::i_ft_needed_file_browse_power, this->calculate_permission(permission::i_ft_file_browse_power, channel->channelId()), true))
|
||||
return command_result{permission::i_ft_file_browse_power};
|
||||
@ -184,13 +186,15 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
|
||||
if(!virtual_file_server) return command_result{error::file_virtual_server_not_registered};
|
||||
auto& file_system = file::server()->file_system();
|
||||
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
if(!channel->permission_granted(permission::i_ft_needed_directory_create_power, this->calculate_permission(permission::i_ft_directory_create_power, channel->channelId()), true))
|
||||
return command_result{permission::i_ft_directory_create_power};
|
||||
@ -242,13 +246,15 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
|
||||
auto file_path = cmd["path"].string();
|
||||
std::shared_ptr<file::ExecuteResponse<file::filesystem::FileDeleteError, file::filesystem::FileDeleteResponse>> delete_response{};
|
||||
if (cmd[0].has("cid") && cmd["cid"] != 0) {
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
if(!channel->permission_granted(permission::i_ft_needed_file_delete_power, this->calculate_permission(permission::i_ft_file_delete_power, channel->channelId()), true))
|
||||
return command_result{permission::i_ft_file_delete_power};
|
||||
@ -447,7 +453,7 @@ command_result ConnectedClient::handleCommandFTGetFileInfo(ts::Command &cmd) {
|
||||
currentChannel = this->server->channelTree->findChannel(cmd[index]["cid"].as<ChannelId>());
|
||||
if(currentChannel) {
|
||||
const auto password = cmd[index]["cpw"].string();
|
||||
if (!currentChannel->passwordMatch(password) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, currentChannel->channelId()))) {
|
||||
if (!currentChannel->verify_password(std::make_optional(password), this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, currentChannel->channelId()))) {
|
||||
if(password.empty())
|
||||
error_error = error::channel_invalid_password;
|
||||
else
|
||||
@ -667,13 +673,15 @@ command_result ConnectedClient::handleCommandFTInitUpload(ts::Command &cmd) {
|
||||
|
||||
ChannelId log_channel_id{0};
|
||||
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id, "Cant resolve channel"};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_upload_power, permission::i_ft_file_upload_power, true);
|
||||
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_UPLOAD, virtual_file_server, channel->channelId(), info);
|
||||
@ -810,13 +818,15 @@ command_result ConnectedClient::handleCommandFTInitDownload(ts::Command &cmd) {
|
||||
|
||||
ChannelId log_channel_id{0};
|
||||
if(cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
|
||||
auto channel = this->server->channelTree->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_download_power, permission::i_ft_file_download_power, true);
|
||||
transfer_response = file::server()->file_transfer().initialize_channel_transfer(file::transfer::Transfer::DIRECTION_DOWNLOAD, virtual_file_server, channel->channelId(), info);
|
||||
@ -912,13 +922,15 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
|
||||
auto channel_id = cmd["cid"].as<ChannelId>();
|
||||
auto target_channel_id = cmd[0].has("tcid") ? cmd["tcid"].as<ChannelId>() : channel_id;
|
||||
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_lock};
|
||||
std::shared_lock channel_tree_lock{this->server->channel_tree_mutex};
|
||||
auto channel = this->server->channelTree->findChannel(channel_id);
|
||||
if (!channel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["cpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_rename_power, permission::i_ft_file_rename_power, true);
|
||||
|
||||
@ -927,8 +939,10 @@ command_result ConnectedClient::handleCommandFTRenameFile(ts::Command &cmd) {
|
||||
if (!targetChannel)
|
||||
return command_result{error::channel_invalid_id};
|
||||
|
||||
if (!channel->passwordMatch(cmd["tcpw"]) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId())))
|
||||
return cmd["tcpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
|
||||
auto channel_password = cmd["cpw"].optional_string();
|
||||
if (!channel->verify_password(channel_password, this->getType() != ClientType::CLIENT_QUERY) && !permission::v2::permission_granted(1, this->calculate_permission(permission::b_ft_ignore_password, channel->channelId()))) {
|
||||
return channel_password.has_value() ? command_result{error::channel_invalid_password} : command_result{permission::b_ft_ignore_password};
|
||||
}
|
||||
|
||||
ACTION_REQUIRES_CHANNEL_PERMISSION(targetChannel, permission::i_ft_needed_file_rename_power, permission::i_ft_file_rename_power, true);
|
||||
}
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
#include <bitset>
|
||||
#include <algorithm>
|
||||
#include <openssl/sha.h>
|
||||
#include "../../build.h"
|
||||
#include "../ConnectedClient.h"
|
||||
#include "../InternalClient.h"
|
||||
#include "../../server/VoiceServer.h"
|
||||
@ -23,11 +21,8 @@
|
||||
#include "helpers.h"
|
||||
#include "./bulk_parsers.h"
|
||||
|
||||
#include <log/LogUtils.h>
|
||||
#include <misc/base64.h>
|
||||
#include <misc/digest.h>
|
||||
#include <misc/rnd.h>
|
||||
#include <misc/scope_guard.h>
|
||||
#include <bbcode/bbcodes.h>
|
||||
|
||||
using namespace std::chrono;
|
||||
|
@ -44,14 +44,14 @@ do { \
|
||||
/* Helper methods for channel resolve */
|
||||
#define RESOLVE_CHANNEL_R(command, force) \
|
||||
auto channel_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();\
|
||||
shared_lock channel_tree_read_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());\
|
||||
shared_lock channel_tree_read_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());\
|
||||
auto channel_id = command.as<ChannelId>(); \
|
||||
auto l_channel = channel_id ? channel_tree->findLinkedChannel(command.as<ChannelId>()) : nullptr; \
|
||||
if (!l_channel && (channel_id != 0 || force)) return command_result{error::channel_invalid_id, "Cant resolve channel"}; \
|
||||
|
||||
#define RESOLVE_CHANNEL_W(command, force) \
|
||||
auto channel_tree = this->server ? this->server->channelTree : serverInstance->getChannelTree().get();\
|
||||
unique_lock channel_tree_write_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());\
|
||||
unique_lock channel_tree_write_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());\
|
||||
auto channel_id = command.as<ChannelId>(); \
|
||||
auto l_channel = channel_id ? channel_tree->findLinkedChannel(command.as<ChannelId>()) : nullptr; \
|
||||
if (!l_channel && (channel_id != 0 || force)) return command_result{error::channel_invalid_id, "Cant resolve channel"}; \
|
||||
|
@ -462,7 +462,7 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_lock}; /* ensure we dont get moved or somebody could move us */
|
||||
std::shared_lock server_channel_lock{this->server->channel_tree_mutex}; /* ensure we dont get moved or somebody could move us */
|
||||
auto channel_id = cmd["cid"].as<ChannelId>();
|
||||
auto channel = this->server->channelTree->findChannel(channel_id);
|
||||
if (!channel) {
|
||||
@ -579,7 +579,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
|
||||
bool chat_open{false};
|
||||
{
|
||||
|
||||
std::unique_lock self_channel_lock{this->channel_lock};
|
||||
std::unique_lock self_channel_lock{this->channel_tree_mutex};
|
||||
this->open_private_conversations.erase(std::remove_if(this->open_private_conversations.begin(), this->open_private_conversations.end(), [](const weak_ptr<ConnectedClient>& weak) {
|
||||
return !weak.lock();
|
||||
}), this->open_private_conversations.end());
|
||||
@ -597,7 +597,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
|
||||
ACTION_REQUIRES_PERMISSION(permission::b_client_even_textmessage_send, 1, this->getChannelId());
|
||||
}
|
||||
|
||||
if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()), false)) {
|
||||
if(!permission::v2::permission_granted(target->calculate_permission(permission::i_client_needed_private_textmessage_power, target->getClientId()), this->calculate_permission(permission::i_client_private_textmessage_power, this->getClientId()))) {
|
||||
return command_result{permission::i_client_private_textmessage_power};
|
||||
}
|
||||
|
||||
@ -608,7 +608,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock self_channel_lock{this->channel_lock};
|
||||
std::unique_lock self_channel_lock{this->channel_tree_mutex};
|
||||
this->open_private_conversations.push_back(target.client);
|
||||
}
|
||||
}
|
||||
@ -636,7 +636,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
|
||||
channel_id = this->currentChannel->channelId();
|
||||
}
|
||||
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_channel_textmessage_send, channel_id), false)) \
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_channel_textmessage_send, channel_id))) \
|
||||
return command_result{permission::b_client_channel_textmessage_send};
|
||||
|
||||
if(channel == this->currentChannel) {
|
||||
@ -917,9 +917,9 @@ command_result ConnectedClient::handleCommandBanClient(Command &cmd) {
|
||||
ban_ids.push_back(_id);
|
||||
}
|
||||
|
||||
auto b_ban_name = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_name, 0), false);
|
||||
auto b_ban_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_ip, 0), false);
|
||||
auto b_ban_hwid = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_hwid, 0), false);
|
||||
auto b_ban_name = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_name, 0));
|
||||
auto b_ban_ip = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_ip, 0));
|
||||
auto b_ban_hwid = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_ban_hwid, 0));
|
||||
|
||||
auto max_ban_time = this->calculate_permission(permission::i_client_ban_max_bantime, 0);
|
||||
if(!max_ban_time.has_value) return command_result{permission::i_client_ban_max_bantime};
|
||||
@ -1351,7 +1351,7 @@ void check_token_action_permissions(const std::shared_ptr<ConnectedClient>& clie
|
||||
|
||||
if(permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, target_channel->channelId()))) {
|
||||
action.text = "ignore";
|
||||
} else if(!target_channel->passwordMatch(action.text, true)) {
|
||||
} else if(!target_channel->verify_password(action.text, true)) {
|
||||
action.type = ActionType::ActionIgnore;
|
||||
result.set_result(index, ts::command_result{error::channel_invalid_password});
|
||||
break;
|
||||
@ -1374,8 +1374,11 @@ command_result ConnectedClient::handleCommandTokenAdd(Command &cmd) {
|
||||
CMD_CHK_AND_INC_FLOOD_POINTS(5);
|
||||
|
||||
auto client_tokens = this->server->tokenManager->client_token_count(this->getClientDatabaseId());
|
||||
if(!permission::v2::permission_granted(client_tokens + 1, this->calculate_permission(permission::i_virtualserver_token_limit, 0), true)) {
|
||||
return ts::command_result{permission::i_virtualserver_token_limit};
|
||||
auto token_limit = this->calculate_permission(permission::i_virtualserver_token_limit, 0);
|
||||
if(token_limit.has_value) {
|
||||
if(!permission::v2::permission_granted(client_tokens + 1, token_limit)) {
|
||||
return ts::command_result{permission::i_virtualserver_token_limit};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<token::TokenAction> actions{};
|
||||
@ -1766,8 +1769,7 @@ command_result ConnectedClient::handleCommandVerifyChannelPassword(Command &cmd)
|
||||
std::shared_ptr<BasicChannel> channel = (this->server ? this->server->channelTree : serverInstance->getChannelTree().get())->findChannel(cmd["cid"].as<ChannelId>());
|
||||
if (!channel) return command_result{error::channel_invalid_id, "Cant resolve channel"};
|
||||
|
||||
std::string password = cmd["password"];
|
||||
if (!channel->passwordMatch(password, false)) return command_result{error::server_invalid_password};
|
||||
if (!channel->verify_password(cmd["password"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) return command_result{error::server_invalid_password};
|
||||
return command_result{error::ok};
|
||||
}
|
||||
|
||||
@ -3071,7 +3073,7 @@ command_result ConnectedClient::handleCommandConversationHistory(ts::Command &co
|
||||
if(conversation_id > 0) {
|
||||
/* test if we're able to see the channel */
|
||||
{
|
||||
shared_lock channel_view_lock(this->channel_lock);
|
||||
shared_lock channel_view_lock(this->channel_tree_mutex);
|
||||
auto channel = this->channel_view()->find_channel(conversation_id);
|
||||
if(!channel)
|
||||
return command_result{error::conversation_invalid_id};
|
||||
@ -3091,16 +3093,14 @@ command_result ConnectedClient::handleCommandConversationHistory(ts::Command &co
|
||||
|
||||
/* test if there is a channel password or join power which denies that we see the conversation */
|
||||
{
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_lock);
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
|
||||
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
|
||||
if(!channel) /* should never happen! */
|
||||
return command_result{error::conversation_invalid_id};
|
||||
|
||||
if(!command[0].has("cpw"))
|
||||
command[0]["cpw"] = "";
|
||||
|
||||
if (!channel->passwordMatch(command["cpw"], true))
|
||||
if (!channel->verify_password(command["cpw"].optional_string(), this->getType() != ClientType::CLIENT_QUERY)) {
|
||||
ACTION_REQUIRES_PERMISSION(permission::b_channel_join_ignore_password, 1, channel->channelId());
|
||||
}
|
||||
|
||||
auto error = this->calculate_and_get_join_state(channel);
|
||||
if(error) return command_result{error};
|
||||
@ -3197,7 +3197,7 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
|
||||
if(conversation_id > 0) {
|
||||
/* test if we're able to see the channel */
|
||||
{
|
||||
shared_lock channel_view_lock(this->channel_lock);
|
||||
shared_lock channel_view_lock(this->channel_tree_mutex);
|
||||
auto channel = this->channel_view()->find_channel(conversation_id);
|
||||
if(!channel) {
|
||||
auto error = findError("conversation_invalid_id");
|
||||
@ -3229,7 +3229,7 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
|
||||
|
||||
/* test if there is a channel password or join power which denies that we see the conversation */
|
||||
{
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_lock);
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
|
||||
auto channel = ref_server->getChannelTree()->findChannel(conversation_id);
|
||||
if(!channel) { /* should never happen! */
|
||||
auto error = findError("conversation_invalid_id");
|
||||
@ -3238,16 +3238,14 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!bulk.has("cpw"))
|
||||
bulk["cpw"] = "";
|
||||
|
||||
if (!channel->passwordMatch(bulk["cpw"], true))
|
||||
if (!channel->verify_password( bulk.has("cpw") ? std::make_optional(bulk["cpw"].string()) : std::nullopt, this->getType() != ClientType::CLIENT_QUERY)) {
|
||||
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_join_ignore_password, 1, channel->channelId()))) {
|
||||
auto error = findError("channel_invalid_password");
|
||||
result_bulk["error_id"] = error.errorId;
|
||||
result_bulk["error_msg"] = error.message;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(auto error_perm = this->calculate_and_get_join_state(channel); error_perm) {
|
||||
auto error = findError("server_insufficeient_permissions");
|
||||
@ -3296,7 +3294,7 @@ command_result ConnectedClient::handleCommandConversationMessageDelete(ts::Comma
|
||||
|
||||
/* test if we're able to see the channel */
|
||||
{
|
||||
shared_lock channel_view_lock(this->channel_lock);
|
||||
shared_lock channel_view_lock(this->channel_tree_mutex);
|
||||
auto channel = this->channel_view()->find_channel(current_conversation_id);
|
||||
if(!channel)
|
||||
return command_result{error::conversation_invalid_id};
|
||||
@ -3304,16 +3302,14 @@ command_result ConnectedClient::handleCommandConversationMessageDelete(ts::Comma
|
||||
|
||||
/* test if there is a channel password or join power which denies that we see the conversation */
|
||||
{
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_lock);
|
||||
shared_lock channel_view_lock(ref_server->channel_tree_mutex);
|
||||
auto channel = ref_server->getChannelTree()->findChannel(current_conversation_id);
|
||||
if(!channel)
|
||||
return command_result{error::conversation_invalid_id};
|
||||
|
||||
if(!bulk.has("cpw"))
|
||||
bulk["cpw"] = "";
|
||||
|
||||
if (!channel->passwordMatch(bulk["cpw"], true))
|
||||
if (!channel->verify_password( bulk.has("cpw") ? std::make_optional(bulk["cpw"].string()) : std::nullopt, this->getType() != ClientType::CLIENT_QUERY)) {
|
||||
ACTION_REQUIRES_PERMISSION(permission::b_channel_join_ignore_password, 1, channel->channelId());
|
||||
}
|
||||
|
||||
if (!permission::v2::permission_granted(1, this->calculate_permission(permission::b_channel_conversation_message_delete, channel->channelId())))
|
||||
return command_result{permission::b_channel_conversation_message_delete};
|
||||
|
@ -112,7 +112,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
|
||||
return command_result{permission::b_client_music_create_temporary};
|
||||
}
|
||||
|
||||
shared_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
shared_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
auto channel = cmd[0].has("cid") ? this->server->channelTree->findChannel(cmd["cid"]) : this->currentChannel;
|
||||
if(!channel) {
|
||||
if(cmd[0].has("cid")) return command_result{error::channel_invalid_id};
|
||||
@ -135,7 +135,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
|
||||
|
||||
{
|
||||
server_channel_lock.unlock();
|
||||
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_w_lock(this->server->channel_tree_mutex);
|
||||
this->server->client_move(
|
||||
bot,
|
||||
channel,
|
||||
|
@ -137,7 +137,7 @@ void MusicClient::initialize_bot() {
|
||||
this->server->registerClient(this->ref());
|
||||
}
|
||||
{
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
this->server->client_move(this->ref(), channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, true, server_channel_lock);
|
||||
}
|
||||
this->playback.volume_modifier = this->properties()[property::CLIENT_PLAYER_VOLUME];
|
||||
|
@ -618,7 +618,7 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) {
|
||||
auto old_server = std::exchange(this->server, nullptr);
|
||||
if(old_server) {
|
||||
{
|
||||
std::unique_lock tree_lock(old_server->channel_tree_lock);
|
||||
std::unique_lock tree_lock(old_server->channel_tree_mutex);
|
||||
if(this->currentChannel) {
|
||||
old_server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
|
||||
}
|
||||
@ -627,8 +627,8 @@ void QueryClient::disconnect_from_virtual_server(const std::string& reason) {
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard channel_lock{this->channel_lock};
|
||||
this->channels->reset();
|
||||
std::lock_guard channel_lock{this->channel_tree_mutex};
|
||||
this->channel_tree->reset();
|
||||
this->currentChannel = nullptr;
|
||||
}
|
||||
|
||||
|
@ -243,7 +243,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
||||
auto joined_channel = this->currentChannel;
|
||||
if(this->server) {
|
||||
{
|
||||
unique_lock tree_lock(this->server->channel_tree_lock);
|
||||
unique_lock tree_lock(this->server->channel_tree_mutex);
|
||||
if(joined_channel) {
|
||||
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
|
||||
}
|
||||
@ -272,18 +272,18 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
|
||||
target_server->registerClient(this->ref());
|
||||
|
||||
{
|
||||
shared_lock server_tree_lock(target_server->channel_tree_lock);
|
||||
shared_lock server_tree_lock(target_server->channel_tree_mutex);
|
||||
if(joined_channel) /* needs only notify if we were already on that server within a channel */
|
||||
target_server->notifyClientPropertyUpdates(this->ref(), deque<property::ClientProperties>{property::CLIENT_NICKNAME, property::CLIENT_UNIQUE_IDENTIFIER});
|
||||
|
||||
unique_lock client_tree_lock(this->channel_lock);
|
||||
this->channels->reset();
|
||||
this->channels->insert_channels(target_server->channelTree->tree_head(), true, false);
|
||||
unique_lock client_tree_lock(this->channel_tree_mutex);
|
||||
this->channel_tree->reset();
|
||||
this->channel_tree->insert_channels(target_server->channelTree->tree_head(), true, false);
|
||||
this->subscribeChannel(this->server->channelTree->channels(), false, false);
|
||||
}
|
||||
|
||||
if(joined_channel) {
|
||||
unique_lock tree_lock(this->server->channel_tree_lock);
|
||||
unique_lock tree_lock(this->server->channel_tree_mutex);
|
||||
if(joined_channel)
|
||||
this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
|
||||
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
|
||||
@ -311,7 +311,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
|
||||
auto joined = this->currentChannel;
|
||||
if(this->server){
|
||||
{
|
||||
unique_lock tree_lock(this->server->channel_tree_lock);
|
||||
unique_lock tree_lock(this->server->channel_tree_mutex);
|
||||
if(joined)
|
||||
this->server->client_move(this->ref(), nullptr, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
|
||||
this->server->unregisterClient(this->ref(), "logout", tree_lock);
|
||||
@ -326,16 +326,16 @@ command_result QueryClient::handleCommandLogout(Command &) {
|
||||
this->server->registerClient(this->ref());
|
||||
|
||||
{
|
||||
shared_lock server_channel_r_lock(this->server->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
shared_lock server_channel_r_lock(this->server->channel_tree_mutex);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex);
|
||||
|
||||
this->channels->reset();
|
||||
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
this->channel_tree->reset();
|
||||
this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
this->subscribeChannel(this->server->channelTree->channels(), false, false);
|
||||
}
|
||||
|
||||
if(joined) {
|
||||
unique_lock server_channel_w_lock(this->server->channel_tree_lock, defer_lock);
|
||||
unique_lock server_channel_w_lock(this->server->channel_tree_mutex, defer_lock);
|
||||
this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
|
||||
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
|
||||
this->server->assignDefaultChannel(this->ref(), true);
|
||||
@ -399,11 +399,11 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
|
||||
this->server->registerClient(this->ref());
|
||||
|
||||
{
|
||||
shared_lock server_channel_lock(target->channel_tree_lock);
|
||||
unique_lock client_channel_lock(this->channel_lock);
|
||||
shared_lock server_channel_lock(target->channel_tree_mutex);
|
||||
unique_lock client_channel_lock(this->channel_tree_mutex);
|
||||
|
||||
this->subscribeToAll = true;
|
||||
this->channels->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
this->channel_tree->insert_channels(this->server->channelTree->tree_head(), true, false);
|
||||
this->subscribeChannel(this->server->channelTree->channels(), false, false);
|
||||
}
|
||||
|
||||
@ -441,7 +441,7 @@ command_result QueryClient::handleCommandLeft(Command&) {
|
||||
CMD_RESET_IDLE;
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_select_godmode, 1);
|
||||
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
this->server->client_move(this->ref(), nullptr, nullptr, "leaving", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
|
||||
return command_result{error::ok};
|
||||
}
|
||||
@ -536,8 +536,8 @@ command_result QueryClient::handleCommandChannelList(Command& cmd) {
|
||||
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channel_list, 1);
|
||||
|
||||
int index = 0;
|
||||
shared_lock channel_lock(this->server ? this->server->channel_tree_lock : serverInstance->getChannelTreeLock());
|
||||
auto entries = this->server ? this->channels->channels() : serverInstance->getChannelTree()->channels();
|
||||
shared_lock channel_lock(this->server ? this->server->channel_tree_mutex : serverInstance->getChannelTreeLock());
|
||||
auto entries = this->server ? this->channel_tree->channels() : serverInstance->getChannelTree()->channels();
|
||||
channel_lock.unlock();
|
||||
|
||||
command_builder result{"", 1024, entries.size()};
|
||||
|
@ -131,7 +131,7 @@ bool QueryClient::notifyChannelDeleted(const std::deque<ChannelId> &deque, const
|
||||
|
||||
bool QueryClient::notifyClientEnterView(const std::deque<std::shared_ptr<ConnectedClient>> &deque, const ViewReasonSystemT &t) {
|
||||
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_JOIN)) {
|
||||
assert(mutex_locked(this->channel_lock));
|
||||
assert(mutex_locked(this->channel_tree_mutex));
|
||||
this->visibleClients.insert(this->visibleClients.end(), deque.begin(), deque.end());
|
||||
return true;
|
||||
} else
|
||||
@ -155,7 +155,7 @@ bool QueryClient::notifyClientMoved(const std::shared_ptr<ConnectedClient> &clie
|
||||
bool QueryClient::notifyClientLeftView(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, ViewReasonId reasonId, const std::string &reasonMessage, std::shared_ptr<ConnectedClient> invoker,
|
||||
bool lock_channel_tree) {
|
||||
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
|
||||
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
|
||||
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
tree_lock.lock();
|
||||
}
|
||||
@ -175,7 +175,7 @@ bool QueryClient::notifyClientLeftView(const std::shared_ptr<ConnectedClient> &c
|
||||
|
||||
bool QueryClient::notifyClientLeftView(const std::deque<std::shared_ptr<ConnectedClient>> &clients, const std::string &string, bool lock_channel_tree, const ViewReasonServerLeftT &t) {
|
||||
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
|
||||
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
|
||||
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
tree_lock.lock();
|
||||
}
|
||||
@ -195,7 +195,7 @@ bool QueryClient::notifyClientLeftView(const std::deque<std::shared_ptr<Connecte
|
||||
|
||||
bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClient> &client, const std::shared_ptr<BasicChannel> &target_channel, const std::string &message, std::shared_ptr<ConnectedClient> invoker, bool lock_channel_tree) {
|
||||
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
|
||||
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
|
||||
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
tree_lock.lock();
|
||||
}
|
||||
@ -215,7 +215,7 @@ bool QueryClient::notifyClientLeftViewKicked(const std::shared_ptr<ConnectedClie
|
||||
|
||||
bool QueryClient::notifyClientLeftViewBanned(const std::shared_ptr<ConnectedClient> &client, const std::string &message, std::shared_ptr<ConnectedClient> invoker, size_t length, bool lock_channel_tree) {
|
||||
if(!this->eventActive(QueryEventGroup::QEVENTGROUP_CLIENT_VIEW, QueryEventSpecifier::QEVENTSPECIFIER_CLIENT_VIEW_LEAVE)) {
|
||||
std::unique_lock tree_lock{this->channel_lock, std::defer_lock};
|
||||
std::unique_lock tree_lock{this->channel_tree_mutex, std::defer_lock};
|
||||
if(lock_channel_tree) {
|
||||
tree_lock.lock();
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ bool VoiceClient::disconnect(ts::ViewReasonId reason_id, const std::string &reas
|
||||
}
|
||||
|
||||
if(notify_viewer && this->server) {
|
||||
unique_lock channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock channel_lock(this->server->channel_tree_mutex);
|
||||
this->server->client_move(this->ref(), nullptr, invoker, reason, reason_id, false, channel_lock);
|
||||
} else {
|
||||
threads::MutexLock lock(this->command_lock);
|
||||
|
@ -110,12 +110,12 @@ command_result VoiceClient::handleCommandClientInit(Command &cmd) {
|
||||
command_result VoiceClient::handleCommandClientDisconnect(Command& cmd) {
|
||||
auto reason = cmd["reasonmsg"].size() > 0 ? cmd["reasonmsg"].as<string>() : "";
|
||||
{
|
||||
std::shared_lock own_lock{this->channel_lock};
|
||||
std::shared_lock own_lock{this->channel_tree_mutex};
|
||||
this->notifyClientLeftView(this->ref(), nullptr, VREASON_SERVER_LEFT, reason, nullptr, false); //Before we're moving us out of the channel tree!
|
||||
}
|
||||
|
||||
if(this->state == CONNECTED) {
|
||||
std::unique_lock channel_lock{this->server->channel_tree_lock};
|
||||
std::unique_lock channel_lock{this->server->channel_tree_mutex};
|
||||
this->server->client_move(this->ref(), nullptr, nullptr, reason, VREASON_SERVER_LEFT, true, channel_lock);
|
||||
}
|
||||
logMessage(this->getServerId(), "{} Got remote disconnect with the reason '{}'", CLIENT_STR_LOG_PREFIX, reason);
|
||||
|
@ -224,7 +224,7 @@ bool WebClient::close_connection(const std::chrono::system_clock::time_point& ti
|
||||
|
||||
if(this->server){
|
||||
{
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
this->server->unregisterClient(this->ref(), "disconnected", server_channel_lock);
|
||||
}
|
||||
//this->server = nullptr;
|
||||
@ -539,9 +539,9 @@ bool WebClient::disconnect(const std::string &reason) {
|
||||
serverInstance->action_logger()->client_channel_logger.log_client_leave(this->getServerId(), this->ref(), old_channel->channelId(), old_channel->name());
|
||||
}
|
||||
{
|
||||
unique_lock server_channel_lock(this->server->channel_tree_lock);
|
||||
unique_lock server_channel_lock(this->server->channel_tree_mutex);
|
||||
{
|
||||
unique_lock own_lock(this->channel_lock);
|
||||
unique_lock own_lock(this->channel_tree_mutex);
|
||||
this->notifyClientLeftViewKicked(this->ref(), nullptr, reason, this->server->serverRoot, false);
|
||||
}
|
||||
this->server->client_move(this->ref(), nullptr, this->server->serverRoot, reason, ViewReasonId::VREASON_SERVER_KICK, false, server_channel_lock);
|
||||
|
@ -142,7 +142,7 @@ void MusicBotManager::deleteBot(std::shared_ptr<server::MusicClient> musicBot) {
|
||||
|
||||
MusicBotManager::adjustTickPool();
|
||||
{
|
||||
unique_lock server_channel_lock(handle->channel_tree_lock);
|
||||
unique_lock server_channel_lock(handle->channel_tree_mutex);
|
||||
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);
|
||||
}
|
||||
@ -274,7 +274,7 @@ void MusicBotManager::disconnectBots() {
|
||||
|
||||
for(const auto& bot : this->music_bots) {
|
||||
if(bot->currentChannel) {
|
||||
unique_lock server_channel_lock(handle->channel_tree_lock);
|
||||
unique_lock server_channel_lock(handle->channel_tree_mutex);
|
||||
handle->client_move(bot, nullptr, nullptr, "Music bot deleted", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
|
||||
}
|
||||
bot->server = nullptr;
|
||||
|
@ -13,17 +13,31 @@ PlaylistPermissions::PlaylistPermissions(std::shared_ptr<permission::v2::Permiss
|
||||
|
||||
permission::v2::PermissionFlaggedValue PlaylistPermissions::calculate_client_specific_permissions(ts::permission::PermissionType permission, const std::shared_ptr<server::ConnectedClient>& client) {
|
||||
auto val = this->_permissions->channel_permission(permission, client->getClientDatabaseId());
|
||||
if(val.flags.value_set)
|
||||
if(val.flags.value_set) {
|
||||
return {val.values.value, true};
|
||||
}
|
||||
return client->calculate_permission(permission, 0);
|
||||
}
|
||||
|
||||
permission::PermissionType PlaylistPermissions::client_has_permissions(
|
||||
const std::shared_ptr<server::ConnectedClient> &client, ts::permission::PermissionType needed_permission, ts::permission::PermissionType granted_permission, uint8_t flags) {
|
||||
if(this->is_playlist_owner(client->getClientDatabaseId())) return permission::ok;
|
||||
const std::shared_ptr<server::ConnectedClient> &client,
|
||||
ts::permission::PermissionType needed_permission,
|
||||
ts::permission::PermissionType granted_permission,
|
||||
uint8_t flags
|
||||
) {
|
||||
if(this->is_playlist_owner(client->getClientDatabaseId())) {
|
||||
return permission::ok;
|
||||
}
|
||||
|
||||
return permission::v2::permission_granted(
|
||||
this->permission_manager()->permission_value_flagged(needed_permission),
|
||||
this->calculate_client_specific_permissions(granted_permission, client),
|
||||
(flags & do_no_require_granted) == 0) ? permission::ok : granted_permission;
|
||||
const auto client_permission = this->calculate_client_specific_permissions(granted_permission, client);
|
||||
auto playlist_permission = this->permission_manager()->permission_value_flagged(needed_permission);
|
||||
|
||||
if((flags & do_no_require_granted) == 0) {
|
||||
playlist_permission.clear_flag_on_zero();
|
||||
} else if(!playlist_permission.has_value) {
|
||||
playlist_permission.value = 0;
|
||||
playlist_permission.has_value = true;
|
||||
}
|
||||
|
||||
return permission::v2::permission_granted(playlist_permission, client_permission) ? permission::ok : granted_permission;
|
||||
}
|
2
shared
2
shared
@ -1 +1 @@
|
||||
Subproject commit 8dde5b1c23f0d84ca1b56a8c80389fb4e887b062
|
||||
Subproject commit 8fb93d1d9d938b78dcf34e7f7953e3d41504d00f
|
Loading…
Reference in New Issue
Block a user