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 b80865f34c
commit 95b9724fff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 87 additions and 31 deletions

View File

@ -10,12 +10,12 @@ namespace big
virtual void on_tick() override
{
*scr_globals::mobile.as<PBOOL>() = TRUE;
*scr_globals::transaction_overlimit.as<PBOOL>() = TRUE;
}
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,
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 mobile(20483);
static inline const script_global transaction_overlimit(20483);
static inline const script_global stats(2359296);

View File

@ -402,6 +402,9 @@ namespace big
bool allow_friends_into_locked_session = false;
bool trust_friends = 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_output_prefix = '>';
@ -442,7 +445,7 @@ namespace big
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{};
struct settings

View File

@ -83,17 +83,17 @@ namespace rage
}
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)
{

View File

@ -5,6 +5,7 @@
#include "hooking.hpp"
#include "packet.hpp"
#include "services/players/player_service.hpp"
#include "util/spam.hpp"
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);
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)
for (auto& player : g_player_service->players())
if (player.second && player.second->is_valid())

View File

@ -107,14 +107,18 @@ namespace big
{
char message[256];
buffer.ReadString(message, 256);
bool is_team;
buffer.ReadBool(&is_team);
if (player->is_spammer)
return true;
if (spam::is_text_spam(message))
if (auto spam_reason = spam::is_text_spam(message, player))
{
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;
if (g.session.kick_chat_spammers
&& !(player->is_trusted || (player->is_friend() && g.session.trust_friends) || g.session.trust_session))
@ -131,7 +135,7 @@ namespace big
else
{
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)
command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
@ -204,7 +208,7 @@ namespace big
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;
}

View File

@ -13,7 +13,7 @@ namespace big
if (g.notifications.transaction_rate_limit.log)
LOG(WARNING) << "Received transaction rate limit";
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;

View File

@ -71,7 +71,7 @@ namespace big
VEHICLE::SET_VEHICLE_ENGINE_ON(m_handle, false, true, false);
}
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",
[this] {
@ -83,7 +83,7 @@ namespace big
VEHICLE::SET_VEHICLE_DIRT_LEVEL(m_handle, 0.f);
}
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",
[this] {
@ -97,7 +97,7 @@ namespace big
}
}
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",
[this] {
@ -106,7 +106,7 @@ namespace big
VEHICLE::BRING_VEHICLE_TO_HALT(m_handle, 1, 5, true);
}
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",
[this] {
@ -119,14 +119,14 @@ namespace big
if (entity::take_control_of(m_handle))
VEHICLE::SET_VEHICLE_FORWARD_SPEED(m_handle, 79);
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",
[this] {
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);
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",
[this] {

View File

@ -88,6 +88,7 @@ namespace big
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<uint32_t> time_difference;
std::optional<std::chrono::time_point<std::chrono::steady_clock>> last_message_time;
uint32_t num_time_syncs_sent = 9999;
bool block_explosions = false;

View File

@ -1,6 +1,7 @@
#pragma once
#include "file_manager/file.hpp"
#include "services/players/player_service.hpp"
#include "core/enums.hpp"
namespace
{
@ -59,32 +60,66 @@ namespace
"LevelLifters",
". com",
"$1,000,000,000",
"Instant Delivery",
"0 Ban Risk",
"Discord For Cheap Money",
};
}
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)
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 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)
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
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();
}

View File

@ -196,6 +196,12 @@ namespace big
if (ImGui::BeginListBox("##chat", get_listbox_dimensions()))
{
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("LOG_CHAT_MSG"_T.data(), &g.session.log_chat_messages);
ImGui::Checkbox("LOG_TXT_MSG"_T.data(), &g.session.log_text_messages);

View File

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