Using new permissions system consequently

This commit is contained in:
WolverinDEV 2020-01-26 14:21:34 +01:00
parent bb2e7699dc
commit c7b6c0a3ba
37 changed files with 8982 additions and 657 deletions

View File

@ -3,7 +3,7 @@ project(TeaSpeak-Server)
set(CMAKE_VERBOSE_MAKEFILE ON)
#--allow-multiple-definition
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -Wall -Wno-reorder -Wno-sign-compare -static-libgcc -static-libstdc++ -g -Wl,--no-whole-archive -pthread ${MEMORY_DEBUG_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -Wall -Wno-reorder -Wno-sign-compare -static-libgcc -static-libstdc++ -g -Wl,--no-whole-archive -pthread ${MEMORY_DEBUG_FLAGS} -Werror=return-type")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3")
@ -55,7 +55,12 @@ set(SERVER_SOURCE_FILES
src/server/VoiceServer.cpp
src/server/POWHandler.cpp
src/client/voice/VoiceClientConnection.cpp
src/client/ConnectedClientCommandHandler.cpp
#src/client/ConnectedClientCommandHandler.cpp
src/client/command_handler/channel.cpp
src/client/command_handler/client.cpp
src/client/command_handler/server.cpp
src/client/command_handler/misc.cpp
src/client/ConnectedClientNotifyHandler.cpp
src/ServerManager.cpp
src/server/file/FileServer.cpp
@ -133,7 +138,7 @@ set(SERVER_SOURCE_FILES
src/manager/ConversationManager.cpp
src/client/SpeakingClientHandshake.cpp
)
src/client/command_handler/music.cpp src/client/command_handler/file.cpp)
if (COMPILE_WEB_CLIENT)
add_definitions(-DCOMPILE_WEB_CLIENT)
@ -146,7 +151,7 @@ if (COMPILE_WEB_CLIENT)
src/client/web/WSWebClient.cpp
src/client/web/SampleHandler.cpp
src/client/web/VoiceBridge.cpp
)
src/client/command_handler/helpers.h)
endif ()
add_executable(PermHelper helpers/permgen.cpp)

View File

@ -881,4 +881,37 @@ void InstanceHandler::loadWebCertificate() {
this->sslMgr->rename_context(strobf("web_default_new").string(), strobf("web_default").string());
this->web_cert_revision = revision;
}
permission::v2::PermissionFlaggedValue InstanceHandler::calculate_permission(permission::PermissionType permission,
ClientDbId cldbid, ClientType type, ChannelId channel, bool granted, std::shared_ptr<CalculateCache> cache) {
auto result = this->calculate_permissions({permission}, cldbid, type, channel, granted, cache);
if(result.empty()) return {0, false};
return result.front().second;
}
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue> > InstanceHandler::calculate_permissions(
const std::deque<permission::PermissionType> &permissions, ClientDbId cldbid, ClientType type, ChannelId channel, bool granted, std::shared_ptr<CalculateCache> cache) {
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> result{};
//TODO: Negate?
//TODO: May move this part to the instance?
auto server_groups = this->getGroupManager()->getServerGroups(cldbid, type);
for(const auto& permission : permissions) {
permission::v2::PermissionFlaggedValue value{0, false};
for(const auto &gr : this->getGroupManager()->getServerGroups(cldbid, type)){
auto group_permissions = gr->group->permissions();
auto flagged_permissions = granted ? group_permissions->permission_granted_flagged(permission) : group_permissions->permission_value_flagged(permission);
if(flagged_permissions.has_value)
if(!value.has_value || flagged_permissions.value > value.value || flagged_permissions.value == -1)
value = flagged_permissions;
}
result.emplace_back(permission, value);
}
return result;
}

View File

