diff --git a/git-teaspeak b/git-teaspeak index fe633dc..d26d083 160000 --- a/git-teaspeak +++ b/git-teaspeak @@ -1 +1 @@ -Subproject commit fe633dc99a6ea91c2c0a8cb13a51a7587a54cb2e +Subproject commit d26d083635929f4df73e94b3feca8287a0608612 diff --git a/server/src/Configuration.cpp b/server/src/Configuration.cpp index df4d49e..77eac41 100644 --- a/server/src/Configuration.cpp +++ b/server/src/Configuration.cpp @@ -47,6 +47,16 @@ bool config::server::strict_ut8_mode; bool config::server::show_invisible_clients_as_online; bool config::server::disable_ip_saving; bool config::server::default_music_bot; +/* + * namespace limits { + extern size_t poke_message_length; + extern size_t talk_power_request_message_length; + } + */ +size_t config::server::limits::poke_message_length; +size_t config::server::limits::talk_power_request_message_length; +size_t config::server::limits::afk_message_length; + ssize_t config::server::max_virtual_server; bool config::server::badges::allow_badges; bool config::server::badges::allow_overwolf; @@ -1299,6 +1309,27 @@ std::deque> config::create_bindings() { ADD_DESCRIPTION("Set the limit for maximal virtual servers. -1 means unlimited."); ADD_NOTE_RELOADABLE(); } + { + BIND_GROUP(limits); + + { + CREATE_BINDING("poke_message_length", FLAG_RELOADABLE); + BIND_INTEGRAL(config::server::limits::poke_message_length, 1024, 1, 262144); + ADD_NOTE_RELOADABLE(); + } + + { + CREATE_BINDING("talk_power_request_message_length", FLAG_RELOADABLE); + BIND_INTEGRAL(config::server::limits::talk_power_request_message_length, 50, 1, 262144); + ADD_NOTE_RELOADABLE(); + } + + { + CREATE_BINDING("afk_message_length", FLAG_RELOADABLE); + BIND_INTEGRAL(config::server::limits::afk_message_length, 50, 1, 262144); + ADD_NOTE_RELOADABLE(); + } + } { /* BIND_GROUP(badges); diff --git a/server/src/Configuration.h b/server/src/Configuration.h index 3340151..2aa49c5 100644 --- a/server/src/Configuration.h +++ b/server/src/Configuration.h @@ -78,6 +78,12 @@ namespace ts::config { extern bool disable_ip_saving; extern bool default_music_bot; + namespace limits { + extern size_t poke_message_length; + extern size_t talk_power_request_message_length; + extern size_t afk_message_length; + } + namespace badges { extern bool allow_overwolf; extern bool allow_badges; diff --git a/server/src/DatabaseHelper.cpp b/server/src/DatabaseHelper.cpp index 7d98f10..a2c1070 100644 --- a/server/src/DatabaseHelper.cpp +++ b/server/src/DatabaseHelper.cpp @@ -989,41 +989,48 @@ std::shared_ptr DatabaseHelper::loadClientProperties(const std::shar } std::string column; - switch (prop.type().property_index) { - case property::CLIENT_NICKNAME: - column = "client_nickname"; - break; + if(prop.type().type_property == property::PROP_TYPE_CLIENT) { + switch (prop.type().property_index) { + case property::CLIENT_NICKNAME: + column = "client_nickname"; + break; - case property::CONNECTION_CLIENT_IP: - column = "client_ip"; - break; + case property::CLIENT_LASTCONNECTED: + column = "client_last_connected"; + break; - case property::CLIENT_LASTCONNECTED: - column = "client_last_connected"; - break; + case property::CLIENT_TOTALCONNECTIONS: + column = "client_total_connections"; + break; - case property::CLIENT_TOTALCONNECTIONS: - column = "client_total_connections"; - break; + case property::CLIENT_MONTH_BYTES_UPLOADED: + column = "client_month_upload"; + break; - case property::CLIENT_MONTH_BYTES_UPLOADED: - column = "client_month_upload"; - break; + case property::CLIENT_TOTAL_BYTES_UPLOADED: + column = "client_total_upload"; + break; - case property::CLIENT_TOTAL_BYTES_UPLOADED: - column = "client_total_upload"; - break; + case property::CLIENT_MONTH_BYTES_DOWNLOADED: + column = "client_month_download"; + break; - case property::CLIENT_MONTH_BYTES_DOWNLOADED: - column = "client_month_download"; - break; + case property::CLIENT_TOTAL_BYTES_DOWNLOADED: + column = "client_total_download"; + break; - case property::CLIENT_TOTAL_BYTES_DOWNLOADED: - column = "client_total_download"; - break; + default: + return; + } + } else if(prop.type().type_property == property::PROP_TYPE_CONNECTION) { + switch (prop.type().property_index) { + case property::CONNECTION_CLIENT_IP: + column = "client_ip"; + break; - default: - return; + default: + return; + } } debugMessage(server ? server->getServerId() : 0, "[Property] Changing client property '{}' for {} (New value: {}, Column: {})", @@ -1233,13 +1240,19 @@ void DatabaseHelper::loadStartupPropertyCache() { }, &arg); } -bool DatabaseHelper::deleteGroupPermissions(const std::shared_ptr &server, ts::GroupId group_id) { - auto command = sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id", - variable{":serverId", server ? server->getServerId() : 0}, - variable{":type", permission::SQL_PERM_GROUP}, - variable{":id", group_id}).execute(); - LOG_SQL_CMD(command); - return !!command; +void DatabaseHelper::deleteGroupArtifacts(ServerId server_id, GroupId group_id) { + sql::result result{}; + + result = sql::command(this->sql, "DELETE FROM `permissions` WHERE `serverId` = :serverId AND `type` = :type AND `id` = :id", + variable{":serverId", server_id}, + variable{":type", permission::SQL_PERM_GROUP}, + variable{":id", group_id}).execute(); + LOG_SQL_CMD(result); + + result = sql::command(this->sql, "DELETE FROM `tokens` WHERE `serverId` = :serverId AND `targetGroup` = :id", + variable{":serverId", server_id}, + variable{":id", group_id}).execute(); + LOG_SQL_CMD(result); } bool DatabaseHelper::deleteChannelPermissions(const std::shared_ptr &server, ts::ChannelId channel_id) { diff --git a/server/src/DatabaseHelper.h b/server/src/DatabaseHelper.h index 0703bb7..a84f1f3 100644 --- a/server/src/DatabaseHelper.h +++ b/server/src/DatabaseHelper.h @@ -109,7 +109,7 @@ namespace ts::server { std::shared_ptr loadChannelProperties(const std::shared_ptr&, ChannelId); //Read and write std::shared_ptr loadClientProperties(const std::shared_ptr&, ClientDbId, ClientType); - bool deleteGroupPermissions(const std::shared_ptr&, GroupId); + void deleteGroupArtifacts(ServerId, GroupId); bool deleteChannelPermissions(const std::shared_ptr&, ChannelId); bool deletePlaylist(const std::shared_ptr&, PlaylistId /* playlist id */); std::deque> query_properties(ServerId /* server */, property::PropertyType /* type */, uint64_t /* id */); /* required for server snapshots */ diff --git a/server/src/Group.cpp b/server/src/Group.cpp index 851baa8..1285cad 100644 --- a/server/src/Group.cpp +++ b/server/src/Group.cpp @@ -451,7 +451,7 @@ bool GroupManager::deleteGroup(std::shared_ptr group) { LOG_SQL_CMD(res); flag_sql |= !res; - flag_sql &= serverInstance->databaseHelper()->deleteGroupPermissions(this->server.lock(), group->groupId()); + serverInstance->databaseHelper()->deleteGroupArtifacts(this->getServerId(), group->groupId()); if(flag_sql) logError(this->getServerId(), "Could not delete group {} ({}) from database. May leader to invalid data", group->name(), group->groupId()); diff --git a/server/src/client/SpeakingClient.cpp b/server/src/client/SpeakingClient.cpp index 5572690..3145260 100644 --- a/server/src/client/SpeakingClient.cpp +++ b/server/src/client/SpeakingClient.cpp @@ -496,10 +496,10 @@ command_result SpeakingClient::handleCommandClientInit(Command& cmd) { return command_result{error::client_hacked}; } } else if(key == "client_talk_request_msg") { - if(cmd["client_talk_request_msg"].string().length() > 50) + if(cmd["client_talk_request_msg"].string().length() > ts::config::server::limits::talk_power_request_message_length) return command_result{error::parameter_invalid_size, "client_talk_request_msg"}; } else if(key == "client_away_message") { - if(cmd["client_away_message"].string().length() > ts::kMaxAfkMessageLength) + if(cmd["client_away_message"].string().length() > ts::config::server::limits::afk_message_length) return command_result{error::parameter_invalid_size, "client_away_message"}; } diff --git a/server/src/client/command_handler/client.cpp b/server/src/client/command_handler/client.cpp index 62e27df..b875305 100644 --- a/server/src/client/command_handler/client.cpp +++ b/server/src/client/command_handler/client.cpp @@ -324,7 +324,7 @@ command_result ConnectedClient::handleCommandClientPoke(Command &cmd) { } auto message = cmd["msg"].string(); - if(count_characters(message) > 100) + if(count_characters(message) > ts::config::server::limits::poke_message_length) return command_result{error::parameter_invalid_size, "msg"}; for(auto& client : clients) @@ -654,12 +654,12 @@ command_result ConnectedClient::handleCommandClientEdit(Command &cmd, const std: } else if(info == property::CLIENT_AWAY_MESSAGE) { if(!self) continue; - if(cmd["client_away_message"].string().length() > ts::kMaxAfkMessageLength) + if(cmd["client_away_message"].string().length() > ts::config::server::limits::afk_message_length) return command_result{error::parameter_invalid}; } else if(!self) { /* dont edit random properties of other clients. For us self its allowed to edit the rest without permissions */ continue; } else if(info == property::CLIENT_TALK_REQUEST_MSG) { - if(cmd["client_talk_request_msg"].string().length() > ts::kMaxRequestTalkPowerMessageLength) + if(cmd["client_talk_request_msg"].string().length() > ts::config::server::limits::talk_power_request_message_length) return command_result{error::parameter_invalid}; } diff --git a/server/src/manager/SqlDataManager.cpp b/server/src/manager/SqlDataManager.cpp index 394a146..db48565 100644 --- a/server/src/manager/SqlDataManager.cpp +++ b/server/src/manager/SqlDataManager.cpp @@ -44,7 +44,7 @@ if(!result && result.msg().find(ignore) == string::npos){ #define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")"); -#define CURRENT_DATABASE_VERSION 14 +#define CURRENT_DATABASE_VERSION 15 #define CURRENT_PERMISSION_VERSION 4 #define CLIENT_UID_LENGTH "64" @@ -191,7 +191,7 @@ bool SqlDataManager::initialize(std::string& error) { return false; } - res = sql::command{this->sql(), "DELETE FROM `general` WHERE `key` = :key ORDER BY `key` LIMIT -1 OFFSET 1;", variable{":key", "lock_test"}}.execute(); + res = sql::command{this->sql(), "DELETE FROM `general` WHERE `id` IN (SELECT `id` FROM `general` WHERE `key` = :key ORDER BY `key` LIMIT -1 OFFSET 1);", variable{":key", "lock_test"}}.execute(); if(!res) { error = res.fmtStr(); return false; @@ -539,6 +539,21 @@ bool SqlDataManager::update_database(std::string &error) { db_version(14); } + case 14: { + constexpr static std::array kUpdateCommands{ + "CREATE TABLE general_dg_tmp(id INTEGER NOT NULL PRIMARY KEY [AUTO_INCREMENT], key VARCHAR(256), value TEXT);", + "INSERT INTO general_dg_tmp(key, value) SELECT key, value FROM general;", + "DROP TABLE general;", + "ALTER TABLE general_dg_tmp rename TO general;", + "CREATE UNIQUE INDEX general_id_uindex ON general (id);" + }; + + if(!execute_commands(this->sql(), error, kUpdateCommands)) + return false; + + db_version(15); + } + default: break; } diff --git a/server/src/snapshots/deploy.cpp b/server/src/snapshots/deploy.cpp index 6ac9517..0d71c94 100644 --- a/server/src/snapshots/deploy.cpp +++ b/server/src/snapshots/deploy.cpp @@ -74,6 +74,11 @@ VirtualServerManager::SnapshotDeployResult VirtualServerManager::deploy_snapshot this->instances.push_back(server); } this->adjust_executor_threads(); + + if(!server->start(error)) { + logWarning(server->getServerId(), "Failed to auto start server after snapshot deployment: {}", error); + error = ""; + } return SnapshotDeployResult::SUCCESS; } @@ -161,16 +166,30 @@ bool VirtualServerManager::try_deploy_snapshot(std::string &error, ts::ServerId channel.properties[property::CHANNEL_ID] = new_id; } - /* Update channel parents */ + /* Update channel parents and order id */ for(auto& channel : snapshot_data.parsed_channels) { - auto pid = channel.properties[property::CHANNEL_PID].as(); - if(pid > 0) { - auto new_id = mappings.channel_id.find(pid); - if(new_id == mappings.channel_id.end()) { - error = "failed to remap channel parent id for channel \"" + channel.properties[property::CHANNEL_NAME].value() + "\" (snapshot/channel tree broken?)"; - return false; + { + auto pid = channel.properties[property::CHANNEL_PID].as(); + if(pid > 0) { + auto new_id = mappings.channel_id.find(pid); + if(new_id == mappings.channel_id.end()) { + error = "failed to remap channel parent id for channel \"" + channel.properties[property::CHANNEL_NAME].value() + "\" (snapshot/channel tree broken?)"; + return false; + } + channel.properties[property::CHANNEL_PID] = new_id->second; + } + } + + { + auto oid = channel.properties[property::CHANNEL_ORDER].as(); + if(oid > 0) { + auto new_id = mappings.channel_id.find(oid); + if(new_id == mappings.channel_id.end()) { + error = "failed to remap channel order id for channel \"" + channel.properties[property::CHANNEL_NAME].value() + "\" (snapshot/channel tree broken?)"; + return false; + } + channel.properties[property::CHANNEL_ORDER] = new_id->second; } - channel.properties[property::CHANNEL_PID] = new_id->second; } } diff --git a/server/src/snapshots/permission.cpp b/server/src/snapshots/permission.cpp index 0547cb4..cf72d1b 100644 --- a/server/src/snapshots/permission.cpp +++ b/server/src/snapshots/permission.cpp @@ -70,7 +70,7 @@ bool permission_parser::parse_entry_teamspeak_v0(std::string &error, std::vector return false; } - permission::PermissionValue value{}; + permission::PermissionValue value; { auto value_string = data.value("permvalue", key_found); if(!key_found) { @@ -104,17 +104,22 @@ bool permission_parser::parse_entry_teamspeak_v0(std::string &error, std::vector continue; permission_entry* entry{nullptr}; - for(auto& e : result) + for(auto& e : result) { if(e.type == type) { entry = &e; break; } + } + if(!entry) { entry = &result.emplace_back(); entry->type = type; } - entry->value = {value, true}; - if(mapped != type->grant_name) { + + if(mapped == type->grant_name) { + entry->granted = {value, true}; + } else { + entry->value = {value, true}; entry->flag_negate = flag_negate; entry->flag_skip = flag_skip; } diff --git a/shared b/shared index 59ec412..f80f629 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit 59ec412fea21d6342311135a697696624fc0e628 +Subproject commit f80f629496aa20d7d4c883c4f8554bcf9271816e