#include #include #include #include #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& server) : server(server), sql(database) { assert(database); this->_properties = std::make_shared(); 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 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(); 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 updatedProps; if(this->server) { auto cclient = dynamic_cast(this); if(cclient){ if(cclient->state == CONNECTED) this->server->notifyClientPropertyUpdates(dynamic_cast(this)->_this.lock(), updatedProps); } } */ this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(this->server, this->getClientDatabaseId()); //Setup / fix stuff if(!this->properties()[property::CLIENT_FLAG_AVATAR].as().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& target, std::shared_ptr cache, std::shared_ptr 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> DataClient::permissionValues(permission::PermissionTestType test, const std::deque& permissions, const std::shared_ptr &channel, std::shared_ptr cache, std::shared_ptr 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> 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& 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& target, bool force_granted, std::shared_ptr cache, std::shared_ptr 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(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& 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(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> 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 DataClient::assignedChannelGroup(const shared_ptr &channel) { if(!this->server || !channel) return {}; return this->server->groups->getChannelGroup(this->getClientDatabaseId(), channel, true); } bool DataClient::serverGroupAssigned(const shared_ptr &group) { for(const auto &gr : this->assignedServerGroups()) if(gr->group == group) return true; return false; } bool DataClient::channelGroupAssigned(const shared_ptr &group, const shared_ptr &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'); }