@ -72,6 +72,24 @@ namespace ts {
std::shared_ptr<permission::PermissionNameMapper> getPermissionMapper() { return this->permission_mapper; }
std::shared_ptr<ts::event::EventExecutor> getConversationIo() { return this->conversation_io; }
permission::v2::PermissionFlaggedValue calculate_permission(
permission::PermissionType,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
private:
std::mutex activeLock;
std::condition_variable activeCon;

View File

@ -8,6 +8,8 @@
#include "InstanceHandler.h"
#include "InstanceHandler.h"
//TODO: When using the new command builder make sure you're using a std::deque as the underlying bulk type!
using namespace std;
using namespace ts;
using namespace ts::server;

View File

@ -182,10 +182,10 @@ bool TSServer::assignDefaultChannel(const shared_ptr<ConnectedClient>& client, b
else
channel = this->channelTree->findChannelByPath(str);
if (channel) {
if(!channel->permission_granted(permission::i_channel_needed_join_power, client->calculate_permission_value(permission::i_channel_join_power, channel->channelId()), false)) {
if(!channel->permission_granted(permission::i_channel_needed_join_power, client->calculate_permission(permission::i_channel_join_power, channel->channelId()), false)) {
logMessage(this->serverId, "{} Client tried to connect to a channel which he hasn't permission for. Channel: {} ({})", CLIENT_STR_LOG_PREFIX_(client), channel->channelId(), channel->name());
channel = nullptr;
} else if (!channel->passwordMatch(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD], true) && client->permissionValue(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, channel) < 1) {
} else if (!channel->passwordMatch(client->properties()[property::CLIENT_DEFAULT_CHANNEL_PASSWORD], true) && !permission::v2::permission_granted(1, client->calculate_permission(permission::b_channel_join_ignore_password, channel->channelId()))) {
logMessage(this->serverId, "{} Client tried to connect to a channel which is password protected and he hasn't the right password. Channel: {} ({})", CLIENT_STR_LOG_PREFIX_(client), channel->channelId(), channel->name());
channel = nullptr;
}
@ -531,10 +531,10 @@ void TSServer::client_move(
auto i_source_channel = s_source_channel->channelId();
if(std::find(deleted.begin(), deleted.end(), i_source_channel) == deleted.end()) {
auto source_channel_sub_power = target->calculate_permission_value(permission::i_channel_subscribe_power, i_source_channel);
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_value(permission::b_channel_ignore_subscribe_power, i_source_channel);
if(!DataClient::permission_granted(source_channel_sub_power_ignore, 1, true)) {
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)) {
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

View File

@ -783,9 +783,9 @@ ts_always_inline bool channel_ignore_permission(ts::permission::PermissionType t
return permission::i_icon_id == type;
}
vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlaggedValue>> TSServer::calculatePermissions2(
ClientDbId client_dbid,
vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlaggedValue>> TSServer::calculate_permissions(
const std::deque<permission::PermissionType>& permissions,
ClientDbId client_dbid,
ClientType client_type,
ChannelId channel_id,
bool calculate_granted,
@ -1000,40 +1000,19 @@ vector<pair<ts::permission::PermissionType, ts::permission::v2::PermissionFlagge
return result;
}
deque<pair<ts::permission::PermissionType, ts::permission::PermissionValue>> TSServer::calculatePermissions(
permission::PermissionTestType test_type,
ClientDbId client_dbid,
const std::deque<permission::PermissionType>& permissions,
ClientType client_type,
const std::shared_ptr<BasicChannel> &channel,
permission::v2::PermissionFlaggedValue TSServer::calculate_permission(
permission::PermissionType permission,
ClientDbId cldbid,
ClientType type,
ChannelId channel,
bool granted,
std::shared_ptr<CalculateCache> cache) {
if(permissions.empty()) return {};
auto result = this->calculate_permissions({permission}, cldbid, type, channel, granted, cache);
if(result.empty()) return {0, false};
auto data = calculatePermissions2(client_dbid, permissions, client_type, channel ? channel->channelId() : 0, false, cache);
deque<pair<ts::permission::PermissionType, ts::permission::PermissionValue>> result;
for(auto& entry : data)
result.emplace_back(entry.first, entry.second.has_value ? entry.second.value : permNotGranted);
return result;
}
permission::v2::PermissionFlaggedValue TSServer::calculatePermission2(ts::permission::PermissionType permission, ts::ClientDbId cldbid, ts::server::ClientType type, ts::ChannelId channel, std::shared_ptr<CalculateCache> cache) {
auto result = this->calculatePermissions2(cldbid, {permission}, type, channel, false, cache);
if(result.empty()) return {permNotGranted, false};
return result.front().second;
}
ts::permission::PermissionValue TSServer::calculatePermission(permission::PermissionTestType test, ClientDbId cldbid, permission::PermissionType permission, ClientType client_type, const std::shared_ptr<BasicChannel>& channel, std::shared_ptr<CalculateCache> cache) {
auto result = this->calculatePermissions(test, cldbid, {permission}, client_type, channel, cache);
if(result.empty()) return permNotGranted;
return result.front().second;
}
ts::permission::PermissionValue TSServer::calculatePermissionGrant(permission::PermissionTestType test, ClientDbId cldbid, permission::PermissionType permission, ClientType client_type, const std::shared_ptr<BasicChannel>& channel) {
auto result = this->calculatePermissions2(cldbid, {permission}, client_type, channel ? channel->channelId() : 0, true, nullptr);
assert(!result.empty());
return result[0].second.has_value ? result[0].second.value : permNotGranted;
}
bool TSServer::verifyServerPassword(std::string password, bool hashed) {
if(!this->properties()[property::VIRTUALSERVER_FLAG_PASSWORD].as<bool>()) return true;
if(password.empty()) return false;

View File

@ -208,27 +208,24 @@ namespace ts {
std::shared_ptr<VoiceServer> getVoiceServer(){ return this->udpVoiceServer; }
WebControlServer* getWebServer(){ return this->webControlServer; }
std::deque<std::pair<permission::PermissionType, permission::PermissionValue>> calculatePermissions(
permission::PermissionTestType,
/* calculate permissions for an client in this server */
permission::v2::PermissionFlaggedValue calculate_permission(
permission::PermissionType,
ClientDbId,
const std::deque<permission::PermissionType>&,
ClientType type,
const std::shared_ptr<BasicChannel>& channel,
std::shared_ptr<CalculateCache> cache = nullptr);
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculatePermissions2(
ClientDbId /* client db id */,
const std::deque<permission::PermissionType>& /* permissions to calculate */,
ClientType type /* client type for default permissions */,
ChannelId /* target channel id */,
bool /* calculate granted */,
std::shared_ptr<CalculateCache> cache = nullptr /* calculate cache */);
permission::PermissionValue calculatePermission(permission::PermissionTestType, ClientDbId, permission::PermissionType, ClientType type, const std::shared_ptr<BasicChannel>& channel, std::shared_ptr<CalculateCache> cache = nullptr);
permission::v2::PermissionFlaggedValue calculatePermission2(permission::PermissionType, ClientDbId, ClientType type, ChannelId channel, std::shared_ptr<CalculateCache> cache = nullptr);
permission::PermissionValue calculatePermissionGrant(permission::PermissionTestType, ClientDbId, permission::PermissionType, ClientType type, const std::shared_ptr<BasicChannel>& channel);
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&,
ClientDbId,
ClientType type,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
bool verifyServerPassword(std::string, bool hashed = false);

View File

@ -127,7 +127,7 @@ std::deque<std::shared_ptr<ViewEntry>> ClientChannelView::insert_channels(shared
std::deque<std::shared_ptr<ViewEntry>> result;
if(!cache && test_permissions) cache = make_shared<CalculateCache>();
bool has_perm = !test_permissions || owner->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_view_power, 1, nullptr, true, cache);
bool has_perm = !test_permissions || permission::v2::permission_granted(1, owner->calculate_permission(permission::b_channel_ignore_view_power, 0, false, cache));
bool first = true;
while(head) {
if(!first && first_only) break;
@ -145,7 +145,7 @@ std::deque<std::shared_ptr<ViewEntry>> ClientChannelView::insert_channels(shared
}
if(!has_perm) {
if(!channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission_value(permission::i_channel_view_power, channel->channelId()), false)) {
if(!channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission(permission::i_channel_view_power, channel->channelId()), false)) {
head = head->next;
debugMessage(this->getServerId(), "{}[CHANNEL] Dropping channel {} ({}) (No permissions)", CLIENT_STR_LOG_PREFIX_(this->owner), channel->channelId(), channel->name());
continue;
@ -245,7 +245,7 @@ std::deque<std::shared_ptr<ViewEntry>> ClientChannelView::test_channel(std::shar
if(!cache) cache = make_shared<CalculateCache>();
std::deque<std::shared_ptr<ViewEntry>> result;
bool has_perm = owner->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_view_power, 1, nullptr, true, cache);
bool has_perm = permission::v2::permission_granted(1, owner->calculate_permission(permission::b_channel_ignore_view_power, 0, false, cache));
if(has_perm) return {};
deque<shared_ptr<TreeView::LinkedTreeEntry>> parents = {l_old};
@ -267,7 +267,7 @@ std::deque<std::shared_ptr<ViewEntry>> ClientChannelView::test_channel(std::shar
auto channel = dynamic_pointer_cast<BasicChannel>(l_entry->entry);
sassert(entry->channelId() == channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission_value(permission::i_channel_view_power, channel->channelId()), false)) {
if(!channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission(permission::i_channel_view_power, channel->channelId()), false)) {
for(const auto& te : this->delete_entry(entry))
result.push_back(dynamic_pointer_cast<ViewEntry>(te));
@ -288,7 +288,7 @@ std::deque<std::pair<bool, std::shared_ptr<ViewEntry>>> ClientChannelView::updat
std::deque<std::pair<bool, std::shared_ptr<ViewEntry>>> ClientChannelView::update_channel_path(std::shared_ptr<ts::TreeView::LinkedTreeEntry> l_channel, std::shared_ptr<ts::TreeView::LinkedTreeEntry> l_own, shared_ptr<CalculateCache> cache, ssize_t length) {
if(!cache) cache = make_shared<CalculateCache>();
std::deque<std::pair<bool, std::shared_ptr<ViewEntry>>> result;
bool has_perm = owner->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_view_power, 1, nullptr, true, cache);
bool has_perm = permission::v2::permission_granted(1, owner->calculate_permission(permission::b_channel_ignore_view_power, 0, false, cache));
while(l_channel && length-- != 0) {
auto b_channel = dynamic_pointer_cast<BasicChannel>(l_channel->entry);
@ -303,7 +303,7 @@ std::deque<std::pair<bool, std::shared_ptr<ViewEntry>>> ClientChannelView::updat
visible = true;
if(!has_perm) {
if(!b_channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission_value(permission::i_channel_view_power, b_channel->channelId()), false)) {
if(!b_channel->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission(permission::i_channel_view_power, b_channel->channelId()), false)) {
visible = false;
}
}
@ -341,9 +341,9 @@ std::deque<std::pair<ClientChannelView::ChannelAction, std::shared_ptr<ViewEntry
if(!l_entry) { //Channel not visible yet
if(!l_parent && parent) return {}; //The invisible channel was moved into an invisible tree
bool has_perm = owner->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_view_power, 1, nullptr);
bool has_perm = permission::v2::permission_granted(1, owner->calculate_permission(permission::b_channel_ignore_view_power, 0, false));
if(!has_perm) {
has_perm = dynamic_pointer_cast<BasicChannel>(channel->entry)->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission_value(permission::i_channel_view_power, dynamic_pointer_cast<BasicChannel>(channel->entry)->channelId()), false);
has_perm = dynamic_pointer_cast<BasicChannel>(channel->entry)->permission_granted(permission::i_channel_needed_view_power, this->owner->calculate_permission(permission::i_channel_view_power, dynamic_pointer_cast<BasicChannel>(channel->entry)->channelId()), false);
}
if(!has_perm) return {}; //Channel wasn't visible and he still has no permission for that :)

View File

@ -23,7 +23,7 @@ namespace ts {
bool subscribed = false;
bool editable = false;
bool joinable = false; /* used within notify text message */
permission::PermissionType join_permission_error = permission::unknown; /* used within notify text message */
ChannelId previous_channel = 0;
uint16_t join_state_id = 0; /* the calculation id for the flag joinable. If this does not match with the join_state_id within the client the flag needs to be recalculated */
std::weak_ptr<BasicChannel> handle;

View File

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

View File

@ -6,6 +6,7 @@
#include "music/Song.h"
#include "../channel/ClientChannelView.h"
#include "DataClient.h"
#include "query/command3.h"
#define CLIENT_STR_LOG_PREFIX_(this) (std::string("[") + this->getLoggingPeerIp() + ":" + std::to_string(this->getPeerPort()) + "/" + this->getDisplayName() + " | " + std::to_string(this->getClientId()) + "]")
#define CLIENT_STR_LOG_PREFIX CLIENT_STR_LOG_PREFIX_(this)
@ -37,40 +38,6 @@ if(this->shouldFloodBlock()) return command_result{error::ban_flooding};
#define CMD_CHK_PARM_COUNT(count) \
if(cmd.bulkCount() != count) return command_result{error::parameter_invalid_count};
#define PERM_CHECK_CHANNEL_CR(pr, required, channel, req, cache) \
do { \
if(!this->permissionGranted(permission::PERMTEST_ORDERED, pr, required, channel, req, cache)) {\
return command_result{pr}; \
}\
} while(false)
//If a permission is required it could not be -1
#define PERM_CHECK_CHANNELR(pr, required, channel, req) PERM_CHECK_CHANNEL_CR(pr, required, channel, req, nullptr)
//If a permission is required it could not be -1
#define PERM_CHECK_CHANNEL(pr, required, channel) PERM_CHECK_CHANNELR(pr, required, channel, false)
#define PERM_CHECKR(pr, required, req) PERM_CHECK_CHANNELR(pr, (required), nullptr, req)
#define PERM_CHECK(pr, required) PERM_CHECKR(pr, required, false)
/* optional parameter required. By default true */
#define CACHED_PERM_CHECK(permission_type, required, ...) \
do { \
if(!this->permission_granted(this->cached_permission_value(permission_type), required, #__VA_ARGS__)) \
return command_result{permission_type}; \
} while(0)
//p = permission | target_permission = channel permission | channel = target channel | requires a power
#define PERM_CHECK_CHANNEL_NEEDED_CR(p, target_permission, channel, req, cache) \
this->permissionGranted(permission::PERMTEST_ORDERED, p, (channel)->permissions()->getPermissionValue(permission::PERMTEST_ORDERED, target_permission, nullptr), channel, req, cache)
#define PERM_CHECK_CHANNEL_NEEDEDR(p, target_permission, channel, req) PERM_CHECK_CHANNEL_NEEDED_CR(p, target_permission, channel, req, nullptr)
#define PERM_CHECK_CHANNEL_NEEDED(p, target_permission, channel) PERM_CHECK_CHANNEL_NEEDEDR(p, target_permission, channel, true)
namespace ts {
class GroupManager;
namespace connection {
@ -120,6 +87,7 @@ namespace ts {
/* Note: Order is not guaranteed here! */
virtual void sendCommand(const ts::Command& command, bool low = false) = 0;
virtual void sendCommand(const ts::command_builder& command, bool low = false) = 0;
//General manager stuff
//FIXME cache the client id for speedup
@ -127,6 +95,7 @@ namespace ts {
virtual void setClientId(uint16_t clId) { properties()[property::CLIENT_ID] = clId; }
inline std::shared_ptr<BasicChannel> getChannel(){ return this->currentChannel; }
inline ChannelId getChannelId(){ auto channel = this->currentChannel; return channel ? channel->channelId() : 0; }
inline std::shared_ptr<TSServer> getServer(){ return this->server; }
inline ServerId getServerId(){ return this->server ? this->server->getServerId() : (ServerId) 0; }
@ -289,18 +258,19 @@ namespace ts {
/*
* permission stuff
*/
/*
inline permission::PermissionValue cached_permission_value(permission::PermissionType type) const {
std::lock_guard lock(this->cached_permissions_lock);
auto index = this->cached_permissions.find(type);
if(index != this->cached_permissions.end())
return index->second;
/* We're only caching permissions which are granted to reduce memory */
We're only caching permissions which are granted to reduce memory
//logError(this->getServerId(), "{} Looked up cached permission, which hasn't been cached!", CLIENT_STR_LOG_PREFIX);
return permNotGranted;
}
*/
bool update_cached_permissions();
permission::v2::PermissionFlaggedValue calculate_permission_value(const permission::PermissionType& /* permission type */, ChannelId /* target channel */);
protected:
std::weak_ptr<ConnectedClient> _this;
@ -309,7 +279,6 @@ namespace ts {
ConnectionState state = ConnectionState::UNKNWON;
sockaddr_storage remote_address;
std::shared_ptr<BasicChannel> currentChannel = nullptr;
bool allowedToTalk = false;
threads::Mutex disconnectLock;
@ -358,23 +327,16 @@ namespace ts {
std::shared_mutex channel_lock;
std::mutex cached_permissions_lock;
std::map<permission::PermissionType, permission::PermissionValue> cached_permissions; /* contains all needed permissions which are set */
#pragma pack(push, 1)
struct CachedPermission {
bool flag_skip : 1; /* could be enabled by server / channel or client group. If this flag is set we need no lookup for channel permissions */
bool flag_value : 1; /* says if we have a value or not */
permission::PermissionValue value;
};
static_assert(sizeof(CachedPermission) == 5);
#pragma pack(pop)
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> cached_permissions; /* contains all needed permissions which are set */
permission::PermissionValue channels_view_power = permNotGranted;
permission::PermissionValue channels_ignore_view = permNotGranted;
permission::v2::PermissionFlaggedValue channels_view_power{0, false};
permission::v2::PermissionFlaggedValue channels_ignore_view{0, false};
permission::v2::PermissionFlaggedValue cpmerission_whisper_power{0, false};
permission::v2::PermissionFlaggedValue cpmerission_needed_whisper_power{0, false};
bool subscribeToAll = false;
uint16_t join_state_id = 1; /* default channel value is 0 and by default we need to calculate at least once, so we use 1 */
bool calculate_and_get_join_state(const std::shared_ptr<BasicChannel>&);
permission::PermissionType calculate_and_get_join_state(const std::shared_ptr<BasicChannel>&);
std::weak_ptr<MusicClient> selectedBot;
std::weak_ptr<MusicClient> subscribed_bot;
@ -435,13 +397,13 @@ namespace ts {
command_result handleCommandServerGroupAutoAddPerm(Command&);
command_result handleCommandServerGroupAutoDelPerm(Command&);
command_result handleCommandClientAddPerm(Command&); //TODO: Use cached permission values
command_result handleCommandClientDelPerm(Command&); //TODO: Use cached permission values
command_result handleCommandClientPermList(Command&); //TODO: Use cached permission values
command_result handleCommandClientAddPerm(Command&);
command_result handleCommandClientDelPerm(Command&);
command_result handleCommandClientPermList(Command&);
command_result handleCommandChannelClientAddPerm(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientDelPerm(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientPermList(Command&); //TODO: Use cached permission values
command_result handleCommandChannelClientAddPerm(Command&);
command_result handleCommandChannelClientDelPerm(Command&);
command_result handleCommandChannelClientPermList(Command&);
command_result handleCommandChannelGroupAdd(Command&);
command_result handleCommandChannelGroupCopy(Command&);
@ -459,12 +421,12 @@ namespace ts {
command_result handleCommandClientChatClosed(Command&);
//File transfare commands
command_result handleCommandFTGetFileList(Command&); //TODO: Use cached permission values
command_result handleCommandFTCreateDir(Command&); //TODO: Use cached permission values
command_result handleCommandFTDeleteFile(Command&); //TODO: Use cached permission values
command_result handleCommandFTInitUpload(Command&); //TODO: Use cached permission values
command_result handleCommandFTInitDownload(Command&); //TODO: Use cached permission values
command_result handleCommandFTGetFileInfo(Command&); //TODO: Use cached permission values
command_result handleCommandFTGetFileList(Command&);
command_result handleCommandFTCreateDir(Command&);
command_result handleCommandFTDeleteFile(Command&);
command_result handleCommandFTInitUpload(Command&);
command_result handleCommandFTInitDownload(Command&);
command_result handleCommandFTGetFileInfo(Command&);
//CMD_TODO handleCommandFTGetFileInfo -> 5 points
//CMD_TODO handleCommandFTStop -> 5 points
//CMD_TODO handleCommandFTRenameFile -> 5 points
@ -527,20 +489,20 @@ namespace ts {
command_result handleCommandPermFind(Command&);
command_result handleCommandPermOverview(Command&);
command_result handleCommandChannelFind(Command&); //TODO: Use cached permission values
command_result handleCommandChannelInfo(Command&); //TODO: Use cached permission values
command_result handleCommandChannelFind(Command&);
command_result handleCommandChannelInfo(Command&);
command_result handleCommandMusicBotCreate(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotDelete(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotSetSubscription(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotCreate(Command&);
command_result handleCommandMusicBotDelete(Command&);
command_result handleCommandMusicBotSetSubscription(Command&);
command_result handleCommandMusicBotPlayerInfo(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotPlayerAction(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotPlayerInfo(Command&);
command_result handleCommandMusicBotPlayerAction(Command&);
command_result handleCommandMusicBotQueueList(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueAdd(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueRemove(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueReorder(Command&); //TODO: Use cached permission values
command_result handleCommandMusicBotQueueList(Command&);
command_result handleCommandMusicBotQueueAdd(Command&);
command_result handleCommandMusicBotQueueRemove(Command&);
command_result handleCommandMusicBotQueueReorder(Command&);
command_result handleCommandMusicBotPlaylistAssign(Command&);
@ -561,9 +523,9 @@ namespace ts {
command_result handleCommandPlaylistSongReorder(Command&);
command_result handleCommandPlaylistSongRemove(Command&);
command_result handleCommandPermReset(Command&); //TODO: Use cached permission values
command_result handleCommandPermReset(Command&);
command_result handleCommandHelp(Command&); //TODO: Use cached permission values
command_result handleCommandHelp(Command&);
command_result handleCommandUpdateMyTsId(Command&);
command_result handleCommandUpdateMyTsData(Command&);

View File

@ -96,7 +96,7 @@ if (!l_channel && (channel_id != 0 || force)) return command_result{error::chann
/* the "newest" channel permission access test */
#define CHANNEL_PERMISSION_TEST(permission_type, permission_needed_type, _channel, permission_required) \
do { \
auto permission_granted = this->calculate_permission_value(permission_type, _channel->channelId()); \
auto permission_granted = this->calculate_permission(permission_type, _channel->channelId()); \
if(!channel->permission_granted(permission_needed_type, permission_granted, permission_required)) \
return command_result{permission_type}; \
} while(0)
@ -104,7 +104,7 @@ do { \
/* the "newest" group permission access test */
#define GROUP_PERMISSION_TEST(permission_type, permission_needed_type, _group, permission_required) \
do { \
auto permission_granted = this->calculate_permission_value(permission_type, 0); \
auto permission_granted = this->calculate_permission(permission_type, 0); \
if(!_group->permission_granted(permission_needed_type, permission_granted, permission_required)) \
return command_result{permission_type}; \
} while(0)
@ -375,7 +375,7 @@ command_result ConnectedClient::handleCommand(Command &cmd) {
if (this->getType() == ClientType::CLIENT_QUERY) return command_result{error::command_not_found}; //Dont log query invalid commands
if (this->getType() == ClientType::CLIENT_TEAMSPEAK)
if (command.empty() || command.find_first_not_of(' ') == -1) {
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_allow_invalid_packet, 1, this->currentChannel))
if (!this->permissionGranted(permission::b_client_allow_invalid_packet, 1, this->currentChannel))
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_command, this->server ? this->server->serverAdmin : static_pointer_cast<ConnectedClient>(serverInstance->getInitialServerAdmin()), true);
}
@ -391,19 +391,19 @@ command_result ConnectedClient::handleCommandServerGetVariables(Command &cmd) {
#define SERVEREDIT_CHK_PROP(name, perm, type)\
else if(key == name) { \
if(!permissionGranted(permission::PERMTEST_HIGHEST, perm, 1, nullptr, true, cache, target_server, true)) return command_result{perm}; \
if(!permissionGranted(perm, 1, nullptr, true, cache, target_server, true)) return command_result{perm}; \
if(toApplay.count(key) == 0) toApplay[key] = cmd[key].as<std::string>(); \
if(!cmd[0][key].castable<type>()) return command_result{error::parameter_invalid};
#define SERVEREDIT_CHK_PROP_CACHED(name, perm, type)\
else if(key == name) { \
if(!this->permission_granted(this->cached_permission_value(perm), 1)) return command_result{perm}; \
if(!this->permission_granted(this->calculate_permission(perm, 0), 1)) return command_result{perm}; \
if(toApplay.count(key) == 0) toApplay[key] = cmd[key].as<std::string>(); \
if(!cmd[0][key].castable<type>()) return command_result{error::parameter_invalid};
#define SERVEREDIT_CHK_PROP2(name, perm, type_a, type_b)\
else if(key == name) { \
if(!permissionGranted(permission::PERMTEST_HIGHEST, perm, 1, nullptr, true, cache, target_server, true)) return command_result{perm}; \
if(!permissionGranted(perm, 1, nullptr, true, cache, target_server, true)) return command_result{perm}; \
if(toApplay.count(key) == 0) toApplay[key] = cmd[key].as<std::string>(); \
if(!cmd[0][key].castable<type_a>() && !!cmd[0][key].castable<type_b>()) return command_result{error::parameter_invalid};
@ -619,11 +619,11 @@ command_result ConnectedClient::handleCommandClientKick(Command &cmd) {
auto type = cmd["reasonid"].as<ViewReasonId>();
if (type == ViewReasonId::VREASON_CHANNEL_KICK) {
auto channel = client->currentChannel;
PERM_CHECK_CHANNELR(permission::i_client_kick_from_channel_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_kick_from_channel_power, channel), channel, true);
PERM_CHECK_CHANNELR(permission::i_client_kick_from_channel_power, client->permissionValue(permission::i_client_needed_kick_from_channel_power, channel), channel, true);
targetChannel = this->server->channelTree->getDefaultChannel();
} else if (type == ViewReasonId::VREASON_SERVER_KICK) {
auto channel = client->currentChannel;
PERM_CHECK_CHANNELR(permission::i_client_kick_from_server_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_kick_from_server_power, channel), channel, true);
PERM_CHECK_CHANNELR(permission::i_client_kick_from_server_power, client->permissionValue(permission::i_client_needed_kick_from_server_power, channel), channel, true);
targetChannel = nullptr;
} else return command_result{error::not_implemented};
@ -643,7 +643,7 @@ command_result ConnectedClient::handleCommandChannelGetDescription(Command &cmd)
auto channel = dynamic_pointer_cast<BasicChannel>(l_channel->entry);
assert(channel);
if(!this->permission_granted(this->permissionValue(permission::b_channel_ignore_description_view_power, channel), 1, true)) {
if(!this->permission_granted(this->calculate_permission(permission::b_channel_ignore_description_view_power, channel->channelId()), 1, true)) {
CHANNEL_PERMISSION_TEST(permission::i_channel_description_view_power, permission::i_channel_needed_description_view_power, channel, false);
}
@ -663,7 +663,7 @@ command_result ConnectedClient::handleCommandGetConnectionInfo(Command &cmd) {
if (info) {
this->notifyConnectionInfo(client, info);
} else if(send_temp) {
this->notifyConnectionInfo(client, nullptr);
return command_result{error::no_cached_connection_info};
}
return command_result{error::ok};
@ -1034,7 +1034,7 @@ command_result ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) {
return command_result{result};
}
if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission_value(permission::i_channel_group_modify_power, 0), true))
if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission(permission::i_channel_group_modify_power, 0), true))
return command_result{permission::i_channel_group_modify_power};
if(!group_manager->copyGroupPermissions(source_group, target_group))
@ -1230,7 +1230,7 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
if (!channelGroup || channelGroup->target() != GROUPTARGET_CHANNEL) return command_result{error::parameter_invalid, "invalid channel group id"};
GROUP_PERMISSION_TEST(permission::i_channel_group_modify_power, permission::i_channel_group_needed_modify_power, channelGroup, true);
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permission_granted(this->cached_permission_value(permission::b_permission_modify_power_ignore), 1);
bool updateList = false;
bool conOnError = cmd[0].has("continueonerror");
@ -1243,7 +1243,7 @@ command_result ConnectedClient::handleCommandChannelGroupAddPerm(Command &cmd) {
if(permission_require_granted_value(permType) && val > maxValue)
return command_result{permission::i_permission_modify_power};
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -1299,7 +1299,7 @@ command_result ConnectedClient::handleCommandChannelGroupDelPerm(Command &cmd) {
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd)
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
permission_manager->set_permission(permType, permission::v2::empty_permission_values, permission::v2::PermissionUpdateType::do_nothing, permission::v2::PermissionUpdateType::delete_value);
@ -1362,7 +1362,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
if(!cmd[0].has("cpw"))
cmd["cpw"] = "";
if (!channel->passwordMatch(cmd["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true, permission_cache))
if (!this->permissionGranted(permission::b_channel_join_ignore_password, 1, channel, true, permission_cache))
return command_result{error::channel_invalid_password};
switch(channel->channelType()) {
@ -1377,7 +1377,7 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
break;
}
if (!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as<bool>() || !channel->properties()[property::CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED].as<bool>()) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_maxclients, 1, channel, true, permission_cache)) {
if(!this->permissionGranted(permission::b_channel_join_ignore_maxclients, 1, channel, true, permission_cache)) {
if(!channel->properties()[property::CHANNEL_FLAG_MAXCLIENTS_UNLIMITED].as<bool>()) {
auto maxClients = channel->properties()[property::CHANNEL_MAXCLIENTS].as<int32_t>();
if (maxClients >= 0 && maxClients <= this->server->getClientsByChannel(channel).size())
@ -1401,23 +1401,23 @@ command_result ConnectedClient::handleCommandClientMove(Command &cmd) {
}
}
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true, permission_cache)) {
if(!this->permissionGranted(permission::b_channel_ignore_join_power, 1, channel, true, permission_cache)) {
CHANNEL_PERMISSION_TEST(permission::i_channel_join_power, permission::i_channel_needed_join_power, channel, false);
}
if (target_client == this) {
auto permission_cache_current = make_shared<CalculateCache>();
auto val = this->permissionValue(permission::PERMTEST_ORDERED, permission::b_client_is_sticky, this->currentChannel, permission_cache_current);
auto val = this->permissionValue(permission::b_client_is_sticky, this->currentChannel, permission_cache_current);
if (val != permNotGranted && val > 0) {
auto st = this->permissionValue(permission::PERMTEST_ORDERED, permission::b_client_ignore_sticky, this->currentChannel, permission_cache_current);
auto st = this->permissionValue(permission::b_client_ignore_sticky, this->currentChannel, permission_cache_current);
if (st != 1)
return command_result{permission::b_client_is_sticky};
}
}
if (target_client != this) {
PERM_CHECK_CHANNELR(permission::i_client_move_power, target_client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_move_power, target_client->getChannel()), target_client->getChannel(), true);
PERM_CHECK_CHANNEL_CR(permission::i_client_move_power, target_client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_move_power, channel), channel, true, permission_cache);
PERM_CHECK_CHANNELR(permission::i_client_move_power, target_client->permissionValue(permission::i_client_needed_move_power, target_client->getChannel()), target_client->getChannel(), true);
PERM_CHECK_CHANNEL_CR(permission::i_client_move_power, target_client->permissionValue(permission::i_client_needed_move_power, channel), channel, true, permission_cache);
}
server_channel_r_lock.unlock();
@ -1524,7 +1524,7 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
}
auto max_channels = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_max_channels, nullptr, permission_cache);
auto max_channels = this->permissionValue(permission::i_client_max_channels, nullptr, permission_cache);
if(max_channels >= 0) {
if(max_channels <= created_perm + created_semi + created_tmp)
@ -1532,21 +1532,21 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
}
if (cmd[0]["channel_flag_permanent"].as<bool>()) {
max_channels = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_max_permanent_channels, nullptr, permission_cache);
max_channels = this->permissionValue(permission::i_client_max_permanent_channels, nullptr, permission_cache);
if(max_channels >= 0) {
if(max_channels <= created_perm)
return command_result{permission::i_client_max_permanent_channels};
}
}
else if (cmd[0]["channel_flag_semi_permanent"].as<bool>()) {
max_channels = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_max_semi_channels, nullptr, permission_cache);
max_channels = this->permissionValue(permission::i_client_max_semi_channels, nullptr, permission_cache);
if(max_channels >= 0) {
if(max_channels <= created_semi)
return command_result{permission::i_client_max_semi_channels};
}
}
else {
max_channels = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_max_temporary_channels, nullptr, permission_cache);
max_channels = this->permissionValue(permission::i_client_max_temporary_channels, nullptr, permission_cache);
if(max_channels >= 0) {
if(max_channels <= created_tmp)
return command_result{permission::i_client_max_temporary_channels};
@ -1567,8 +1567,8 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
{
auto min_channel_deep = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_min_depth, nullptr, permission_cache);
auto max_channel_deep = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_max_depth, nullptr, permission_cache);
auto min_channel_deep = this->permissionValue(permission::i_channel_min_depth, nullptr, permission_cache);
auto max_channel_deep = this->permissionValue(permission::i_channel_max_depth, nullptr, permission_cache);
if(min_channel_deep >= 0 || max_channel_deep >= 0) {
auto channel_deep = 0;
@ -1622,13 +1622,13 @@ command_result ConnectedClient::handleCommandChannelCreate(Command &cmd) {
auto permission_manager = created_channel->permissions();
permission_manager->set_permission(
permission::i_channel_needed_modify_power,
{this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_modify_power, this->currentChannel, permission_cache), 0},
{this->permissionValue(permission::i_channel_modify_power, this->currentChannel, permission_cache), 0},
permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing
);
permission_manager->set_permission(
permission::i_channel_needed_delete_power,
{this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_delete_power, this->currentChannel, permission_cache), 0},
{this->permissionValue(permission::i_channel_delete_power, this->currentChannel, permission_cache), 0},
permission::v2::PermissionUpdateType::set_value,
permission::v2::PermissionUpdateType::do_nothing
);
@ -1849,13 +1849,13 @@ command_result ConnectedClient::handleCommandChannelEdit(Command &cmd) {
CHANNEL_PERM_TEST(permission::b_channel_modify_topic, 1, true);
} else if (key == "channel_description") {
CHANNEL_PERM_TEST(permission::b_channel_modify_description, 1, true);
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_use_bbcode_any, 1, this->currentChannel)) {
if(!this->permissionGranted(permission::b_client_use_bbcode_any, 1, this->currentChannel)) {
auto bbcode_image = bbcode::sloppy::has_image(cmd[key]);
auto bbcode_url = bbcode::sloppy::has_url(cmd[key]);
debugMessage(this->getServerId(), "Channel description contains bb codes: Image: {} URL: {}", bbcode_image, bbcode_url);
if(bbcode_image && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_use_bbcode_image, 1, this->currentChannel))
if(bbcode_image && !this->permissionGranted(permission::b_client_use_bbcode_image, 1, this->currentChannel))
return command_result{permission::b_client_use_bbcode_image};
if(bbcode_url && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_use_bbcode_url, 1, this->currentChannel))
if(bbcode_url && !this->permissionGranted(permission::b_client_use_bbcode_url, 1, this->currentChannel))
return command_result{permission::b_client_use_bbcode_url};
}
} else if (key == "channel_codec") {
@ -2270,8 +2270,8 @@ command_result ConnectedClient::handleCommandChannelMove(Command &cmd) {
{
auto min_channel_deep = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_min_depth, nullptr, nullptr);
auto max_channel_deep = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_channel_max_depth, nullptr, nullptr);
auto min_channel_deep = this->permissionValue(permission::i_channel_min_depth, nullptr, nullptr);
auto max_channel_deep = this->permissionValue(permission::i_channel_max_depth, nullptr, nullptr);
if(min_channel_deep >= 0 || max_channel_deep >= 0) {
auto channel_deep = 0;
@ -2355,7 +2355,7 @@ command_result ConnectedClient::handleCommandClientPoke(Command &cmd) {
auto client = this->server->findClient(cmd["clid"].as<ClientId>());
if (!client) return command_result{error::client_invalid_id};
if (client->getType() == CLIENT_MUSIC) return command_result{error::client_invalid_type};
CACHED_PERM_CHECK(permission::i_client_poke_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_poke_power, client->currentChannel), false);
CACHED_PERM_CHECK(permission::i_client_poke_power, client->permissionValue(permission::i_client_needed_poke_power, client->currentChannel), false);
client->notifyClientPoke(_this.lock(), cmd["msg"]);
return command_result{error::ok};
@ -2432,8 +2432,8 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
CHANNEL_PERMISSION_TEST(permission::i_channel_permission_modify_power, permission::i_channel_needed_permission_modify_power, channel, true);
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, channel);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, channel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, channel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, channel);
auto updateClients = false, update_view = false, update_channel_properties = false;
bool conOnError = cmd[0].has("continueonerror");
@ -2449,7 +2449,7 @@ command_result ConnectedClient::handleCommandChannelAddPerm(Command &cmd) {
return command_result{permission::i_permission_modify_power};
}
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, channel)) {
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, channel)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
@ -2536,7 +2536,7 @@ command_result ConnectedClient::handleCommandChannelDelPerm(Command &cmd) {
assert(channel);
CHANNEL_PERMISSION_TEST(permission::i_channel_permission_modify_power, permission::i_channel_needed_permission_modify_power, channel, true);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, channel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, channel);
bool conOnError = cmd[0].has("continueonerror");
auto updateClients = false, update_view = false, update_channel_properties = false;
@ -2544,7 +2544,7 @@ command_result ConnectedClient::handleCommandChannelDelPerm(Command &cmd) {
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, channel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, channel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -2681,7 +2681,7 @@ command_result ConnectedClient::handleCommandServerGroupCopy(Command &cmd) {
return command_result{result};
}
if(!target_group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true))
if(!target_group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true))
return command_result{permission::i_server_group_modify_power};
if(!group_manager->copyGroupPermissions(source_group, target_group))
@ -2836,7 +2836,7 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"};
auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
auto needed_client_permission = this->server->calculatePermission(target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
if(needed_client_permission != permNotGranted) {
if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission))
return command_result{permission::i_client_needed_permission_modify_power};
@ -2848,8 +2848,8 @@ command_result ConnectedClient::handleCommandServerGroupAddClient(Command &cmd)
auto continue_on_error = cmd.hasParm("continueonerror");
{
auto permission_add_power = this->calculate_permission_value(permission::i_server_group_member_add_power, -1);
auto permission_self_add_power = this->calculate_permission_value(permission::i_server_group_member_add_power, -1);
auto permission_add_power = this->calculate_permission(permission::i_server_group_member_add_power, -1);
auto permission_self_add_power = this->calculate_permission(permission::i_server_group_member_add_power, -1);
for(auto index = 0; index < cmd.bulkCount(); index++) {
auto group_id = cmd[index]["sgid"];
@ -2952,7 +2952,7 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
if (!serverInstance->databaseHelper()->validClientDatabaseId(target_server, cmd["cldbid"])) return command_result{error::client_invalid_id, "invalid cldbid"};
auto needed_client_permission = this->server->calculatePermission(permission::PERMTEST_ORDERED, target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
auto needed_client_permission = this->server->calculatePermission(target_cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr);
if(needed_client_permission != permNotGranted) {
if(!this->permission_granted(this->permissionValue(permission::i_client_permission_modify_power), needed_client_permission))
return command_result{permission::i_client_needed_permission_modify_power};
@ -2964,8 +2964,8 @@ command_result ConnectedClient::handleCommandServerGroupDelClient(Command &cmd)
auto continue_on_error = cmd.hasParm("continueonerror");
{
auto permission_remove_power = this->calculate_permission_value(permission::i_server_group_member_remove_power, -1);
auto permission_self_remove_power = this->calculate_permission_value(permission::i_server_group_member_remove_power, -1);
auto permission_remove_power = this->calculate_permission(permission::i_server_group_member_remove_power, -1);
auto permission_self_remove_power = this->calculate_permission(permission::i_server_group_member_remove_power, -1);
for(auto index = 0; index < cmd.bulkCount(); index++) {
auto group_id = cmd[index]["sgid"];
@ -3104,7 +3104,7 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
return command_result{permission::b_serverinstance_modify_templates};
}
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permission_granted(this->cached_permission_value(permission::b_permission_modify_power_ignore), 1);
bool conOnError = cmd[0].has("continueonerror");
bool checkTp = false;
@ -3121,7 +3121,7 @@ command_result ConnectedClient::handleCommandServerGroupAddPerm(Command &cmd) {
return command_result{permission::i_permission_modify_power};
}
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel)) {
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
@ -3194,7 +3194,7 @@ command_result ConnectedClient::handleCommandServerGroupDelPerm(Command &cmd) {
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel)) {
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
@ -3250,13 +3250,13 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
deque<shared_ptr<Group>> groups;
for(const auto& group : group_manager->availableGroups(false)) {
if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true)) {
auto type = group->type();
if(type == GroupType::GROUP_TYPE_QUERY) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_querygroup, 1))
if(!this->permissionGranted(permission::b_serverinstance_modify_querygroup, 1))
continue;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_templates, 1))
if(!this->permissionGranted(permission::b_serverinstance_modify_templates, 1))
continue;
}
groups.push_back(group);//sgtype
@ -3267,9 +3267,9 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
if(groups.empty())
return command_result{error::ok};
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1);
bool conOnError = cmd[0].has("continueonerror");
bool checkTp = false;
bool sgroupUpdate = false;
@ -3284,7 +3284,7 @@ command_result ConnectedClient::handleCommandServerGroupAutoAddPerm(ts::Command&
return command_result{permission::i_permission_modify_power};
}
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel)) {
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
@ -3347,13 +3347,13 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
deque<shared_ptr<Group>> groups;
for(const auto& group : group_manager->availableGroups(false)) {
if(group->updateType() == cmd["sgtype"].as<permission::PermissionValue>() && group->target() == GROUPTARGET_SERVER) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission_value(permission::i_server_group_modify_power, 0), true)) {
if(group->permission_granted(permission::i_server_group_needed_modify_power, this->calculate_permission(permission::i_server_group_modify_power, 0), true)) {
auto type = group->type();
if(type == GroupType::GROUP_TYPE_QUERY) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_querygroup, 1))
if(!this->permissionGranted(permission::b_serverinstance_modify_querygroup, 1))
continue;
} else if(type == GroupType::GROUP_TYPE_TEMPLATE) {
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_serverinstance_modify_templates, 1))
if(!this->permissionGranted(permission::b_serverinstance_modify_templates, 1))
continue;
}
groups.push_back(group);//sgtype
@ -3363,14 +3363,14 @@ command_result ConnectedClient::handleCommandServerGroupAutoDelPerm(ts::Command&
if(groups.empty()) return command_result{error::ok};
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1);
bool conOnError = cmd[0].has("continueonerror");
bool checkTp = false;
auto sgroupUpdate = false;
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel)) {
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
@ -3441,18 +3441,18 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
auto target_cldbid = cmd["cldbid"].as<ClientDbId>();
{
auto channel_group_member_add_power = this->calculate_permission_value(permission::i_channel_group_member_add_power, channel_id);
auto channel_group_member_add_power = this->calculate_permission(permission::i_channel_group_member_add_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_member_add_power, true)) {
if(target_cldbid != this->getClientDatabaseId())
return command_result{permission::i_channel_group_member_add_power};
auto channel_group_self_add_power = this->calculate_permission_value(permission::i_channel_group_self_add_power, channel_id);
auto channel_group_self_add_power = this->calculate_permission(permission::i_channel_group_self_add_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_add_power, channel_group_self_add_power, true))
return command_result{permission::i_channel_group_self_add_power};
}
auto client_permission_modify_power = this->calculate_permission_value(permission::i_client_permission_modify_power, channel_id);
auto client_permission_modify_power = this->calculate_permission(permission::i_client_permission_modify_power, channel_id);
auto client_needed_permission_modify_power = this->server->calculatePermission2(
permission::i_client_needed_permission_modify_power, target_cldbid, ClientType::CLIENT_TEAMSPEAK, channel_id);
@ -3466,12 +3466,12 @@ command_result ConnectedClient::handleCommandSetClientChannelGroup(Command &cmd)
{
auto old_group = this->server->groups->getChannelGroupExact(target_cldbid, channel, false);
if(old_group) {
auto channel_group_member_remove_power = this->calculate_permission_value(permission::i_channel_group_member_remove_power, channel_id);
auto channel_group_member_remove_power = this->calculate_permission(permission::i_channel_group_member_remove_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_member_remove_power, true)) {
if(target_cldbid != this->getClientDatabaseId())
return command_result{permission::i_channel_group_member_remove_power};
auto channel_group_self_remove_power = this->calculate_permission_value(permission::i_channel_group_self_remove_power, channel_id);
auto channel_group_self_remove_power = this->calculate_permission(permission::i_channel_group_self_remove_power, channel_id);
if(!serverGroup->permission_granted(permission::i_channel_group_needed_member_remove_power, channel_group_self_remove_power, true))
return command_result{permission::i_channel_group_self_remove_power};
}
@ -3534,7 +3534,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
PERM_CHECK_CHANNELR(permission::b_client_even_textmessage_send, 1, this->currentChannel, true);
}
PERM_CHECK_CHANNELR(permission::i_client_private_textmessage_power, target->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_private_textmessage_power, target->currentChannel), this->currentChannel, false);
PERM_CHECK_CHANNELR(permission::i_client_private_textmessage_power, target->permissionValue(permission::i_client_needed_private_textmessage_power, target->currentChannel), this->currentChannel, false);
{
@ -3568,7 +3568,7 @@ command_result ConnectedClient::handleCommandSendTextMessage(Command &cmd) {
channel_tree_read_lock.lock();
}
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_channel_textmessage_send, 1, channel, false))
if(!this->permissionGranted(permission::b_client_channel_textmessage_send, 1, channel, false))
return command_result{permission::b_client_channel_textmessage_send};
bool conversation_private = channel->properties()[property::CHANNEL_FLAG_CONVERSATION_PRIVATE].as<bool>();
@ -3715,7 +3715,7 @@ command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
CHANNEL_PERMISSION_TEST(permission::i_ft_file_browse_power, permission::i_ft_needed_file_browse_power, channel, true);
cmd_filelist_append_files(
@ -3759,7 +3759,7 @@ command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
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"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
CHANNEL_PERMISSION_TEST(permission::i_ft_directory_create_power, permission::i_ft_needed_directory_create_power, channel, true);
@ -3780,7 +3780,7 @@ command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
CHANNEL_PERMISSION_TEST(permission::i_ft_file_delete_power, permission::i_ft_needed_file_delete_power, channel, true);
for (int index = 0; index < cmd.bulkCount(); index++)
@ -3834,17 +3834,17 @@ command_result ConnectedClient::handleCommandFTInitUpload(Command &cmd) {
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
CHANNEL_PERMISSION_TEST(permission::i_ft_file_upload_power, permission::i_ft_needed_file_upload_power, channel, true);
directory = serverInstance->getFileServer()->resolveDirectory(this->server, channel);
} else {
if (cmd["path"].as<std::string>().empty() && cmd["name"].as<std::string>().find("/icon_") == 0) {
auto max_size = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_max_icon_filesize, this->currentChannel);
auto max_size = this->permissionValue(permission::i_max_icon_filesize, this->currentChannel);
if(max_size != -1 && max_size < (ssize_t) cmd["size"].as<size_t>()) return command_result{permission::i_max_icon_filesize};
directory = serverInstance->getFileServer()->iconDirectory(this->server);
} else if (cmd["path"].as<std::string>().empty() && cmd["name"].string() == "/avatar") {
auto max_size = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_max_avatar_filesize, this->currentChannel);
auto max_size = this->permissionValue(permission::i_client_max_avatar_filesize, this->currentChannel);
if(max_size != -1 && max_size < (ssize_t) cmd["size"].as<size_t>()) return command_result{permission::i_client_max_avatar_filesize};
directory = serverInstance->getFileServer()->avatarDirectory(this->server);
@ -3870,7 +3870,7 @@ command_result ConnectedClient::handleCommandFTInitUpload(Command &cmd) {
server_used_quota += trans->remaining_bytes();
if(server_quota >= 0 && server_quota * 1024 * 1024 < (int64_t) server_used_quota) return command_result{error::file_transfer_server_quota_exceeded};
auto client_quota = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_ft_quota_mb_upload_per_client, this->currentChannel);
auto client_quota = this->permissionValue(permission::i_ft_quota_mb_upload_per_client, this->currentChannel);
auto client_used_quota = this->properties()[property::CLIENT_MONTH_BYTES_UPLOADED].as<size_t>();
client_used_quota += cmd["size"].as<uint64_t>();
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers(_this.lock()))
@ -3932,7 +3932,7 @@ command_result ConnectedClient::handleCommandFTInitDownload(Command &cmd) {
if (!channel) return command_result{error::channel_invalid_id, "Cant resolve channel"};
CHANNEL_PERMISSION_TEST(permission::i_ft_file_download_power, permission::i_ft_needed_file_download_power, channel, true);
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
directory = serverInstance->getFileServer()->resolveDirectory(this->server, channel);
@ -3970,7 +3970,7 @@ command_result ConnectedClient::handleCommandFTInitDownload(Command &cmd) {
if(server_quota >= 0 && server_quota * 1024 * 1024 < (int64_t) server_used_quota) return command_result{error::file_transfer_server_quota_exceeded};
auto client_quota = this->permissionValue(permission::PERMTEST_ORDERED, permission::i_ft_quota_mb_download_per_client, this->currentChannel);
auto client_quota = this->permissionValue(permission::i_ft_quota_mb_download_per_client, this->currentChannel);
auto client_used_quota = this->properties()[property::CLIENT_MONTH_BYTES_DOWNLOADED].as<size_t>();
client_used_quota += key->size;
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers(_this.lock()))
@ -4042,7 +4042,7 @@ command_result ConnectedClient::handleCommandFTGetFileInfo(ts::Command &cmd) {
if (request.has("cid") && request["cid"].as<ChannelId>() != 0) { //Channel
auto channel = this->server->channelTree->findChannel(request["cid"].as<ChannelId>());
if (!channel) return command_result{error::channel_invalid_id, "Cant resolve channel"};
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_ft_ignore_password, 1, channel, true))
if (!channel->passwordMatch(cmd["cpw"]) && !this->permissionGranted(permission::b_ft_ignore_password, 1, channel, true))
return cmd["cpw"].string().empty() ? command_result{permission::b_ft_ignore_password} : command_result{error::channel_invalid_password};
CHANNEL_PERMISSION_TEST(permission::i_ft_file_browse_power, permission::i_ft_needed_file_browse_power, channel, true);
@ -4097,7 +4097,7 @@ command_result ConnectedClient::handleCommandBanList(Command &cmd) {
auto server = serverInstance->getVoiceServerManager()->findServerById(sid);
if (!server) return command_result{error::parameter_invalid};
if (server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_client_ban_list, this->getType(), nullptr) != 1)
if (server->calculatePermission(this->getClientDatabaseId(), permission::b_client_ban_list, this->getType(), nullptr) != 1)
return command_result{permission::b_client_ban_list};
}
@ -4159,7 +4159,7 @@ command_result ConnectedClient::handleCommandBanAdd(Command &cmd) {
} else {
auto server = serverInstance->getVoiceServerManager()->findServerById(sid);
if (!server) return command_result{error::parameter_invalid};
if (server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_client_ban_create, this->getType(), nullptr) != 1)
if (server->calculatePermission(this->getClientDatabaseId(), permission::b_client_ban_create, this->getType(), nullptr) != 1)
return command_result{permission::b_client_ban_create_global};
}
@ -4210,7 +4210,7 @@ command_result ConnectedClient::handleCommandBanEdit(Command &cmd) {
auto server = serverInstance->getVoiceServerManager()->findServerById(sid);
if (!server) return command_result{error::parameter_invalid};
if (server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_client_ban_edit, this->getType(), nullptr) != 1) return command_result{permission::b_client_ban_edit};
if (server->calculatePermission(this->getClientDatabaseId(), permission::b_client_ban_edit, this->getType(), nullptr) != 1) return command_result{permission::b_client_ban_edit};
}
/* ip name uid reason time hwid */
@ -4298,9 +4298,9 @@ command_result ConnectedClient::handleCommandBanClient(Command &cmd) {
return command_result{error::client_unknown};
}
if (target_dbid != 0) {
if (this->server->calculatePermission(permission::PERMTEST_ORDERED, target_dbid, permission::i_client_needed_ban_power, ClientType::CLIENT_TEAMSPEAK, nullptr) > this->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_ban_power))
if (this->server->calculatePermission(target_dbid, permission::i_client_needed_ban_power, ClientType::CLIENT_TEAMSPEAK, nullptr) > this->permissionValue(permission::i_client_ban_power))
return command_result{permission::i_client_ban_power};
if (this->server->calculatePermission(permission::PERMTEST_ORDERED, target_dbid, permission::b_client_ignore_bans, ClientType::CLIENT_TEAMSPEAK, nullptr) >= 1) return command_result{permission::b_client_ignore_bans};
if (this->server->calculatePermission(target_dbid, permission::b_client_ignore_bans, ClientType::CLIENT_TEAMSPEAK, nullptr) >= 1) return command_result{permission::b_client_ignore_bans};
}
deque<BanId> ban_ids;
auto _id = serverInstance->banManager()->registerBan(this->getServer()->getServerId(), this->getClientDatabaseId(), reason, uid, "", "", "", until);
@ -4376,7 +4376,7 @@ command_result ConnectedClient::handleCommandBanDel(Command &cmd) {
if (!server) return command_result{error::parameter_invalid};
auto perm = ban->invokerDbId == this->getClientDatabaseId() ? permission::b_client_ban_delete_own : permission::b_client_ban_delete;
if (server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), perm, this->getType(), nullptr) != 1) return command_result{perm};
if (server->calculatePermission(this->getClientDatabaseId(), perm, this->getType(), nullptr) != 1) return command_result{perm};
}
serverInstance->banManager()->unban(ban);
return command_result{error::ok};
@ -4763,7 +4763,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
PERM_CHECKR(permission::b_client_modify_own_description, 1, true);
else if(client->getType() == ClientType::CLIENT_MUSIC) {
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
} else {
PERM_CHECKR(permission::b_client_modify_description, 1, true);
@ -4784,7 +4784,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
if(!self) {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_rename_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_rename_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_rename_power, client->permissionValue(permission::i_client_music_needed_rename_power, client->currentChannel), true);
}
}
@ -4792,7 +4792,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
if (count_characters(name) < 3) return command_result{error::parameter_invalid, "Invalid name length. A minimum of 3 characters is required!"};
if (count_characters(name) > 30) return command_result{error::parameter_invalid, "Invalid name length. A maximum of 30 characters is allowed!"};
auto banIgnore = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_ignore_bans, 1, this->currentChannel);
auto banIgnore = this->permissionGranted(permission::b_client_ignore_bans, 1, this->currentChannel);
if (!banIgnore) {
auto banRecord = serverInstance->banManager()->findBanByName(this->getServerId(), name);
if (banRecord)
@ -4817,7 +4817,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
} else if(*info == property::CLIENT_PLAYER_VOLUME) {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
auto bot = dynamic_pointer_cast<MusicClient>(client);
assert(bot);
@ -4831,7 +4831,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
if(!self) {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
}
@ -4844,7 +4844,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
if(client->getType() != ClientType::CLIENT_MUSIC)
return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
}
@ -4871,7 +4871,7 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
index++;
} while (index < str.length() && index != 0);
if (badgesTags >= 2) {
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_allow_invalid_badges, 1, this->currentChannel))
if (!this->permissionGranted(permission::b_client_allow_invalid_badges, 1, this->currentChannel))
((VoiceClient *) this)->disconnect(VREASON_SERVER_KICK, config::messages::kick_invalid_badges, this->server ? this->server->serverAdmin : dynamic_pointer_cast<ConnectedClient>(serverInstance->getInitialServerAdmin()), true);
return command_result{error::parameter_invalid, "Invalid badges"};
}
@ -4879,27 +4879,27 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std:
} else if(!self && key == "client_version") {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
} else if(!self && key == "client_platform") {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
} else if(!self && key == "client_country") {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
} else if(!self && (*info == property::CLIENT_FLAG_NOTIFY_SONG_CHANGE/* || *info == property::CLIENT_NOTIFY_SONG_MESSAGE*/)) {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
} else if(!self && key == "client_uptime_mode") {
if(client->getType() != ClientType::CLIENT_MUSIC) return command_result{error::client_invalid_type};
if(client->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId()) {
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_modify_power, client->currentChannel), true);
CACHED_PERM_CHECK(permission::i_client_music_modify_power, client->permissionValue(permission::i_client_music_needed_modify_power, client->currentChannel), true);
}
if(cmd[key].as<MusicClient::UptimeMode::value>() == MusicClient::UptimeMode::TIME_SINCE_SERVER_START) {
@ -5253,10 +5253,10 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) {
return command_result{error::client_invalid_id};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool conOnError = cmd[0].has("continueonerror");
auto update_channels = false;
for (int index = 0; index < cmd.bulkCount(); index++) {
@ -5266,7 +5266,7 @@ command_result ConnectedClient::handleCommandClientAddPerm(Command &cmd) {
if(permission_require_granted_value(permType) && val > maxValue)
return command_result{permission::i_permission_modify_power};
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -5299,16 +5299,16 @@ command_result ConnectedClient::handleCommandClientDelPerm(Command &cmd) {
if(!serverInstance->databaseHelper()->validClientDatabaseId(this->server, cldbid))
return command_result{error::client_invalid_id};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(cldbid, permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool conOnError = cmd[0].has("continueonerror");
auto onlineClients = this->server->findClientsByCldbId(cmd["cldbid"]);
auto update_channel = false;
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd)
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
@ -5411,19 +5411,19 @@ command_result ConnectedClient::handleCommandChannelClientDelPerm(Command &cmd)
return command_result{error::parameter_invalid, "Invalid manager db id"};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
PERM_CHECKR(permission::i_client_permission_modify_power, this->server->calculatePermission(cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, nullptr), true);
RESOLVE_CHANNEL_R(cmd["cid"], true);
auto channel = dynamic_pointer_cast<ServerChannel>(l_channel->entry);
if(!channel) return command_result{error::vs_critical};
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool conOnError = cmd[0].has("continueonerror"), update_view = false;
auto cll = this->server->findClientsByCldbId(cldbid);
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -5479,11 +5479,11 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
if(!channel) return command_result{error::vs_critical};
auto mgr = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, cldbid);
PERM_CHECK_CHANNELR(permission::i_client_permission_modify_power, this->server->calculatePermission(permission::PERMTEST_ORDERED, cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, channel), channel, true);
PERM_CHECK_CHANNELR(permission::i_client_permission_modify_power, this->server->calculatePermission(cmd["cldbid"], permission::i_client_needed_permission_modify_power, ClientType::CLIENT_TEAMSPEAK, channel), channel, true);
auto maxValue = this->getPermissionGrantValue(permission::PERMTEST_ORDERED, permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_permission_modify_power_ignore, 1, this->currentChannel);
auto maxValue = this->getPermissionGrantValue(permission::i_permission_modify_power, this->currentChannel);
bool ignoreGrant = this->permissionGranted(permission::b_permission_modify_power_ignore, 1, this->currentChannel);
bool conOnError = cmd[0].has("continueonerror");
auto onlineClientInstances = this->server->findClientsByCldbId(cldbid);
bool update_view = false;
@ -5494,7 +5494,7 @@ command_result ConnectedClient::handleCommandChannelClientAddPerm(Command &cmd)
if(permission_require_granted_value(permType) && val > maxValue)
return command_result{permission::i_permission_modify_power};
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
@ -5872,7 +5872,7 @@ command_result ConnectedClient::handleCommandPermGet(Command &cmd) {
}
int index = 0;
for(const auto& entry : this->permissionValues(permission::PERMTEST_ORDERED, requrested, this->currentChannel)) {
for(const auto& entry : this->permissionValues(requrested, this->currentChannel)) {
res[index]["permsid"] = permission_mapper->permission_name(type, entry.first);;
res[index]["permid"] = entry.first;
res[index++]["permvalue"] = entry.second;
@ -6374,7 +6374,7 @@ command_result ConnectedClient::handleCommandComplainAdd(Command &cmd) {
auto cl = this->server->findClientsByCldbId(target);
if (cl.empty()) return command_result{error::client_invalid_id};
PERM_CHECKR(permission::i_client_complain_power, cl[0]->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_needed_complain_power), true);
PERM_CHECKR(permission::i_client_complain_power, cl[0]->permissionValue(permission::i_client_needed_complain_power), true);
/*
if(!serverInstance->databaseHelper()->validClientDatabaseId(target))
@ -6488,7 +6488,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
}
auto permissions_list = this->permissionValues(permission::PERMTEST_ORDERED, {
auto permissions_list = this->permissionValues({
permission::i_client_music_limit,
permission::b_client_music_create_permanent,
permission::b_client_music_create_semi_permanent,
@ -6543,7 +6543,7 @@ command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
if(cmd[0].has("cid")) return command_result{error::channel_invalid_id};
} else {
CHANNEL_PERMISSION_TEST(permission::i_channel_description_view_power, permission::i_channel_needed_description_view_power, channel, false);
auto permission_granted = this->calculate_permission_value(permission::i_channel_join_power, channel->channelId());
auto permission_granted = this->calculate_permission(permission::i_channel_join_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_join_power, permission_granted, false))
channel = nullptr;
}
@ -6600,7 +6600,7 @@ command_result ConnectedClient::handleCommandMusicBotDelete(Command& cmd) {
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
bool permPower = this->permissionGranted(permission::PERMTEST_ORDERED, permission::i_client_music_delete_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_delete_power));
bool permPower = this->permissionGranted(permission::i_client_music_delete_power, bot->permissionValue(permission::i_client_music_needed_delete_power));
if(bot->getOwner() != this->getClientDatabaseId()) {
if(!permPower) return command_result{permission::i_client_music_delete_power};
}
@ -6697,7 +6697,7 @@ command_result ConnectedClient::handleCommandMusicBotPlayerAction(Command& cmd)
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
if(cmd["action"] == 0) {
bot->stopMusic();
@ -6963,7 +6963,7 @@ command_result ConnectedClient::handleCommandPlaylistAddPerm(ts::Command &cmd) {
if(permission_require_granted_value(permType) && val > maxValue)
return command_result{permission::i_permission_modify_power};
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -6994,7 +6994,7 @@ command_result ConnectedClient::handleCommandPlaylistDelPerm(ts::Command &cmd) {
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignoreGrant && !this->permissionGrantGranted(permission::PERMTEST_ORDERED, permType, 1, this->currentChannel))
if(!ignoreGrant && !this->permissionGrantGranted(permType, 1, this->currentChannel))
return command_result{permission::i_permission_modify_power};
if (grant) {
@ -7128,7 +7128,7 @@ command_result ConnectedClient::handleCommandMusicBotQueueList(Command& cmd) {
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_info, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_info, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_info, bot->permissionValue(permission::i_client_music_needed_info, bot->currentChannel), this->currentChannel, true);
bool bulked = cmd.hasParm("bulk") || cmd.hasParm("balk") || cmd.hasParm("pipe") || cmd.hasParm("bar") || cmd.hasParm("paypal");
@ -7209,7 +7209,7 @@ command_result ConnectedClient::handleCommandMusicBotQueueAdd(Command& cmd) {
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
MusicClient::loader_t loader;
auto& type = cmd[0]["type"];
@ -7245,7 +7245,7 @@ command_result ConnectedClient::handleCommandMusicBotQueueRemove(Command& cmd) {
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
std::deque<std::shared_ptr<music::SongInfo>> songs;
for(int index = 0; index < cmd.bulkCount(); index++) {
@ -7277,7 +7277,7 @@ command_result ConnectedClient::handleCommandMusicBotQueueReorder(Command& cmd)
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
auto entry = bot->queue()->find_queue(cmd["song_id"]);
if(!entry) return command_result{error::database_empty_result};
@ -7299,7 +7299,7 @@ command_result ConnectedClient::handleCommandMusicBotPlaylistAssign(ts::Command
auto bot = ref_server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
if(bot->getOwner() != this->getClientDatabaseId())
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::PERMTEST_ORDERED, permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id};
@ -7530,8 +7530,8 @@ command_result ConnectedClient::handleCommandQueryList(ts::Command &cmd) {
if(!server && server_id != EmptyServerId && server_id != 0)
return command_result{error::server_invalid_id};
auto global_list = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_list, 1, nullptr, true, nullptr, server, true);
auto own_list = global_list || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_list_own, 1, nullptr, true, nullptr, server, true);
auto global_list = this->permissionGranted(permission::b_client_query_list, 1, nullptr, true, nullptr, server, true);
auto own_list = global_list || this->permissionGranted(permission::b_client_query_list_own, 1, nullptr, true, nullptr, server, true);
if(!own_list && !global_list)
return command_result{permission::b_client_query_list};
@ -7575,7 +7575,7 @@ command_result ConnectedClient::handleCommandQueryCreate(ts::Command &cmd) {
if(!server && server_id != EmptyServerId && server_id != 0)
return command_result{error::server_invalid_id};
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_create, 1, nullptr, true, nullptr, server, true))
if(!this->permissionGranted(permission::b_client_query_create, 1, nullptr, true, nullptr, server, true))
return command_result{permission::b_client_query_create};
auto username = cmd["client_login_name"].as<string>();
@ -7613,8 +7613,8 @@ command_result ConnectedClient::handleCommandQueryDelete(ts::Command &cmd) {
return command_result{error::server_invalid_id};
*/
auto delete_all = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_delete, 1, nullptr, true, nullptr, server, true);
auto delete_own = delete_all || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_delete_own, 1, nullptr, true, nullptr, server, true);
auto delete_all = this->permissionGranted(permission::b_client_query_delete, 1, nullptr, true, nullptr, server, true);
auto delete_own = delete_all || this->permissionGranted(permission::b_client_query_delete_own, 1, nullptr, true, nullptr, server, true);
if(account->unique_id == this->getUid()) {
if(!delete_own)
@ -7643,8 +7643,8 @@ command_result ConnectedClient::handleCommandQueryRename(ts::Command &cmd) {
if(!server && account->bound_server != 0)
return command_result{error::server_invalid_id};
auto rename_all = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_rename, 1, nullptr, true, nullptr, server, true);
auto rename_own = rename_all || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_rename_own, 1, nullptr, true, nullptr, server, true);
auto rename_all = this->permissionGranted(permission::b_client_query_rename, 1, nullptr, true, nullptr, server, true);
auto rename_own = rename_all || this->permissionGranted(permission::b_client_query_rename_own, 1, nullptr, true, nullptr, server, true);
if(account->unique_id == this->getUid()) {
if(!rename_own)
@ -7676,8 +7676,8 @@ command_result ConnectedClient::handleCommandQueryChangePassword(ts::Command &cm
if(!server && account->bound_server != 0)
return command_result{error::server_invalid_id};
auto change_all = this->permissionGranted(permission::PERMTEST_ORDERED, server ? permission::b_client_query_change_password : permission::b_client_query_change_password_global, 1, nullptr, true, nullptr, server, true);
auto change_own = change_all || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_query_change_own_password, 1, nullptr, true, nullptr, server, true);
auto change_all = this->permissionGranted(server ? permission::b_client_query_change_password : permission::b_client_query_change_password_global, 1, nullptr, true, nullptr, server, true);
auto change_own = change_all || this->permissionGranted(permission::b_client_query_change_own_password, 1, nullptr, true, nullptr, server, true);
auto password = cmd[0].has("client_login_password") ? cmd["client_login_password"].as<string>() : "";
@ -7707,7 +7707,7 @@ command_result ConnectedClient::handleCommandDummy_IpChange(ts::Command &cmd) {
CMD_REF_SERVER(server);
logMessage(this->getServerId(), "[{}] Address changed from {} to {}", CLIENT_STR_LOG_PREFIX, cmd["old_ip"].string(), cmd["new_ip"].string());
if(geoloc::provider_vpn && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_ignore_vpn, 1)) {
if(geoloc::provider_vpn && !this->permissionGranted(permission::b_client_ignore_vpn, 1)) {
auto provider = this->isAddressV4() ? geoloc::provider_vpn->resolveInfoV4(this->getPeerIp(), true) : geoloc::provider_vpn->resolveInfoV6(this->getPeerIp(), true);
if(provider) {
this->disconnect(strvar::transform(ts::config::messages::kick_vpn, strvar::StringValue{"provider.name", provider->name}, strvar::StringValue{"provider.website", provider->side}));
@ -7764,10 +7764,10 @@ command_result ConnectedClient::handleCommandConversationHistory(ts::Command &co
command[0]["cpw"] = "";
if (!channel->passwordMatch(command["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true))
if (!this->permissionGranted(permission::b_channel_join_ignore_password, 1, channel, true))
return command_result{error::channel_invalid_password, "invalid password"};
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true)) {
if(!this->permissionGranted(permission::b_channel_ignore_join_power, 1, channel, true)) {
CHANNEL_PERMISSION_TEST(permission::i_channel_join_power, permission::i_channel_needed_join_power, channel, false);
}
}
@ -7894,15 +7894,15 @@ command_result ConnectedClient::handleCommandConversationFetch(ts::Command &cmd)
bulk["cpw"] = "";
if (!channel->passwordMatch(bulk["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true)) {
if (!this->permissionGranted(permission::b_channel_join_ignore_password, 1, channel, true)) {
auto error = findError("channel_invalid_password");
result_bulk["error_id"] = error.errorId;
result_bulk["error_msg"] = error.message;
continue;
}
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true)) {
auto permission_granted = this->calculate_permission_value(permission::i_channel_join_power, channel->channelId());
if(!this->permissionGranted(permission::b_channel_ignore_join_power, 1, channel, true)) {
auto permission_granted = this->calculate_permission(permission::i_channel_join_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_join_power, permission_granted, false)) {
auto error = findError("server_insufficeient_permissions");
result_bulk["error_id"] = error.errorId;
@ -7966,14 +7966,14 @@ command_result ConnectedClient::handleCommandConversationMessageDelete(ts::Comma
bulk["cpw"] = "";
if (!channel->passwordMatch(bulk["cpw"], true))
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_join_ignore_password, 1, channel, true))
if (!this->permissionGranted(permission::b_channel_join_ignore_password, 1, channel, true))
return command_result{error::channel_invalid_password};
if (!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_conversation_message_delete, 1, channel))
if (!this->permissionGranted(permission::b_channel_conversation_message_delete, 1, channel))
return command_result{permission::b_channel_conversation_message_delete};
if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_channel_ignore_join_power, 1, channel, true)) {
auto permission_granted = this->calculate_permission_value(permission::i_channel_join_power, channel->channelId());
if(!this->permissionGranted(permission::b_channel_ignore_join_power, 1, channel, true)) {
auto permission_granted = this->calculate_permission(permission::i_channel_join_power, channel->channelId());
if(!channel->permission_granted(permission::i_channel_needed_join_power, permission_granted, false))
return command_result{permission::i_channel_needed_join_power};
}

View File

@ -13,6 +13,7 @@
#include <misc/sassert.h>
#include <misc/timer.h>
#include "./web/WebClient.h"
#include "query/command3.h"
using namespace std::chrono;
using namespace std;
@ -35,6 +36,18 @@ do { \
} \
} while(0)
#define INVOKER_NEW(command, invoker) \
do { \
if(invoker) { \
command.put_unchecked(0, "invokerid", invoker->getClientId()); \
command.put_unchecked(0, "invokername", invoker->getDisplayName()); \
command.put_unchecked(0, "invokeruid", invoker->getUid()); \
} else { \
command.put_unchecked(0, "invokerid", "0"); \
command.put_unchecked(0, "invokername", "undefined"); \
command.put_unchecked(0, "invokeruid", "undefined"); \
} \
} while(0)
bool ConnectedClient::notifyServerGroupList() {
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyservergrouplist" : "");
@ -65,30 +78,34 @@ bool ConnectedClient::notifyServerGroupList() {
bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<Group>& group, bool as_sid) {
Command cmd(this->getExternalType() == CLIENT_TEAMSPEAK ? group->target() == GROUPTARGET_SERVER ? "notifyservergrouppermlist" : "notifychannelgrouppermlist" : "");
ts::command_builder result{this->getExternalType() == CLIENT_TEAMSPEAK ? group->target() == GROUPTARGET_SERVER ? "notifyservergrouppermlist" : "notifychannelgrouppermlist" : ""};
if (group->target() == GROUPTARGET_SERVER)
cmd["sgid"] = group->groupId();
result.put_unchecked(0, "sgid", group->groupId());
else
cmd["cgid"] = group->groupId();
result.put_unchecked(0, "cgid", group->groupId());
int index = 0;
auto permissions = group->permissions()->permissions();
auto permission_mapper = serverInstance->getPermissionMapper();
auto client_type = this->getType();
result.reserve_bulks(permissions.size() * 2);
for (const auto &permission_data : permissions) {
auto& permission = get<1>(permission_data);
if(!permission.flags.value_set)
continue;
if(as_sid) {
cmd[index]["permsid"] = permission_mapper->permission_name(client_type, get<0>(permission_data));
result.put_unchecked(index, "permsid", permission_mapper->permission_name(client_type, get<0>(permission_data)));
} else {
cmd[index]["permid"] = (uint16_t) get<0>(permission_data);
result.put_unchecked(index, "permid", (uint16_t) get<0>(permission_data));
}
cmd[index]["permvalue"] = permission.values.value;
cmd[index]["permnegated"] = permission.flags.negate;
cmd[index]["permskip"] = permission.flags.skip;
result.put_unchecked(index, "permvalue", permission.values.value);
result.put_unchecked(index, "permnegated", permission.flags.negate);
result.put_unchecked(index, "permskip", permission.flags.skip);
index++;
}
for (const auto &permission_data : permissions) {
@ -96,21 +113,23 @@ bool ConnectedClient::notifyGroupPermList(const std::shared_ptr<Group>& group, b
if(!permission.flags.grant_set)
continue;
if(as_sid) {
cmd[index]["permsid"] = permission_mapper->permission_name_grant(client_type, get<0>(permission_data));
result.put_unchecked(index, "permsid", permission_mapper->permission_name_grant(client_type, get<0>(permission_data)));
} else {
cmd[index]["permid"] = (uint16_t) (get<0>(permission_data) | PERM_ID_GRANT);
result.put_unchecked(index, "permid", (uint16_t) (get<0>(permission_data) | PERM_ID_GRANT));
}
cmd[index]["permvalue"] = permission.values.grant;
cmd[index]["permnegated"] = permission.flags.negate;
cmd[index]["permskip"] = permission.flags.skip;
result.put_unchecked(index, "permvalue", permission.values.value);
result.put_unchecked(index, "permnegated", permission.flags.negate);
result.put_unchecked(index, "permskip", permission.flags.skip);
index++;
}
if (index == 0)
return false;
this->sendCommand(cmd);
this->sendCommand(result); //Need hack
return true;
}
@ -341,7 +360,7 @@ bool ConnectedClient::notifyConnectionInfo(const shared_ptr<ConnectedClient> &ta
}
}
if(target->getClientId() == this->getClientId() || this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_remoteaddress_view, 1, target->currentChannel, true)) {
if(target->getClientId() == this->getClientId() || permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_remoteaddress_view, this->getChannelId()))) {
notify["connection_client_ip"] = target->getLoggingPeerIp();
notify["connection_client_port"] = target->getPeerPort();
}
@ -569,29 +588,29 @@ bool ConnectedClient::notifyClientEnterView(const std::shared_ptr<ConnectedClien
break;
}
Command cmd("notifycliententerview");
ts::command_builder builder{"notifycliententerview", 1024, 1};
cmd["cfid"] = from ? from->channelId() : 0;
cmd["ctid"] = to ? to->channelId() : 0;
cmd["reasonid"] = reasonId;
INVOKER(cmd, invoker);
builder.put_unchecked(0, "cfid", from ? from->channelId() : 0);
builder.put_unchecked(0, "ctid", to ? to->channelId() : 0);
builder.put_unchecked(0, "reasonid", reasonId);
INVOKER_NEW(builder, invoker);
switch (reasonId) {
case ViewReasonId::VREASON_MOVED:
case ViewReasonId::VREASON_BAN:
case ViewReasonId::VREASON_CHANNEL_KICK:
case ViewReasonId::VREASON_SERVER_KICK:
cmd["reasonmsg"] = reason;
builder.put_unchecked(0, "reasonmsg", reason);
break;
default:
break;
}
for (const auto &elm : client->properties()->list_properties(property::FLAG_CLIENT_VIEW, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0)) {
cmd[elm.type().name] = elm.value();
builder.put_unchecked(0, elm.type().name, elm.value());
}
visibleClients.emplace_back(client);
this->sendCommand(cmd);
this->sendCommand(builder);
return true;
}

View File

@ -66,8 +66,8 @@ inline string filterUrl(string in){
}
inline void permissionableCommand(ConnectedClient* client, stringstream& ss, const std::string& cmd, permission::PermissionType perm, permission::PermissionType sec = permission::unknown) {
auto permA = perm == permission::unknown || client->permissionGranted(permission::PERMTEST_ORDERED, perm, 1, client->getChannel(), true);
auto permB = permA || (sec != permission::unknown && client->permissionGranted(permission::PERMTEST_ORDERED, sec, 1, client->getChannel(), true));
auto permA = perm == permission::unknown || permission::v2::permission_granted(1, client->calculate_permission(perm, client->getChannelId()));
auto permB = permA || (sec != permission::unknown && permission::v2::permission_granted(1, client->calculate_permission(sec, client->getChannelId())));
if(!(permA || permB)) {
ss << "[color=red]" << cmd << "[/color]" << endl;
} else {
@ -98,7 +98,8 @@ bool ConnectedClient::handleTextMessage(ChatMessageMode mode, std::string text,
#define PERM_CHECK_BOT(perm, reqperm, err) \
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::perm, this->permissionValue(permission::PERMTEST_ORDERED, permission::reqperm, this->currentChannel), this->currentChannel, true)) { \
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && \
!permission::v2::permission_granted(bot->calculate_permission(permission::reqperm, bot->getChannelId()), this->calculate_permission(permission::perm, bot->getChannelId()))) { \
send_message(serverInstance->musicRoot(), err); \
return true; \
}
@ -170,7 +171,7 @@ bool ConnectedClient::handle_text_command(
server = true;
string locationStr = server ? "on this server" : "in this channel";
if(!this->permissionGranted(permission::PERMTEST_ORDERED, server ? permission::b_client_music_server_list : permission::b_client_music_channel_list, 1, this->currentChannel, true)) {
if(!permission::v2::permission_granted(1, this->calculate_permission(server ? permission::b_client_music_server_list : permission::b_client_music_channel_list, this->getChannelId()))) {
send_message(serverInstance->musicRoot(), "You don't have the permission to list all music bots " + locationStr);
return true;
}
@ -197,7 +198,9 @@ bool ConnectedClient::handle_text_command(
auto botId = static_cast<ClientDbId>(stoll(arguments[1]));
auto bot = this->server->musicManager->findBotById(botId);
if (!bot) ERR(serverInstance->musicRoot(), "Could not find target bot");
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_music_channel_list, 1, this->currentChannel, true) && !this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_music_server_list, 1, this->currentChannel, true)) { //No perms for listing
if(bot->properties()[property::CLIENT_OWNER] != this->getClientDatabaseId() &&
!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_channel_list, this->getChannelId())) &&
!permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_server_list, this->getChannelId()))) { //No perms for listing
send_message(serverInstance->musicRoot(), "You don't have the permission to select a music bot");
return true;
}
@ -430,9 +433,9 @@ bool ConnectedClient::handle_text_command(
return true;
}
auto max_volume = this->cached_permission_value(permission::i_client_music_create_modify_max_volume);
if(max_volume != permNotGranted && !this->permission_granted(max_volume, volume, true)) {
send_message(bot, "You don't have the permission to use higher volumes that " + to_string(max_volume) + "%");
auto max_volume = this->calculate_permission(permission::i_client_music_create_modify_max_volume, 0);
if(max_volume.has_value && !permission::v2::permission_granted(volume, max_volume)) {
send_message(bot, "You don't have the permission to use higher volumes that " + to_string(max_volume.value) + "%");
return true;
}
@ -567,8 +570,8 @@ bool ConnectedClient::handle_text_command(
stringstream ss;
ss << "Available music bot commands: ([color=green]green[/color] = permission granted | [color=red]red[/color] = insufficient permissions)" << endl;
bool has_list_server = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_music_server_list, 1, this->currentChannel);
bool has_list_channel = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_client_music_channel_list, 1, this->currentChannel);
bool has_list_server = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_server_list, this->getChannelId()));
bool has_list_channel = permission::v2::permission_granted(1, this->calculate_permission(permission::b_client_music_channel_list, this->getChannelId()));
permissionableCommand(this, ss, string() + " .mbot list [<[color=" + (has_list_server ? "green" : "red") + "]server[/color]|[color=" + (has_list_channel ? "green" : "red") + "]channel[/color]>]", permission::b_client_music_channel_list, permission::b_client_music_server_list);
permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot select <id>", permission::b_client_music_channel_list, permission::b_client_music_server_list);
permissionableCommand(this, ss, " " + ts::config::music::command_prefix + "mbot formats", permission::unknown);

View File

@ -130,126 +130,32 @@ bool DataClient::loadDataForCurrentServer() { //TODO for query
return true;
}
permission::v2::PermissionFlaggedValue DataClient::permissionValueFlagged(permission::PermissionType type, const std::shared_ptr<BasicChannel>& target, std::shared_ptr<CalculateCache> cache, std::shared_ptr<TSServer> server, bool server_defined) {
if(!server_defined && !server)
server = this->server;
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> DataClient::calculate_permissions(
const std::deque<permission::PermissionType> &permissions,
ChannelId channel,
bool granted,
std::shared_ptr<CalculateCache> cache) {
if(permissions.empty()) return {};
if(server) {
auto result = server->calculatePermissions2(this->getClientDatabaseId(), {type}, this->getType(), target ? target->channelId() : 0, false, cache);
if(result.empty() || result[0].first != type)
return permission::v2::empty_permission_flagged_value;
return result[0].second;
} else {
/* if you're not bound to a channel then you cant be bound to a server as well. */
bool permission_set = false;
permission::PermissionValue result = permNotGranted;
for(const auto &gr : serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType())){
auto group_permissions = gr->group->permissions();
auto flagged_permissions = group_permissions->permission_value_flagged(type);
if(flagged_permissions.has_value) {
if(flagged_permissions.value > result || flagged_permissions.value == -1) {
result = flagged_permissions.value;
permission_set = true;
}
}
}
return {result, permission_set};
}
if(!cache)
cache = std::make_shared<CalculateCache>();
if(!cache->client_permissions) /* so we don't have to load that shit later */
cache->client_permissions = this->clientPermissions;
if(channel == -1)
channel = this->currentChannel ? this->currentChannel->channelId() : 0;
auto ref_server = this->server;
if(ref_server)
return ref_server->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
else
return serverInstance->calculate_permissions(permissions, this->getClientDatabaseId(), this->getType(), channel, granted, cache);
}
permission::PermissionValue DataClient::permissionValue(permission::PermissionTestType test, permission::PermissionType type, const std::shared_ptr<BasicChannel>& target, std::shared_ptr<CalculateCache> cache, std::shared_ptr<TSServer> server, bool server_defined) {
auto result = this->permissionValueFlagged(type, target, cache, server, server_defined);
if(result.has_value)
return result.value;
return permNotGranted;
}
std::deque<std::pair<permission::PermissionType, permission::PermissionValue>> DataClient::permissionValues(permission::PermissionTestType test, const std::deque<permission::PermissionType>& permissions, const std::shared_ptr<BasicChannel> &channel, std::shared_ptr<CalculateCache> cache, std::shared_ptr<TSServer> server, bool server_defined) {
if(!server_defined && !server) server = this->server;
if(server) return server->calculatePermissions(test, this->getClientDatabaseId(), permissions, this->getType(), channel, cache);
deque<pair<permission::PermissionType, permission::PermissionValue>> result;
/* when you're not bound to any channel cou could only have server group permissions */
/* we're loading here all server groups */
{
auto server_groups = serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType());
for(const auto& permission : permissions) {
permission::PermissionValue value = permNotGranted;
for(const auto &gr : serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType())){
auto group_permissions = gr->group->permissions();
auto flagged_permissions = group_permissions->permission_value_flagged(permission);
if(flagged_permissions.has_value)
if(flagged_permissions.value > value || flagged_permissions.value == -1) value = flagged_permissions.value;
}
result.emplace_back(permission, value);
}
}
return result;
}
permission::PermissionValue DataClient::getPermissionGrantValue(permission::PermissionTestType test, permission::PermissionType type, const std::shared_ptr<BasicChannel>& target) {
permission::PermissionValue result = permNotGranted;
if(this->server) {
return this->server->calculatePermissionGrant(test, this->getClientDatabaseId(), type, this->getType(), target);
} else {
/* if you're not bound to a channel then you cant be bound to a server as well. */
//TODO: Implement negate flag!
for(const auto &gr : serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType())){
auto group_permissions = gr->group->permissions();
auto flagged_permissions = group_permissions->permission_granted_flagged(type);
if(flagged_permissions.has_value)
if(flagged_permissions.value > result || flagged_permissions.value == -1) result = flagged_permissions.value;
}
}
return result;
}
bool DataClient::permissionGranted(PermissionTestType test, permission::PermissionType type, permission::PermissionValue required, const shared_ptr<BasicChannel>& target, bool force_granted, std::shared_ptr<CalculateCache> cache, std::shared_ptr<TSServer> server, bool server_defined) {
auto value = this->permissionValue(test, type, target, cache, server, server_defined);
bool result = this->permission_granted(value, required, force_granted);
#ifdef DEBUG_PERMISSION
{
auto serverId = 0;
auto client = dynamic_cast<ConnectedClient*>(this);
if(client)
serverId = client->getServerId();
debugMessage(serverId, "[Permission] Value test result for test type {}.", test);
debugMessage(serverId,
"[Permission] Permission: {} Required value: {} Gained value: {} Force required: {} Channel: {} Result: {}",
permission::resolvePermissionData(type)->name,
required, value, force_granted, (target ? target->name() : "none"), result
);
};
#endif
return result;
}
bool DataClient::permissionGrantGranted(PermissionTestType test, permission::PermissionType type, permission::PermissionValue required, const shared_ptr<BasicChannel>& target, bool force_granted) {
auto value = this->getPermissionGrantValue(test, type, target);
bool result = this->permission_granted(value, required, force_granted);
#ifdef DEBUG_PERMISSION
{
auto serverId = 0;
auto client = dynamic_cast<ConnectedClient*>(this);
if(client)
serverId = client->getServerId();
debugMessage(serverId, "[Permission] Grant test result for test type {}.", test);
debugMessage(serverId,
"[Permission] Permission: {} Required value: {} Gained value: {} Force required: {} Channel: {} Result: {}",
permission::resolvePermissionData(type)->name,
required, value, force_granted, (target ? target->name() : "none"), result
);
};
#endif
return result;
permission::v2::PermissionFlaggedValue DataClient::calculate_permission(
permission::PermissionType permission, ChannelId channel, bool granted, std::shared_ptr<CalculateCache> cache) {
auto result = this->calculate_permissions({permission}, channel, granted, cache);
if(result.empty()) return {0, false};
return result.back().second;
}
std::vector<std::shared_ptr<GroupAssignment>> DataClient::assignedServerGroups() {
@ -278,4 +184,4 @@ bool DataClient::channelGroupAssigned(const shared_ptr<Group> &group, const shar
std::string DataClient::getAvatarId() {
return hex::hex(base64::validate(this->getUid()) ? base64::decode(this->getUid()) : this->getUid(), 'a', 'q');
}
}

View File

@ -57,69 +57,20 @@ namespace ts {
PropertyWrapper properties(){ return { this->_properties }; }
virtual std::deque<std::pair<permission::PermissionType, permission::PermissionValue>> permissionValues(permission::PermissionTestType test,
const std::deque<permission::PermissionType>&,
const std::shared_ptr<BasicChannel>& channel = nullptr,
std::shared_ptr<CalculateCache> cache = nullptr,
std::shared_ptr<TSServer> server = nullptr,
bool server_defined = false);
inline permission::PermissionValue permissionValue(permission::PermissionType type, const std::shared_ptr<BasicChannel>& targetChannel = nullptr) {
return this->permissionValue(permission::PERMTEST_ORDERED, type, targetChannel);
}
virtual permission::PermissionValue permissionValue(permission::PermissionTestType test,
permission::PermissionType,
const std::shared_ptr<BasicChannel>& channel = nullptr,
std::shared_ptr<CalculateCache> cache = nullptr,
std::shared_ptr<TSServer> server = nullptr,
bool server_defined = false);
virtual permission::v2::PermissionFlaggedValue permissionValueFlagged(
permission::PermissionType,
const std::shared_ptr<BasicChannel>& channel = nullptr,
std::shared_ptr<CalculateCache> cache = nullptr,
std::shared_ptr<TSServer> server = nullptr,
bool server_defined = false
/* main permission calculate function */
permission::v2::PermissionFlaggedValue calculate_permission(
permission::PermissionType,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
virtual bool permissionGranted(permission::PermissionTestType test,
permission::PermissionType,
permission::PermissionValue,
const std::shared_ptr<BasicChannel>& channel = nullptr,
bool required = true,
std::shared_ptr<CalculateCache> cache = nullptr,
std::shared_ptr<TSServer> server = nullptr,
bool server_defined = false);
inline permission::PermissionValue getPermissionGrantValue(permission::PermissionType type, const std::shared_ptr<BasicChannel>& targetChannel = nullptr) {
return this->getPermissionGrantValue(permission::PERMTEST_ORDERED, type, targetChannel);
}
virtual permission::PermissionValue getPermissionGrantValue(permission::PermissionTestType test, permission::PermissionType, const std::shared_ptr<BasicChannel>& targetChannel = nullptr);
virtual bool permissionGrantGranted(permission::PermissionTestType test, permission::PermissionType, permission::PermissionValue, const std::shared_ptr<BasicChannel>& targetChannel = nullptr, bool required = true);
template <typename T>
inline bool permission_granted(T, permission::PermissionValue, bool = false) = delete; /* only permission values */
[[deprecated]] __always_inline bool permission_granted(ts::permission::PermissionValue value, ts::permission::PermissionValue required, bool enforce_required = true) {
return DataClient::permission_granted({value, value != permNotGranted}, required, enforce_required);
}
static inline bool permission_granted(ts::permission::v2::PermissionFlaggedValue value, ts::permission::PermissionValue required, bool enforce_required = true) {
if(required == permNotGranted || required == 0) {
if(enforce_required)
return value.value == -1 || value.value > 0;
else
return true;
} else if(!value.has_value) {
return false;
} else {
if(value.value == -1)
return true;
else if(value.value >= required)
return true;
}
return false;
}
std::vector<std::pair<permission::PermissionType, permission::v2::PermissionFlaggedValue>> calculate_permissions(
const std::deque<permission::PermissionType>&,
ChannelId channel,
bool granted = false,
std::shared_ptr<CalculateCache> cache = nullptr
);
virtual std::vector<std::shared_ptr<GroupAssignment>> assignedServerGroups();
virtual std::shared_ptr<GroupAssignment> assignedChannelGroup(const std::shared_ptr<BasicChannel> &);
@ -153,6 +104,8 @@ namespace ts {
std::shared_ptr<permission::v2::PermissionManager> clientPermissions = nullptr;
std::shared_ptr<Properties> _properties;
std::shared_ptr<BasicChannel> currentChannel = nullptr;
};
}
}

View File

@ -22,9 +22,8 @@ InternalClient::~InternalClient() {
memtrack::freed<InternalClient>(this);
}
void InternalClient::sendCommand(const ts::Command &command, bool low) {
}
void InternalClient::sendCommand(const ts::Command &command, bool low) { }
void InternalClient::sendCommand(const ts::command_builder &command, bool low) { }
bool InternalClient::closeConnection(const std::chrono::system_clock::time_point& timeout) {
logError(this->getServerId(), "Internal client is force to disconnect?");

View File

@ -15,6 +15,7 @@ namespace ts {
}
void sendCommand(const ts::Command &command, bool low) override;
void sendCommand(const ts::command_builder &command, bool low) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;
bool disconnect(const std::string &reason) override;
protected:

View File

@ -39,12 +39,7 @@ bool SpeakingClient::shouldReceiveVoiceWhisper(const std::shared_ptr<ConnectedCl
if(!this->shouldReceiveVoice(sender))
return false;
auto required_permission = this->cached_permission_value(permission::i_client_needed_whisper_power);
if(required_permission == permNotGranted)
return true;
auto granted_permission = sender->cached_permission_value(permission::i_client_whisper_power);
return granted_permission >= required_permission;
return permission::v2::permission_granted(this->cpmerission_needed_whisper_power, sender->cpmerission_whisper_power);
}
void SpeakingClient::handlePacketVoice(const pipes::buffer_view& data, bool head, bool fragmented) {
@ -445,7 +440,7 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
debugMessage(this->getServerId(), "{} Got client init. (HWID: {})", CLIENT_STR_LOG_PREFIX, this->getHardwareId());
TIMING_STEP(timings, "props apply");
auto permissions_list = this->permissionValues(permission::PERMTEST_ORDERED, {
auto permissions_list = this->calculate_permissions({
permission::b_virtualserver_join_ignore_password,
permission::b_client_ignore_bans,
permission::b_client_ignore_vpn,
@ -457,17 +452,17 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
permission::b_client_enforce_valid_hwid,
permission::b_client_use_reserved_slot
}, nullptr);
auto permissions = map<permission::PermissionType, permission::PermissionValue>(permissions_list.begin(), permissions_list.end());
}, 0);
auto permissions = map<permission::PermissionType, permission::v2::PermissionFlaggedValue>(permissions_list.begin(), permissions_list.end());
TIMING_STEP(timings, "perm calc 1");
if(geoloc::provider_vpn && permissions[permission::b_client_ignore_vpn] == permNotGranted) {
if(geoloc::provider_vpn && !permission::v2::permission_granted(1, permissions[permission::b_client_ignore_vpn])) {
auto provider = this->isAddressV4() ? geoloc::provider_vpn->resolveInfoV4(this->getPeerIp(), true) : geoloc::provider_vpn->resolveInfoV6(this->getPeerIp(), true);
if(provider)
return command_result{error::server_connect_banned, strvar::transform(ts::config::messages::kick_vpn, strvar::StringValue{"provider.name", provider->name}, strvar::StringValue{"provider.website", provider->side})};
}
if(this->getType() == ClientType::CLIENT_TEAMSPEAK && (permissions[permission::b_client_enforce_valid_hwid] == permNotGranted && permissions[permission::b_client_enforce_valid_hwid] == 0)) {
if(this->getType() == ClientType::CLIENT_TEAMSPEAK && permission::v2::permission_granted(1, permissions[permission::b_client_enforce_valid_hwid])) {
auto hwid = this->properties()[property::CLIENT_HARDWARE_ID].as<string>();
if(
!std::regex_match(hwid, regex_hwid_windows) &&
@ -480,8 +475,7 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
}
TIMING_STEP(timings, "valid hw ip");
auto ignorePassword = permissions[permission::b_virtualserver_join_ignore_password] > 0 && permissions[permission::b_virtualserver_join_ignore_password] != permNotGranted;
if(!ignorePassword)
if(!permission::v2::permission_granted(1, permissions[permission::b_virtualserver_join_ignore_password]))
if(!this->server->verifyServerPassword(cmd["client_server_password"].string(), true))
return command_result{error::server_invalid_password};
@ -500,17 +494,17 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
clones_hwid++;
});
if(permissions[permission::i_client_max_clones_uid] > 0 && clones_uid >= permissions[permission::i_client_max_clones_uid]) {
if(clones_uid > 0 && permissions[permission::i_client_max_clones_uid].has_value && !permission::v2::permission_granted(clones_uid, permissions[permission::i_client_max_clones_uid])) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} uid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_uid, permissions[permission::i_client_max_clones_uid]);
return command_result{error:: client_too_many_clones_connected, "too many clones connected (uid)"};
}
if(permissions[permission::i_client_max_clones_ip] > 0 && clones_ip >= permissions[permission::i_client_max_clones_ip]) {
if(clones_ip > 0 && permissions[permission::i_client_max_clones_ip].has_value && !permission::v2::permission_granted(clones_ip, permissions[permission::i_client_max_clones_ip])) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} ip clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_ip, permissions[permission::i_client_max_clones_ip]);
return command_result{error:: client_too_many_clones_connected, "too many clones connected (ip)"};
}
if(permissions[permission::i_client_max_clones_hwid] > 0 && clones_hwid >= permissions[permission::i_client_max_clones_hwid] && !_own_hwid.empty()) {
if(clones_hwid > 0 && permissions[permission::i_client_max_clones_hwid].has_value && !permission::v2::permission_granted(clones_hwid, permissions[permission::i_client_max_clones_hwid])) {
logMessage(this->getServerId(), "{} Disconnecting because there are already {} hwid clones connected. (Allowed: {})", CLIENT_STR_LOG_PREFIX, clones_hwid, permissions[permission::i_client_max_clones_hwid]);
return command_result{error:: client_too_many_clones_connected, "too many clones connected (hwid)"};
}
@ -581,7 +575,7 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) {
auto maxClients = this->server->properties()[property::VIRTUALSERVER_MAXCLIENTS].as<size_t>();
auto reserved = this->server->properties()[property::VIRTUALSERVER_RESERVED_SLOTS].as<size_t>();
bool allowReserved = permissions[permission::b_client_use_reserved_slot] != permNotGranted && permissions[permission::b_client_use_reserved_slot] != 0;
bool allowReserved = permission::v2::permission_granted(1, permissions[permission::b_client_use_reserved_slot]);
if(reserved > maxClients){
if(!allowReserved)
return command_result{error::server_maxclients_reached};
@ -782,7 +776,7 @@ void SpeakingClient::tick(const std::chrono::system_clock::time_point &time) {
void SpeakingClient::updateChannelClientProperties(bool channel_lock, bool notify) {
ConnectedClient::updateChannelClientProperties(channel_lock, notify);
this->max_idle_time = this->permissionValueFlagged(permission::i_client_max_idletime, this->currentChannel);
this->max_idle_time = this->calculate_permission(permission::i_client_max_idletime, this->currentChannel ? this->currentChannel->channelId() : 0);
}
command_result SpeakingClient::handleCommand(Command &command) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,486 @@
//
// Created by wolverindev on 26.01.20.
//
#include <memory>
#include <spdlog/sinks/rotating_file_sink.h>
#include <iostream>
#include <bitset>
#include <algorithm>
#include <openssl/sha.h>
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
#include "../music/MusicClient.h"
#include "../query/QueryClient.h"
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include <experimental/filesystem>
#include <cstdint>
#include <StringVariable.h>
#include "helpers.h"
#include <Properties.h>
#include <log/LogUtils.h>
#include <misc/sassert.h>
#include <misc/base64.h>
#include <misc/hex.h>
#include <misc/digest.h>
#include <misc/rnd.h>
#include <misc/timer.h>
#include <misc/strobf.h>
#include <misc/scope_guard.h>
#include <bbcode/bbcodes.h>
namespace fs = std::experimental::filesystem;
using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
#define QUERY_PASSWORD_LENGTH 12
//ftgetfilelist cid=1 cpw path=\/ return_code=1:x
//Answer:
//1 .. n
// notifyfilelist cid=1 path=\/ return_code=1:x name=testFile size=35256 datetime=1509459767 type=1|name=testDir size=0 datetime=1509459741 type=0|name=testDir_2 size=0 datetime=1509459763 type=0
//notifyfilelistfinished cid=1 path=\/
inline void cmd_filelist_append_files(ServerId sid, Command &command, vector<std::shared_ptr<file::FileEntry>> files) {
int index = 0;
logTrace(sid, "Sending file list for path {}", command["path"].string());
for (const auto& fileEntry : files) {
logTrace(sid, " - {} ({})", fileEntry->name, fileEntry->type == file::FileType::FILE ? "file" : "directory");
command[index]["name"] = fileEntry->name;
command[index]["datetime"] = std::chrono::duration_cast<std::chrono::seconds>(fileEntry->lastChanged.time_since_epoch()).count();
command[index]["type"] = fileEntry->type;
if (fileEntry->type == file::FileType::FILE)
command[index]["size"] = static_pointer_cast<file::File>(fileEntry)->fileSize;
else
command[index]["size"] = 0;
index++;
}
}
#define CMD_REQ_FSERVER if(!serverInstance->getFileServer()) return command_result{error::vs_critical, "file server not started yet!"}
command_result ConnectedClient::handleCommandFTGetFileList(Command &cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_REQ_FSERVER;
std::string code = cmd["return_code"].size() > 0 ? cmd["return_code"].string() : "";
Command fileList(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyfilelist" : "");
Command fileListFinished("notifyfilelistfinished");
fileList["path"] = cmd["path"].as<std::string>();
if(!code.empty()) fileList["return_code"] = code;
fileListFinished["path"] = cmd["path"].as<std::string>();
fileList["cid"] = cmd["cid"].as<size_t>();
fileListFinished["cid"] = cmd["cid"].as<ChannelId>();
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_browse_power, permission::i_ft_file_browse_power, true);
cmd_filelist_append_files(
this->getServerId(),
fileList,
serverInstance->getFileServer()->listFiles(serverInstance->getFileServer()->resolveDirectory(this->server, channel, cmd["path"].as<std::string>()))
);
} else {
if (cmd["path"].as<string>() == "/icons" || cmd["path"].as<string>() == "/icons/") {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_icon_manage, 1);
cmd_filelist_append_files(this->getServerId(), fileList, serverInstance->getFileServer()->listFiles(serverInstance->getFileServer()->iconDirectory(this->server)));
} else if (cmd["path"].as<string>() == "/") {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_icon_manage, 1);
cmd_filelist_append_files(this->getServerId(), fileList, serverInstance->getFileServer()->listFiles(serverInstance->getFileServer()->avatarDirectory(this->server)));
} else {
logMessage(this->getServerId(), "{} Requested file list for unknown path/name: path: {} name: {}", cmd["path"].string(), cmd["name"].string());
return command_result{error::not_implemented};
}
}
if (fileList[0].has("name")) {
if(dynamic_cast<VoiceClient*>(this)) {
dynamic_cast<VoiceClient*>(this)->sendCommand0(fileList.build(), false, true); /* We need to process this directly else the order could get shuffled up! */
this->sendCommand(fileListFinished);
} else {
this->sendCommand(fileList);
if(this->getType() != CLIENT_QUERY)
this->sendCommand(fileListFinished);
}
return command_result{error::ok};
} else {
return command_result{error::database_empty_result};
}
}
//ftcreatedir cid=4 cpw dirname=\/TestDir return_code=1:17
command_result ConnectedClient::handleCommandFTCreateDir(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
CMD_REQ_FSERVER;
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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_directory_create_power, permission::i_ft_directory_create_power, true);
auto dir = serverInstance->getFileServer()->createDirectory(cmd["dirname"], serverInstance->getFileServer()->resolveDirectory(this->server, channel, cmd["path"].as<std::string>()));
if (!dir) return command_result{error::file_invalid_path, "could not create dir"};
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandFTDeleteFile(Command &cmd) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
CMD_REQ_FSERVER;
std::vector<std::shared_ptr<file::FileEntry>> files;
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_delete_power, permission::i_ft_file_delete_power, true);
for (int index = 0; index < cmd.bulkCount(); index++)
files.push_back(serverInstance->getFileServer()->findFile(cmd[index]["name"].as<std::string>(), serverInstance->getFileServer()->resolveDirectory(this->server, channel)));
} else {
if (cmd["name"].string().find("/icon_") == 0 && cmd["path"].string().empty()) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_icon_manage, 1);
files.push_back(serverInstance->getFileServer()->findFile(cmd["name"].string(), serverInstance->getFileServer()->iconDirectory(this->server)));
} else if (cmd["name"].string().find("/avatar_") == 0 && cmd["path"].string().empty()) {
if (cmd["name"].string() != "/avatar_") {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_client_avatar_delete_other, 1);
auto uid = cmd["name"].string().substr(strlen("/avatar_"));
auto avId = hex::hex(base64::decode(uid), 'a', 'q');
auto cls = this->server->findClientsByUid(uid);
for (const auto &cl : cls) {
cl->properties()[property::CLIENT_FLAG_AVATAR] = "";
this->server->notifyClientPropertyUpdates(cl, deque<property::ClientProperties>{property::CLIENT_FLAG_AVATAR});
}
cmd["name"] = "/avatar_" + avId;
} else {
cmd["name"] = "/avatar_" + this->getAvatarId();
this->properties()[property::CLIENT_FLAG_AVATAR] = "";
this->server->notifyClientPropertyUpdates(_this.lock(), deque<property::ClientProperties>{property::CLIENT_FLAG_AVATAR});
}
files.push_back(serverInstance->getFileServer()->findFile(cmd["name"].string(), serverInstance->getFileServer()->avatarDirectory(this->server)));
} else {
logError(this->getServerId(), "Unknown requested file to delete: {}", cmd["path"].as<std::string>());
return command_result{error::not_implemented};
}
}
for (const auto &file : files) {
if (!file) continue;
if (!serverInstance->getFileServer()->deleteFile(file)) {
logCritical(this->getServerId(), "Could not delete file {}/{}", file->path, file->name);
}
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandFTInitUpload(Command &cmd) {
CMD_REQ_SERVER;
CMD_REQ_FSERVER;
std::shared_ptr<file::Directory> directory = nullptr;
if (cmd[0].has("cid") && cmd["cid"] != 0) { //Channel
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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_upload_power, permission::i_ft_file_upload_power, true);
directory = serverInstance->getFileServer()->resolveDirectory(this->server, channel);
} else {
if (cmd["path"].as<std::string>().empty() && cmd["name"].as<std::string>().find("/icon_") == 0) {
auto max_size = this->calculate_permission(permission::i_max_icon_filesize, 0);
if(max_size.has_value && !max_size.has_infinite_power() && (max_size.value < 0 || max_size.value < cmd["size"].as<size_t>()))
return command_result{permission::i_max_icon_filesize};
directory = serverInstance->getFileServer()->iconDirectory(this->server);
} else if (cmd["path"].as<std::string>().empty() && cmd["name"].string() == "/avatar") {
auto max_size = this->calculate_permission(permission::i_client_max_avatar_filesize, 0);
if(max_size.has_value && !max_size.has_infinite_power() && (max_size.value < 0 || max_size.value < cmd["size"].as<size_t>()))
return command_result{permission::i_client_max_avatar_filesize};
directory = serverInstance->getFileServer()->avatarDirectory(this->server);
cmd["name"] = "/avatar_" + this->getAvatarId();
} else {
cerr << "Unknown requested directory: " << cmd["path"].as<std::string>() << endl;
return command_result{error::not_implemented};
}
}
if (!directory || directory->type != file::FileType::DIRECTORY) { //Should not happen
cerr << "Invalid upload file path!" << endl;
return command_result{error::file_invalid_path, "could not resolve directory"};
}
{
auto server_quota = this->server->properties()[property::VIRTUALSERVER_UPLOAD_QUOTA].as<ssize_t>();
auto server_used_quota = this->server->properties()[property::VIRTUALSERVER_MONTH_BYTES_UPLOADED].as<size_t>();
server_used_quota += cmd["size"].as<uint64_t>();
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers())
server_used_quota += trans->size;
for(const auto& trans : serverInstance->getFileServer()->running_file_transfers())
server_used_quota += trans->remaining_bytes();
if(server_quota >= 0 && server_quota * 1024 * 1024 < (int64_t) server_used_quota) return command_result{error::file_transfer_server_quota_exceeded};
auto client_quota = this->calculate_permission(permission::i_ft_quota_mb_upload_per_client, 0);
auto client_used_quota = this->properties()[property::CLIENT_MONTH_BYTES_UPLOADED].as<size_t>();
client_used_quota += cmd["size"].as<uint64_t>();
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers(_this.lock()))
client_used_quota += trans->size;
for(const auto& trans : serverInstance->getFileServer()->running_file_transfers(_this.lock()))
client_used_quota += trans->remaining_bytes();
if(client_quota.has_value && !client_quota.has_infinite_power() && (client_quota.value < 0 || client_quota.value * 1024 * 1024 < (int64_t) client_used_quota))
return command_result{error::file_transfer_client_quota_exceeded};
}
if (cmd["overwrite"].as<bool>() && cmd["resume"].as<bool>()) return command_result{error::file_overwrite_excludes_resume};
if (serverInstance->getFileServer()->findFile(cmd["name"].as<std::string>(), directory) && !(cmd["overwrite"].as<bool>() || cmd["resume"].as<bool>()))
return command_result{error::file_already_exists, "file already exists"};
//Request: clientftfid=1 serverftfid=6 ftkey=itRNdsIOvcBiBg\/Xj4Ge51ZSrsShHuid port=30033 seekpos=0
//Reqpose: notifystartupload clientftfid=4079 serverftfid=1 ftkey=aX9CFQbfaddHpOYxhQiSLu\/BumfVtPyP port=30033 seekpos=0 proto=1
string error = "success";
auto key = serverInstance->getFileServer()->generateUploadTransferKey(error, directory->path + "/" + directory->name + cmd["name"].string(), cmd["size"].as<uint64_t>(), 0, _this.lock()); //TODO implement resume!
if (!key) return command_result{error::vs_critical};
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifystartupload" : "");
result["clientftfid"] = cmd["clientftfid"].as<uint64_t>();
result["ftkey"] = key->key;
auto bindings = serverInstance->getFileServer()->list_bindings();
if(!bindings.empty()) {
result["port"] = net::port(bindings[0]->address);
string ip = "";
for(auto& entry : bindings) {
if(net::is_anybind(entry->address)) {
ip = "";
break;
}
ip += net::to_string(entry->address, false) + ",";
}
if(!ip.empty())
result["ip"] = ip;
} else {
return command_result{error::server_is_not_running, "file server is not bound to any address"};
}
result["seekpos"] = 0;
result["proto"] = 1;
result["serverftfid"] = key->key_id; //TODO generate!
this->sendCommand(result);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandFTInitDownload(Command &cmd) {
CMD_REQ_SERVER;
CMD_REQ_FSERVER;
std::shared_ptr<file::Directory> directory = nullptr;
if(!cmd[0].has("path")) cmd["path"] = "";
if (cmd[0].has("cid") && cmd["cid"] != (ChannelId) 0) { //Channel
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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_download_power, permission::i_ft_file_download_power, true);
directory = serverInstance->getFileServer()->resolveDirectory(this->server, channel);
} else {
if (cmd["path"].as<std::string>().empty() && cmd["name"].as<std::string>().find("/icon_") == 0) {
directory = serverInstance->getFileServer()->iconDirectory(this->server);
} else if (cmd["path"].as<std::string>().empty() && cmd["name"].as<std::string>().find("/avatar_") == 0) { //TODO fix avatar download not working
directory = serverInstance->getFileServer()->avatarDirectory(this->server);
} else {
cerr << "Unknown requested directory: " << cmd["path"].as<std::string>() << endl;
return command_result{error::not_implemented};
}
}
if (!directory || directory->type != file::FileType::DIRECTORY) { //Should not happen
cerr << "Invalid download file path!" << endl;
return command_result{error::file_invalid_path, "could not resolve directory"};
}
if (!serverInstance->getFileServer()->findFile(cmd["name"].as<std::string>(), directory))
return command_result{error::file_not_found, "file not exists"};
string error = "success";
auto key = serverInstance->getFileServer()->generateDownloadTransferKey(error, directory->path + "/" + directory->name + cmd["name"].as<std::string>(), 0, _this.lock()); //TODO implement resume!
if (!key) return command_result{error::vs_critical, "cant generate key (" + error + ")"};
{
auto server_quota = this->server->properties()[property::VIRTUALSERVER_DOWNLOAD_QUOTA].as<ssize_t>();
auto server_used_quota = this->server->properties()[property::VIRTUALSERVER_MONTH_BYTES_DOWNLOADED].as<size_t>();
server_used_quota += key->size;
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers())
server_used_quota += trans->size;
for(const auto& trans : serverInstance->getFileServer()->running_file_transfers())
server_used_quota += trans->remaining_bytes();
if(server_quota >= 0 && server_quota * 1024 * 1024 < (int64_t) server_used_quota) return command_result{error::file_transfer_server_quota_exceeded};
auto client_quota = this->calculate_permission(permission::i_ft_quota_mb_download_per_client, 0);
auto client_used_quota = this->properties()[property::CLIENT_MONTH_BYTES_DOWNLOADED].as<size_t>();
client_used_quota += key->size;
for(const auto& trans : serverInstance->getFileServer()->pending_file_transfers(_this.lock()))
client_used_quota += trans->size;
for(const auto& trans : serverInstance->getFileServer()->running_file_transfers(_this.lock()))
client_used_quota += trans->remaining_bytes();
if(client_quota.has_value && !client_quota.has_infinite_power() && (client_quota.value < 0 || client_quota.value * 1024 * 1024 < (int64_t) client_used_quota))
return command_result{error::file_transfer_client_quota_exceeded};
}
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifystartdownload" : "");
result["clientftfid"] = cmd["clientftfid"].as<uint64_t>();
result["proto"] = 1;
result["serverftfid"] = key->key_id;
result["ftkey"] = key->key;
auto bindings = serverInstance->getFileServer()->list_bindings();
if(!bindings.empty()) {
result["port"] = net::port(bindings[0]->address);
string ip = "";
for(auto& entry : bindings) {
if(net::is_anybind(entry->address)) {
ip = "";
break;
}
ip += net::to_string(entry->address, false) + ",";
}
if(!ip.empty())
result["ip"] = ip;
} else {
return command_result{error::server_is_not_running, "file server is not bound to any address"};
}
result["size"] = key->size;
this->sendCommand(result);
return command_result{error::ok};
}
/*
* Usage: ftgetfileinfo cid={channelID} cpw={channelPassword} name={filePath}...
Permissions:
i_ft_file_browse_power
i_ft_needed_file_browse_power
Description:
Displays detailed information about one or more specified files stored in a
channels file repository.
Example:
ftgetfileinfo cid=2 cpw= path=\/Pic1.PNG|cid=2 cpw= path=\/Pic2.PNG
cid=2 path=\/ name=Stuff size=0 datetime=1259415210 type=0|name=Pic1.PNG size=563783 datetime=1259425462 type=1|name=Pic2.PNG ...
error id=0 msg=ok
*/
command_result ConnectedClient::handleCommandFTGetFileInfo(ts::Command &cmd) {
CMD_REQ_SERVER;
CMD_REQ_FSERVER;
CMD_RESET_IDLE;
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifyfileinfo" : "");
int result_index = 0;
for(int index = 0; index < cmd.bulkCount(); index++) {
auto& request = cmd[index];
std::shared_ptr<file::FileEntry> file;
if (request.has("cid") && request["cid"].as<ChannelId>() != 0) { //Channel
auto channel = this->server->channelTree->findChannel(request["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};
ACTION_REQUIRES_CHANNEL_PERMISSION(channel, permission::i_ft_needed_file_browse_power, permission::i_ft_file_browse_power, true);
file = serverInstance->getFileServer()->findFile(request["name"],serverInstance->getFileServer()->resolveDirectory(this->server, channel, request["path"]));
} else {
std::shared_ptr<file::Directory> directory;
if (!request.has("path") || request["path"].as<string>() == "/") {
directory = serverInstance->getFileServer()->avatarDirectory(this->server);
} else if (request["path"].as<string>() == "/icons" || request["path"].as<string>() == "/icons/") {
directory = serverInstance->getFileServer()->iconDirectory(this->server);
} else {
cerr << "Unknown requested directory: '" << request["path"].as<std::string>() << "'" << endl;
return command_result{error::not_implemented};
}
if(!directory) continue;
file = serverInstance->getFileServer()->findFile(cmd["name"].as<std::string>(), directory);
}
if(!file) continue;
result[result_index]["cid"] = request["cid"].as<ChannelId>();
result[result_index]["name"] = request["name"];
result[result_index]["path"] = request["path"];
result[result_index]["type"] = file->type;
result[result_index]["datetime"] = duration_cast<seconds>(file->lastChanged.time_since_epoch()).count();
if (file->type == file::FileType::FILE)
result[result_index]["size"] = static_pointer_cast<file::File>(file)->fileSize;
else
result[result_index]["size"] = 0;
result_index++;
}
if(result_index == 0)
return command_result{error::database_empty_result};
this->sendCommand(result);
return command_result{error::ok};
}

View File

@ -0,0 +1,193 @@
#pragma once
/** Permission tests against required values **/
/* use this for any action which will do something with the server */
#define ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(required_permission_type, required_value, cache) \
do { \
if(!permission::v2::permission_granted(required_value, this->calculate_permission(required_permission_type, 0, false, cache))) \
return command_result{required_permission_type}; \
} while(0)
#define ACTION_REQUIRES_GLOBAL_PERMISSION(required_permission_type, required_value) \
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(required_permission_type, required_value, nullptr)
//TODO: Fixme: Really check for instance permissions!
#define ACTION_REQUIRES_INSTANCE_PERMISSION(required_permission_type, required_value) \
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED(required_permission_type, required_value, nullptr)
/* use this for anything which will do something local in relation to the target channel */
#define ACTION_REQUIRES_PERMISSION(required_permission_type, required_value, channel_id) \
do { \
if(!permission::v2::permission_granted(required_value, this->calculate_permission(required_permission_type, channel_id))) \
return command_result{required_permission_type}; \
} while(0)
/** Permission tests against groups **/
/* use this when testing a permission against a group */
#define ACTION_REQUIRES_GROUP_PERMISSION(group, required_permission_type, own_permission_type, is_required) \
do { \
auto _permission_granted = this->calculate_permission(own_permission_type, 0); \
if(!(group)->permission_granted(required_permission_type, _permission_granted, is_required)) \
return command_result{own_permission_type}; \
} while(0)
/** Permission tests against channels **/
/* use this when testing a permission against a group */
#define ACTION_REQUIRES_CHANNEL_PERMISSION(channel, required_permission_type, own_permission_type, is_required) \
do { \
auto _permission_granted = this->calculate_permission(own_permission_type, channel ? channel->channelId() : 0); \
if(!(channel)->permission_granted(required_permission_type, _permission_granted, is_required)) \
return command_result{own_permission_type}; \
} while(0)
/* 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());\
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());\
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"}; \
//TODO: Map permsid!
#define PARSE_PERMISSION(cmd) \
permission::PermissionType permType = permission::PermissionType::unknown; \
bool grant = false; \
if (cmd[index].has("permid")) { \
permType = cmd[index]["permid"].as<permission::PermissionType>(); \
if ((permType & PERM_ID_GRANT) != 0) { \
grant = true; \
permType &= ~PERM_ID_GRANT; \
} \
} else if (cmd[index].has("permsid")) { \
auto resv = permission::resolvePermissionData(cmd[index]["permsid"].as<string>()); \
permType = resv->type; \
if (resv->grantName() == cmd[index]["permsid"].as<string>()) grant = true; \
} \
if (permission::resolvePermissionData(permType)->type == permission::PermissionType::unknown) { \
if (conOnError) continue; \
return ts::command_result{error::parameter_invalid}; \
}
inline bool permission_require_granted_value(ts::permission::PermissionType type) {
using namespace ts;
switch (type) {
case permission::i_permission_modify_power:
case permission::i_channel_group_member_add_power:
case permission::i_channel_group_member_remove_power:
case permission::i_channel_group_modify_power:
case permission::i_channel_group_needed_member_add_power:
case permission::i_channel_group_needed_member_remove_power:
case permission::i_channel_group_needed_modify_power:
case permission::i_server_group_member_add_power:
case permission::i_server_group_member_remove_power:
case permission::i_server_group_modify_power:
case permission::i_server_group_needed_member_add_power:
case permission::i_server_group_needed_member_remove_power:
case permission::i_server_group_needed_modify_power:
case permission::i_displayed_group_member_add_power:
case permission::i_displayed_group_member_remove_power:
case permission::i_displayed_group_modify_power:
case permission::i_displayed_group_needed_member_add_power:
case permission::i_displayed_group_needed_member_remove_power:
case permission::i_displayed_group_needed_modify_power:
case permission::i_channel_permission_modify_power:
case permission::i_channel_needed_permission_modify_power:
case permission::i_client_permission_modify_power:
case permission::i_client_needed_permission_modify_power:
case permission::i_client_needed_kick_from_server_power:
case permission::i_client_needed_kick_from_channel_power:
case permission::i_client_kick_from_channel_power:
case permission::i_client_kick_from_server_power:
return true;
default:
return false;
}
}
inline bool permission_is_group_property(ts::permission::PermissionType type) {
using namespace ts;
switch (type) {
case permission::i_icon_id:
case permission::i_group_show_name_in_tree:
case permission::i_group_sort_id:
case permission::b_group_is_permanent:
case permission::i_displayed_group_needed_modify_power:
case permission::i_displayed_group_needed_member_add_power:
case permission::i_displayed_group_needed_member_remove_power:
return true;
default:
return false;
}
}
inline bool permission_is_client_property(ts::permission::PermissionType type) {
using namespace ts;
switch (type) {
case permission::i_icon_id:
case permission::i_client_talk_power:
case permission::i_client_max_idletime:
case permission::i_group_sort_id:
case permission::i_channel_view_power:
case permission::b_channel_ignore_view_power:
case permission::b_client_is_priority_speaker:
return true;
default:
return false;
}
}
inline ssize_t count_characters(const std::string& in) {
size_t index = 0;
size_t count = 0;
while(index < in.length()){
count++;
auto current = (uint8_t) in[index];
if(current >= 128) { //UTF8 check
if(current >= 192 && (current <= 193 || current >= 245)) {
return -1;
} else if(current >= 194 && current <= 223) {
if(in.length() - index <= 1) return -1;
else if((uint8_t) in[index + 1] >= 128 && (uint8_t) in[index + 1] <= 191) index += 1; //Valid
else return -1;
} else if(current >= 224 && current <= 239) {
if(in.length() - index <= 2) return -1;
else if((uint8_t) in[index + 1] >= 128 && (uint8_t) in[index + 1] <= 191 &&
(uint8_t) in[index + 2] >= 128 && (uint8_t) in[index + 2] <= 191) index += 2; //Valid
else return -1;
} else if(current >= 240 && current <= 244) {
if(in.length() - index <= 3) return -1;
else if((uint8_t) in[index + 1] >= 128 && (uint8_t) in[index + 1] <= 191 &&
(uint8_t) in[index + 2] >= 128 && (uint8_t) in[index + 2] <= 191 &&
(uint8_t) in[index + 3] >= 128 && (uint8_t) in[index + 3] <= 191) index += 3; //Valid
else return -1;
} else {
return -1;
}
}
index++;
}
return count;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,924 @@
//
// Created by wolverindev on 26.01.20.
//
#include <memory>
#include <spdlog/sinks/rotating_file_sink.h>
#include <iostream>
#include <bitset>
#include <algorithm>
#include <openssl/sha.h>
#include "../../build.h"
#include "../ConnectedClient.h"
#include "../InternalClient.h"
#include "../../server/file/FileServer.h"
#include "../../server/VoiceServer.h"
#include "../voice/VoiceClient.h"
#include "PermissionManager.h"
#include "../../InstanceHandler.h"
#include "../../server/QueryServer.h"
#include "../file/FileClient.h"
#include "../music/MusicClient.h"
#include "../query/QueryClient.h"
#include "../../weblist/WebListManager.h"
#include "../../manager/ConversationManager.h"
#include "../../manager/PermissionNameMapper.h"
#include <experimental/filesystem>
#include <cstdint>
#include <StringVariable.h>
#include "helpers.h"
#include <Properties.h>
#include <log/LogUtils.h>
#include <misc/sassert.h>
#include <misc/base64.h>
#include <misc/hex.h>
#include <misc/digest.h>
#include <misc/rnd.h>
#include <misc/timer.h>
#include <misc/strobf.h>
#include <misc/scope_guard.h>
#include <bbcode/bbcodes.h>
namespace fs = std::experimental::filesystem;
using namespace std::chrono;
using namespace std;
using namespace ts;
using namespace ts::server;
using namespace ts::token;
command_result ConnectedClient::handleCommandMusicBotCreate(Command& cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
if(this->server->musicManager->max_bots() != -1 && this->server->musicManager->max_bots() <= this->server->musicManager->current_bot_count()){
if(config::license->isPremium())
return command_result{error::music_limit_reached};
else
return command_result{error::music_limit_reached, strobf("You reached the server music bot limit. You could increase this limit by extend your server with a premium license.").string()};
}
auto permissions_list = this->calculate_permissions({
permission::i_client_music_limit,
permission::b_client_music_create_permanent,
permission::b_client_music_create_semi_permanent,
permission::b_client_music_create_temporary,
permission::i_channel_join_power,
permission::i_client_music_delete_power,
permission::i_client_music_create_modify_max_volume
}, this->getChannelId());
auto permissions = map<permission::PermissionType, permission::v2::PermissionFlaggedValue>(permissions_list.begin(), permissions_list.end());
auto max_bots = permissions[permission::i_client_music_limit];
if(max_bots.has_value) {
auto ownBots = this->server->musicManager->listBots(this->getClientDatabaseId());
if(!permission::v2::permission_granted(ownBots.size() + 1, max_bots))
return command_result{error::music_client_limit_reached};
}
MusicClient::Type::value create_type;
if(cmd[0].has("type")) {
create_type = cmd["type"].as<MusicClient::Type::value>();
switch(create_type) {
case MusicClient::Type::PERMANENT:
if(!permission::v2::permission_granted(1, permissions[permission::b_client_music_create_permanent]))
return command_result{permission::b_client_music_create_permanent};
break;
case MusicClient::Type::SEMI_PERMANENT:
if(!permission::v2::permission_granted(1, permissions[permission::b_client_music_create_semi_permanent]))
return command_result{permission::b_client_music_create_semi_permanent};
break;
case MusicClient::Type::TEMPORARY:
if(!permission::v2::permission_granted(1, permissions[permission::b_client_music_create_temporary]))
return command_result{permission::b_client_music_create_temporary};
break;
default:
return command_result{error::vs_critical};
}
} else {
if(permission::v2::permission_granted(1, permissions[permission::b_client_music_create_permanent]))
create_type = MusicClient::Type::PERMANENT;
else if(permission::v2::permission_granted(1, permissions[permission::b_client_music_create_semi_permanent]))
create_type = MusicClient::Type::SEMI_PERMANENT;
else if(permission::v2::permission_granted(1, permissions[permission::b_client_music_create_temporary]))
create_type = MusicClient::Type::TEMPORARY;
else
return command_result{permission::b_client_music_create_temporary};
}
shared_lock server_channel_lock(this->server->channel_tree_lock);
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};
} else {
if(!this->calculate_and_get_join_state(channel))
channel = nullptr;
}
if(!channel)
channel = this->server->channelTree->getDefaultChannel();
auto bot = this->server->musicManager->createBot(this->getClientDatabaseId());
if(!bot) return command_result{error::vs_critical};
bot->set_bot_type(create_type);
if(permissions[permission::i_client_music_create_modify_max_volume].has_value) {
auto max_volume = min(100, max(0, permissions[permission::i_client_music_create_modify_max_volume].value));
if(max_volume >= 0)
bot->volume_modifier(max_volume / 100.f);
}
this->selectedBot = bot;
{
server_channel_lock.unlock();
unique_lock server_channel_w_lock(this->server->channel_tree_lock);
this->server->client_move(
bot,
channel,
nullptr,
"music bot created",
ViewReasonId::VREASON_USER_ACTION,
false,
server_channel_w_lock
);
}
bot->properties()[property::CLIENT_LAST_CHANNEL] = channel ? channel->channelId() : 0;
bot->properties()[property::CLIENT_COUNTRY] = config::geo::countryFlag;
if(permissions[permission::i_client_music_delete_power].has_value && permissions[permission::i_client_music_delete_power].value >= 0) {
bot->clientPermissions->set_permission(permission::i_client_music_needed_delete_power, {permissions[permission::i_client_music_delete_power].value,0}, permission::v2::set_value, permission::v2::do_nothing);
}
Command notify(this->getExternalType() == ClientType::CLIENT_TEAMSPEAK ? "notifymusiccreated" : "");
notify["bot_id"] = bot->getClientDatabaseId();
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandMusicBotDelete(Command& cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
if(bot->getOwner() != this->getClientDatabaseId()) {
ACTION_REQUIRES_PERMISSION(permission::i_client_music_delete_power, bot->calculate_permission(permission::i_client_music_needed_delete_power, bot->getChannelId()), this->getChannelId());
}
this->server->musicManager->deleteBot(bot);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandMusicBotSetSubscription(ts::Command &cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot && cmd["bot_id"].as<ClientDbId>() != 0) return command_result{error::music_invalid_id};
{
auto old_bot = this->subscribed_bot.lock();
if(old_bot)
old_bot->remove_subscriber(_this.lock());
}
if(bot) {
bot->add_subscriber(_this.lock());
this->subscribed_bot = bot;
}
return command_result{error::ok};
}
void apply_song(Command& command, const std::shared_ptr<ts::music::SongInfo>& element, int index = 0) {
if(!element) return;
command[index]["song_id"] = element ? element->getSongId() : 0;
command[index]["song_url"] = element ? element->getUrl() : "";
command[index]["song_invoker"] = element ? element->getInvoker() : 0;
command[index]["song_loaded"] = false;
auto entry = dynamic_pointer_cast<ts::music::PlayableSong>(element);
if(entry) {
auto data = entry->song_loaded_data();
command[index]["song_loaded"] = entry->song_loaded() && data;
if(entry->song_loaded() && data) {
command[index]["song_title"] = data->title;
command[index]["song_description"] = data->description;
command[index]["song_thumbnail"] = data->thumbnail;
command[index]["song_length"] = data->length.count();
}
}
}
command_result ConnectedClient::handleCommandMusicBotPlayerInfo(Command& cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
Command result(this->getExternalType() == CLIENT_TEAMSPEAK ? "notifymusicplayerinfo" : "");
result["bot_id"] = bot->getClientDatabaseId();
result["player_state"] =(int) bot->player_state();
if(bot->current_player()) {
result["player_buffered_index"] = bot->current_player()->bufferedUntil().count();
result["player_replay_index"] = bot->current_player()->currentIndex().count();
result["player_max_index"] = bot->current_player()->length().count();
result["player_seekable"] = bot->current_player()->seek_supported();
result["player_title"] = bot->current_player()->songTitle();
result["player_description"] = bot->current_player()->songDescription();
} else {
result["player_buffered_index"] = 0;
result["player_replay_index"] = 0;
result["player_max_index"] = 0;
result["player_seekable"] = 0;
result["player_title"] = "";
result["player_description"] = "";
}
apply_song(result, bot->current_song());
this->sendCommand(result);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandMusicBotPlayerAction(Command& cmd) {
if(!config::music::enabled) return command_result{error::music_disabled};
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
ACTION_REQUIRES_PERMISSION(permission::i_client_music_play_power, bot->calculate_permission(permission::i_client_music_needed_play_power, bot->getChannelId()), this->getChannelId());
if(cmd["action"] == 0) {
bot->stopMusic();
} else if(cmd["action"] == 1) {
bot->playMusic();
} else if(cmd["action"] == 2) {
bot->player_pause();
} else if(cmd["action"] == 3) {
bot->forwardSong();
} else if(cmd["action"] == 4) {
bot->rewindSong();
} else if(cmd["action"] == 5) {
if(!bot->current_player()) return command_result{error::music_no_player};
bot->current_player()->forward(::music::PlayerUnits(cmd["units"].as<int64_t>()));
} else if(cmd["action"] == 6) {
if(!bot->current_player()) return command_result{error::music_no_player};
bot->current_player()->rewind(::music::PlayerUnits(cmd["units"].as<int64_t>()));
} else return command_result{error::music_invalid_action};
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistList(ts::Command &cmd) {
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto self_dbid = this->getClientDatabaseId();
auto playlist_view_power = this->calculate_permission(permission::i_playlist_view_power, 0);
auto playlists = this->server->musicManager->playlists();
playlists.erase(find_if(playlists.begin(), playlists.end(), [&](const shared_ptr<music::PlayablePlaylist>& playlist) {
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] == self_dbid)
return false;
auto needed_view_power = playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power);
return !permission::v2::permission_granted(needed_view_power, playlist_view_power, false);;
}), playlists.end());
if(playlists.empty())
return command_result{error::database_empty_result};
Command notify(this->notify_response_command("notifyplaylistlist"));
size_t index = 0;
for(const auto& entry : playlists) {
notify[index]["playlist_id"] = entry->playlist_id();
auto bot = entry->current_bot();
notify[index]["playlist_bot_id"] = bot ? bot->getClientDatabaseId() : 0;
notify[index]["playlist_title"] = entry->properties()[property::PLAYLIST_TITLE].value();
notify[index]["playlist_type"] = entry->properties()[property::PLAYLIST_TYPE].value();
notify[index]["playlist_owner_dbid"] = entry->properties()[property::PLAYLIST_OWNER_DBID].value();
notify[index]["playlist_owner_name"] = entry->properties()[property::PLAYLIST_OWNER_NAME].value();
notify[index]["needed_power_modify"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_modify_power);
notify[index]["needed_power_permission_modify"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power);
notify[index]["needed_power_delete"] = entry->permissions()->getPermissionValue(permission::i_playlist_needed_delete_power);
notify[index]["needed_power_song_add"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_add_power);
notify[index]["needed_power_song_move"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_move_power);
notify[index]["needed_power_song_remove"] = entry->permissions()->getPermissionValue(permission::i_playlist_song_needed_remove_power);
index++;
}
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistCreate(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_playlist_create, 1);
{
auto max_playlists = this->calculate_permission(permission::i_max_playlists, 0);
if(max_playlists.has_value) {
auto playlists = ref_server->musicManager->find_playlists_by_client(this->getClientDatabaseId());
if(!permission::v2::permission_granted(playlists.size(), max_playlists))
return command_result{permission::i_max_playlists};
}
}
auto playlist = ref_server->musicManager->create_playlist(this->getClientDatabaseId(), this->getDisplayName());
if(!playlist) return command_result{error::vs_critical};
playlist->properties()[property::PLAYLIST_TYPE] = music::Playlist::Type::GENERAL;
{
auto max_songs = this->calculate_permission(permission::i_max_playlist_size, 0);
if(max_songs.has_value && max_songs.value >= 0)
playlist->properties()[property::PLAYLIST_MAX_SONGS] = max_songs.value;
}
auto power = this->calculate_permission(permission::i_playlist_song_remove_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_song_needed_remove_power, power.value, nullptr);
power = this->calculate_permission(permission::i_playlist_delete_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_delete_power, power.value, nullptr);
power = this->calculate_permission(permission::i_playlist_modify_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_modify_power, power.value, nullptr);
power = this->calculate_permission(permission::i_playlist_permission_modify_power, 0);
if(power.has_value && power.value >= 0)
playlist->permissions()->setPermission(permission::i_playlist_needed_permission_modify_power, power.value, nullptr);
Command notify(this->notify_response_command("notifyplaylistcreated"));
notify["playlist_id"] = playlist->playlist_id();
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistDelete(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_delete_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_delete_power));
string error;
if(!ref_server->musicManager->delete_playlist(playlist->playlist_id(), error)) {
logError(this->getServerId(), "Failed to delete playlist with id {}. Error: {}", playlist->playlist_id(), error);
return command_result{error::vs_critical};
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistInfo(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
Command notify(this->notify_response_command("notifyplaylistinfo"));
for(const auto& property : playlist->properties().list_properties(property::FLAG_PLAYLIST_VARIABLE)) {
notify[property.type().name] = property.value();
}
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistEdit(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_modify_power));
deque<pair<shared_ptr<property::PropertyDescription>, string>> properties;
for(const auto& key : cmd[0].keys()) {
if(key == "playlist_id") continue;
if(key == "return_code") continue;
auto property = property::info<property::PlaylistProperties>(key);
if(*property == property::PLAYLIST_UNDEFINED) {
logError(this->getServerId(), R"([{}] Tried to edit a not existing playlist property "{}" to "{}")", CLIENT_STR_LOG_PREFIX, key, cmd[key].string());
continue;
}
if((property->flags & property::FLAG_USER_EDITABLE) == 0) {
logError(this->getServerId(), "[{}] Tried to change a playlist property which is not changeable. (Key: {}, Value: \"{}\")", CLIENT_STR_LOG_PREFIX, key, cmd[key].string());
continue;
}
if(!property->validate_input(cmd[key].as<string>())) {
logError(this->getServerId(), "[{}] Tried to change a playlist property to an invalid value. (Key: {}, Value: \"{}\")", CLIENT_STR_LOG_PREFIX, key, cmd[key].string());
continue;
}
if(*property == property::PLAYLIST_CURRENT_SONG_ID) {
auto song_id = cmd[key].as<SongId>();
auto song = song_id > 0 ? playlist->find_song(song_id) : nullptr;
if(song_id != 0 && !song)
return command_result{error::playlist_invalid_song_id};
} else if(*property == property::PLAYLIST_MAX_SONGS) {
auto value = cmd[key].as<int32_t>();
auto max_value = this->calculate_permission(permission::i_max_playlist_size, this->getChannelId());
if(max_value.has_value && !permission::v2::permission_granted(value, max_value))
return command_result{permission::i_max_playlist_size};
}
properties.emplace_back(property, key);
}
for(const auto& property : properties) {
if(*property.first == property::PLAYLIST_CURRENT_SONG_ID) {
playlist->set_current_song(cmd[property.second]);
continue;
}
playlist->properties()[property.first] = cmd[property.second].string();
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistPermList(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_playlist_permission_list, 1);
auto permissions = playlist->permissions()->listPermissions(PERM_FLAG_PUBLIC);
if(permissions.empty())
return command_result{error::vs_critical};
Command result(this->notify_response_command("notifyplaylistpermlist"));
int index = 0;
result["playlist_id"] = playlist->playlist_id();
for (const auto &elm : permissions) {
if(elm->hasValue()) {
result[index]["permid"] = elm->type->type;
result[index]["permvalue"] = elm->value;
result[index]["permnegated"] = elm->flag_negate;
result[index]["permskip"] = elm->flag_skip;
index++;
}
if(elm->hasGrant()) {
result[index]["permid"] = (uint16_t) (elm->type->type | PERM_ID_GRANT);
result[index]["permvalue"] = elm->granted;
result[index]["permnegated"] = 0;
result[index]["permskip"] = 0;
index++;
}
}
this->sendCommand(result);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistAddPerm(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_permission_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power));
auto max_value = this->calculate_permission(permission::i_permission_modify_power, 0, true);
if(!max_value.has_value) return command_result{permission::i_permission_modify_power};
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
bool conOnError = cmd[0].has("continueonerror");
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
auto val = cmd[index]["permvalue"].as<permission::PermissionValue>();
if(permission_require_granted_value(permType) && !permission::v2::permission_granted(val, max_value)) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if(!ignore_granted_values && !permission::v2::permission_granted(val, this->calculate_permission(permType, 0, true))) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if (grant) {
playlist->permissions()->setPermissionGranted(permType, cmd[index]["permvalue"], nullptr);
} else {
playlist->permissions()->setPermission(permType, cmd[index]["permvalue"], nullptr, cmd[index]["permskip"], cmd[index]["permnegated"]);
}
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistDelPerm(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_permission_modify_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_permission_modify_power));
auto ignore_granted_values = permission::v2::permission_granted(1, this->calculate_permission(permission::b_permission_modify_power_ignore, 0));
bool conOnError = cmd[0].has("continueonerror");
for (int index = 0; index < cmd.bulkCount(); index++) {
PARSE_PERMISSION(cmd);
if(!ignore_granted_values && !permission::v2::permission_granted(0, this->calculate_permission(permType, 0, true))) {
if(conOnError) continue;
return command_result{permission::i_permission_modify_power};
}
if (grant) {
playlist->permissions()->setPermissionGranted(permType, permNotGranted, nullptr);
} else {
playlist->permissions()->deletePermission(permType, nullptr);
}
}
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistSongList(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
auto songs = playlist->list_songs();
if(songs.empty())
return command_result{error::database_empty_result};
Command notify(this->notify_response_command("notifyplaylistsonglist"));
notify["playlist_id"] = playlist->playlist_id();
size_t index = 0;
for(const auto& song : songs) {
notify[index]["song_id"] = song->id;
notify[index]["song_invoker"] = song->invoker;
notify[index]["song_previous_song_id"] = song->previous_song_id;
notify[index]["song_url"] = song->url;
notify[index]["song_url_loader"] = song->url_loader;
notify[index]["song_loaded"] = song->loaded;
notify[index]["song_metadata"] = song->metadata;
index++;
}
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistSongAdd(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_add_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_add_power));
if(!cmd[0].has("invoker"))
cmd["invoker"] = "";
if(!cmd[0].has("previous")) {
auto songs = playlist->list_songs();
if(songs.empty())
cmd["previous"] = "0";
else
cmd["previous"] = songs.back()->id;
}
auto song = playlist->add_song(_this.lock(), cmd["url"], cmd["invoker"], cmd["previous"]);
if(!song) return command_result{error::vs_critical};
Command notify(this->notify_response_command("notifyplaylistsongadd"));
notify["song_id"] = song->id;
this->sendCommand(notify);
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistSongReorder(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_move_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_move_power));
SongId song_id = cmd["song_id"];
SongId previous_id = cmd["song_previous_song_id"];
auto song = playlist->find_song(song_id);
if(!song) return command_result{error::playlist_invalid_song_id};
if(!playlist->reorder_song(song_id, previous_id))
return command_result{error::vs_critical};
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandPlaylistSongRemove(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist) return command_result{error::playlist_invalid_id};
if(playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_song_remove_power, playlist->permissions()->getPermissionValue(permission::i_playlist_song_needed_remove_power));
SongId song_id = cmd["song_id"];
auto song = playlist->find_song(song_id);
if(!song) return command_result{error::playlist_invalid_song_id};
if(!playlist->delete_song(song_id))
return command_result{error::vs_critical};
return command_result{error::ok};
}
command_result ConnectedClient::handleCommandMusicBotQueueList(Command& cmd) {
return command_result{error::not_implemented}; //FIXME
/*
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_info, bot->permissionValue(permission::i_client_music_needed_info, bot->currentChannel), this->currentChannel, true);
bool bulked = cmd.hasParm("bulk") || cmd.hasParm("balk") || cmd.hasParm("pipe") || cmd.hasParm("bar") || cmd.hasParm("paypal");
int command_index = 0;
Command notify(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
{
auto history = bot->queue()->history();
for(int index = history.size(); index > 0; index--) {
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
apply_song(notify, history[index - 1], command_index);
notify[command_index]["queue_index"] = -index;
if(!bulked)
this->sendCommand(notify);
else
command_index++;
}
}
{
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
auto song = bot->queue()->currentSong();
apply_song(notify, song, command_index);
notify[command_index]["queue_index"] = 0;
if(!bulked)
this->sendCommand(notify);
else if(song)
command_index++;
}
{
auto queue = bot->queue()->queueEntries();
for(int index = 0; index < queue.size(); index++) {
if(!bulked)
notify = Command(this->getExternalType() == CLIENT_VOICE ? "notifymusicqueueentry" : "");
apply_song(notify, queue[index], command_index);
notify[command_index]["queue_index"] = index + 1;
if(!bulked)
this->sendCommand(notify);
else
command_index++;
}
}
debugMessage(this->getServerId(),"Send: {}",notify.build());
if(bulked) {
if(command_index > 0) {
this->sendCommand(notify);
} else return { ErrorType::DBEmpty };
}
if(this->getExternalType() == CLIENT_VOICE) {
Command notify("notifymusicqueuefinish");
notify["bot_id"] = bot->getClientDatabaseId();
this->sendCommand(notify);
}
return command_result{error::ok};
*/
}
command_result ConnectedClient::handleCommandMusicBotQueueAdd(Command& cmd) {
return command_result{error::not_implemented}; //FIXME
/*
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
MusicClient::loader_t loader;
auto& type = cmd[0]["type"];
if((type.castable<int>() && type.as<int>() == 0) || type.as<string>() == "yt") {
loader = bot->ytLoader(this->getServer());
} else if((type.castable<int>() && type.as<int>() == 1) || type.as<string>() == "ffmpeg") {
loader = bot->ffmpegLoader(this->getServer());
} else if((type.castable<int>() && type.as<int>() == 2) || type.as<string>() == "channel") {
loader = bot->channelLoader(this->getServer());
} else if((type.castable<int>() && type.as<int>() == -1) || type.as<string>() == "any") {
loader = bot->providerLoader(this->getServer(), "");
}
if(!loader) return command_result{error::music_invalid_action};
auto entry = bot->queue()->insertEntry(cmd["url"], _this.lock(), loader);
if(!entry) return command_result{error::vs_critical};
this->server->forEachClient([&](shared_ptr<ConnectedClient> client) {
client->notifyMusicQueueAdd(bot, entry, bot->queue()->queueEntries().size() - 1, _this.lock());
});
return command_result{error::ok};
*/
}
command_result ConnectedClient::handleCommandMusicBotQueueRemove(Command& cmd) {
return command_result{error::not_implemented}; //FIXME
/*
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
std::deque<std::shared_ptr<music::SongInfo>> songs;
for(int index = 0; index < cmd.bulkCount(); index++) {
auto entry = bot->queue()->find_queue(cmd["song_id"]);
if(!entry) {
if(cmd.hasParm("skip_error")) continue;
return command_result{error::database_empty_result};
}
songs.push_back(move(entry));
}
for(const auto& entry : songs)
bot->queue()->deleteEntry(dynamic_pointer_cast<music::PlayableSong>(entry));
this->server->forEachClient([&](shared_ptr<ConnectedClient> client) {
client->notifyMusicQueueRemove(bot, songs, _this.lock());
});
return command_result{error::ok};
*/
}
command_result ConnectedClient::handleCommandMusicBotQueueReorder(Command& cmd) {
return command_result{error::not_implemented}; //FIXME
/*
CMD_REQ_SERVER;
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = this->server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
PERM_CHECK_CHANNELR(permission::i_client_music_play_power, bot->permissionValue(permission::i_client_music_needed_play_power, bot->currentChannel), this->currentChannel, true);
auto entry = bot->queue()->find_queue(cmd["song_id"]);
if(!entry) return command_result{error::database_empty_result};
auto order = bot->queue()->changeOrder(entry, cmd["index"]);
if(order < 0) return command_result{error::vs_critical};
this->server->forEachClient([&](shared_ptr<ConnectedClient> client) {
client->notifyMusicQueueOrderChange(bot, entry, order, _this.lock());
});
return command_result{error::ok};
*/
}
command_result ConnectedClient::handleCommandMusicBotPlaylistAssign(ts::Command &cmd) {
CMD_REF_SERVER(ref_server);
CMD_RESET_IDLE;
CMD_CHK_AND_INC_FLOOD_POINTS(25);
auto bot = ref_server->musicManager->findBotById(cmd["bot_id"]);
if(!bot) return command_result{error::music_invalid_id};
if(bot->getOwner() != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_client_music_play_power, bot->calculate_permission(permission::i_client_music_needed_play_power, 0));
auto playlist = ref_server->musicManager->find_playlist(cmd["playlist_id"]);
if(!playlist && cmd["playlist_id"] != 0) return command_result{error::playlist_invalid_id};
if(ref_server->musicManager->find_bot_by_playlist(playlist))
return command_result{error::playlist_already_in_use};
if(playlist && playlist->properties()[property::PLAYLIST_OWNER_DBID] != this->getClientDatabaseId())
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::i_playlist_view_power, playlist->permissions()->getPermissionValue(permission::i_playlist_needed_view_power));
if(!ref_server->musicManager->assign_playlist(bot, playlist))
return command_result{error::vs_critical};
return command_result{error::ok};
}

