diff --git a/bin/config_sample/config.ini b/bin/config_sample/config.ini index 3c14874..844d00c 100644 --- a/bin/config_sample/config.ini +++ b/bin/config_sample/config.ini @@ -18,6 +18,7 @@ logbuffer=500 logging=modcall maximum_statements=10 multiclient_limit=15 +maximum_characters=256 [Dice] max_value=100 diff --git a/include/aoclient.h b/include/aoclient.h index 71ddf6f..1c2f799 100644 --- a/include/aoclient.h +++ b/include/aoclient.h @@ -2049,6 +2049,11 @@ class AOClient : public QObject { * @param incoming_message QString to be decoded. */ QString decodeMessage(QString incoming_message); + + /** + * @brief The size, in bytes, of the last data the client sent to the server. + */ + int last_read; }; #endif // AOCLIENT_H diff --git a/include/server.h b/include/server.h index a8d1d21..e53ec81 100644 --- a/include/server.h +++ b/include/server.h @@ -303,6 +303,11 @@ class Server : public QObject { */ int multiclient_limit; + /** + * @brief Integer representing the maximum amount of characters an IC or OOC message can contain. + */ + int max_chars; + public slots: /** * @brief Handles a new connection. diff --git a/src/aoclient.cpp b/src/aoclient.cpp index 5ccfdf6..1fc9c92 100644 --- a/src/aoclient.cpp +++ b/src/aoclient.cpp @@ -19,7 +19,12 @@ void AOClient::clientData() { + if (last_read + socket->bytesAvailable() > 30720) { // Client can send a max of 30KB to the server over two sequential reads + socket->close(); + } + QString data = QString::fromUtf8(socket->readAll()); + last_read = data.size(); if (is_partial) { data = partial_packet + data; @@ -73,6 +78,10 @@ void AOClient::handlePacket(AOPacket packet) AreaData* area = server->areas[current_area]; PacketInfo info = packets.value(packet.header, {false, 0, &AOClient::pktDefault}); + if (packet.contents.join("").size() > 16384) { + return; + } + if (!checkAuth(info.acl_mask)) { return; } diff --git a/src/aopacket.cpp b/src/aopacket.cpp index 2d16997..9eb703b 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -25,6 +25,9 @@ AOPacket::AOPacket(QString p_header, QStringList p_contents) AOPacket::AOPacket(QString p_packet) { + if (p_packet.isEmpty()) + return; + QStringList packet_contents = p_packet.split("#"); if (p_packet.at(0) == '#') { // The header is encrypted with FantaCrypt diff --git a/src/area_data.cpp b/src/area_data.cpp index 8289dc3..dfedd32 100644 --- a/src/area_data.cpp +++ b/src/area_data.cpp @@ -32,6 +32,7 @@ AreaData::AreaData(QString p_name, int p_index) : name_split.removeFirst(); name = name_split.join(":"); QSettings areas_ini("config/areas.ini", QSettings::IniFormat); + areas_ini.setIniCodec("UTF-8"); areas_ini.beginGroup(p_name); background = areas_ini.value("background", "gs4").toString(); is_protected = areas_ini.value("protected_area", "false").toBool(); @@ -41,8 +42,10 @@ AreaData::AreaData(QString p_name, int p_index) : blankposting_allowed = areas_ini.value("blankposting_allowed","true").toBool(); force_immediate = areas_ini.value("force_immediate", "false").toBool(); toggle_music = areas_ini.value("toggle_music", "true").toBool(); + showname_allowed = areas_ini.value("shownames_allowed", "true").toBool(); areas_ini.endGroup(); QSettings config_ini("config/config.ini", QSettings::IniFormat); + config_ini.setIniCodec("UTF-8"); config_ini.beginGroup("Options"); int log_size = config_ini.value("logbuffer", 50).toInt(); log_type = config_ini.value("logger","modcall").toString(); diff --git a/src/commands/area.cpp b/src/commands/area.cpp index efa55f1..8ae19af 100644 --- a/src/commands/area.cpp +++ b/src/commands/area.cpp @@ -291,6 +291,7 @@ void AOClient::cmdStatus(int argc, QStringList argv) return; } arup(ARUPType::STATUS, true); + sendServerMessageArea(ooc_name + " changed status to " + arg); } void AOClient::cmdJudgeLog(int argc, QStringList argv) diff --git a/src/commands/casing.cpp b/src/commands/casing.cpp index f7050ea..a83cb94 100644 --- a/src/commands/casing.cpp +++ b/src/commands/casing.cpp @@ -107,7 +107,6 @@ void AOClient::cmdTestify(int argc, QStringList argv) } else { clearTestimony(); - area->statement = 0; area->test_rec = AreaData::TestimonyRecording::RECORDING; sendServerMessage("Started testimony recording."); } @@ -157,6 +156,7 @@ void AOClient::cmdDeleteStatement(int argc, QStringList argv) } if (c_statement > 0 && area->testimony.size() > 2) { area->testimony.remove(c_statement); + area->statement = c_statement - 1; sendServerMessage("The statement with id " + QString::number(c_statement) + " has been deleted from the testimony."); } } diff --git a/src/config_manager.cpp b/src/config_manager.cpp index 048bd4d..2fb2186 100644 --- a/src/config_manager.cpp +++ b/src/config_manager.cpp @@ -21,6 +21,7 @@ bool ConfigManager::initConfig() { QSettings config("config/config.ini", QSettings::IniFormat); + config.setIniCodec("UTF-8"); QFileInfo config_dir_info("config/"); if (!config_dir_info.exists() || !config_dir_info.isDir()) { qCritical() << "Config directory doesn't exist!"; @@ -39,6 +40,7 @@ bool ConfigManager::initConfig() } else { QSettings areas_ini("config/areas.ini", QSettings::IniFormat); + areas_ini.setIniCodec("UTF-8"); if (areas_ini.childGroups().length() < 1) { qCritical() << "areas.ini is invalid!"; return false; @@ -105,6 +107,7 @@ bool ConfigManager::initConfig() bool ConfigManager::updateConfig(int current_version) { QSettings config("config/config.ini", QSettings::IniFormat); + config.setIniCodec("UTF-8"); if (current_version > CONFIG_VERSION) { // Config version is newer than the latest version, and the config is // invalid This could also mean the server is out of date, and the user @@ -137,6 +140,7 @@ bool ConfigManager::updateConfig(int current_version) bool ConfigManager::loadServerSettings(server_settings* settings) { QSettings config("config/config.ini", QSettings::IniFormat); + config.setIniCodec("UTF-8"); bool port_conversion_success; bool ws_port_conversion_success; bool local_port_conversion_success; diff --git a/src/main.cpp b/src/main.cpp index e8b63e0..ab475d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("akashi"); - QCoreApplication::setApplicationVersion("apricot r3 prerelease"); + QCoreApplication::setApplicationVersion("banana"); std::atexit(cleanup); ConfigManager config_manager; diff --git a/src/packets.cpp b/src/packets.cpp index 32a0629..42733db 100644 --- a/src/packets.cpp +++ b/src/packets.cpp @@ -180,9 +180,14 @@ void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket p ooc_name = dezalgo(argv[0]).replace(QRegExp("\\[|\\]|\\{|\\}|\\#|\\$|\\%|\\&"), ""); // no fucky wucky shit here if (ooc_name.isEmpty() || ooc_name == server->server_name) // impersonation & empty name protection return; + + if (ooc_name.length() > 30) { + sendServerMessage("Your name is too long! Please limit it to under 30 characters."); + return; + } QString message = dezalgo(argv[1]); - if (message.length() == 0) + if (message.length() == 0 || message.length() > server->max_chars) return; AOPacket final_packet("CT", {ooc_name, message, "0"}); if(message.at(0) == '/') { @@ -464,7 +469,6 @@ AOPacket AOClient::validateIcPacket(AOPacket packet) // and outgoing packets are different. Just RTFM. AOPacket invalid("INVALID", {}); - QStringList args; if (current_char == "" || !joined) // Spectators cannot use IC @@ -509,6 +513,9 @@ AOPacket AOClient::validateIcPacket(AOPacket packet) args.append(emote); // message text + if (incoming_args[4].toString().size() > server->max_chars) + return invalid; + QString incoming_msg = dezalgo(incoming_args[4].toString().trimmed()); if (!area->last_ic_message.isEmpty() && incoming_msg == area->last_ic_message[4] @@ -615,6 +622,15 @@ AOPacket AOClient::validateIcPacket(AOPacket packet) if (incoming_args.length() > 15) { // showname QString incoming_showname = dezalgo(incoming_args[15].toString().trimmed()); + if (!(incoming_showname == current_char || incoming_showname.isEmpty()) && !area->showname_allowed) { + sendServerMessage("Shownames are not allowed in this area!"); + return invalid; + } + if (incoming_showname.length() > 30) { + sendServerMessage("Your showname is too long! Please limit it to under 30 characters"); + return invalid; + } + // if the raw input is not empty but the trimmed input is, use a single space if (incoming_showname.isEmpty() && !incoming_args[15].toString().isEmpty()) incoming_showname = " "; @@ -726,7 +742,7 @@ AOPacket AOClient::validateIcPacket(AOPacket packet) if (args[5] != "wit") return AOPacket("MS", args); - if (area->statement == 0) { + if (area->statement == -1) { args[4] = "~~\\n-- " + args[4] + " --"; args[14] = "3"; server->broadcast(AOPacket("RT",{"testimony1"}), current_area); diff --git a/src/server.cpp b/src/server.cpp index c7b23ac..6b45068 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -290,6 +290,10 @@ void Server::loadServerConfig() multiclient_limit = config.value("multiclient_limit", "15").toInt(&multiclient_limit_conversion_success); if (!multiclient_limit_conversion_success) multiclient_limit = 15; + bool max_char_conversion_success; + max_chars = config.value("maximum_characters", "256").toInt(&max_char_conversion_success); + if (!max_char_conversion_success) + max_chars = 256; config.endGroup(); //Load dice values diff --git a/src/testimony_recorder.cpp b/src/testimony_recorder.cpp index 01178b5..312ebf9 100644 --- a/src/testimony_recorder.cpp +++ b/src/testimony_recorder.cpp @@ -23,15 +23,15 @@ void AOClient::addStatement(QStringList packet) { AreaData* area = server->areas[current_area]; int c_statement = area->statement; - if (c_statement >= 0) { + if (c_statement >= -1) { if (area->test_rec == AreaData::TestimonyRecording::RECORDING) { if (c_statement <= server->maximum_statements) { - if (c_statement == 0) + if (c_statement == -1) packet[14] = "3"; else packet[14] = "1"; - area->testimony.append(packet); area->statement = c_statement + 1; + area->testimony.append(packet); return; } else { @@ -70,6 +70,7 @@ void AOClient::clearTestimony() { AreaData* area = server->areas[current_area]; area->test_rec = AreaData::TestimonyRecording::STOPPED; + area->statement = -1; area->testimony.clear(); //!< Empty out the QVector area->testimony.squeeze(); //!< Release memory. Good idea? God knows, I do not. }