#include #include #include #include #include "./DataClient.h" #include "../InstanceHandler.h" using namespace std; using namespace ts; using namespace ts::server; using namespace ts::permission; DataClient::DataClient(sql::SqlManager* database, const std::shared_ptr& server) : server(server), sql(database) { assert(database); this->_properties = DatabaseHelper::default_properties_client(nullptr, ClientType::CLIENT_INTERNAL); } DataClient::~DataClient() { this->clientPermissions = nullptr; this->_properties = nullptr; } constexpr static std::string_view kClientLoadCommand{R"( SELECT `client_database_id`, `client_created`, `client_last_connected`, `client_total_connections`, `client_month_upload`, `client_month_download`, `client_total_upload`, `client_total_download` FROM `clients_server` WHERE `server_id` = :sid AND `client_unique_id` = :uid )"}; bool DataClient::loadDataForCurrentServer() { auto uniqueId = this->getUid(); if(uniqueId.empty()) { return false; } auto ref_server = this->server; auto server_id = ref_server ? ref_server->getServerId() : 0; properties()[property::CLIENT_DATABASE_ID] = 0; this->clientPermissions = std::make_shared(); auto properties = this->properties(); sql::command{this->sql, std::string{kClientLoadCommand}, variable{":uid", uniqueId}, variable{":sid", server_id}}.query([&](int length, std::string* values, std::string* names) { auto index{0}; try { assert(names[index] == "client_database_id"); properties[property::CLIENT_DATABASE_ID] = std::stoull(values[index++]); assert(names[index] == "client_created"); properties[property::CLIENT_CREATED] = std::stoull(values[index++]); assert(names[index] == "client_last_connected"); properties[property::CLIENT_LASTCONNECTED] = std::stoull(values[index++]); assert(names[index] == "client_total_connections"); properties[property::CLIENT_TOTALCONNECTIONS] = std::stoull(values[index++]); assert(names[index] == "client_month_upload"); properties[property::CLIENT_MONTH_BYTES_UPLOADED] = std::stoull(values[index++]); assert(names[index] == "client_month_download"); properties[property::CLIENT_MONTH_BYTES_DOWNLOADED] = std::stoull(values[index++]); assert(names[index] == "client_total_upload"); properties[property::CLIENT_TOTAL_BYTES_UPLOADED] = std::stoull(values[index++]); assert(names[index] == "client_total_download"); properties[property::CLIENT_TOTAL_BYTES_DOWNLOADED] = std::stoull(values[index++]); assert(index == length); } catch (std::exception& ex) { logError(server_id, "Failed to load client {} base properties from database: {} (Index {})", this->getUid(), ex.what(), index - 1 ); properties[property::CLIENT_DATABASE_ID] = 0; } }); if(this->properties()[property::CLIENT_DATABASE_ID].as() == 0) return false; //Load general properties std::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(!ref_server) { if(this->getType() == ClientType::CLIENT_WEB || this->getType() == ClientType::CLIENT_TEAMSPEAK) { logCritical(LOG_INSTANCE, "Got a voice or web client, which is unbound to any server!"); } return false; } this->_properties = serverInstance->databaseHelper()->loadClientProperties(ref_server, this->getClientDatabaseId(), this->getType()); 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); this->clientPermissions = serverInstance->databaseHelper()->loadClientPermissionManager(ref_server, this->getClientDatabaseId()); //Setup / fix stuff #if 0 if(!this->properties()[property::CLIENT_FLAG_AVATAR].as().empty()){ if( !ref_server || !serverInstance->getFileServer()->findFile("/avatar_" + this->getAvatarId(),serverInstance->getFileServer()->avatarDirectory(ref_server))) { if(config::server::delete_missing_icon_permissions) this->properties()[property::CLIENT_FLAG_AVATAR] = ""; } } #endif if(ref_server) { this->properties()[property::CLIENT_UNREAD_MESSAGES] = ref_server->letters->unread_letter_count(this->getUid()); } return true; } std::vector> DataClient::calculate_permissions( const std::deque &permissions, ChannelId channel, bool granted, std::shared_ptr cache) { if(permissions.empty()) { return {}; } if(!cache) { cache = std::make_shared(); } if(!cache->client_permissions) { /* so we don't have to load that shit later */ cache->client_permissions = this->clientPermissions; } if(channel == -1) { auto current_channel = this->currentChannel; channel = current_channel ? current_channel->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::v2::PermissionFlaggedValue DataClient::calculate_permission( permission::PermissionType permission, ChannelId channel, bool granted, std::shared_ptr cache) { auto result = this->calculate_permissions({permission}, channel, granted, cache); if(result.empty()) return {0, false}; return result.back().second; } std::vector> DataClient::assignedServerGroups() { if(!this->server) return serverInstance->getOldGroupManager()->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'); }