Added more spam messages to the filter. (#2488)

* Added more spam messages to the filter.

* Removed duplicate remote control vehicle button from the player vehicle menu.

* Added heuristical spam detector.

* Fixed clock in spam logger.

* Added date output to the chat logger.

* Added a message to show the user when someone is spamming.
More static text translations.

* Removed redundant mobile global in scr_globals.hpp.

* Added a spam reason to the spam logger.

* Added team/all to the chat logger.
Added a logger call for the user's chats.
This commit is contained in:
gir489 2023-12-07 14:04:00 -05:00 committed by GitHub
parent a3be8d9c03
commit ab970764fc
13 changed files with 87 additions and 31 deletions

View File

@ -10,12 +10,12 @@ namespace big
virtual void on_tick() override virtual void on_tick() override
{ {
*scr_globals::mobile.as<PBOOL>() = TRUE; *scr_globals::transaction_overlimit.as<PBOOL>() = TRUE;
} }
virtual void on_disable() override virtual void on_disable() override
{ {
*scr_globals::mobile.as<PBOOL>() = FALSE; *scr_globals::transaction_overlimit.as<PBOOL>() = FALSE;
} }
}; };

View File

@ -378,4 +378,11 @@ namespace big
RELEASE = WM_KEYUP, RELEASE = WM_KEYUP,
DOWN = WM_KEYDOWN DOWN = WM_KEYDOWN
}; };
enum SpamReason : int
{
NOT_A_SPAMMER,
STATIC_DETECTION,
TIMER_DETECTION
};
} }

View File

@ -41,8 +41,6 @@ namespace big::scr_globals
static inline const script_global dance_state(1950837); static inline const script_global dance_state(1950837);
static inline const script_global mobile(20483);
static inline const script_global transaction_overlimit(20483); static inline const script_global transaction_overlimit(20483);
static inline const script_global stats(2359296); static inline const script_global stats(2359296);

View File

@ -402,6 +402,9 @@ namespace big
bool allow_friends_into_locked_session = false; bool allow_friends_into_locked_session = false;
bool trust_friends = false; bool trust_friends = false;
bool trust_session = false; bool trust_session = false;
bool use_spam_timer = true;
float spam_timer = 2.5f;
int spam_length = 55;
const char chat_command_prefix = '/'; const char chat_command_prefix = '/';
const char chat_output_prefix = '>'; const char chat_output_prefix = '>';
@ -442,7 +445,7 @@ namespace big
bool fast_join = false; bool fast_join = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(session, log_chat_messages, log_text_messages, decloak_players, force_session_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, join_in_sctv_slots, kick_chat_spammers, kick_host_when_forcing_host, explosion_karma, damage_karma, disable_traffic, disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, block_jobs, block_muggers, block_ceo_raids, send_to_apartment_idx, send_to_warehouse_idx, chat_commands, chat_command_default_access_level, show_cheating_message, anonymous_bounty, lock_session, fast_join, unhide_players_from_player_list, allow_friends_into_locked_session, trust_friends) NLOHMANN_DEFINE_TYPE_INTRUSIVE(session, log_chat_messages, log_text_messages, decloak_players, force_session_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, join_in_sctv_slots, kick_chat_spammers, kick_host_when_forcing_host, explosion_karma, damage_karma, disable_traffic, disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, block_jobs, block_muggers, block_ceo_raids, send_to_apartment_idx, send_to_warehouse_idx, chat_commands, chat_command_default_access_level, show_cheating_message, anonymous_bounty, lock_session, fast_join, unhide_players_from_player_list, allow_friends_into_locked_session, trust_friends, use_spam_timer, spam_timer, spam_length)
} session{}; } session{};
struct settings struct settings

View File