File diff suppressed because it is too large Load Diff

View File

@ -94,6 +94,7 @@ MusicClient::~MusicClient() {
}
void MusicClient::sendCommand(const ts::Command &command, bool low) { }
void MusicClient::sendCommand(const ts::command_builder &command, bool low) { }
bool MusicClient::closeConnection(const std::chrono::system_clock::time_point&) {
logError(this->getServerId(), "Music manager is forced to disconnect!");

View File

@ -54,6 +54,8 @@ namespace ts {
//Basic TeaSpeak stuff
void sendCommand(const ts::Command &command, bool low) override;
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& = std::chrono::system_clock::time_point()) override;
void initialize_bot();

View File

@ -529,6 +529,11 @@ void QueryClient::sendCommand(const ts::Command &command, bool) {
logTrace(LOG_QUERY, "Send command {}", cmd);
}
void QueryClient::sendCommand(const ts::command_builder &command, bool) {
writeMessage(command.build() + config::query::newlineCharacter);
logTrace(LOG_QUERY, "Send command {}", command.build());
}
void QueryClient::tick(const std::chrono::system_clock::time_point &time) {
ConnectedClient::tick(time);
}

View File

@ -26,6 +26,7 @@ namespace ts {
void writeMessage(const std::string&);
void sendCommand(const ts::Command &command, bool low = false) override;
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;

View File

@ -11,6 +11,8 @@
#include <src/ShutdownHelper.h>
#include <ThreadPool/Timer.h>
#include "src/client/command_handler/helpers.h"
using namespace std;
using namespace std::chrono;
using namespace ts;
@ -219,7 +221,7 @@ command_result QueryClient::handleCommandLogin(Command& cmd) {
unique_lock tree_lock(this->server->channel_tree_lock);
if(joined_channel)
this->server->client_move(this->ref(), joined_channel, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, tree_lock);
} else if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1))
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1)))
this->server->assignDefaultChannel(this->ref(), true);
else
this->update_cached_permissions();
@ -271,7 +273,7 @@ command_result QueryClient::handleCommandLogout(Command &) {
if(joined) {
unique_lock server_channel_w_lock(this->server->channel_tree_lock, defer_lock);
this->server->client_move(this->ref(), joined, nullptr, "", ViewReasonId::VREASON_USER_ACTION, false, server_channel_w_lock);
} else if(!this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1)) {
} else if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1))) {
this->server->assignDefaultChannel(this->ref(), true);
} else {
this->update_cached_permissions();
@ -310,8 +312,8 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
if(target->getServerId() != this->query_account->bound_server)
return command_result{error::server_invalid_id, "You're a server bound query, and the target server isn't your origin."};
} else {
auto allowed = target->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_select, this->getType(), nullptr);
if(allowed != -1 && allowed <= 0) return command_result{permission::b_virtualserver_select};
auto allowed = target->calculate_permission(permission::b_virtualserver_select, this->getClientDatabaseId(), this->getType(), 0);
if(!permission::v2::permission_granted(1, allowed)) return command_result{permission::b_virtualserver_select};
}
}
@ -356,7 +358,7 @@ command_result QueryClient::handleCommandServerSelect(Command &cmd) {
this->subscribeChannel(this->server->channelTree->channels(), false, false);
}
auto negated_enforce_join = this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_select_godmode, 1);
auto negated_enforce_join = permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_select_godmode, 1));
if(!negated_enforce_join)
this->server->assignDefaultChannel(this->ref(), true);
else
@ -387,8 +389,8 @@ command_result QueryClient::handleCommandLeft(Command&) {
CMD_REQ_SERVER;
CMD_REQ_CHANNEL;
CMD_RESET_IDLE;
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_select_godmode, 1);
PERM_CHECK_CHANNELR(permission::b_virtualserver_select_godmode, 1, nullptr, 1);
unique_lock server_channel_lock(this->server->channel_tree_lock);
this->server->client_move(this->ref(), nullptr, nullptr, "leaving", ViewReasonId::VREASON_SERVER_LEFT, true, server_channel_lock);
return command_result{error::ok};
@ -396,7 +398,7 @@ command_result QueryClient::handleCommandLeft(Command&) {
command_result QueryClient::handleCommandServerInfo(Command &) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_info_view, 1, true);
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_info_view, 1);
Command cmd("");
@ -409,7 +411,7 @@ command_result QueryClient::handleCommandServerInfo(Command &) {
cmd["virtualserver_status"] = this->server ? ServerState::string(this->server->state) : "template";
if(this->server && this->permissionGranted(permission::PERMTEST_ORDERED, permission::b_virtualserver_connectioninfo_view, 1, nullptr, true)) {
if(this->server && permission::v2::permission_granted(1, this->calculate_permission(permission::b_virtualserver_connectioninfo_view, 0))) {
auto stats = this->server->getServerStatistics()->statistics();
auto report = this->server->serverStatistics->dataReport();
cmd["connection_bandwidth_sent_last_second_total"] = report.send_second;
@ -478,8 +480,8 @@ command_result QueryClient::handleCommandServerInfo(Command &) {
}
command_result QueryClient::handleCommandChannelList(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_channel_list, 1, true);
CMD_RESET_IDLE;
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_channel_list, 1);
Command result("");
@ -497,7 +499,7 @@ command_result QueryClient::handleCommandChannelList(Command& cmd) {
bulk["channel_name"] = channel->name();
bulk["channel_order"] = channel->channelOrder();
bulk["total_clients"] = this->server ? this->server->getClientsByChannel(channel).size() : 0;
/* bulk["channel_needed_subscribe_power"] = channel->permissions()->getPermissionValue(permission::PERMTEST_ORDERED, permission::i_channel_needed_subscribe_power, channel, 0); */
/* bulk["channel_needed_subscribe_power"] = channel->permissions()->getPermissionValue(permission::i_channel_needed_subscribe_power, channel, 0); */
if(cmd.hasParm("flags")){
bulk["channel_flag_default"] = channel->properties()[property::CHANNEL_FLAG_DEFAULT].as<string>();
@ -540,7 +542,8 @@ command_result QueryClient::handleCommandChannelList(Command& cmd) {
command_result QueryClient::handleCommandServerList(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_serverinstance_virtualserver_list, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_virtualserver_list, 1);
Command res("");
int index = 0;
@ -573,7 +576,7 @@ command_result QueryClient::handleCommandServerList(Command& cmd) {
command_result QueryClient::handleCommandServerCreate(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_create, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_create, 1);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED) {
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
@ -650,7 +653,7 @@ command_result QueryClient::handleCommandServerCreate(Command& cmd) {
command_result QueryClient::handleCommandServerDelete(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_delete, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_delete, 1);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
@ -664,7 +667,6 @@ command_result QueryClient::handleCommandServerDelete(Command& cmd) {
command_result QueryClient::handleCommandServerStart(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_start_any, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
@ -672,10 +674,8 @@ command_result QueryClient::handleCommandServerStart(Command& cmd) {
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
if(server->running()) return command_result{error::server_running, "server already running"};
if(server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_start, ClientType::CLIENT_QUERY, nullptr) != 1) {
if(!this->permissionGranted(permission::PERMTEST_HIGHEST, permission::b_virtualserver_start_any, 1))
return command_result{permission::b_virtualserver_start};
}
if(!permission::v2::permission_granted(1, server->calculate_permission(permission::b_virtualserver_start, this->getClientDatabaseId(), ClientType::CLIENT_QUERY, 0)))
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_start_any, 1);
string err;
if(!server->start(err)) return command_result{error::vs_critical, err};
@ -684,7 +684,7 @@ command_result QueryClient::handleCommandServerStart(Command& cmd) {
command_result QueryClient::handleCommandServerStop(Command& cmd) {
CMD_RESET_IDLE;
PERM_CHECKR(permission::b_virtualserver_stop, 1, true);
if(serverInstance->getVoiceServerManager()->getState() != ServerManager::STARTED)
return command_result{error::vs_critical, "Server manager isn't started yet or not finished starting"};
@ -692,10 +692,8 @@ command_result QueryClient::handleCommandServerStop(Command& cmd) {
if(!server) return command_result{error::server_invalid_id, "invalid bounded server"};
if(!server->running()) return command_result{error::server_is_not_running, "server is not running"};
if(server->calculatePermission(permission::PERMTEST_ORDERED, this->getClientDatabaseId(), permission::b_virtualserver_stop, ClientType::CLIENT_QUERY, nullptr) != 1) {
if(!this->permissionGranted(permission::PERMTEST_HIGHEST, permission::b_virtualserver_stop_any, 1))
return command_result{permission::b_virtualserver_stop};
}
if(!permission::v2::permission_granted(1, server->calculate_permission(permission::b_virtualserver_stop, this->getClientDatabaseId(), ClientType::CLIENT_QUERY, 0)))
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_stop_any, 1);
server->stop("server stopped");
return command_result{error::ok};
@ -703,7 +701,7 @@ command_result QueryClient::handleCommandServerStop(Command& cmd) {
command_result QueryClient::handleCommandInstanceInfo(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_info_view, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_info_view, 1);
Command res("");
for(const auto& e : serverInstance->properties().list_properties(property::FLAG_INSTANCE_VARIABLE, this->getType() == CLIENT_TEAMSPEAK ? property::FLAG_NEW : (uint16_t) 0))
@ -716,7 +714,7 @@ command_result QueryClient::handleCommandInstanceInfo(Command& cmd) {
}
command_result QueryClient::handleCommandInstanceEdit(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_modify_settings, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_modify_settings, 1);
for(const auto &key : cmd[0].keys()){
auto info = property::impl::info<property::InstanceProperties>(key);
@ -739,7 +737,7 @@ command_result QueryClient::handleCommandInstanceEdit(Command& cmd) {
}
command_result QueryClient::handleCommandHostInfo(Command &) {
PERM_CHECKR(permission::b_serverinstance_info_view, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_info_view, 1);
Command res("");
res["instance_uptime"] = duration_cast<seconds>(system_clock::now() - serverInstance->getStartTimestamp()).count();
@ -774,7 +772,7 @@ command_result QueryClient::handleCommandHostInfo(Command &) {
}
command_result QueryClient::handleCommandGlobalMessage(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_textmessage_send, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_textmessage_send, 1);
for(const auto &server : serverInstance->getVoiceServerManager()->serverInstances())
if(server->running()) server->broadcastMessage(server->getServerRoot(), cmd["msg"]);
@ -801,7 +799,6 @@ command_result QueryClient::handleCommandBindingList(Command& cmd) {
//TODO with mapping!
command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_snapshot_deploy, 1, true);
CMD_RESET_IDLE;
auto start = system_clock::now();
@ -809,8 +806,11 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
string host = "0.0.0.0";
uint16_t port = 0;
if(this->server) {
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_deploy, 1);
host = this->server->properties()[property::VIRTUALSERVER_HOST].as<string>();
port = this->server->properties()[property::VIRTUALSERVER_PORT].as<uint16_t>();
} else {
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_virtualserver_snapshot_deploy, 1);
}
auto hash = cmd["hash"].string();
@ -862,7 +862,7 @@ command_result QueryClient::handleCommandServerSnapshotDeploy(Command& cmd) {
}
command_result QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
PERM_CHECKR(permission::b_virtualserver_snapshot_create, 1, true);
ACTION_REQUIRES_GLOBAL_PERMISSION(permission::b_virtualserver_snapshot_create, 1);
CMD_RESET_IDLE;
CMD_REQ_SERVER;
@ -887,7 +887,7 @@ command_result QueryClient::handleCommandServerSnapshotCreate(Command& cmd) {
extern bool mainThreadActive;
command_result QueryClient::handleCommandServerProcessStop(Command& cmd) {
PERM_CHECKR(permission::b_serverinstance_stop, 1, true);
ACTION_REQUIRES_INSTANCE_PERMISSION(permission::b_serverinstance_stop, 1);
if(cmd[0].has("type")) {
if(cmd["type"] == "cancel") {

View File

@ -47,8 +47,7 @@ VoiceClient::~VoiceClient() {
memtrack::freed<VoiceClient>(this);
}
void VoiceClient::sendCommand0(const ts::Command &command, bool low, bool direct, std::unique_ptr<threads::Future<bool>> listener) {
auto cmd = command.build();
void VoiceClient::sendCommand0(const std::string_view& cmd, bool low, bool direct, std::unique_ptr<threads::Future<bool>> listener) {
if(cmd.empty()) {
logCritical(this->getServerId(), "{} Attempted to send an empty command!", CLIENT_STR_LOG_PREFIX);
return;
@ -65,7 +64,7 @@ void VoiceClient::sendCommand0(const ts::Command &command, bool low, bool direct
this->connection->sendPacket(packet, false, direct);
#ifdef PKT_LOG_CMD
logTrace(this->getServerId(), "{}[Command][Server -> Client] Sending command {}. Command low: {}. Full command: {}", CLIENT_STR_LOG_PREFIX, command.command(), low, cmd);
logTrace(this->getServerId(), "{}[Command][Server -> Client] Sending command {}. Command low: {}. Full command: {}", CLIENT_STR_LOG_PREFIX, cmd.substr(0, cmd.find(' ')), low, cmd);
#endif
}
void VoiceClient::sendAcknowledge(uint16_t packetId, bool low) {
@ -173,7 +172,7 @@ bool VoiceClient::disconnect(ts::ViewReasonId reason_id, const std::string &reas
self->closeConnection();
}, system_clock::now() + seconds(5));
this->sendCommand0(cmd, false, false, std::move(listener));
this->sendCommand0(cmd.build(), false, false, std::move(listener));
return true;
}

View File

@ -54,9 +54,11 @@ namespace ts {
bool disconnect(const std::string&) override;
bool disconnect(ViewReasonId /* reason type */, const std::string& /* reason */, const std::shared_ptr<ts::server::ConnectedClient>& /* invoker */, bool /* notify viewer */);
virtual void sendCommand(const ts::Command &command, bool low = false) { return this->sendCommand0(command, low); }
virtual void sendCommand(const ts::Command &command, bool low = false) { return this->sendCommand0(command.build(), low); }
virtual void sendCommand(const ts::command_builder &command, bool low) { return this->sendCommand0(command.build(), low); }
/* Note: Order is only guaranteed if progressDirectly is on! */
virtual void sendCommand0(const ts::Command &command, bool low = false, bool progressDirectly = false, std::unique_ptr<threads::Future<bool>> listener = nullptr);
virtual void sendCommand0(const std::string_view& /* data */, bool low = false, bool progressDirectly = false, std::unique_ptr<threads::Future<bool>> listener = nullptr);
virtual void sendAcknowledge(uint16_t packetId, bool low = false);
connection::VoiceClientConnection* getConnection(){ return connection; }

View File

@ -153,7 +153,7 @@ ts::command_result VoiceClient::handleCommandClientInitIv(Command& command) {
} else {
this->handshake.state = HandshakeState::SUCCEEDED; /* we're doing the verify via TeamSpeak */
}
this->sendCommand0(initivexpand, false, true); //If we setup the encryption now
this->sendCommand0(initivexpand.build(), false, true); //If we setup the encryption now
}
{

View File

@ -157,6 +157,19 @@ void WebClient::sendCommand(const ts::Command &command, bool low) {
this->sendJson(value);
}
void WebClient::sendCommand(const ts::command_builder &command, bool low) {
#if false
Json::Value value{};
value["type"] = "command2";
value["payload"] = command.build();
this->sendJson(value);
#else
auto data = command.build();
Command parsed_command = Command::parse(pipes::buffer_view{data.data(), data.length()}, true, false);
this->sendCommand(parsed_command, low);
#endif
}
bool WebClient::closeConnection(const std::chrono::system_clock::time_point& timeout) {
bool flushing = timeout.time_since_epoch().count() > 0;

View File

@ -26,6 +26,7 @@ namespace ts {
void sendJson(const Json::Value&);
void sendCommand(const ts::Command &command, bool low = false) override;
void sendCommand(const ts::command_builder &command, bool low) override;
bool disconnect(const std::string &reason) override;
bool closeConnection(const std::chrono::system_clock::time_point& timeout = std::chrono::system_clock::time_point()) override;

2
shared

@ -1 +1 @@
Subproject commit d42ec40a58892f4c7ff1da6dd4e69df94e2aa848
Subproject commit 23a9385afebbbdb2cba88c5ea5f84daf4c85acc4