252 lines
12 KiB
C++
252 lines
12 KiB
C++
#include <log/LogUtils.h>
|
|
#include <src/client/voice/VoiceClient.h>
|
|
#include <misc/sassert.h>
|
|
#include <misc/hex.h>
|
|
#include "DataClient.h"
|
|
#include "ConnectedClient.h"
|
|
#include "src/server/file/FileServer.h"
|
|
#include "src/InstanceHandler.h"
|
|
#include "misc/base64.h"
|
|
|
|
using namespace std;
|
|
using namespace ts;
|
|
using namespace ts::server;
|
|
using namespace ts::permission;
|
|
|
|
extern ts::server::InstanceHandler* serverInstance;
|
|
|
|
DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr<TSServer>& server) : server(server), sql(database) {
|
|
assert(database);
|
|
this->_properties = std::make_shared<Properties>();
|
|
DatabaseHelper::assign_default_properties_client(this->_properties.get(), ClientType::CLIENT_INTERNAL);
|
|
}
|
|
|
|
DataClient::~DataClient() {
|
|
this->clientPermissions = nullptr;
|
|
this->_properties = nullptr;
|
|
}
|
|
|
|
bool DataClient::loadDataForCurrentServer() { //TODO for query
|
|
if(this->getUid().empty()) return false;
|
|
properties()[property::CLIENT_DATABASE_ID] = 0;
|
|
properties()[property::CLIENT_CREATED] = 0;
|
|
properties()[property::CLIENT_TOTALCONNECTIONS] = 0;
|
|
|
|
|
|
sql::command(this->sql, "SELECT `cldbid`,`firstConnect`,`connections` FROM `clients` WHERE `serverId` = :sid AND `clientUid`=:uid LIMIT 1", variable{":sid", this->server ? this->server->getServerId() : 0}, variable{":uid", this->getUid()}).query([&](DataClient* cl, int length, string* values, string* names){
|
|
for (int index = 0; index < length; index++) {
|
|
logTrace(this->server ? this->server->getServerId() : 0, "Reading client (" + this->getUid() + ") property from client database table. (Key: " + names[index] + ", Value: " + values[index] + ")");
|
|
if (names[index] == "cldbid") {
|
|
cl->properties()[property::CLIENT_DATABASE_ID] = string(values[index]);
|
|
} else if (names[index] == "firstConnect") {
|
|
cl->properties()[property::CLIENT_CREATED] = values[index];
|
|
} else if (names[index] == "connections") {
|
|
cl->properties()[property::CLIENT_TOTALCONNECTIONS] = values[index];
|
|
} else {
|
|
debugMessage(lstream << "Unknown row name '" << names[index] << "'" << endl);
|
|
}
|
|
}
|
|
return 0;
|
|
}, this);
|
|
//Load general properties
|
|
deque<ts::PropertyWrapper> copied;
|
|
for(const auto& prop : this->_properties->list_properties()){
|
|
if((prop.type().flags & property::FLAG_GLOBAL) == 0) continue;
|
|
if(prop.type().default_value == prop.value()) continue;
|
|
copied.push_back(prop);
|
|
}
|
|
|
|
if(this->getClientDatabaseId() == 0) return false;
|
|
if(!this->server) {
|
|
if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK)
|
|
logCritical("Got a voice or web manager, which is unbound to any server!");
|
|
return false;
|
|
}
|
|
|
|
auto clType = this->getType();
|
|
if(this->getType() == CLIENT_TEAMSPEAK || this->server) {
|
|
this->_properties = serverInstance->databaseHelper()->loadClientProperties(this->server, this->getClientDatabaseId(), clType);
|
|
} else {
|
|
this->_properties = std::make_shared<Properties>();
|
|
DatabaseHelper::assign_default_properties_client(this->_properties.get(), clType);
|
|
this->_properties->registerNotifyHandler([&](Property& prop){
|
|
std::string query;
|
|
if(prop.type() == property::CLIENT_TOTALCONNECTIONS)
|
|
query = "UPDATE `clients` SET `connections` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
else if(prop.type() == property::CLIENT_NICKNAME)
|
|
query = "UPDATE `clients` SET `lastName` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
else if(prop.type() == property::CLIENT_LASTCONNECTED)
|
|
query = "UPDATE `clients` SET `lastConnect` = :value WHERE `serverId` = :sid AND `cldbid` = :cldbid";
|
|
if(query.empty()) return;
|
|
debugMessage("[SQL] " + query + " - " + to_string(0) + " - " + prop.value() + " - " + to_string(this->getClientDatabaseId()));
|
|
sql::command(this->sql, query, variable{":sid", 0}, variable{":cldbid", this->getClientDatabaseId()}, variable{":value", prop.value()}).executeLater().waitAndGetLater(LOG_SQL_CMD, {1, "future failed"});
|
|
});
|
|
}
|
|
|
|
this->_properties->toggleSave(false);
|
|
for(const auto& e : copied) {
|
|
auto p = this->properties()->find(e.type().type_property, e.type().property_index);
|
|
p = e.value();
|
|
p.setModified(false);
|
|
}
|
|
this->_properties->toggleSave(true);
|
|
|
|
/*
|
|
* //TODO What did this?
|
|
vector<string> updatedProps;
|
|
if(this->server) {
|
|
auto cclient = dynamic_cast<ConnectedClient*>(this);
|
|
if(cclient){
|
|
if(cclient->state == CONNECTED)
|
|
this->server->notifyClientPropertyUpdates(dynamic_cast<ConnectedClient*>(this)->_this.lock(), updatedProps);
|
|
}
|
|
}
|
|
*/
|
|
this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, this->getClientDatabaseId());
|
|
|
|
//Setup / fix stuff
|
|
if(!this->properties()[property::CLIENT_FLAG_AVATAR].as<string>().empty()){
|
|
if(
|
|
!this->server ||
|
|
!serverInstance->getFileServer()->findFile("/avatar_" + this->getAvatarId(),serverInstance->getFileServer()->avatarDirectory(this->server))) {
|
|
if(config::server::delete_missing_icon_permissions)
|
|
this->properties()[property::CLIENT_FLAG_AVATAR] = "";
|
|
}
|
|
}
|
|
|
|
if(this->server){
|
|
int ureadMessages = 0;
|
|
for(const auto &elm : this->server->letters->avariableLetters(this->getUid()))
|
|
if(!elm->read) ureadMessages++;
|
|
this->properties()[property::CLIENT_UNREAD_MESSAGES] = ureadMessages;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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) {
|
|
permission::PermissionValue result = permNotGranted;
|
|
if(!server_defined && !server) server = this->server;
|
|
|
|
if(server) {
|
|
return server->calculatePermission(test, this->getClientDatabaseId(), type, this->getType(), target, cache);
|
|
} 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_value_flagged(type);
|
|
if(flagged_permissions.has_value)
|
|
if(flagged_permissions.value > result || flagged_permissions.value == -1) result = flagged_permissions.value;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
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, lstream << "[Permission] Value test result for test type " << test << ".");
|
|
debugMessage(serverId, lstream << "[Permission] Permission: " << permission::resolvePermissionData(type)->name << " Required value: " << required << " Gained value: " << value << " Force required: " << force_granted << " Channel: " << (target ? target->name() : "none") << " Result: " << 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, lstream << "[Permission] Grant test result for test type " << test << ".");
|
|
debugMessage(serverId, lstream << "[Permission] Permission: " << permission::resolvePermissionData(type)->name << " Required value: " << required << " Gained value: " << value << " Force required: " << force_granted << " Channel: " << (target ? target->name() : "none") << " Result: " << result);
|
|
};
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::shared_ptr<GroupAssignment>> DataClient::assignedServerGroups() {
|
|
if(!this->server) return serverInstance->getGroupManager()->getServerGroups(this->getClientDatabaseId(), this->getType());
|
|
return this->server->groups->getServerGroups(this->getClientDatabaseId(), this->getType());
|
|
}
|
|
|
|
std::shared_ptr<GroupAssignment> DataClient::assignedChannelGroup(const shared_ptr<BasicChannel> &channel) {
|
|
if(!this->server || !channel) return {};
|
|
return this->server->groups->getChannelGroup(this->getClientDatabaseId(), channel, true);
|
|
}
|
|
|
|
bool DataClient::serverGroupAssigned(const shared_ptr<Group> &group) {
|
|
for(const auto &gr : this->assignedServerGroups())
|
|
if(gr->group == group) return true;
|
|
return false;
|
|
}
|
|
|
|
bool DataClient::channelGroupAssigned(const shared_ptr<Group> &group, const shared_ptr<BasicChannel> &channel) {
|
|
if(!channel) return false;
|
|
auto gr = this->assignedChannelGroup(channel);
|
|
sassert(gr);
|
|
if(!gr) return false;
|
|
return gr->group == group;
|
|
}
|
|
|
|
std::string DataClient::getAvatarId() {
|
|
return hex::hex(base64::validate(this->getUid()) ? base64::decode(this->getUid()) : this->getUid(), 'a', 'q');
|
|
} |