@ -83,17 +83,17 @@ namespace rage
} }
return false; return false;
} }
bool WriteBool(bool integer) bool WriteBool(bool boolean)
{ {
return big::g_pointers->m_gta.m_write_bitbuf_bool(this, integer, 1); return big::g_pointers->m_gta.m_write_bitbuf_bool(this, boolean, 1);
} }
bool ReadBool(bool* integer) bool ReadBool(bool* boolean)
{ {
return big::g_pointers->m_gta.m_read_bitbuf_bool(this, integer, 1); return big::g_pointers->m_gta.m_read_bitbuf_bool(this, boolean, 1);
} }
bool ReadPeerId(uint64_t* integer) bool ReadPeerId(uint64_t* peer_id)
{ {
return this->ReadQWord(integer, 0x40); return this->ReadQWord(peer_id, 0x40);
} }
uint64_t ReadBits(size_t numBits) uint64_t ReadBits(size_t numBits)
{ {

View File

@ -5,6 +5,7 @@
#include "hooking.hpp" #include "hooking.hpp"
#include "packet.hpp" #include "packet.hpp"
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "util/spam.hpp"
namespace big namespace big
{ {
@ -27,6 +28,9 @@ namespace big
gamer_handle_serialize(g_player_service->get_self()->get_net_data()->m_gamer_handle, msg.m_buffer); gamer_handle_serialize(g_player_service->get_self()->get_net_data()->m_gamer_handle, msg.m_buffer);
msg.write<bool>(is_team, 1); msg.write<bool>(is_team, 1);
if (g.session.log_chat_messages)
spam::log_chat(message, g_player_service->get_self(), SpamReason::NOT_A_SPAMMER, is_team);
if (*g_pointers->m_gta.m_is_session_started) if (*g_pointers->m_gta.m_is_session_started)
for (auto& player : g_player_service->players()) for (auto& player : g_player_service->players())
if (player.second && player.second->is_valid()) if (player.second && player.second->is_valid())

View File

@ -107,14 +107,18 @@ namespace big
{ {
char message[256]; char message[256];
buffer.ReadString(message, 256); buffer.ReadString(message, 256);
bool is_team;
buffer.ReadBool(&is_team);
if (player->is_spammer) if (player->is_spammer)
return true; return true;
if (spam::is_text_spam(message)) if (auto spam_reason = spam::is_text_spam(message, player))
{ {
if (g.session.log_chat_messages) if (g.session.log_chat_messages)
spam::log_chat(message, player, true); spam::log_chat(message, player, spam_reason, is_team);
g_notification_service->push("PROTECTIONS"_T.data(),
std::format("{} {}", player->get_name(), "IS_A_SPAMMER"_T.data()));
player->is_spammer = true; player->is_spammer = true;
if (g.session.kick_chat_spammers if (g.session.kick_chat_spammers
&& !(player->is_trusted || (player->is_friend() && g.session.trust_friends) || g.session.trust_session)) && !(player->is_trusted || (player->is_friend() && g.session.trust_friends) || g.session.trust_session))
@ -131,7 +135,7 @@ namespace big
else else
{ {
if (g.session.log_chat_messages) if (g.session.log_chat_messages)
spam::log_chat(message, player, false); spam::log_chat(message, player, SpamReason::NOT_A_SPAMMER, is_team);
if (g.session.chat_commands && message[0] == g.session.chat_command_prefix) if (g.session.chat_commands && message[0] == g.session.chat_command_prefix)
command::process(std::string(message + 1), std::make_shared<chat_command_context>(player)); command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
@ -204,7 +208,7 @@ namespace big
if (reason == KickReason::VOTED_OUT) if (reason == KickReason::VOTED_OUT)
{ {
g_notification_service->push_warning("Protections", "You have been kicked by the host"); g_notification_service->push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
return true; return true;
} }

View File

@ -13,7 +13,7 @@ namespace big
if (g.notifications.transaction_rate_limit.log) if (g.notifications.transaction_rate_limit.log)
LOG(WARNING) << "Received transaction rate limit"; LOG(WARNING) << "Received transaction rate limit";
if (g.notifications.transaction_rate_limit.notify) if (g.notifications.transaction_rate_limit.notify)
g_notification_service->push_warning("Transaction Rate Limit", "You're receiving transaction rate limits, whatever you're doing do it less."); g_notification_service->push_warning("TRANSACTION_RATE_LIMIT"_T.data(), "TRANSACTION_RATE_LIMIT_MESSAGE"_T.data());
*scr_globals::transaction_overlimit.as<PBOOL>() = FALSE; *scr_globals::transaction_overlimit.as<PBOOL>() = FALSE;

View File

@ -71,7 +71,7 @@ namespace big
VEHICLE::SET_VEHICLE_ENGINE_ON(m_handle, false, true, false); VEHICLE::SET_VEHICLE_ENGINE_ON(m_handle, false, true, false);
} }
else else
g_notification_service->push_warning("Toxic", "Failed to take control of vehicle."); g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"FIX VEHICLE", {"FIX VEHICLE",
[this] { [this] {
@ -83,7 +83,7 @@ namespace big
VEHICLE::SET_VEHICLE_DIRT_LEVEL(m_handle, 0.f); VEHICLE::SET_VEHICLE_DIRT_LEVEL(m_handle, 0.f);
} }
else else
g_notification_service->push_warning("Warning", "Failed to take control of vehicle."); g_notification_service->push_warning("WARNING"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"BURST TIRES", {"BURST TIRES",
[this] { [this] {
@ -97,7 +97,7 @@ namespace big
} }
} }
else else
g_notification_service->push_warning("Toxic", "Failed to take control of vehicle."); g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"HALT", {"HALT",
[this] { [this] {
@ -106,7 +106,7 @@ namespace big
VEHICLE::BRING_VEHICLE_TO_HALT(m_handle, 1, 5, true); VEHICLE::BRING_VEHICLE_TO_HALT(m_handle, 1, 5, true);
} }
else else
g_notification_service->push_warning("Toxic", "Failed to take control of vehicle."); g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"COPY VEHICLE", {"COPY VEHICLE",
[this] { [this] {
@ -119,14 +119,14 @@ namespace big
if (entity::take_control_of(m_handle)) if (entity::take_control_of(m_handle))
VEHICLE::SET_VEHICLE_FORWARD_SPEED(m_handle, 79); VEHICLE::SET_VEHICLE_FORWARD_SPEED(m_handle, 79);
else else
g_notification_service->push_warning("Toxic", "Failed to take control of vehicle."); g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"LAUNCH", {"LAUNCH",
[this] { [this] {
if (entity::take_control_of(m_handle)) if (entity::take_control_of(m_handle))
ENTITY::APPLY_FORCE_TO_ENTITY(m_handle, 1, 0.f, 0.f, 50000.f, 0.f, 0.f, 0.f, 0, 0, 1, 1, 0, 1); ENTITY::APPLY_FORCE_TO_ENTITY(m_handle, 1, 0.f, 0.f, 50000.f, 0.f, 0.f, 0.f, 0, 0, 1, 1, 0, 1);
else else
g_notification_service->push_warning("Toxic", "Failed to take control of vehicle."); g_notification_service->push_warning("TOXIC"_T.data(), "VEHICLE_FAILED_CONTROL"_T.data());
}}, }},
{"EJECT", {"EJECT",
[this] { [this] {

View File

@ -88,6 +88,7 @@ namespace big
std::optional<uint32_t> player_time_value; std::optional<uint32_t> player_time_value;
std::optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>> player_time_value_received_time; std::optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>> player_time_value_received_time;
std::optional<uint32_t> time_difference; std::optional<uint32_t> time_difference;
std::optional<std::chrono::time_point<std::chrono::steady_clock>> last_message_time;
uint32_t num_time_syncs_sent = 9999; uint32_t num_time_syncs_sent = 9999;
bool block_explosions = false; bool block_explosions = false;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "file_manager/file.hpp" #include "file_manager/file.hpp"
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "core/enums.hpp"
namespace namespace
{ {
@ -59,32 +60,66 @@ namespace
"LevelLifters", "LevelLifters",
". com", ". com",
"$1,000,000,000", "$1,000,000,000",
"Instant Delivery",
"0 Ban Risk",
"Discord For Cheap Money",
}; };
} }
namespace big::spam namespace big::spam
{ {
inline bool is_text_spam(const char* text) inline SpamReason is_text_spam(const char* text, player_ptr player)
{ {
if (g.session.use_spam_timer)
{
if (player->last_message_time.has_value())
{
auto currentTime = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::seconds>(currentTime - player->last_message_time.value());
player->last_message_time.emplace(currentTime);
if (strlen(text) > g.session.spam_length && diff.count() <= g.session.spam_timer)
return SpamReason::TIMER_DETECTION;
}
else
{
player->last_message_time.emplace(std::chrono::steady_clock::now());
}
}
for (auto e : spam_texts) for (auto e : spam_texts)
if (strstr(text, e) != 0) if (strstr(text, e) != 0)
return true; return SpamReason::STATIC_DETECTION;
return false; return SpamReason::NOT_A_SPAMMER;
} }
inline void log_chat(char* msg, player_ptr player, bool is_spam) inline void log_chat(char* msg, player_ptr player, SpamReason spam_reason, bool is_team)
{ {
std::ofstream log(g_file_manager.get_project_file(is_spam ? "./spam.log" : "./chat.log").get_path(), std::ios::app); std::ofstream log(g_file_manager.get_project_file(spam_reason != SpamReason::NOT_A_SPAMMER ? "./spam.log" : "./chat.log").get_path(), std::ios::app);
auto& data = *player->get_net_data(); auto& data = *player->get_net_data();
auto ip = player->get_ip_address(); auto ip = player->get_ip_address();
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
auto timer = std::chrono::system_clock::to_time_t(now);
auto local_time = *std::localtime(&timer);
std::string spam_reason_str = "";
switch (spam_reason)
{
case SpamReason::STATIC_DETECTION: spam_reason_str = "(Static Detection) "; break;
case SpamReason::TIMER_DETECTION: spam_reason_str = "(Timer Detection) "; break;
}
log << spam_reason_str << "[" << std::put_time(&local_time, "%m/%d/%Y %I:%M:%S") << ":" << std::setfill('0') << std::setw(3) << ms.count() << " " << std::put_time(&local_time, "%p") << "] ";
if (ip) if (ip)
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <" << (int)ip.value().m_field1 << "." log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <" << (int)ip.value().m_field1 << "."
<< (int)ip.value().m_field2 << "." << (int)ip.value().m_field3 << "." << (int)ip.value().m_field4 << ">: " << msg << std::endl; << (int)ip.value().m_field2 << "." << (int)ip.value().m_field3 << "." << (int)ip.value().m_field4 << "> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
else else
log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <UNKNOWN>: " << msg << std::endl; log << player->get_name() << " (" << data.m_gamer_handle.m_rockstar_id << ") <UNKNOWN> " << ((is_team == true) ? "[TEAM]: " : "[ALL]: ") << msg << std::endl;
log.close(); log.close();
} }

View File

@ -196,6 +196,12 @@ namespace big
if (ImGui::BeginListBox("##chat", get_listbox_dimensions())) if (ImGui::BeginListBox("##chat", get_listbox_dimensions()))
{ {
static char msg[256]; static char msg[256];
ImGui::Checkbox("USE_SPAM_TIMER"_T.data(), &g.session.use_spam_timer);
if (g.session.use_spam_timer)
{
ImGui::SliderFloat("SPAM_TIMER"_T.data(), &g.session.spam_timer, 0.5f, 5.0f);
ImGui::SliderInt("SPAM_LENGTH"_T.data(), &g.session.spam_length, 1, 256);
}
ImGui::Checkbox("AUTO_KICK_CHAT_SPAMMERS"_T.data(), &g.session.kick_chat_spammers); ImGui::Checkbox("AUTO_KICK_CHAT_SPAMMERS"_T.data(), &g.session.kick_chat_spammers);
ImGui::Checkbox("LOG_CHAT_MSG"_T.data(), &g.session.log_chat_messages); ImGui::Checkbox("LOG_CHAT_MSG"_T.data(), &g.session.log_chat_messages);
ImGui::Checkbox("LOG_TXT_MSG"_T.data(), &g.session.log_text_messages); ImGui::Checkbox("LOG_TXT_MSG"_T.data(), &g.session.log_text_messages);

View File

@ -50,8 +50,6 @@ namespace big
ImGui::SameLine(); ImGui::SameLine();
components::player_command_button<"sshuntright">(g_player_service->get_selected(), {}); components::player_command_button<"sshuntright">(g_player_service->get_selected(), {});
components::player_command_button<"rcplayer">(g_player_service->get_selected());
ImGui::EndListBox(); ImGui::EndListBox();
} }
ImGui::EndGroup(); ImGui::EndGroup();