├── .gitignore ├── LICENSE ├── README.md ├── SecureServe ├── bans.json ├── config.lua ├── fxmanifest.lua ├── secureserve.key └── src │ ├── client │ ├── blacklists │ │ ├── blacklisted_commands.lua │ │ ├── blacklisted_sprites.lua │ │ └── blacklisted_weapons.lua │ ├── core │ │ ├── blue_screen.lua │ │ ├── cache.lua │ │ ├── client_logger.lua │ │ ├── config_loader.lua │ │ └── entity_monitor.lua │ ├── init.lua │ ├── main.lua │ └── protections │ │ ├── anti_afk_injection.lua │ │ ├── anti_ai.lua │ │ ├── anti_aim_assist.lua │ │ ├── anti_bigger_hitbox.lua │ │ ├── anti_entity_security.lua │ │ ├── anti_explosion_bullet.lua │ │ ├── anti_freecam.lua │ │ ├── anti_give_weapon.lua │ │ ├── anti_god_mode.lua │ │ ├── anti_infinite_stamina.lua │ │ ├── anti_invisible.lua │ │ ├── anti_load_resource_file.lua │ │ ├── anti_magic_bullet.lua │ │ ├── anti_no_ragdoll.lua │ │ ├── anti_no_recoil.lua │ │ ├── anti_no_reload.lua │ │ ├── anti_noclip.lua │ │ ├── anti_ocr.lua │ │ ├── anti_player_blips.lua │ │ ├── anti_resource_stop.lua │ │ ├── anti_spectate.lua │ │ ├── anti_speed_hack.lua │ │ ├── anti_state_bag_overflow.lua │ │ ├── anti_super_jump.lua │ │ ├── anti_teleport.lua │ │ ├── anti_visions.lua │ │ ├── anti_weapon_damage_modifier.lua │ │ ├── anti_weapon_pickup.lua │ │ ├── index.html │ │ └── protection_manager.lua │ ├── main.lua │ ├── module │ ├── module.js │ └── module.lua │ ├── server │ ├── core │ │ ├── admin_whitelist.lua │ │ ├── auto_config.lua │ │ ├── ban_manager.lua │ │ ├── config_manager.lua │ │ ├── debug_module.lua │ │ ├── discord_logger.lua │ │ ├── install.js │ │ ├── logger.lua │ │ └── player_manager.lua │ ├── main.lua │ └── protections │ │ ├── anti_create_entity.lua │ │ ├── anti_entity_spam.lua │ │ ├── anti_execution.lua │ │ ├── anti_explosions.lua │ │ ├── anti_explosive_damage.lua │ │ ├── anti_particle_effects.lua │ │ ├── anti_resource_injection.lua │ │ ├── anti_server_cfg_options.lua │ │ ├── anti_weapon_damage_modifier.lua │ │ ├── heartbeat.lua │ │ └── resource_manager.lua │ └── shared │ ├── init.lua │ └── lib │ ├── callbacks.lua │ ├── encryption.lua │ ├── require.lua │ └── utils.lua └── keep-alive ├── client.lua └── fxmanifest.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | .vscode/ 43 | SecureServe-AC.rar 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## New Update | Soon 2 | # SecureServe - Free & Open Source Fivem Anti-Cheat 3 | 4 | - **Discord:** [Join Our Server](https://discord.gg/z6qGGtbcr4) for live support and updates. 5 | - **Docs:** [SecureServe Documentation](https://peleg.gitbook.io/secureserve/) 6 | - **Support the anticheat for future updates:** [KOFI](https://ko-fi.com/peleg) 7 | - **Please use the release beta or v versions only unless u want to the test latest version (might be bugged)!** 8 | 9 | SecureServe is a state-of-the-art anti-cheat solution designed specifically for FiveM servers. Combining advanced detection techniques with comprehensive server protection, it ensures a fair and secure gaming environment. This open-source script is completely free to use, modify, and extend. 10 | 11 | --- 12 | 13 | ## 🚀 **Getting Started** 14 | 15 | ### Step-by-Step Installation 16 | 1. **Encountering Ban Messages:** During the initial setup, you may see the following ban reason: 17 | > *"A player has been banned for Trigger Event with an executor (name of the event)"* 18 | 2. **How to Fix It:** 19 | - Open the configuration file. 20 | - Identify the event name causing the issue. 21 | - Add the event name to the **whitelisted events list** in the config. 22 | 3. **Still Have Issues?** 23 | - Read our docs: [SecureServe Documentation](https://peleg.gitbook.io/secureserve/) 24 | - Join our [Discord](https://discord.gg/z6qGGtbcr4) and open a ticket for personalized support. 25 | 26 | --- 27 | 28 | ## 🛡️ **Core Features** 29 | 30 | ### Advanced Entity Detections 31 | - **Unauthorized Entity Blocking:** Prevents cheats from spawning illegitimate entities. 32 | - **Trigger Event Monitoring:** Automatically detects and prevents unauthorized triggers. 33 | - **Suspicious Resource Scanning:** Identifies and flags unauthorized resources. 34 | - **Internal Executor Protection:** Detects hidden executor exploits. 35 | - **Audio Manipulation Defense:** Stops unauthorized sound exploits. 36 | - **Entity Control Safeguard:** Secures entities from control hijacking. 37 | - **Enhanced Player Safety:** Ensures players are shielded from typical exploits. 38 | 39 | ### Intelligent Client-Side Protections 40 | - **Menu and Cheat Detection:** Flags unauthorized cheat menus. 41 | - **Noclip & Freecam Defense:** Prevents players from abusing these features. 42 | - **Godmode Prevention:** Detects invincibility cheats. 43 | - **Weapon Exploit Detection:** Identifies rapid-fire and recoil cheats. 44 | - **AI Modification Alerts:** Flags altered AI files used for exploits. 45 | 46 | ### Comprehensive Server-Side Monitoring 47 | - **Weapon and Particle Oversight:** Tracks unauthorized items and particle effects. 48 | - **Explosion Management:** Detects and blocks unauthorized explosions. 49 | - **Resource Security:** Stops unauthorized attempts to halt server resources. 50 | 51 | --- 52 | 53 | ## 📥 **Installation Guide** 54 | 55 | 1. **Set Up Logging Webhooks:** Enable webhook logs for monitoring actions. 56 | 2. **Adjust Whitelisted Events:** Update the config file with events causing false positives. 57 | 3. **Explosion Threshold Tuning:** Set minimum and maximum values for explosion detections tailored to your server. 58 | 59 | **Sample Ban Export Command:** 60 | ```lua 61 | exports['SecureServe']:banPlayer(source, 'Detected Cheat Activity') 62 | ``` 63 | 64 | --- 65 | 66 | ## 🌐 **Upcoming Enhancements** 67 | - **Anti Internal Module:** Returning soon with optimized performance. 68 | - **Standalone Admin Panel:** Features added for ESX, QBCore, and standalone frameworks. 69 | 70 | --- 71 | 72 | ## 🤝 **Contributing to SecureServe** 73 | We value contributions! If you encounter issues, have suggestions, or want to contribute code, submit a pull request or report issues on our GitHub. 74 | 75 | --- 76 | 77 | ## 🎥 **Screenshots & Video Previews** 78 | 79 | # **Admin Panel (Ingame Panel)** 80 | ![Admin Panel](https://github.com/user-attachments/assets/17db7796-9602-474a-9549-e2fb7b701a22) 81 | ![Detection Interface](https://github.com/user-attachments/assets/5ec653eb-6fdd-47ce-9e4a-d727fb449aa2) 82 | ![Image 1](https://github.com/user-attachments/assets/4d5864d8-a984-4b89-bce6-7c26a74264f2) 83 | ![Image 2](https://github.com/user-attachments/assets/19745935-d0e8-460a-af98-944ca078ee8e) 84 | ![Image 3](https://github.com/user-attachments/assets/e680de5d-eef3-44b0-bf47-65b5397a1b55) 85 | ![Image 4](https://github.com/user-attachments/assets/93aae8da-67ae-43c4-bdff-e7f3ecc1adb0) 86 | 87 | # **Detections** 88 | ![Image 5](https://github.com/user-attachments/assets/6d381556-3273-4b45-b2c6-fd1e07c836b9) 89 | ![Image 6](https://github.com/user-attachments/assets/f7f51ae5-0229-4261-a91f-525cd64afd6d) 90 | ![Image 7](https://github.com/user-attachments/assets/7ff2e07e-5f4c-4caa-b308-fedb87e44aa3) 91 | ![Image 8](https://github.com/user-attachments/assets/7a73d5ec-bd6f-441e-9761-7f4734d8c471) 92 | ![Image 9](https://github.com/user-attachments/assets/14964ca5-85eb-4df1-8aa1-b8b000790d8c) 93 | ![Image 10](https://github.com/user-attachments/assets/788300fa-0c1b-4361-bf84-c0d066af9cba) 94 | ![Image 11](https://github.com/user-attachments/assets/74bbe83a-1967-4f2f-8ec6-0b9bc85604eb) 95 | 96 | ### Video Previews 97 | - **[Watch Preview 1](https://www.youtube.com/watch?v=xgFFfGNQehk)** 98 | - **[Watch Preview 2](https://youtu.be/BfSHgVtE3eE)** 99 | 100 | --- 101 | 102 | ## 🏷️ **License** 103 | SecureServe is licensed under the [GNU Affero General Public License v3.0](https://www.gnu.org/licenses/agpl-3.0.en.html). You are free to use, modify, and share it under the terms of this license. 104 | 105 | --- 106 | 107 | ## 📞 **Contact & Support** 108 | - **Join Us on Discord:** [Get Help Here](https://discord.gg/z6qGGtbcr4) 109 | 110 | --- 111 | 112 | ## 📚 **Documentation** 113 | Access our detailed documentation for installation, configuration, and troubleshooting guides: 114 | - **GitBook:** [SecureServe Documentation](https://peleg.gitbook.io/secureserve/) 115 | 116 | **Experience unmatched security with SecureServe, the professional-grade anti-cheat solution for FiveM servers.** 117 | -------------------------------------------------------------------------------- /SecureServe/bans.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /SecureServe/fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version "cerulean" 2 | game "gta5" 3 | 4 | author "SecureServe.net" 5 | version "1.2.1" 6 | 7 | files { 8 | "bans.json", 9 | "src/client/protections/index.html", 10 | "secureserve.key" 11 | } 12 | 13 | ui_page "src/client/protections/index.html" 14 | 15 | shared_scripts { 16 | "src/module/module.lua", 17 | "src/module/module.js", 18 | "src/shared/lib/require.lua", 19 | "src/shared/lib/encryption.lua", 20 | "src/shared/lib/utils.lua", 21 | "src/shared/lib/callbacks.lua", 22 | "src/shared/init.lua", 23 | } 24 | 25 | client_scripts { 26 | "src/client/init.lua", 27 | "src/client/core/config_loader.lua", 28 | "src/client/core/cache.lua", 29 | "src/client/core/entity_monitor.lua", 30 | "src/client/core/client_logger.lua", 31 | "src/client/core/blue_screen.lua", 32 | "src/client/protections/protection_manager.lua", 33 | "src/client/protections/anti_load_resource_file.lua", 34 | "src/client/protections/anti_invisible.lua", 35 | "src/client/protections/anti_no_reload.lua", 36 | "src/client/protections/anti_explosion_bullet.lua", 37 | "src/client/protections/anti_entity_security.lua", 38 | "src/client/protections/anti_magic_bullet.lua", 39 | "src/client/protections/anti_aim_assist.lua", 40 | "src/client/protections/anti_noclip.lua", 41 | "src/client/protections/anti_resource_stop.lua", 42 | "src/client/protections/anti_god_mode.lua", 43 | "src/client/protections/anti_spectate.lua", 44 | "src/client/protections/anti_give_weapon.lua", 45 | "src/client/protections/anti_freecam.lua", 46 | "src/client/protections/anti_teleport.lua", 47 | "src/client/protections/anti_weapon_damage_modifier.lua", 48 | "src/client/protections/anti_ocr.lua", 49 | "src/client/protections/anti_player_blips.lua", 50 | "src/client/protections/anti_speed_hack.lua", 51 | "src/client/protections/anti_state_bag_overflow.lua", 52 | "src/client/protections/anti_afk_injection.lua", 53 | "src/client/protections/anti_ai.lua", 54 | "src/client/protections/anti_bigger_hitbox.lua", 55 | "src/client/protections/anti_no_recoil.lua", 56 | "src/client/protections/anti_visions.lua", 57 | "src/client/protections/anti_weapon_pickup.lua", 58 | "src/client/main.lua" 59 | } 60 | server_scripts { 61 | "config.lua", 62 | "src/server/main.lua", 63 | "src/server/core/config_manager.lua", 64 | "src/server/core/ban_manager.lua", 65 | "src/server/core/player_manager.lua", 66 | "src/server/core/logger.lua", 67 | "src/server/core/debug_module.lua", 68 | "src/server/core/auto_config.lua", 69 | "src/server/core/discord_logger.lua", 70 | "src/server/core/admin_whitelist.lua", 71 | "src/server/protections/resource_manager.lua", 72 | "src/server/protections/anti_execution.lua", 73 | "src/server/protections/anti_entity_spam.lua", 74 | "src/server/protections/anti_resource_injection.lua", 75 | "src/server/protections/anti_weapon_damage_modifier.lua", 76 | "src/server/protections/anti_explosions.lua", 77 | "src/server/protections/anti_particle_effects.lua", 78 | "src/server/protections/heartbeat.lua", 79 | "src/server/core/install.js" 80 | } 81 | 82 | dependencies { 83 | "/server:5181", 84 | "screenshot-basic", 85 | "keep-alive" 86 | } 87 | 88 | lua54 "yes" 89 | 90 | exports { 91 | "get_event_whitelist", 92 | "add_event_handler", 93 | "register_net_event" 94 | } 95 | 96 | server_exports { 97 | "banPlayer", 98 | "get_logger", 99 | "get_debug_module", 100 | "get_auto_config", 101 | "whitelist_event", 102 | "validate_event", 103 | "module_punish", 104 | "SecureLog" 105 | } -------------------------------------------------------------------------------- /SecureServe/secureserve.key: -------------------------------------------------------------------------------- 1 | dont-touch-this-will-auto-update-next-restart -------------------------------------------------------------------------------- /SecureServe/src/client/blacklists/blacklisted_commands.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | 3 | ---@class BlacklistedCommandsModule 4 | local BlacklistedCommands = {} 5 | 6 | ---@description Initialize Blacklisted Commands check 7 | function BlacklistedCommands.initialize() 8 | Citizen.CreateThread(function() 9 | while true do 10 | local registered_commands = GetRegisteredCommands() 11 | for _, k in pairs(SecureServe.Protection.BlacklistedCommands) do 12 | for _, v in pairs(registered_commands) do 13 | if k.command == v.name then 14 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Blacklisted Command (" .. k.command .. ")", k.webhook, k.time) 15 | end 16 | end 17 | end 18 | 19 | Citizen.Wait(7600) 20 | end 21 | end) 22 | end 23 | 24 | ProtectionManager.register_protection("blacklisted_commands", BlacklistedCommands.initialize) 25 | 26 | return BlacklistedCommands -------------------------------------------------------------------------------- /SecureServe/src/client/blacklists/blacklisted_sprites.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | 3 | ---@class BlacklistedSpritesModule 4 | local BlacklistedSprites = {} 5 | 6 | ---@description Initialize Blacklisted Sprites check 7 | function BlacklistedSprites.initialize() 8 | Citizen.CreateThread(function() 9 | while true do 10 | for k, v in pairs(SecureServe.Protection.BlacklistedSprites) do 11 | if HasStreamedTextureDictLoaded(v.sprite) then 12 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Blacklisted Sprite (" .. v.name .. ")", v.webhook, v.time) 13 | end 14 | end 15 | 16 | Citizen.Wait(5700) 17 | end 18 | end) 19 | end 20 | 21 | ProtectionManager.register_protection("blacklisted_sprites", BlacklistedSprites.initialize) 22 | 23 | return BlacklistedSprites -------------------------------------------------------------------------------- /SecureServe/src/client/blacklists/blacklisted_weapons.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local Cache = require("client/core/cache") 3 | 4 | ---@class BlacklistedWeaponsModule 5 | local BlacklistedWeapons = {} 6 | 7 | ---@description Initialize Blacklisted Weapons check 8 | function BlacklistedWeapons.initialize() 9 | Citizen.CreateThread(function() 10 | while true do 11 | Citizen.Wait(4000) 12 | 13 | local player = Cache.Get("ped") 14 | local weapon = Cache.Get("selectedWeapon") 15 | 16 | for k, v in pairs(SecureServe.Protection.BlacklistedWeapons) do 17 | if weapon == GetHashKey(v.name) then 18 | RemoveWeaponFromPed(player, weapon) 19 | end 20 | end 21 | end 22 | end) 23 | end 24 | 25 | ProtectionManager.register_protection("blacklisted_weapons", BlacklistedWeapons.initialize) 26 | 27 | return BlacklistedWeapons -------------------------------------------------------------------------------- /SecureServe/src/client/core/blue_screen.lua: -------------------------------------------------------------------------------- 1 | ---@class BlueScreenModule 2 | local BlueScreen = {} 3 | local bluescreenActive = false 4 | 5 | ---@description Initialize the blue screen module 6 | function BlueScreen.initialize() 7 | local bluescreenActive = false 8 | 9 | RegisterNetEvent("SecureServe:ShowWindowsBluescreen", function() 10 | if bluescreenActive then return end 11 | bluescreenActive = true 12 | 13 | local soundId = GetSoundId() 14 | PlaySoundFrontend(soundId, "Bed", "WastedSounds", true) 15 | 16 | local stopCodes = { 17 | "SYSTEM_SERVICE_EXCEPTION", 18 | "CRITICAL_PROCESS_DIED", 19 | "PAGE_FAULT_IN_NONPAGED_AREA", 20 | "MEMORY_MANAGEMENT", 21 | "UNEXPECTED_KERNEL_MODE_TRAP", 22 | "DPC_WATCHDOG_VIOLATION", 23 | "IRQL_NOT_LESS_OR_EQUAL", 24 | "KERNEL_SECURITY_CHECK_FAILURE", 25 | "SYSTEM_THREAD_EXCEPTION_NOT_HANDLED", 26 | "UNEXPECTED_STORE_EXCEPTION", 27 | "DRIVER_POWER_STATE_FAILURE", 28 | "KMODE_EXCEPTION_NOT_HANDLED" 29 | } 30 | 31 | local cheatingErrorCodes = { 32 | "SECURE_SERV_ANTICHEAT_VIOLATION", 33 | "MEMORY_INTEGRITY_FAILURE", 34 | "CHEAT_ENGINE_DETECTED", 35 | "MEMORY_INJECTION_DETECTED", 36 | "INVALID_GAME_MODIFICATION", 37 | "PROCESS_TAMPERING_DETECTED" 38 | } 39 | 40 | local stopCode = math.random() > 0.4 41 | and cheatingErrorCodes[math.random(1, #cheatingErrorCodes)] 42 | or stopCodes[math.random(1, #stopCodes)] 43 | 44 | local randomErr = string.format("0x%08X", math.random(0, 4294967295)) 45 | 46 | local percent = 0 47 | local lastUpdate = GetGameTimer() 48 | 49 | Citizen.CreateThread(function() 50 | SetNuiFocus(true, true) 51 | 52 | while bluescreenActive do 53 | DisableAllControlActions(0) 54 | 55 | DrawRect(0.5, 0.5, 1.0, 1.0, 0, 120, 212, 255) 56 | 57 | SetTextFont(4) 58 | SetTextScale(1.8, 1.8) 59 | SetTextColour(255, 255, 255, 255) 60 | SetTextCentre(true) 61 | SetTextDropShadow(0, 0, 0, 0, 255) 62 | SetTextEdge(0, 0, 0, 0, 0) 63 | BeginTextCommandDisplayText("STRING") 64 | AddTextComponentSubstringPlayerName(":(") 65 | EndTextCommandDisplayText(0.5, 0.22) 66 | 67 | SetTextFont(4) 68 | SetTextScale(0.65, 0.65) 69 | SetTextColour(255, 255, 255, 255) 70 | SetTextCentre(true) 71 | SetTextDropShadow(0, 0, 0, 0, 255) 72 | BeginTextCommandDisplayText("STRING") 73 | AddTextComponentSubstringPlayerName("Your PC ran into a problem and needs to restart.") 74 | EndTextCommandDisplayText(0.5, 0.33) 75 | 76 | SetTextFont(4) 77 | SetTextScale(0.43, 0.43) 78 | SetTextColour(255, 255, 255, 190) 79 | SetTextCentre(true) 80 | BeginTextCommandDisplayText("STRING") 81 | AddTextComponentSubstringPlayerName( 82 | "We're just collecting some error info, and then we'll restart for you.") 83 | EndTextCommandDisplayText(0.5, 0.39) 84 | 85 | local currentTime = GetGameTimer() 86 | if currentTime - lastUpdate > 30 then 87 | if percent < 30 then 88 | percent = percent + math.random(2, 3) 89 | elseif percent < 70 then 90 | percent = percent + math.random(3, 5) 91 | elseif percent < 90 then 92 | percent = percent + math.random(1, 3) 93 | elseif percent < 100 then 94 | percent = percent + 1 95 | end 96 | percent = math.min(percent, 100) 97 | lastUpdate = currentTime 98 | end 99 | 100 | SetTextFont(4) 101 | SetTextScale(0.43, 0.43) 102 | SetTextColour(255, 255, 255, 190) 103 | SetTextCentre(true) 104 | BeginTextCommandDisplayText("STRING") 105 | AddTextComponentSubstringPlayerName(percent .. "% complete") 106 | EndTextCommandDisplayText(0.5, 0.44) 107 | 108 | SetTextFont(4) 109 | SetTextScale(0.37, 0.37) 110 | SetTextColour(255, 255, 255, 190) 111 | SetTextCentre(false) 112 | BeginTextCommandDisplayText("STRING") 113 | AddTextComponentSubstringPlayerName( 114 | "If you'd like to know more, you can search online later for this error:") 115 | EndTextCommandDisplayText(0.33, 0.7) 116 | 117 | SetTextFont(4) 118 | SetTextScale(0.37, 0.37) 119 | SetTextColour(255, 255, 255, 190) 120 | SetTextCentre(false) 121 | BeginTextCommandDisplayText("STRING") 122 | AddTextComponentSubstringPlayerName(stopCode) 123 | EndTextCommandDisplayText(0.33, 0.74) 124 | 125 | SetTextFont(4) 126 | SetTextScale(0.37, 0.37) 127 | SetTextColour(255, 255, 255, 190) 128 | SetTextCentre(false) 129 | BeginTextCommandDisplayText("STRING") 130 | AddTextComponentSubstringPlayerName(randomErr) 131 | EndTextCommandDisplayText(0.33, 0.78) 132 | 133 | Citizen.Wait(0) 134 | end 135 | 136 | SetNuiFocus(false, false) 137 | end) 138 | 139 | Citizen.SetTimeout(3000, function() 140 | bluescreenActive = false 141 | if soundId then 142 | StopSound(soundId) 143 | ReleaseSoundId(soundId) 144 | end 145 | end) 146 | end) 147 | 148 | AddEventHandler('onResourceStop', function(resourceName) 149 | if GetCurrentResourceName() ~= resourceName then return end 150 | bluescreenActive = false 151 | SetNuiFocus(false, false) 152 | end) 153 | end 154 | 155 | return BlueScreen 156 | -------------------------------------------------------------------------------- /SecureServe/src/client/core/cache.lua: -------------------------------------------------------------------------------- 1 | ---@class Cache 2 | local Cache = {} 3 | local config_loader = require("client/core/config_loader") 4 | 5 | Cache.Values = { 6 | ped = nil, 7 | vehicle = nil, 8 | isInVehicle = false, 9 | isSwimming = false, 10 | isSwimmingUnderWater = false, 11 | isFalling = false, 12 | isInvisible = false, 13 | health = 0, 14 | armor = 0, 15 | coords = vector3(0,0,0), 16 | lastUpdate = 0, 17 | selectedWeapon = nil, 18 | damageTaken = false, 19 | isAdmin = false, 20 | permissions = {}, 21 | permissionsLastUpdate = 0 22 | } 23 | 24 | Cache.UpdateIntervals = { 25 | coords = 1000, 26 | selectedWeapon = 2500, 27 | ped = 5000, 28 | permissions = 30000, -- Check permissions every 30 seconds 29 | default = 3000 30 | } 31 | 32 | Cache.LastUpdated = {} 33 | Cache.LastValues = {} 34 | 35 | local updateThreads = {} 36 | 37 | ---@description Initialize the cache 38 | function Cache.initialize() 39 | for _, threadId in pairs(updateThreads) do 40 | if threadId then 41 | TerminateThread(threadId) 42 | end 43 | end 44 | updateThreads = {} 45 | 46 | Cache.UpdateAll() 47 | Cache.StartUpdateThreads() 48 | 49 | -- Request permission check on initialization 50 | Cache.RequestPermissionCheck() 51 | end 52 | 53 | function Cache.UpdateAll() 54 | local currentTime = GetGameTimer() 55 | Cache.Values.lastUpdate = currentTime 56 | 57 | local ped = PlayerPedId() 58 | Cache.Values.ped = ped 59 | 60 | for k, v in pairs(Cache.Values) do 61 | Cache.LastValues[k] = v 62 | Cache.LastUpdated[k] = currentTime 63 | end 64 | 65 | Cache.Values.health = GetEntityHealth(ped) 66 | Cache.Values.armor = GetPedArmour(ped) 67 | Cache.Values.coords = GetEntityCoords(ped) 68 | Cache.Values.selectedWeapon = GetSelectedPedWeapon(ped) 69 | Cache.Values.isInVehicle = IsPedInAnyVehicle(ped, false) 70 | if Cache.Values.isInVehicle then 71 | Cache.Values.vehicle = GetVehiclePedIsIn(ped, false) 72 | else 73 | Cache.Values.vehicle = nil 74 | end 75 | 76 | Cache.Values.isSwimming = IsPedSwimming(ped) 77 | Cache.Values.isSwimmingUnderWater = IsPedSwimmingUnderWater(ped) 78 | Cache.Values.isFalling = IsPedFalling(ped) 79 | Cache.Values.isInvisible = IsEntityVisible(ped) == 0 80 | Cache.Values.isAdmin = config_loader.is_whitelisted(GetPlayerServerId(PlayerId())) 81 | end 82 | 83 | function Cache.Get(key, subKey) 84 | local currentTime = GetGameTimer() 85 | local updateInterval = Cache.UpdateIntervals[key] or Cache.UpdateIntervals.default 86 | 87 | -- Handle special case for permission check 88 | if key == "hasPermission" and subKey then 89 | Cache.CheckPermission(subKey) 90 | return Cache.Values.permissions[subKey] or false 91 | end 92 | 93 | if not Cache.LastUpdated[key] or (currentTime - Cache.LastUpdated[key]) > updateInterval then 94 | Cache.ForceUpdate(key) 95 | end 96 | 97 | return Cache.Values[key] 98 | end 99 | 100 | function Cache.ForceUpdate(key) 101 | local currentTime = GetGameTimer() 102 | local ped = Cache.Values.ped 103 | 104 | if currentTime - (Cache.LastUpdated["ped"] or 0) > Cache.UpdateIntervals.ped then 105 | ped = PlayerPedId() 106 | Cache.Values.ped = ped 107 | Cache.LastUpdated["ped"] = currentTime 108 | end 109 | 110 | if key == "ped" then 111 | elseif key == "vehicle" then 112 | if Cache.Values.isInVehicle then 113 | Cache.Values.vehicle = GetVehiclePedIsIn(ped, false) 114 | else 115 | Cache.Values.vehicle = nil 116 | end 117 | elseif key == "isInVehicle" then 118 | Cache.Values.isInVehicle = IsPedInAnyVehicle(ped, false) 119 | elseif key == "isSwimming" then 120 | Cache.Values.isSwimming = IsPedSwimming(ped) 121 | elseif key == "isSwimmingUnderWater" then 122 | Cache.Values.isSwimmingUnderWater = IsPedSwimmingUnderWater(ped) 123 | elseif key == "isFalling" then 124 | Cache.Values.isFalling = IsPedFalling(ped) 125 | elseif key == "isInvisible" then 126 | Cache.Values.isInvisible = IsEntityVisible(ped) == 0 127 | elseif key == "health" then 128 | Cache.Values.health = GetEntityHealth(ped) 129 | elseif key == "armor" then 130 | Cache.Values.armor = GetPedArmour(ped) 131 | elseif key == "coords" then 132 | Cache.Values.coords = GetEntityCoords(ped) 133 | elseif key == "selectedWeapon" then 134 | Cache.Values.selectedWeapon = GetSelectedPedWeapon(ped) 135 | elseif key == "isAdmin" then 136 | Cache.Values.isAdmin = config_loader.is_whitelisted(GetPlayerServerId(PlayerId())) 137 | elseif key == "permissions" then 138 | Cache.RequestPermissionCheck() 139 | end 140 | 141 | Cache.LastUpdated[key] = currentTime 142 | 143 | Cache.LastValues[key] = Cache.Values[key] 144 | end 145 | 146 | function Cache.StartUpdateThreads() 147 | local updateGroups = { 148 | fast = { 149 | interval = 1000, 150 | keys = {"coords", "selectedWeapon"} 151 | }, 152 | medium = { 153 | interval = 2500, 154 | keys = {"isInVehicle", "vehicle", "health", "armor", "isFalling"} 155 | }, 156 | slow = { 157 | interval = 5000, 158 | keys = {"isSwimming", "isSwimmingUnderWater", "isInvisible", "isAdmin"} 159 | }, 160 | permission = { 161 | interval = 30000, -- Every 30 seconds 162 | keys = {"permissions"} 163 | } 164 | } 165 | 166 | for groupName, groupData in pairs(updateGroups) do 167 | updateThreads[groupName] = Citizen.CreateThread(function() 168 | while true do 169 | Citizen.Wait(groupData.interval) 170 | 171 | if groupName == "slow" then 172 | local ped = PlayerPedId() 173 | Cache.Values.ped = ped 174 | Cache.LastUpdated["ped"] = GetGameTimer() 175 | end 176 | 177 | for _, key in ipairs(groupData.keys) do 178 | Cache.ForceUpdate(key) 179 | end 180 | end 181 | end) 182 | end 183 | end 184 | 185 | ---@description Request permission check from server 186 | function Cache.RequestPermissionCheck() 187 | TriggerServerEvent("SecureServe:RequestPermissions") 188 | Cache.Values.permissionsLastUpdate = GetGameTimer() 189 | Cache.LastUpdated["permissions"] = GetGameTimer() 190 | end 191 | 192 | ---@description Check if player has specific permission 193 | ---@param permission string The permission to check 194 | function Cache.CheckPermission(permission) 195 | local currentTime = GetGameTimer() 196 | -- If permissions haven't been checked recently, request an update 197 | if currentTime - Cache.Values.permissionsLastUpdate > Cache.UpdateIntervals.permissions then 198 | Cache.RequestPermissionCheck() 199 | end 200 | end 201 | 202 | -- Event handler for receiving permissions from server 203 | RegisterNetEvent("SecureServe:ReceivePermissions", function(permissions) 204 | Cache.Values.permissions = permissions or {} 205 | Cache.Values.permissionsLastUpdate = GetGameTimer() 206 | Cache.LastUpdated["permissions"] = GetGameTimer() 207 | end) 208 | 209 | AddEventHandler("gameEventTriggered", function(name, args) 210 | if name == "CEventNetworkEntityDamage" then 211 | local victim = args[1] 212 | if victim == Cache.Values.ped then 213 | Cache.Values.damageTaken = true 214 | Cache.ForceUpdate("health") 215 | Cache.ForceUpdate("armor") 216 | end 217 | end 218 | end) 219 | 220 | AddEventHandler('onResourceStop', function(resourceName) 221 | if GetCurrentResourceName() ~= resourceName then return end 222 | 223 | for _, threadId in pairs(updateThreads) do 224 | if threadId then 225 | TerminateThread(threadId) 226 | end 227 | end 228 | 229 | updateThreads = {} 230 | Cache.Values = {} 231 | Cache.LastUpdated = {} 232 | Cache.LastValues = {} 233 | end) 234 | 235 | return Cache -------------------------------------------------------------------------------- /SecureServe/src/client/core/client_logger.lua: -------------------------------------------------------------------------------- 1 | ---@class ClientLoggerModule 2 | local ClientLogger = { 3 | levels = { 4 | DEBUG = 0, 5 | INFO = 1, 6 | WARN = 2, 7 | ERROR = 3, 8 | FATAL = 4 9 | }, 10 | colors = { 11 | DEBUG = "^5", 12 | INFO = "^2", 13 | WARN = "^3", 14 | ERROR = "^1", 15 | FATAL = "^1", 16 | RESET = "^7" 17 | }, 18 | level = 1, 19 | max_history = 4, 20 | history = {}, 21 | debug_enabled = false, 22 | cleanup_thread = nil, 23 | last_cleanup = 0 24 | } 25 | 26 | ---@description Initialize the client logger 27 | ---@param config table Configuration options 28 | function ClientLogger.initialize(config) 29 | if ClientLogger.cleanup_thread then 30 | TerminateThread(ClientLogger.cleanup_thread) 31 | ClientLogger.cleanup_thread = nil 32 | end 33 | 34 | ClientLogger.history = {} 35 | ClientLogger.last_cleanup = GetGameTimer() 36 | 37 | if config then 38 | ClientLogger.level = config.LogLevel or ClientLogger.level 39 | ClientLogger.max_history = config.MaxLogHistory or ClientLogger.max_history 40 | ClientLogger.debug_enabled = config.Debug or false 41 | end 42 | 43 | ClientLogger.info("Client logger initialized with debug mode: " .. tostring(ClientLogger.debug_enabled)) 44 | 45 | RegisterNetEvent("SecureServe:UpdateDebugMode") 46 | AddEventHandler("SecureServe:UpdateDebugMode", function(enabled) 47 | ClientLogger.debug_enabled = enabled 48 | ClientLogger.info("Debug mode " .. (enabled and "enabled" or "disabled")) 49 | end) 50 | 51 | ClientLogger.cleanup_thread = Citizen.CreateThread(function() 52 | while true do 53 | Citizen.Wait(60000) 54 | 55 | local current_time = GetGameTimer() 56 | if (current_time - ClientLogger.last_cleanup) < 60000 then 57 | goto continue 58 | end 59 | 60 | if #ClientLogger.history > (ClientLogger.max_history * 1.5) then 61 | local target_size = ClientLogger.max_history 62 | local history_copy = {} 63 | 64 | for i = #ClientLogger.history - target_size + 1, #ClientLogger.history do 65 | if ClientLogger.history[i] then 66 | table.insert(history_copy, ClientLogger.history[i]) 67 | end 68 | end 69 | 70 | ClientLogger.history = history_copy 71 | ClientLogger.last_cleanup = current_time 72 | 73 | collectgarbage("step", 50) 74 | end 75 | 76 | ::continue:: 77 | end 78 | end) 79 | end 80 | 81 | ---@description Format a log message 82 | ---@param level string The log level 83 | ---@param message string The message to log 84 | ---@param ... any Additional values to include in the log 85 | ---@return string formatted_message The formatted log message 86 | function ClientLogger.format(level, message, ...) 87 | local color = ClientLogger.colors[level] or ClientLogger.colors.INFO 88 | local reset = ClientLogger.colors.RESET 89 | 90 | local final_message = string.format("[%s%s%s] %s", 91 | color, 92 | level, 93 | reset, 94 | message 95 | ) 96 | 97 | local args = {...} 98 | if #args > 0 then 99 | for i, v in ipairs(args) do 100 | if type(v) == "table" then 101 | final_message = final_message .. " " .. ClientLogger.simple_table_format(v) 102 | else 103 | final_message = final_message .. " " .. tostring(v) 104 | end 105 | end 106 | end 107 | 108 | return final_message 109 | end 110 | 111 | function ClientLogger.simple_table_format(t) 112 | if type(t) ~= "table" then return tostring(t) end 113 | 114 | local count = 0 115 | local max_entries = 5 116 | local result = "{" 117 | 118 | for k, v in pairs(t) do 119 | count = count + 1 120 | if count > max_entries then 121 | result = result .. ",...}" 122 | return result 123 | end 124 | 125 | local val 126 | if type(v) == "table" then 127 | val = "{...}" 128 | elseif type(v) == "string" and #v > 20 then 129 | val = string.sub(v, 1, 20) .. "..." 130 | else 131 | val = tostring(v) 132 | end 133 | 134 | result = result .. tostring(k) .. "=" .. val 135 | 136 | if count < max_entries then 137 | result = result .. "," 138 | end 139 | end 140 | 141 | return result .. "}" 142 | end 143 | 144 | ---@description Add a log entry to the history 145 | ---@param level string The log level 146 | ---@param message string The message to log 147 | function ClientLogger.add_to_history(level, message) 148 | if level == "DEBUG" and not ClientLogger.debug_enabled then 149 | return 150 | end 151 | 152 | if #message > 200 then 153 | message = string.sub(message, 1, 200) .. "..." 154 | end 155 | 156 | table.insert(ClientLogger.history, { 157 | level = level, 158 | message = message, 159 | time = GetGameTimer() 160 | }) 161 | 162 | if #ClientLogger.history > (ClientLogger.max_history * 1.5) then 163 | local current_time = GetGameTimer() 164 | 165 | if (current_time - ClientLogger.last_cleanup) < 30000 then 166 | return 167 | end 168 | 169 | local target_size = ClientLogger.max_history 170 | local history_copy = {} 171 | 172 | for i = #ClientLogger.history - target_size + 1, #ClientLogger.history do 173 | if ClientLogger.history[i] then 174 | table.insert(history_copy, ClientLogger.history[i]) 175 | end 176 | end 177 | 178 | ClientLogger.history = history_copy 179 | ClientLogger.last_cleanup = current_time 180 | end 181 | end 182 | 183 | ---@description Send a log to the server for potential Discord logging 184 | ---@param level string The log level 185 | ---@param message string The message to log 186 | function ClientLogger.send_to_server(level, message) 187 | if level == "ERROR" or level == "FATAL" then 188 | if #message > 500 then 189 | message = string.sub(message, 1, 500) .. "..." 190 | end 191 | TriggerServerEvent("SecureServe:ClientLog", level, message) 192 | end 193 | end 194 | 195 | ---@description Log a debug message 196 | ---@param message string The message to log 197 | ---@param ... any Additional values to include in the log 198 | function ClientLogger.debug(message, ...) 199 | if ClientLogger.levels.DEBUG < ClientLogger.level then 200 | return 201 | end 202 | 203 | if not ClientLogger.debug_enabled then 204 | return 205 | end 206 | 207 | local formatted = ClientLogger.format("DEBUG", message, ...) 208 | ClientLogger.add_to_history("DEBUG", formatted) 209 | 210 | print(formatted) 211 | end 212 | 213 | ---@description Log an info message 214 | ---@param message string The message to log 215 | ---@param ... any Additional values to include in the log 216 | function ClientLogger.info(message, ...) 217 | if ClientLogger.levels.INFO < ClientLogger.level then 218 | return 219 | end 220 | 221 | local formatted = ClientLogger.format("INFO", message, ...) 222 | ClientLogger.add_to_history("INFO", formatted) 223 | 224 | if ClientLogger.debug_enabled then 225 | print(formatted) 226 | end 227 | end 228 | 229 | ---@description Log a warning message 230 | ---@param message string The message to log 231 | ---@param ... any Additional values to include in the log 232 | function ClientLogger.warn(message, ...) 233 | if ClientLogger.levels.WARN < ClientLogger.level then 234 | return 235 | end 236 | 237 | local formatted = ClientLogger.format("WARN", message, ...) 238 | ClientLogger.add_to_history("WARN", formatted) 239 | 240 | if ClientLogger.debug_enabled then 241 | print(formatted) 242 | end 243 | 244 | if #message < 100 then 245 | TriggerServerEvent("SecureServe:ForwardLog", "WARN", message) 246 | end 247 | end 248 | 249 | ---@description Log an error message 250 | ---@param message string The message to log 251 | ---@param ... any Additional values to include in the log 252 | function ClientLogger.error(message, ...) 253 | if ClientLogger.levels.ERROR < ClientLogger.level then 254 | return 255 | end 256 | 257 | local formatted = ClientLogger.format("ERROR", message, ...) 258 | ClientLogger.add_to_history("ERROR", formatted) 259 | 260 | print(formatted) 261 | 262 | TriggerServerEvent("SecureServe:ForwardLog", "ERROR", message) 263 | end 264 | 265 | ---@description Log a fatal error message 266 | ---@param message string The message to log 267 | ---@param ... any Additional values to include in the log 268 | function ClientLogger.fatal(message, ...) 269 | if ClientLogger.levels.FATAL < ClientLogger.level then 270 | return 271 | end 272 | 273 | local formatted = ClientLogger.format("FATAL", message, ...) 274 | ClientLogger.add_to_history("FATAL", formatted) 275 | 276 | print(formatted) 277 | 278 | TriggerServerEvent("SecureServe:ForwardLog", "FATAL", message) 279 | end 280 | 281 | ---@description Get the log history 282 | ---@param count number The number of entries to retrieve (default: all) 283 | ---@param level string Optional filter by log level 284 | ---@return table log_entries The log entries 285 | function ClientLogger.get_history(count, level) 286 | local result = {} 287 | local actual_count = math.min(count or #ClientLogger.history, #ClientLogger.history) 288 | local start_index = #ClientLogger.history - actual_count + 1 289 | start_index = math.max(1, start_index) 290 | 291 | for i = start_index, #ClientLogger.history do 292 | local entry = ClientLogger.history[i] 293 | if not level or entry.level == level then 294 | table.insert(result, entry) 295 | end 296 | end 297 | 298 | return result 299 | end 300 | 301 | ---@description Set the debug mode 302 | ---@param enabled boolean The debug mode 303 | function ClientLogger.set_debug_mode(enabled) 304 | ClientLogger.debug_enabled = enabled 305 | end 306 | 307 | function ClientLogger.cleanup() 308 | if ClientLogger.cleanup_thread then 309 | TerminateThread(ClientLogger.cleanup_thread) 310 | ClientLogger.cleanup_thread = nil 311 | end 312 | 313 | ClientLogger.history = {} 314 | collectgarbage("step", 50) 315 | end 316 | 317 | AddEventHandler('onResourceStop', function(resourceName) 318 | if GetCurrentResourceName() ~= resourceName then return end 319 | ClientLogger.cleanup() 320 | end) 321 | 322 | return ClientLogger -------------------------------------------------------------------------------- /SecureServe/src/client/core/config_loader.lua: -------------------------------------------------------------------------------- 1 | ---@class ConfigLoaderModule 2 | local ConfigLoader = {} 3 | 4 | local Utils = require("shared/lib/utils") 5 | local ClientLogger = require("client/core/client_logger") 6 | local protection_count = {} 7 | 8 | -- Initialize global variables 9 | _G.SecureServeConfig = nil 10 | _G.SecureServeLoaded = false 11 | _G.SecureServeProtectionSettings = {} 12 | _G.SecureServeInitCalled = false 13 | _G.SecureServeAdminList = {} 14 | _G.SecureServeLastAdminUpdate = 0 15 | 16 | ---@description Initialize the client-side config loader 17 | function ConfigLoader.initialize() 18 | if _G.SecureServeInitCalled then return end 19 | _G.SecureServeInitCalled = true 20 | 21 | ClientLogger.info("^5[LOADING] ^3Client Config^7") 22 | 23 | TriggerServerEvent("requestConfig") 24 | 25 | RegisterNetEvent("receiveConfig", function(serverConfig) 26 | _G.SecureServeConfig = serverConfig 27 | _G.SecureServe = serverConfig 28 | ConfigLoader.process_config(serverConfig) 29 | _G.SecureServeLoaded = true 30 | ClientLogger.info("^5[SUCCESS] ^3Client Config^7 received from server") 31 | end) 32 | 33 | local attempts = 0 34 | local maxAttempts = 10 35 | 36 | while not _G.SecureServeLoaded and attempts < maxAttempts do 37 | Wait(1000) 38 | attempts = attempts + 1 39 | if not _G.SecureServeLoaded then 40 | TriggerServerEvent("requestConfig") 41 | end 42 | end 43 | end 44 | 45 | ---@description Get config value with optional default 46 | ---@param key string The config key to get 47 | ---@param default any Optional default value if key doesn't exist 48 | ---@return any The config value or default 49 | function ConfigLoader.get(key, default) 50 | if not _G.SecureServeLoaded or not _G.SecureServeConfig then 51 | return default 52 | end 53 | 54 | local parts = {} 55 | for part in key:gmatch("[^%.]+") do 56 | table.insert(parts, part) 57 | end 58 | 59 | local value = _G.SecureServeConfig 60 | for _, part in ipairs(parts) do 61 | if type(value) ~= "table" then 62 | return default 63 | end 64 | value = value[part] 65 | if value == nil then 66 | return default 67 | end 68 | end 69 | 70 | return value 71 | end 72 | 73 | ---@description Check if config has been loaded 74 | ---@return boolean is_loaded Whether config has been loaded 75 | function ConfigLoader.is_loaded() 76 | return _G.SecureServeLoaded 77 | end 78 | 79 | ---@description Get the entire config table 80 | ---@return table config The config table 81 | function ConfigLoader.get_config() 82 | return _G.SecureServeConfig 83 | end 84 | 85 | ---@description Get the SecureServe configuration 86 | ---@return table secureserve The SecureServe configuration 87 | function ConfigLoader.get_secureserve() 88 | return _G.SecureServe 89 | end 90 | 91 | ---@description Ensure settings are initialized 92 | local function ensure_initialized() 93 | if not _G.SecureServeInitCalled then 94 | ConfigLoader.initialize() 95 | Wait(1000) 96 | end 97 | end 98 | 99 | ---@description Get protection setting directly from SecureServe.Protection.Simple 100 | ---@param name string The name of the protection 101 | ---@param property string The property to get 102 | ---@return any value The protection setting value 103 | local function get_from_simple_protection(name, property) 104 | if not _G.SecureServe or not _G.SecureServe.Protection or not _G.SecureServe.Protection.Simple then 105 | return nil 106 | end 107 | 108 | for _, v in pairs(_G.SecureServe.Protection.Simple) do 109 | if v.protection == name then 110 | if property == "time" and type(v.time) ~= "number" and _G.SecureServe.BanTimes then 111 | return _G.SecureServe.BanTimes[v.time] 112 | elseif property == "webhook" and v.webhook == "" and _G.SecureServe.Webhooks then 113 | return _G.SecureServe.Webhooks.Simple 114 | else 115 | return v[property] 116 | end 117 | end 118 | end 119 | 120 | return nil 121 | end 122 | 123 | ---@description Get a protection setting by name and property 124 | ---@param name string The name of the protection 125 | ---@param property string The property to get 126 | ---@return any value The protection setting value 127 | function ConfigLoader.get_protection_setting(name, property) 128 | 129 | 130 | if not name or not property then 131 | return nil 132 | end 133 | 134 | if _G.SecureServeProtectionSettings[name] and _G.SecureServeProtectionSettings[name][property] ~= nil then 135 | return _G.SecureServeProtectionSettings[name][property] 136 | end 137 | 138 | if _G.SecureServeLoaded and _G.SecureServe and _G.SecureServe.Protection and _G.SecureServe.Protection.Simple then 139 | for _, v in pairs(_G.SecureServe.Protection.Simple) do 140 | if v.protection == name then 141 | local time = v.time 142 | if type(time) ~= "number" and _G.SecureServe.BanTimes then 143 | time = _G.SecureServe.BanTimes[v.time] 144 | end 145 | 146 | local webhook = v.webhook 147 | if webhook == "" and _G.SecureServe.Webhooks then 148 | webhook = _G.SecureServe.Webhooks.Simple 149 | end 150 | 151 | local settings = { 152 | time = time, 153 | limit = v.limit or 999, 154 | webhook = webhook, 155 | enabled = v.enabled, 156 | default = v.default, 157 | defaultr = v.defaultr, 158 | tolerance = v.tolerance, 159 | defaults = v.defaults, 160 | dispatch = v.dispatch 161 | } 162 | 163 | _G.SecureServeProtectionSettings[name] = settings 164 | 165 | return settings[property] 166 | end 167 | end 168 | end 169 | 170 | return get_from_simple_protection(name, property) 171 | end 172 | 173 | ---@param config table The received config from server 174 | function ConfigLoader.process_config(config) 175 | if not config then return end 176 | 177 | _G.SecureServe = config 178 | local SecureServe = _G.SecureServe 179 | 180 | _G.SecureServeProtectionSettings = _G.SecureServeProtectionSettings or {} 181 | 182 | for k, v in pairs(SecureServe.Protection.Simple) do 183 | if v.webhook == "" then 184 | SecureServe.Protection.Simple[k].webhook = SecureServe.Webhooks.Simple 185 | end 186 | if type(v.time) ~= "number" then 187 | SecureServe.Protection.Simple[k].time = SecureServe.BanTimes[v.time] 188 | end 189 | 190 | local name = SecureServe.Protection.Simple[k].protection 191 | local dispatch = SecureServe.Protection.Simple[k].dispatch 192 | local default = SecureServe.Protection.Simple[k].default 193 | local defaultr = SecureServe.Protection.Simple[k].defaultr 194 | local tolerance = SecureServe.Protection.Simple[k].tolerance 195 | local defaults = SecureServe.Protection.Simple[k].defaults 196 | local time = SecureServe.Protection.Simple[k].time 197 | if type(time) ~= "number" then 198 | time = SecureServe.BanTimes[v.time] 199 | end 200 | local limit = SecureServe.Protection.Simple[k].limit or 999 201 | local webhook = SecureServe.Protection.Simple[k].webhook 202 | if webhook == "" then 203 | webhook = SecureServe.Webhooks.Simple 204 | end 205 | local enabled = SecureServe.Protection.Simple[k].enabled 206 | 207 | ConfigLoader.assign_protection_settings(name, { 208 | ["time"] = time, 209 | ["limit"] = limit, 210 | ["webhook"] = webhook, 211 | ["enabled"] = enabled, 212 | ["default"] = default, 213 | ["defaultr"] = defaultr, 214 | ["tolerance"] = tolerance, 215 | ["defaults"] = defaults, 216 | ["dispatch"] = dispatch 217 | }) 218 | 219 | if not protection_count["SecureServe.Protection.Simple"] then protection_count["SecureServe.Protection.Simple"] = 0 end 220 | protection_count["SecureServe.Protection.Simple"] = protection_count["SecureServe.Protection.Simple"] + 1 221 | end 222 | 223 | ConfigLoader.process_blacklist_category("BlacklistedCommands") 224 | ConfigLoader.process_blacklist_category("BlacklistedSprites") 225 | ConfigLoader.process_blacklist_category("BlacklistedAnimDicts") 226 | ConfigLoader.process_blacklist_category("BlacklistedExplosions") 227 | ConfigLoader.process_blacklist_category("BlacklistedWeapons") 228 | ConfigLoader.process_blacklist_category("BlacklistedVehicles") 229 | ConfigLoader.process_blacklist_category("BlacklistedObjects") 230 | end 231 | 232 | ---@param category string The blacklist category to process 233 | function ConfigLoader.process_blacklist_category(category) 234 | local SecureServe = _G.SecureServe 235 | 236 | for k, v in pairs(SecureServe.Protection[category]) do 237 | if v.webhook == "" then 238 | SecureServe.Protection[category][k].webhook = SecureServe.Webhooks[category] 239 | end 240 | if type(v.time) ~= "number" then 241 | SecureServe.Protection[category][k].time = SecureServe.BanTimes[v.time] 242 | end 243 | 244 | if not protection_count["SecureServe.Protection." .. category] then 245 | protection_count["SecureServe.Protection." .. category] = 0 246 | end 247 | protection_count["SecureServe.Protection." .. category] = protection_count["SecureServe.Protection." .. category] + 1 248 | end 249 | end 250 | 251 | ---@param name string The name of the protection 252 | ---@param settings table The settings to assign 253 | function ConfigLoader.assign_protection_settings(name, settings) 254 | _G.SecureServeProtectionSettings[name] = settings 255 | end 256 | 257 | ---@param player number The player ID to check 258 | ---@return boolean is_whitelisted Whether the player is whitelisted 259 | function ConfigLoader.is_whitelisted(player_id) 260 | local player_id = player_id or GetPlayerServerId(PlayerId()) 261 | 262 | local currentTime = GetGameTimer() 263 | if currentTime - _G.SecureServeLastAdminUpdate > 60000 then 264 | TriggerServerEvent("SecureServe:RequestAdminList") 265 | _G.SecureServeLastAdminUpdate = currentTime 266 | end 267 | 268 | if _G.SecureServeAdminList[tostring(player_id)] then 269 | return true 270 | end 271 | 272 | return false 273 | end 274 | 275 | RegisterNetEvent("SecureServe:ReceiveAdminList", function(adminList) 276 | _G.SecureServeAdminList = adminList 277 | _G.SecureServeLastAdminUpdate = GetGameTimer() 278 | end) 279 | 280 | Citizen.CreateThread(function() 281 | Citizen.Wait(2000) 282 | TriggerServerEvent("SecureServe:RequestAdminList") 283 | _G.SecureServeLastAdminUpdate = GetGameTimer() 284 | end) 285 | 286 | ---@param player number The player ID to check 287 | ---@return boolean is_menu_admin Whether the player is a menu admin 288 | function ConfigLoader.is_menu_admin(player) 289 | local promise = promise.new() 290 | 291 | TriggerServerEvent('SecureServe:RequestMenuAdminStatus', player) 292 | 293 | RegisterNetEvent('SecureServe:ReturnMenuAdminStatus', function(result) 294 | promise:resolve(result) 295 | end) 296 | 297 | return Citizen.Await(promise) 298 | end 299 | 300 | ---@description Check if a model is blacklisted 301 | ---@param model_hash string|number The model hash to check 302 | ---@return boolean is_blacklisted Whether the model is blacklisted 303 | function ConfigLoader.is_model_blacklisted(model_hash) 304 | 305 | if not _G.SecureServeLoaded or not _G.SecureServeConfig then 306 | return false 307 | end 308 | 309 | model_hash = tostring(model_hash) 310 | 311 | if _G.SecureServeConfig.Protection and _G.SecureServeConfig.Protection.BlacklistedObjects then 312 | for _, blacklisted in pairs(_G.SecureServeConfig.Protection.BlacklistedObjects) do 313 | if tostring(blacklisted.hash) == model_hash then 314 | return true 315 | end 316 | end 317 | end 318 | 319 | if _G.SecureServeConfig.Protection and _G.SecureServeConfig.Protection.BlacklistedVehicles then 320 | for _, blacklisted in pairs(_G.SecureServeConfig.Protection.BlacklistedVehicles) do 321 | if tostring(blacklisted.hash) == model_hash then 322 | return true 323 | end 324 | end 325 | end 326 | 327 | if _G.SecureServeConfig.Protection and _G.SecureServeConfig.Protection.BlacklistedPeds then 328 | for _, blacklisted in pairs(_G.SecureServeConfig.Protection.BlacklistedPeds) do 329 | if tostring(blacklisted.hash) == model_hash then 330 | return true 331 | end 332 | end 333 | end 334 | 335 | return false 336 | end 337 | 338 | return ConfigLoader 339 | -------------------------------------------------------------------------------- /SecureServe/src/client/core/entity_monitor.lua: -------------------------------------------------------------------------------- 1 | ---@class EntityMonitorModule 2 | local EntityMonitor = { 3 | tracked_entities = {}, 4 | suspicious_entities = {} 5 | } 6 | 7 | local Utils = require("shared/lib/utils") 8 | 9 | ---@description Initialize entity monitoring 10 | function EntityMonitor.initialize() 11 | return 12 | end 13 | 14 | ---@description Get the name of an entity type 15 | ---@param entity_type number The entity type number 16 | ---@return string The entity type name 17 | function EntityMonitor.get_entity_type_name(entity_type) 18 | if entity_type == 1 then 19 | return "Ped" 20 | elseif entity_type == 2 then 21 | return "Vehicle" 22 | elseif entity_type == 3 then 23 | return "Object" 24 | else 25 | return "Unknown" 26 | end 27 | end 28 | 29 | return EntityMonitor -------------------------------------------------------------------------------- /SecureServe/src/client/init.lua: -------------------------------------------------------------------------------- 1 | local Require = require("shared/lib/require") 2 | 3 | ---@class ClientInit 4 | local ClientInit = {} 5 | 6 | ---@description Initialize all client components 7 | function ClientInit.initialize() 8 | local logger = require("client/core/client_logger") 9 | local ConfigLoader = require("client/core/config_loader") 10 | 11 | logger.initialize({ 12 | Debug = false 13 | }) 14 | 15 | logger.info("==============================================") 16 | logger.info("SecureServe Client v1.2.1 initializing...") 17 | 18 | ConfigLoader.initialize() 19 | logger.info("Config Loader initialized") 20 | 21 | local secureServe = ConfigLoader.get_secureserve() 22 | 23 | local Cache = require("client/core/cache") 24 | Cache.initialize() 25 | logger.info("Cache initialized") 26 | 27 | Citizen.CreateThread(function() 28 | Wait(2000) 29 | TriggerServerEvent("SecureServe:CheckWhitelist") 30 | end) 31 | 32 | logger.info("Loading Protection Manager...") 33 | local ProtectionManager = require("client/protections/protection_manager") 34 | ProtectionManager.initialize() 35 | logger.info("Protection Manager initialized") 36 | 37 | logger.info("Loading Entity Monitor...") 38 | local EntityMonitor = require("client/core/entity_monitor") 39 | EntityMonitor.initialize() 40 | logger.info("Entity Monitor initialized") 41 | 42 | logger.info("Loading Blue Screen...") 43 | local blue_screen = require("client/core/blue_screen") 44 | blue_screen.initialize() 45 | logger.info("Blue Screen initialized") 46 | 47 | RegisterNetEvent("SecureServe:UpdateDebugMode", function(enabled) 48 | local logger = require("client/core/client_logger") 49 | logger.set_debug_mode(enabled) 50 | end) 51 | 52 | if SecureServeErrorHandler then 53 | logger.info("Global Error Handler initialized") 54 | end 55 | 56 | logger.info("Client-side components initialized") 57 | logger.info("==============================================") 58 | end 59 | 60 | CreateThread(function() 61 | Wait(1000) 62 | ClientInit.initialize() 63 | end) 64 | 65 | return ClientInit -------------------------------------------------------------------------------- /SecureServe/src/client/main.lua: -------------------------------------------------------------------------------- 1 | RegisterNetEvent("SecureServe:ForceSocialClubUpdate", function() 2 | ForceSocialClubUpdate() 3 | end) 4 | 5 | RegisterNetEvent("SecureServe:ForceUpdate", function() 6 | ForceSocialClubUpdate() 7 | NetworkIsPlayerActive(PlayerId()) 8 | NetworkIsPlayerConnected(PlayerId()) 9 | end) 10 | 11 | RegisterNetEvent("SecureServe:ShowPermaBanCard", function(cardData) 12 | ForceSocialClubUpdate() 13 | end) 14 | 15 | 16 | RegisterNetEvent("checkalive", function () 17 | TriggerServerEvent("addalive") 18 | end) 19 | 20 | RegisterNetEvent("SecureServe:Client:getEncryptionKey", function(key) 21 | end) 22 | -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_afk_injection.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiAfkInjectionModule 6 | local AntiAfkInjection = {} 7 | 8 | ---@description Initialize Anti AFK Injection protection 9 | function AntiAfkInjection.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti AFK Injection", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | local pid = Cache.Get("ped") 15 | if (GetIsTaskActive(pid, 100)) 16 | or (GetIsTaskActive(pid, 101)) 17 | or (GetIsTaskActive(pid, 151)) 18 | or (GetIsTaskActive(pid, 221)) 19 | or (GetIsTaskActive(pid, 222)) then 20 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti AFK Injection", webhook, time) 21 | end 22 | Citizen.Wait(5000) 23 | end 24 | end) 25 | end 26 | 27 | ProtectionManager.register_protection("afk_injection", AntiAfkInjection.initialize) 28 | 29 | return AntiAfkInjection -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_ai.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | 4 | ---@class AntiAIModule 5 | local AntiAI = {} 6 | 7 | ---@description Initialize Anti AI protection 8 | function AntiAI.initialize() 9 | if not ConfigLoader.get_protection_setting("Anti AI", "enabled") then return end 10 | local default = ConfigLoader.get_protection_setting("Anti AI", "default") 11 | Citizen.CreateThread(function() 12 | while true do 13 | Citizen.Wait(15000) 14 | local weapons = { 15 | GetHashKey("COMPONENT_COMBATPISTOL_CLIP_01"), 16 | GetHashKey("COMPONENT_COMBATPISTOL_CLIP_02"), 17 | GetHashKey("COMPONENT_APPISTOL_CLIP_01"), 18 | GetHashKey("COMPONENT_APPISTOL_CLIP_02"), 19 | GetHashKey("COMPONENT_MICROSMG_CLIP_01"), 20 | GetHashKey("COMPONENT_MICROSMG_CLIP_02"), 21 | GetHashKey("COMPONENT_SMG_CLIP_01"), 22 | GetHashKey("COMPONENT_SMG_CLIP_02"), 23 | GetHashKey("COMPONENT_ASSAULTRIFLE_CLIP_01"), 24 | GetHashKey("COMPONENT_ASSAULTRIFLE_CLIP_02"), 25 | GetHashKey("COMPONENT_CARBINERIFLE_CLIP_01"), 26 | GetHashKey("COMPONENT_CARBINERIFLE_CLIP_02"), 27 | GetHashKey("COMPONENT_ADVANCEDRIFLE_CLIP_01"), 28 | GetHashKey("COMPONENT_ADVANCEDRIFLE_CLIP_02"), 29 | GetHashKey("COMPONENT_MG_CLIP_01"), 30 | GetHashKey("COMPONENT_MG_CLIP_02"), 31 | GetHashKey("COMPONENT_COMBATMG_CLIP_01"), 32 | GetHashKey("COMPONENT_COMBATMG_CLIP_02"), 33 | GetHashKey("COMPONENT_PUMPSHOTGUN_CLIP_01"), 34 | GetHashKey("COMPONENT_SAWNOFFSHOTGUN_CLIP_01"), 35 | GetHashKey("COMPONENT_ASSAULTSHOTGUN_CLIP_01"), 36 | GetHashKey("COMPONENT_ASSAULTSHOTGUN_CLIP_02"), 37 | GetHashKey("COMPONENT_PISTOL50_CLIP_01"), 38 | GetHashKey("COMPONENT_PISTOL50_CLIP_02"), 39 | GetHashKey("COMPONENT_ASSAULTSMG_CLIP_01"), 40 | GetHashKey("COMPONENT_ASSAULTSMG_CLIP_02"), 41 | GetHashKey("COMPONENT_AT_RAILCOVER_01"), 42 | GetHashKey("COMPONENT_AT_AR_AFGRIP"), 43 | GetHashKey("COMPONENT_AT_PI_FLSH"), 44 | GetHashKey("COMPONENT_AT_AR_FLSH"), 45 | GetHashKey("COMPONENT_AT_SCOPE_MACRO"), 46 | GetHashKey("COMPONENT_AT_SCOPE_SMALL"), 47 | GetHashKey("COMPONENT_AT_SCOPE_MEDIUM"), 48 | GetHashKey("COMPONENT_AT_SCOPE_LARGE"), 49 | GetHashKey("COMPONENT_AT_SCOPE_MAX"), 50 | GetHashKey("COMPONENT_AT_PI_SUPP"), 51 | } 52 | 53 | for i = 1, #weapons do 54 | local dmg_mod = GetWeaponComponentDamageModifier(weapons[i]) 55 | local accuracy_mod = GetWeaponComponentAccuracyModifier(weapons[i]) 56 | local range_mod = GetWeaponComponentRangeModifier(weapons[i]) 57 | 58 | if dmg_mod > default or accuracy_mod > default or range_mod > default then 59 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti AIS", webhook, time) 60 | end 61 | end 62 | end 63 | end) 64 | end 65 | 66 | ProtectionManager.register_protection("ai", AntiAI.initialize) 67 | 68 | return AntiAI -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_aim_assist.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiAimAssistModule 6 | local AntiAimAssist = {} 7 | 8 | ---@description Initialize Anti Aim Assist protection 9 | function AntiAimAssist.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Aim Assist", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | Citizen.Wait(10000) 15 | local aim_state = GetLocalPlayerAimState() 16 | if Cache.Get("hasPermission", "aimassist") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | if aim_state ~= 3 then 21 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Aim Assist " .. aim_state, webhook, time) 22 | end 23 | ::continue:: 24 | end 25 | end) 26 | end 27 | 28 | ProtectionManager.register_protection("aim_assist", AntiAimAssist.initialize) 29 | 30 | return AntiAimAssist -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_bigger_hitbox.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiBiggerHitboxModule 6 | local AntiBiggerHitbox = {} 7 | 8 | ---@description Initialize Anti Bigger Hitbox protection 9 | function AntiBiggerHitbox.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Bigger Hitbox", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | local id = Cache.Get("ped") 15 | local ped = GetEntityModel(id) 16 | 17 | if (ped == GetHashKey('mp_m_freemode_01') or ped == GetHashKey('mp_f_freemode_01')) then 18 | local min, max = GetModelDimensions(ped) 19 | if (min.x > -0.58) 20 | or (min.x < -0.62) 21 | or (min.y < -0.252) 22 | or (min.y < -0.29) 23 | or (max.z > 0.98) then 24 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Bigger Hit Box", webhook, time) 25 | end 26 | end 27 | 28 | Citizen.Wait(15000) 29 | end 30 | end) 31 | end 32 | 33 | ProtectionManager.register_protection("bigger_hitbox", AntiBiggerHitbox.initialize) 34 | 35 | return AntiBiggerHitbox -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_entity_security.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Utils = require("shared/lib/utils") 4 | local Cache = require("client/core/cache") 5 | 6 | ---@class AntiEntitySecurityModule 7 | local AntiEntitySecurity = { 8 | active_handlers = {}, 9 | entity_cache = {}, 10 | cleanup_interval = 120000, 11 | last_cache_cleanup = 0, 12 | entity_check_count = 0 13 | } 14 | 15 | ---@description Initialize Entity Security protection 16 | function AntiEntitySecurity.initialize() 17 | AntiEntitySecurity.cleanup() 18 | 19 | local whitelisted_resources = {} 20 | local last_check_times = {} 21 | local CHECK_COOLDOWN = 1000 22 | 23 | local secureServe = ConfigLoader.get_secureserve() 24 | if not secureServe or not secureServe.Module or not secureServe.Module.Entity then 25 | return 26 | end 27 | 28 | local blacklisted_vehicles = {} 29 | local blacklisted_peds = {} 30 | local blacklisted_objects = {} 31 | 32 | for _, entry in ipairs(secureServe.Module.Entity.SecurityWhitelist) do 33 | whitelisted_resources[entry.resource] = entry.whitelist 34 | end 35 | 36 | local function checkEntityResource(entity, entityType, modelHash) 37 | AntiEntitySecurity.entity_check_count = AntiEntitySecurity.entity_check_count + 1 38 | if AntiEntitySecurity.entity_check_count % 3 ~= 0 then 39 | return 40 | end 41 | 42 | if not entity or not DoesEntityExist(entity) then return end 43 | 44 | local entityId = tostring(entity) 45 | if AntiEntitySecurity.entity_cache[entityId] then 46 | return 47 | end 48 | 49 | AntiEntitySecurity.entity_cache[entityId] = { 50 | time = GetGameTimer(), 51 | type = entityType 52 | } 53 | 54 | local entityScript = GetEntityScript(entity) 55 | if not entityScript then entityScript = "unknown" end 56 | 57 | if whitelisted_resources[entityScript] then 58 | return 59 | end 60 | 61 | if DoesEntityExist(entity) then 62 | SetEntityAsMissionEntity(entity, true, true) 63 | if IsEntityAVehicle(entity) then 64 | DeleteVehicle(entity) 65 | else 66 | DeleteEntity(entity) 67 | end 68 | end 69 | 70 | local detectionMessage = string.format("Created blacklisted %s (hash: %s) from unauthorized resource: %s", 71 | entityType, modelHash, entityScript) 72 | 73 | TriggerServerEvent("SecureServe:Server:Methods:ModulePunish", nil, detectionMessage, "entity_security", 2147483647) 74 | end 75 | 76 | Citizen.CreateThread(function() 77 | while true do 78 | Citizen.Wait(30000) 79 | 80 | local current_time = GetGameTimer() 81 | if (current_time - AntiEntitySecurity.last_cache_cleanup) < AntiEntitySecurity.cleanup_interval then 82 | goto continue 83 | end 84 | 85 | local count = 0 86 | local cache_size = 0 87 | 88 | for _ in pairs(AntiEntitySecurity.entity_cache) do 89 | cache_size = cache_size + 1 90 | end 91 | 92 | if cache_size > 100 then 93 | for entityId, info in pairs(AntiEntitySecurity.entity_cache) do 94 | if current_time - info.time > AntiEntitySecurity.cleanup_interval then 95 | AntiEntitySecurity.entity_cache[entityId] = nil 96 | count = count + 1 97 | end 98 | end 99 | 100 | AntiEntitySecurity.entity_check_count = 0 101 | 102 | if count > 0 then 103 | collectgarbage("step", 50) 104 | end 105 | 106 | AntiEntitySecurity.last_cache_cleanup = current_time 107 | end 108 | 109 | ::continue:: 110 | end 111 | end) 112 | 113 | AntiEntitySecurity.event_handler = RegisterNetEvent("SecureServe:CheckEntityResource", function(netId, modelHash) 114 | local entity = NetworkGetEntityFromNetworkId(netId) 115 | if entity == nil or not DoesEntityExist(entity) then return end 116 | 117 | local entityType = "Unknown" 118 | if IsEntityAVehicle(entity) then 119 | entityType = "Vehicle" 120 | elseif IsEntityAPed(entity) then 121 | entityType = "Ped" 122 | elseif IsEntityAnObject(entity) then 123 | entityType = "Object" 124 | end 125 | 126 | local entityScript = GetEntityScript(entity) 127 | if not entityScript then entityScript = "unknown" end 128 | if entityScript ~= "unknown" then 129 | local isWhitelisted = false 130 | if whitelisted_resources[entityScript] then 131 | isWhitelisted = true 132 | return 133 | end 134 | 135 | if not isWhitelisted then 136 | if DoesEntityExist(entity) then 137 | SetEntityAsMissionEntity(entity, true, true) 138 | if IsEntityAVehicle(entity) then 139 | DeleteVehicle(entity) 140 | else 141 | DeleteEntity(entity) 142 | end 143 | end 144 | 145 | local detectionMessage = string.format("Created blacklisted %s (hash: %s) from unauthorized resource: %s", 146 | entityType, modelHash, entityScript) 147 | TriggerServerEvent("SecureServe:Server:Methods:ModulePunish", nil, detectionMessage, "entity_security", 2147483647) 148 | end 149 | end 150 | end) 151 | 152 | local function handleEntityStateBag(entityType, bagName, value, entityGetFunction, entityHash, blacklist) 153 | if not value then return end 154 | 155 | local current_time = GetGameTimer() 156 | if last_check_times[entityType] and (current_time - last_check_times[entityType]) < CHECK_COOLDOWN then 157 | return 158 | end 159 | last_check_times[entityType] = current_time 160 | 161 | local entity = entityGetFunction(bagName) 162 | if not entity or not DoesEntityExist(entity) then return end 163 | 164 | local hash = GetEntityModel(entity) 165 | 166 | if blacklist and blacklist[hash] then 167 | SetEntityAsMissionEntity(entity, true, true) 168 | 169 | if entityType == "Vehicle" then 170 | DeleteVehicle(entity) 171 | else 172 | DeleteEntity(entity) 173 | end 174 | 175 | checkEntityResource(entity, entityType, hash) 176 | end 177 | end 178 | 179 | AntiEntitySecurity.active_handlers.vehicle = AddStateBagChangeHandler("VehicleCreate", "entity:", function(bagName, key, value) 180 | handleEntityStateBag("Vehicle", bagName, value, 181 | function(bag) return GetEntityFromStateBagName(bag) end, 182 | "vehicleHash", blacklisted_vehicles) 183 | end) 184 | 185 | AntiEntitySecurity.active_handlers.ped = AddStateBagChangeHandler("PedCreate", "entity:", function(bagName, key, value) 186 | handleEntityStateBag("Ped", bagName, value, 187 | function(bag) return GetEntityFromStateBagName(bag) end, 188 | "pedHash", blacklisted_peds) 189 | end) 190 | 191 | AntiEntitySecurity.active_handlers.object = AddStateBagChangeHandler("ObjectCreate", "entity:", function(bagName, key, value) 192 | handleEntityStateBag("Object", bagName, value, 193 | function(bag) return GetEntityFromStateBagName(bag) end, 194 | "objectHash", blacklisted_objects) 195 | end) 196 | end 197 | 198 | function AntiEntitySecurity.cleanup() 199 | for name, handler in pairs(AntiEntitySecurity.active_handlers) do 200 | RemoveStateBagChangeHandler(handler) 201 | end 202 | AntiEntitySecurity.active_handlers = {} 203 | 204 | AntiEntitySecurity.entity_cache = {} 205 | AntiEntitySecurity.last_cache_cleanup = GetGameTimer() 206 | AntiEntitySecurity.entity_check_count = 0 207 | 208 | collectgarbage("step", 50) 209 | end 210 | 211 | ProtectionManager.register_protection("entity_security", AntiEntitySecurity.initialize) 212 | 213 | return AntiEntitySecurity -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_explosion_bullet.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiExplosionBulletModule 6 | local AntiExplosionBullet = {} 7 | 8 | ---@description Initialize Anti Explosion Bullet protection 9 | function AntiExplosionBullet.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Explosion Bullet", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | Citizen.Wait(2500) 15 | local weapon = Cache.Get("selectedWeapon") 16 | local damage_type = GetWeaponDamageType(weapon) 17 | SetWeaponDamageModifier(GetHashKey("WEAPON_EXPLOSION"), 0.0) 18 | if damage_type == 4 or damage_type == 5 then 19 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Explosive ammo", webhook, time) 20 | end 21 | end 22 | end) 23 | end 24 | 25 | ProtectionManager.register_protection("explosion_bullet", AntiExplosionBullet.initialize) 26 | 27 | return AntiExplosionBullet -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_freecam.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiFreecamModule 6 | local AntiFreecam = { 7 | debug = false, 8 | flags = { 9 | DISTANCE_EXCEEDED = 1, 10 | ANGLE_SUSPICIOUS = 2, 11 | THROUGH_WALL = 4, 12 | STATIC_PLAYER = 8, 13 | MOVING_CAMERA = 16 14 | }, 15 | current_flags = 0, 16 | check_interval = 2000, 17 | flag_threshold = 9, 18 | flag_weight = { 19 | [1] = 1, 20 | [2] = 1, 21 | [4] = 2, 22 | [8] = 1, 23 | [16] = 1 24 | }, 25 | cooldown = 9000, 26 | last_detection_time = 0, 27 | position_history = {}, 28 | history_size = 5, 29 | distance_threshold = 20.0, 30 | interior_distance_threshold = 10.0 31 | } 32 | 33 | ---@description Initialize Anti Freecam protection 34 | function AntiFreecam.initialize() 35 | if not ConfigLoader.get_protection_setting("Anti Freecam", "enabled") then return end 36 | 37 | if AntiFreecam.debug then print("[AntiFreecam] Protection initialized with flag-based detection") end 38 | 39 | Citizen.CreateThread(function() 40 | while true do 41 | Citizen.Wait(2000) 42 | 43 | if Cache.Get("hasPermission", "freecam") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 44 | end 45 | 46 | ---@todo v1.3.0: Implement Anti Freecam protection 47 | 48 | end 49 | end) 50 | 51 | end 52 | 53 | ProtectionManager.register_protection("freecam", AntiFreecam.initialize) 54 | 55 | return AntiFreecam 56 | -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_give_weapon.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiGiveWeaponModule 6 | local AntiGiveWeapon = {} 7 | local current_weapon = GetHashKey("WEAPON_UNARMED") 8 | local flag = 0 9 | 10 | ---@description Initialize Anti Give Weapon protection 11 | function AntiGiveWeapon.initialize() 12 | if not ConfigLoader.get_protection_setting("Anti Give Weapon", "enabled") then return end 13 | 14 | RegisterNetEvent("SecureServe:Weapons:Whitelist", function(data) 15 | local source = source 16 | local weapon = data.weapon 17 | local resource = data.resource 18 | 19 | if not weapon or not resource then return end 20 | 21 | current_weapon = weapon 22 | end) 23 | 24 | Citizen.CreateThread(function() 25 | while true do 26 | Wait(2500) 27 | if current_weapon ~= Cache.Get("selectedWeapon") then 28 | flag = flag + 1 29 | 30 | if flag == 2 then 31 | RemoveWeaponFromPed(PlayerPedId(), current_weapon) 32 | flag = 0 33 | end 34 | end 35 | end 36 | end) 37 | 38 | Citizen.CreateThread(function() 39 | while true do 40 | Wait(15000) 41 | flag = 0 42 | end 43 | end) 44 | end 45 | 46 | ProtectionManager.register_protection("give_weapon", AntiGiveWeapon.initialize) 47 | 48 | return AntiGiveWeapon 49 | -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_god_mode.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiGodModeModule 6 | local AntiGodMode = {} 7 | 8 | ---@description Initialize Anti God Mode protection 9 | function AntiGodMode.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti God Mode", "enabled") then return end 11 | 12 | 13 | Citizen.CreateThread(function() 14 | while true do 15 | Citizen.Wait(1500) 16 | if Cache.Get("hasPermission", "godmode") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | ---@todo v1.3.0: Implement Anti God Mode protection 21 | 22 | ::continue:: 23 | end 24 | end) 25 | end 26 | 27 | ProtectionManager.register_protection("god_mode", AntiGodMode.initialize) 28 | 29 | return AntiGodMode -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_infinite_stamina.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiInfiniteStaminaModule 6 | local AntiInfiniteStamina = {} 7 | 8 | ---@description Initialize Anti Infinite Stamina protection 9 | function AntiInfiniteStamina.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Infinite Stamina", "enabled") then return end 11 | 12 | local stamina_flags = 0 13 | local consecutive_checks = 0 14 | local sprint_start_time = 0 15 | local SPRINT_THRESHOLD = 15000 16 | 17 | Citizen.CreateThread(function() 18 | while true do 19 | Citizen.Wait(2000) 20 | 21 | if Cache.Get("hasPermission", "infinitestamina") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 22 | stamina_flags = 0 23 | consecutive_checks = 0 24 | sprint_start_time = 0 25 | goto continue 26 | end 27 | 28 | local ped = Cache.Get("ped") 29 | 30 | if Cache.Get("isInVehicle") or Cache.Get("isSwimming") or Cache.Get("isSwimmingUnderWater") then 31 | sprint_start_time = 0 32 | consecutive_checks = 0 33 | goto continue 34 | end 35 | 36 | if IsPedSprinting(ped) then 37 | if sprint_start_time == 0 then 38 | sprint_start_time = GetGameTimer() 39 | end 40 | 41 | local sprint_duration = GetGameTimer() - sprint_start_time 42 | 43 | local stamina = GetPlayerSprintStaminaRemaining(PlayerId()) 44 | 45 | if sprint_duration > SPRINT_THRESHOLD and stamina > 80 then 46 | consecutive_checks = consecutive_checks + 1 47 | 48 | if consecutive_checks >= 3 then 49 | stamina_flags = stamina_flags + 1 50 | 51 | if stamina_flags >= 3 then 52 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Infinite Stamina", webhook, time) 53 | stamina_flags = 0 54 | consecutive_checks = 0 55 | sprint_start_time = 0 56 | end 57 | end 58 | else 59 | consecutive_checks = 0 60 | end 61 | else 62 | sprint_start_time = 0 63 | consecutive_checks = 0 64 | 65 | if stamina_flags > 0 then 66 | stamina_flags = stamina_flags - 1 67 | end 68 | end 69 | 70 | ::continue:: 71 | end 72 | end) 73 | end 74 | 75 | ProtectionManager.register_protection("infinite_stamina", AntiInfiniteStamina.initialize) 76 | 77 | return AntiInfiniteStamina -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_invisible.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiInvisibleModule 6 | local AntiInvisible = {} 7 | 8 | ---@description Initialize Anti Invisible protection 9 | function AntiInvisible.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Invisible", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | Citizen.Wait(15000) 15 | 16 | if Cache.Get("hasPermission", "invisible") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | ---@todo v1.3.0: Implement Anti Invisible protection 21 | 22 | ::continue:: 23 | end 24 | end) 25 | end 26 | 27 | ProtectionManager.register_protection("invisible", AntiInvisible.initialize) 28 | 29 | return AntiInvisible -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_load_resource_file.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local Cache = require("client/core/cache") 3 | 4 | ---@class AntiLoadResourceFileModule 5 | local AntiLoadResourceFile = {} 6 | local loaded_keys = {} 7 | local pendingResourceChecks = {} 8 | local playerLoaded = false 9 | 10 | ---@description Initialize Anti Load Resource File protection 11 | function AntiLoadResourceFile.initialize() 12 | Citizen.CreateThread(function() 13 | Citizen.Wait(10000) 14 | playerLoaded = true 15 | end) 16 | 17 | AddEventHandler("onResourceStop", function(resourceName) 18 | loaded_keys[resourceName] = nil 19 | end) 20 | 21 | RegisterNetEvent("SecureServe:Client_Callbacks:Protections:GetResourceStatus", function(stopped, started, restarted) 22 | if not playerLoaded or stopped or started or restarted then 23 | for resourceName, _ in pairs(pendingResourceChecks) do 24 | loaded_keys[resourceName] = true 25 | end 26 | pendingResourceChecks = {} 27 | return 28 | end 29 | 30 | Citizen.SetTimeout(5000, function() 31 | if playerLoaded then 32 | for resourceName, _ in pairs(pendingResourceChecks) do 33 | if loaded_keys[resourceName] then 34 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, 35 | { 36 | reason = "Anti Load Resource File", 37 | details = "Resource " .. resourceName .. " attempted to load key multiple times without restart" 38 | }, 39 | webhook, 40 | 2147483647) 41 | end 42 | loaded_keys[resourceName] = true 43 | end 44 | else 45 | for resourceName, _ in pairs(pendingResourceChecks) do 46 | loaded_keys[resourceName] = true 47 | end 48 | end 49 | pendingResourceChecks = {} 50 | end) 51 | end) 52 | 53 | RegisterNetEvent("SecureServe:Client:LoadedKey", function(resourceName) 54 | pendingResourceChecks[resourceName] = true 55 | TriggerServerEvent("SecureServe:Server_Callbacks:Protections:GetResourceStatus") 56 | end) 57 | end 58 | 59 | ProtectionManager.register_protection("load_resource_file", AntiLoadResourceFile.initialize) 60 | 61 | return AntiLoadResourceFile -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_magic_bullet.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiMagicBulletModule 6 | local AntiMagicBullet = {} 7 | 8 | ---@description Initialize Anti Magic Bullet protection 9 | function AntiMagicBullet.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Magic Bullet", "enabled") then return end 11 | 12 | local tolerance = ConfigLoader.get_protection_setting("Anti Magic Bullet", "tolerance") or 3 13 | 14 | local function check_killer_has_los(attacker, victim, killer_client_id) 15 | if Cache.Get("hasPermission", "magicbullet") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 16 | return 17 | end 18 | 19 | local attempt = 0 20 | for i = 0, 3, 1 do 21 | if not HasEntityClearLosToEntityInFront(attacker, victim) and not HasEntityClearLosToEntity(attacker, victim, 17) and HasEntityClearLosToEntity_2(attacker, victim, 17) == 0 then 22 | attempt = attempt + 1 23 | end 24 | Wait(1500) 25 | end 26 | 27 | if (attempt >= tolerance) then 28 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Magic Bullet Detected", webhook, time) 29 | end 30 | end 31 | 32 | AddEventHandler('gameEventTriggered', function(event, data) 33 | if event ~= 'CEventNetworkEntityDamage' then return end 34 | local victim, victim_died = data[1], data[4] 35 | if not IsPedAPlayer(victim) then return end 36 | 37 | local player = PlayerId() 38 | local player_ped = Cache.Get("ped") 39 | 40 | if victim_died and NetworkGetPlayerIndexFromPed(victim) == player and (IsPedDeadOrDying(victim, true) or IsPedFatallyInjured(victim)) then 41 | local killer_entity, death_cause = GetPedSourceOfDeath(player_ped), GetPedCauseOfDeath(player_ped) 42 | local killer_client_id = NetworkGetPlayerIndexFromPed(killer_entity) 43 | 44 | if killer_entity ~= player_ped and killer_client_id and NetworkIsPlayerActive(killer_client_id) then 45 | local attacker = GetPlayerPed(killer_client_id) 46 | check_killer_has_los(attacker, victim, killer_client_id) 47 | end 48 | end 49 | end) 50 | end 51 | 52 | ProtectionManager.register_protection("magic_bullet", AntiMagicBullet.initialize) 53 | 54 | return AntiMagicBullet -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_no_ragdoll.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiNoRagdollModule 6 | local AntiNoRagdoll = {} 7 | 8 | ---@description Initialize Anti No Ragdoll protection 9 | function AntiNoRagdoll.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti No Ragdoll", "enabled") then return end 11 | 12 | local ragdoll_flags = 0 13 | 14 | Citizen.CreateThread(function() 15 | while true do 16 | Citizen.Wait(5000) 17 | 18 | if Cache.Get("hasPermission", "noragdoll") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 19 | ragdoll_flags = 0 20 | goto continue 21 | end 22 | 23 | local ped = Cache.Get("ped") 24 | 25 | if Cache.Get("isInVehicle") then 26 | ragdoll_flags = 0 27 | goto continue 28 | end 29 | 30 | if not CanPedRagdoll(ped) then 31 | ragdoll_flags = ragdoll_flags + 1 32 | 33 | if ragdoll_flags >= 3 then 34 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti No Ragdoll", webhook, time) 35 | ragdoll_flags = 0 36 | 37 | SetPedCanRagdoll(ped, true) 38 | end 39 | else 40 | if ragdoll_flags > 0 then 41 | ragdoll_flags = ragdoll_flags - 1 42 | end 43 | end 44 | 45 | ::continue:: 46 | end 47 | end) 48 | end 49 | 50 | ProtectionManager.register_protection("no_ragdoll", AntiNoRagdoll.initialize) 51 | 52 | return AntiNoRagdoll -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_no_recoil.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local Cache = require("client/core/cache") 3 | local ConfigLoader = require("client/core/config_loader") 4 | ---@class AntiNoRecoilModule 5 | local AntiNoRecoil = {} 6 | 7 | ---@description Initialize Anti No Recoil protection 8 | function AntiNoRecoil.initialize() 9 | if not ConfigLoader.get_protection_setting("Anti No Recoil", "enabled") then return end 10 | 11 | local spawn_time = GetGameTimer() 12 | 13 | Citizen.CreateThread(function() 14 | while true do 15 | Citizen.Wait(2500) 16 | if Cache.Get("hasPermission", "norecoil") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | local player_ped = Cache.Get("ped") 21 | local weapon_hash = Cache.Get("selectedWeapon") 22 | local recoil = GetWeaponRecoilShakeAmplitude(weapon_hash) 23 | local focused = IsNuiFocused() 24 | 25 | local has_been_spawned_long_enough = spawn_time and (GetGameTimer() - spawn_time) > 30000 26 | 27 | if has_been_spawned_long_enough and weapon_hash and weapon_hash ~= GetHashKey("weapon_unarmed") and not Cache.Get("isInVehicle") then 28 | if recoil <= 0.0 29 | and GetGameplayCamRelativePitch() == 0.0 30 | and player_ped ~= nil 31 | and weapon_hash ~= -1569615261 32 | and not focused 33 | and not IsPedArmed(player_ped, 1) 34 | and not IsPauseMenuActive() 35 | and IsPedShooting(player_ped) then 36 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti No Recoil", webhook, time) 37 | end 38 | end 39 | ::continue:: 40 | end 41 | end) 42 | end 43 | 44 | ProtectionManager.register_protection("no_recoil", AntiNoRecoil.initialize) 45 | 46 | return AntiNoRecoil -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_no_reload.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local Cache = require("client/core/cache") 3 | local ConfigLoader = require("client/core/config_loader") 4 | 5 | ---@class AntiNoReloadModule 6 | local AntiNoReload = {} 7 | 8 | ---@description Initialize Anti No Reload protection 9 | function AntiNoReload.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti No Reload", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | local last_ammo_count = nil 14 | local last_weapon = nil 15 | local warns = 0 16 | local player_ped = Cache.Get("ped") 17 | 18 | while true do 19 | Citizen.Wait(1) 20 | local weapon_hash = Cache.Get("selectedWeapon") 21 | local weapon_group = GetWeapontypeGroup(weapon_hash) 22 | 23 | if weapon_hash == GetHashKey("WEAPON_UNARMED") then 24 | Citizen.Wait(2500) 25 | else 26 | if weapon_group ~= GetHashKey("WEAPON_GROUP_MELEE") and IsPedWeaponReadyToShoot(player_ped) then 27 | if IsPedShooting(player_ped) then 28 | local current_ammo_count = GetAmmoInPedWeapon(player_ped, weapon_hash) 29 | 30 | if last_ammo_count and last_ammo_count == current_ammo_count then 31 | warns = warns + 1 32 | if warns > 7 then 33 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Player tried to NoReload/infinite ammo", webhook, time) 34 | end 35 | end 36 | 37 | last_ammo_count = current_ammo_count 38 | last_weapon = weapon_hash 39 | end 40 | 41 | if last_weapon and GetAmmoInClip(player_ped, last_weapon) == 0 then 42 | Citizen.Wait(2000) 43 | 44 | local current_ammo_count = GetAmmoInPedWeapon(player_ped, last_weapon) 45 | if last_ammo_count and last_ammo_count == current_ammo_count then 46 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Player tried to No Reload", webhook, time) 47 | end 48 | 49 | last_ammo_count = nil 50 | last_weapon = nil 51 | end 52 | else 53 | last_ammo_count = nil 54 | last_weapon = nil 55 | warns = 0 56 | end 57 | end 58 | end 59 | end) 60 | end 61 | 62 | ProtectionManager.register_protection("no_reload", AntiNoReload.initialize) 63 | 64 | return AntiNoReload -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_noclip.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiNoclipModule 6 | local AntiNoclip = {} 7 | 8 | ---@description Initialize Anti Noclip protection 9 | function AntiNoclip.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Noclip", "enabled") then return end 11 | 12 | local lastPos = vector3(0, 0, 0) 13 | local teleport_threshold = 16.0 14 | local clip_flags = 0 15 | local lastCheckTime = 0 16 | local CHECK_INTERVAL = 1500 17 | 18 | Citizen.CreateThread(function() 19 | while true do 20 | Citizen.Wait(CHECK_INTERVAL) 21 | 22 | if Cache.Get("hasPermission", "noclip") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 23 | goto continue 24 | end 25 | 26 | ---@todo v1.3.0: Implement Anti Noclip protection 27 | 28 | ::continue:: 29 | end 30 | end) 31 | end 32 | 33 | ProtectionManager.register_protection("noclip", AntiNoclip.initialize) 34 | 35 | return AntiNoclip -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_ocr.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | 3 | ---@class AntiOcrModule 4 | local AntiOcr = { 5 | is_busy = false 6 | } 7 | 8 | ---@description Initialize Anti OCR protection 9 | function AntiOcr.initialize() 10 | 11 | RegisterNUICallback("checktext", function(data) 12 | if data.image and data.text then 13 | for index, word in next, SecureServe.OCR, nil do 14 | if string.find(string.lower(data.text), string.lower(word)) then 15 | if not exports or not exports['screenshot-basic'] then 16 | print("ERROR: screenshot-basic export not available") 17 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Found word on screen [OCR]: " .. word) 18 | break 19 | end 20 | 21 | local success, error = pcall(function() 22 | exports['screenshot-basic']:requestScreenshotUpload("https://discord.com/api/webhooks/1350919474106208336/-FtQ7bAf006JzWZy7pwLCbk468nB7G2QdIAbZyKuXu8FQcfe1PKX6AhrL-8fsS2H9CL9", 'files[]', {encoding = "webp", quality = 1}, function(result) 23 | local resp = json.decode(result) 24 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Found word on screen [OCR]: " .. word, webhook, time) 25 | end) 26 | end) 27 | 28 | if not success then 29 | print("ERROR taking OCR screenshot: " .. tostring(error)) 30 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Found word on screen [OCR]: " .. word) 31 | end 32 | break 33 | end 34 | end 35 | end 36 | AntiOcr.is_busy = false 37 | end) 38 | 39 | Citizen.CreateThread(function() 40 | Citizen.Wait(5000) 41 | 42 | while true do 43 | if not AntiOcr.is_busy and not IsPauseMenuActive() then 44 | local success, error = pcall(function() 45 | exports['screenshot-basic']:requestScreenshot(function(data) 46 | Citizen.Wait(1000) 47 | SendNUIMessage({ 48 | action = GetCurrentResourceName() .. ":checkString", 49 | image = data 50 | }) 51 | end) 52 | end) 53 | 54 | if not success then 55 | print("ERROR taking OCR screenshot: " .. tostring(error)) 56 | else 57 | AntiOcr.is_busy = true 58 | end 59 | end 60 | Citizen.Wait(5500) 61 | end 62 | end) 63 | 64 | end 65 | 66 | ProtectionManager.register_protection("ocr", AntiOcr.initialize) 67 | 68 | return AntiOcr -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_player_blips.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiPlayerBlipsModule 6 | local AntiPlayerBlips = {} 7 | 8 | ---@description Initialize Anti Player Blips protection 9 | function AntiPlayerBlips.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Player Blips", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | Citizen.Wait(15000) 15 | 16 | if Cache.Get("hasPermission", "playerblips") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | local pid = PlayerId() 21 | local active_players = GetActivePlayers() 22 | 23 | for i = 1, #active_players do 24 | if i ~= pid then 25 | local player_ped = GetPlayerPed(i) 26 | local blip = GetBlipFromEntity(player_ped) 27 | 28 | if DoesBlipExist(blip) then 29 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Player Blips", webhook, time) 30 | end 31 | end 32 | end 33 | 34 | ::continue:: 35 | end 36 | end) 37 | end 38 | 39 | ProtectionManager.register_protection("player_blips", AntiPlayerBlips.initialize) 40 | 41 | return AntiPlayerBlips -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_resource_stop.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | 4 | ---@class AntiResourceStopModule 5 | local AntiResourceStop = {} 6 | 7 | ---@description Initialize Anti Resource Stop protection 8 | function AntiResourceStop.initialize() 9 | if ConfigLoader.get_protection_setting("Anti Resource Stop", "enabled") then 10 | AddEventHandler('onClientResourceStart', function(resource_name) 11 | TriggerServerCallback { 12 | eventName = 'SecureServe:Server_Callbacks:Protections:GetResourceStatus', 13 | args = {}, 14 | callback = function(stopped_by_server, started_resources, restarted) 15 | if not stopped_by_server and not started_resources and not restarted then 16 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, 17 | "Anti Start Resource " .. resource_name, webhook, time) 18 | end 19 | end 20 | } 21 | end) 22 | end 23 | 24 | if ConfigLoader.get_protection_setting("Anti Resource Stop", "enabled") then 25 | AddEventHandler('onClientResourceStop', function(resource_name) 26 | TriggerServerCallback { 27 | eventName = 'SecureServe:Server_Callbacks:Protections:GetResourceStatus', 28 | args = {}, 29 | callback = function(stopped_by_server, started_resources, restarted) 30 | if not stopped_by_server and not restarted and not started_resources then 31 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, 32 | "Anti Stop Resource " .. resource_name, webhook, time) 33 | end 34 | end 35 | } 36 | end) 37 | end 38 | end 39 | 40 | ProtectionManager.register_protection("resource_stop", AntiResourceStop.initialize) 41 | 42 | return AntiResourceStop 43 | -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_spectate.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiSpectateModule 6 | local AntiSpectate = {} 7 | 8 | ---@description Initialize Anti Spectate protection 9 | function AntiSpectate.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Spectate", "enabled") then return end 11 | 12 | Citizen.CreateThread(function() 13 | while true do 14 | Citizen.Wait(4500) 15 | 16 | if Cache.Get("hasPermission", "spectate") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 17 | goto continue 18 | end 19 | 20 | if NetworkIsInSpectatorMode() then 21 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Spectate", webhook, time) 22 | end 23 | 24 | ::continue:: 25 | end 26 | end) 27 | end 28 | 29 | ProtectionManager.register_protection("spectate", AntiSpectate.initialize) 30 | 31 | return AntiSpectate -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_speed_hack.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local Cache = require("client/core/cache") 3 | local ConfigLoader = require("client/core/config_loader") 4 | ---@class AntiSpeedHackModule 5 | local AntiSpeedHack = {} 6 | 7 | ---@description Initialize Anti Speed Hack protection 8 | function AntiSpeedHack.initialize() 9 | if not ConfigLoader.get_protection_setting("Anti Speed Hack", "enabled") then return end 10 | 11 | Citizen.CreateThread(function() 12 | while true do 13 | Citizen.Wait(2750) 14 | 15 | if Cache.Get("hasPermission", "speedhack") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 16 | goto continue 17 | end 18 | 19 | if Cache.Get("isInVehicle") then 20 | local vehicle = Cache.Get("vehicle") 21 | if vehicle and GetVehicleTopSpeedModifier(vehicle) > -1.0 then 22 | if GetVehiclePedIsIn(GetPlayerPed(-1), false) then return end 23 | 24 | if not Cache.Get("isSwimming") and not Cache.Get("isSwimmingUnderWater") and not Cache.Get("isFalling") then 25 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Speed Hack", webhook, time) 26 | end 27 | end 28 | 29 | SetVehicleTyresCanBurst(vehicle, true) 30 | SetEntityInvincible(vehicle, false) 31 | end 32 | 33 | ::continue:: 34 | end 35 | end) 36 | end 37 | 38 | ProtectionManager.register_protection("speed_hack", AntiSpeedHack.initialize) 39 | 40 | return AntiSpeedHack -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_state_bag_overflow.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | 4 | ---@class AntiStateBagOverflowModule 5 | local AntiStateBagOverflow = { 6 | active_handlers = {}, 7 | last_check_time = 0, 8 | cooldown = 2000 9 | } 10 | 11 | ---@description Initialize Anti State Bag Overflow protection 12 | function AntiStateBagOverflow.initialize() 13 | if not ConfigLoader.get_protection_setting("Anti State Bag Overflow", "enabled") then return end 14 | 15 | AntiStateBagOverflow.cleanup() 16 | 17 | AntiStateBagOverflow.active_handlers.main = AddStateBagChangeHandler(nil, nil, function(bag_name, key, value) 18 | local current_time = GetGameTimer() 19 | if current_time - AntiStateBagOverflow.last_check_time < AntiStateBagOverflow.cooldown then 20 | return 21 | end 22 | AntiStateBagOverflow.last_check_time = current_time 23 | 24 | if type(key) == "string" and #key > 131072 then 25 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti State Bag Overflow", webhook, time) 26 | end 27 | end) 28 | end 29 | 30 | function AntiStateBagOverflow.cleanup() 31 | for _, handler in pairs(AntiStateBagOverflow.active_handlers) do 32 | RemoveStateBagChangeHandler(handler) 33 | end 34 | AntiStateBagOverflow.active_handlers = {} 35 | end 36 | 37 | AddEventHandler('onResourceStop', function(resourceName) 38 | if GetCurrentResourceName() ~= resourceName then return end 39 | AntiStateBagOverflow.cleanup() 40 | collectgarbage("collect") 41 | end) 42 | 43 | ProtectionManager.register_protection("state_bag_overflow", AntiStateBagOverflow.initialize) 44 | 45 | return AntiStateBagOverflow -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_super_jump.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiSuperJumpModule 6 | local AntiSuperJump = {} 7 | 8 | ---@description Initialize Anti Super Jump protection 9 | function AntiSuperJump.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Super Jump", "enabled") then return end 11 | 12 | local jump_flags = 0 13 | local last_height = 0 14 | local normal_jump_height = 1.2 15 | 16 | Citizen.CreateThread(function() 17 | while true do 18 | Citizen.Wait(1000) 19 | 20 | if Cache.Get("hasPermission", "superjump") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 21 | jump_flags = 0 22 | goto continue 23 | end 24 | 25 | local ped = Cache.Get("ped") 26 | local current_pos = Cache.Get("coords") 27 | 28 | if Cache.Get("isInVehicle") or Cache.Get("isSwimming") or Cache.Get("isSwimmingUnderWater") then 29 | last_height = current_pos.z 30 | goto continue 31 | end 32 | 33 | if IsPedJumping(ped) then 34 | Citizen.CreateThread(function() 35 | local start_z = current_pos.z 36 | local max_height = start_z 37 | 38 | for i = 1, 20 do 39 | Citizen.Wait(50) 40 | local pos = GetEntityCoords(ped) 41 | if pos.z > max_height then 42 | max_height = pos.z 43 | end 44 | 45 | if not IsPedJumping(ped) then 46 | break 47 | end 48 | end 49 | 50 | local jump_height = max_height - start_z 51 | 52 | if jump_height > normal_jump_height and not IsPedFalling(ped) then 53 | jump_flags = jump_flags + 1 54 | 55 | if jump_flags >= 3 then 56 | local webhook = ConfigLoader.get_protection_setting("Anti Super Jump", "webhook") or "" 57 | local time = ConfigLoader.get_protection_setting("Anti Super Jump", "time") or 0 58 | 59 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Super Jump", webhook, time) 60 | jump_flags = 0 61 | end 62 | else 63 | if jump_flags > 0 then 64 | jump_flags = jump_flags - 1 65 | end 66 | end 67 | end) 68 | end 69 | 70 | last_height = current_pos.z 71 | 72 | ::continue:: 73 | end 74 | end) 75 | end 76 | 77 | ProtectionManager.register_protection("super_jump", AntiSuperJump.initialize) 78 | 79 | return AntiSuperJump -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_teleport.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiTeleportModule 6 | local AntiTeleport = {} 7 | 8 | ---@description Initialize Anti Teleport protection 9 | function AntiTeleport.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Teleport", "enabled") then return end 11 | 12 | ---@todo v1.3.0: Implement Anti Teleport protection 13 | end 14 | 15 | ProtectionManager.register_protection("teleport", AntiTeleport.initialize) 16 | 17 | return AntiTeleport -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_visions.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiVisionsModule 6 | local AntiVisions = {} 7 | 8 | ---@description Initialize Anti Night Vision and Anti Thermal Vision protections 9 | function AntiVisions.initialize() 10 | local enabled = ConfigLoader.get_protection_setting("Anti Thermal Vision", "enabled") 11 | or ConfigLoader.get_protection_setting("Anti Night Vision", "enabled") 12 | if not enabled then return end 13 | 14 | Citizen.CreateThread(function() 15 | while true do 16 | Citizen.Wait(6500) 17 | 18 | if Cache.Get("hasPermission", "visions") or Cache.Get("hasPermission", "all") or Cache.Get("isAdmin") then 19 | goto continue 20 | end 21 | 22 | if GetUsingseethrough() then 23 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Thermal Vision", webhook, time) 24 | end 25 | 26 | if GetUsingnightvision() then 27 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, "Anti Night Vision", webhook, time) 28 | end 29 | 30 | ::continue:: 31 | end 32 | end) 33 | end 34 | 35 | ProtectionManager.register_protection("visions", AntiVisions.initialize) 36 | 37 | return AntiVisions 38 | -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_weapon_damage_modifier.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | local Cache = require("client/core/cache") 4 | 5 | ---@class AntiWeaponDamageModifierModule 6 | local AntiWeaponDamageModifier = {} 7 | 8 | ---@description Initialize Anti Weapon Damage Modifier protection 9 | function AntiWeaponDamageModifier.initialize() 10 | if not ConfigLoader.get_protection_setting("Anti Weapon Damage Modifier", "enabled") then return end 11 | 12 | local lastCheckedWeapon = nil 13 | local suspiciousModifiers = 0 14 | 15 | Citizen.CreateThread(function() 16 | while true do 17 | Citizen.Wait(2000) 18 | 19 | if not Cache.Get("isAdmin") then 20 | local currentWeapon = Cache.Get("selectedWeapon") 21 | 22 | if currentWeapon ~= GetHashKey("WEAPON_UNARMED") then 23 | if Citizen.InvokeNative(0x4757f00bc6323cfe, currentWeapon, 1.0) > 1.5 then 24 | suspiciousModifiers = suspiciousModifiers + 1 25 | 26 | if suspiciousModifiers >= 3 then 27 | local damage = Citizen.InvokeNative(0x4757f00bc6323cfe, currentWeapon, 1.0) 28 | TriggerServerEvent("SecureServe:Server:Methods:PunishPlayer", nil, 29 | "Weapon damage modifier detected: " .. damage, 30 | webhook, 31 | time) 32 | 33 | N_0x4757f00bc6323cfe(currentWeapon, 1.0) 34 | suspiciousModifiers = 0 35 | end 36 | else 37 | if suspiciousModifiers > 0 then 38 | suspiciousModifiers = suspiciousModifiers - 1 39 | end 40 | end 41 | end 42 | 43 | lastCheckedWeapon = currentWeapon 44 | end 45 | end 46 | end) 47 | end 48 | 49 | ProtectionManager.register_protection("weapon_damage_modifier", AntiWeaponDamageModifier.initialize) 50 | 51 | return AntiWeaponDamageModifier -------------------------------------------------------------------------------- /SecureServe/src/client/protections/anti_weapon_pickup.lua: -------------------------------------------------------------------------------- 1 | local ProtectionManager = require("client/protections/protection_manager") 2 | local ConfigLoader = require("client/core/config_loader") 3 | 4 | ---@class AntiWeaponPickupModule 5 | local AntiWeaponPickup = {} 6 | 7 | ---@description Initialize Anti Weapon Pickup protection 8 | function AntiWeaponPickup.initialize() 9 | if not ConfigLoader.get_protection_setting("Anti Weapon Pickup", "enabled") then return end 10 | 11 | Citizen.CreateThread(function() 12 | while true do 13 | Citizen.Wait(1750) 14 | 15 | RemoveAllPickupsOfType(GetHashKey("PICKUP_ARMOUR_STANDARD")) 16 | RemoveAllPickupsOfType(GetHashKey("PICKUP_VEHICLE_ARMOUR_STANDARD")) 17 | RemoveAllPickupsOfType(GetHashKey("PICKUP_HEALTH_SNACK")) 18 | RemoveAllPickupsOfType(GetHashKey("PICKUP_HEALTH_STANDARD")) 19 | RemoveAllPickupsOfType(GetHashKey("PICKUP_VEHICLE_HEALTH_STANDARD")) 20 | RemoveAllPickupsOfType(GetHashKey("PICKUP_VEHICLE_HEALTH_STANDARD_LOW_GLOW")) 21 | end 22 | end) 23 | end 24 | 25 | ProtectionManager.register_protection("weapon_pickup", AntiWeaponPickup.initialize) 26 | 27 | return AntiWeaponPickup -------------------------------------------------------------------------------- /SecureServe/src/client/protections/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SecureServe Anticheat Panel 6 | 7 | 8 | 9 | 10 | 11 | 12 | 33 | 34 | -------------------------------------------------------------------------------- /SecureServe/src/main.lua: -------------------------------------------------------------------------------- 1 | local Require = require("shared/lib/require") 2 | 3 | local SharedInit = require("shared/init") 4 | SharedInit.initialize() 5 | 6 | if IsDuplicityVersion() then 7 | local ServerMain = require("server/main") 8 | else 9 | local ClientInit = require("client/init") 10 | CreateThread(function() 11 | Wait(1000) 12 | ClientInit.initialize() 13 | end) 14 | end 15 | 16 | -------------------------------------------------------------------------------- /SecureServe/src/module/module.js: -------------------------------------------------------------------------------- 1 | let encryption_key = ""; 2 | 3 | /** 4 | * @return {string} - The encryption key from secureserve.key file 5 | */ 6 | function getEncryptionKey() { 7 | try { 8 | const keyFile = LoadResourceFile("SecureServe", "secureserve.key"); 9 | 10 | if (!keyFile || keyFile === "") { 11 | console.warn("[WARNING] Failed to load SecureServe encryption key. Using temporary key."); 12 | return "temp_key_" + GetCurrentResourceName(); 13 | } 14 | 15 | return keyFile.trim(); 16 | } catch (error) { 17 | console.error("[ERROR] Failed to load SecureServe encryption key:", error); 18 | return "c4a2ec5dc103a3f730460948f2e3c01df39ea4212bc2c82f"; 19 | } 20 | } 21 | 22 | encryption_key = getEncryptionKey(); 23 | 24 | /** 25 | * @param {string|number} input - The input string or number to encrypt 26 | * @return {string} - The encrypted string 27 | */ 28 | function encryptDecrypt(input) { 29 | const output = []; 30 | const inputStr = String(input); 31 | for (let i = 0; i < inputStr.length; i++) { 32 | const char = inputStr.charCodeAt(i); 33 | const keyChar = encryption_key.charCodeAt(i % encryption_key.length); 34 | const encryptedChar = (char + keyChar) % 256; 35 | output.push(String.fromCharCode(encryptedChar)); 36 | } 37 | return output.join(''); 38 | } 39 | 40 | /** 41 | * @param {string} input - The encrypted string to decrypt 42 | * @return {string} - The decrypted string 43 | */ 44 | function decrypt(input) { 45 | const output = []; 46 | const inputStr = String(input); 47 | for (let i = 0; i < inputStr.length; i++) { 48 | const char = inputStr.charCodeAt(i); 49 | const keyChar = encryption_key.charCodeAt(i % encryption_key.length); 50 | const decryptedChar = (char - keyChar) % 256; 51 | output.push(String.fromCharCode(decryptedChar)); 52 | } 53 | return output.join(''); 54 | } 55 | 56 | const originalEmit = typeof emit !== 'undefined' ? emit : null; 57 | const originalOn = typeof on !== 'undefined' ? on : null; 58 | const originalOnServer = typeof onServer !== 'undefined' ? onServer : null; 59 | const originalOnAll = typeof onAll !== 'undefined' ? onAll : null; 60 | const originalEmitNet = typeof emitNet !== 'undefined' ? emitNet : null; 61 | const originalOnNet = typeof onNet !== 'undefined' ? onNet : null; 62 | 63 | if (originalEmit) { 64 | /** 65 | * @param {string} eventName - The name of the event to emit 66 | * @param {...any} args - The arguments to pass to the event handlers 67 | * @return {void} 68 | */ 69 | emit = function(eventName, ...args) { 70 | return originalEmit(encryptDecrypt(eventName), ...args); 71 | }; 72 | } 73 | 74 | if (originalEmitNet) { 75 | /** 76 | * @param {string} eventName - The name of the event to emit over the network 77 | * @param {...any} args - The arguments to pass to the event handlers 78 | * @return {void} 79 | */ 80 | emitNet = function(eventName, ...args) { 81 | return originalEmitNet(encryptDecrypt(eventName), ...args); 82 | }; 83 | } 84 | 85 | if (originalOn) { 86 | /** 87 | * @param {string} eventName - The name of the event to listen for 88 | * @param {Function} callback - The callback function to execute when the event is triggered 89 | * @return {number} - The event handler ID 90 | */ 91 | on = function(eventName, callback) { 92 | originalOn(encryptDecrypt(eventName), callback); 93 | return originalOn(eventName, callback); 94 | }; 95 | } 96 | 97 | if (originalOnNet) { 98 | /** 99 | * @param {string} eventName - The name of the network event to listen for 100 | * @param {Function} callback - The callback function to execute when the event is triggered 101 | * @return {void} 102 | */ 103 | onNet = function(eventName, callback) { 104 | const encryptedEvent = encryptDecrypt(eventName); 105 | 106 | originalOnNet(eventName, (...args) => { 107 | if (IsDuplicityVersion()) { 108 | const src = source; 109 | if (GetPlayerPing(src) > 0) { 110 | const resourceName = GetCurrentResourceName(); 111 | const banMessage = `Tried triggering a restricted event: ${eventName} in resource: ${resourceName}.`; 112 | if (exports["SecureServe"] && exports["SecureServe"].module_punish) { 113 | exports["SecureServe"].module_punish(src, banMessage); 114 | } 115 | } 116 | } 117 | callback(...args); 118 | }); 119 | 120 | originalOnNet(encryptedEvent, (...args) => { 121 | if (IsDuplicityVersion()) { // Server side 122 | const src = source; 123 | if (GetPlayerPing(src) > 0 && 124 | eventName !== "add_to_trigger_list" && 125 | eventName !== "check_trigger_list") { 126 | 127 | emit(encryptDecrypt("check_trigger_list"), src, eventName, GetCurrentResourceName()); 128 | } 129 | } 130 | callback(...args); 131 | }); 132 | }; 133 | } 134 | 135 | if (originalOnServer) { 136 | /** 137 | * @param {string} eventName - The name of the server event to listen for 138 | * @param {Function} callback - The callback function to execute when the event is triggered 139 | * @return {void} 140 | */ 141 | onServer = function(eventName, callback) { 142 | return originalOnServer(encryptDecrypt(eventName), callback); 143 | }; 144 | } 145 | 146 | if (originalOnAll) { 147 | /** 148 | * @param {Function} callback - The callback function to execute when any event is triggered 149 | * @return {void} 150 | */ 151 | onAll = function(callback) { 152 | return originalOnAll(callback); 153 | }; 154 | } 155 | 156 | /** 157 | * @param {Function} originalFunction - The original entity creation function 158 | * @return {Function} - The wrapped entity creation function 159 | */ 160 | function createEntityWrapper(originalFunction) { 161 | /** 162 | * @param {...any} args - The arguments to pass to the original function 163 | * @return {number} - The entity handle 164 | */ 165 | return function(...args) { 166 | const entity = originalFunction(...args); 167 | if (entity && DoesEntityExist(entity)) { 168 | if (IsDuplicityVersion()) { // Server-side 169 | emitNet('entity2', -1, GetEntityModel(entity)); 170 | emit("entityCreatedByScript", entity, 'fdgfd', true, GetEntityModel(entity)); 171 | } else { 172 | emit('entityCreatedByScriptClient', entity); 173 | emitNet(encryptDecrypt("entityCreatedByScript"), entity, 'fdgfd', true, GetEntityModel(entity)); 174 | } 175 | return entity; 176 | } 177 | return entity; 178 | }; 179 | } 180 | 181 | /** 182 | * @param {string} resourceName - The name of the resource to check 183 | * @return {boolean} - Whether the resource is valid 184 | */ 185 | function isValidResource(resourceName) { 186 | const invalidResources = [null, "fivem", "gta", "citizen", "system"]; 187 | return !invalidResources.includes(resourceName); 188 | } 189 | 190 | /** 191 | * @param {Function} originalFunction - The original explosion function 192 | * @return {Function} - The wrapped explosion function 193 | */ 194 | function handleExplosionEvent(originalFunction) { 195 | /** 196 | * @param {...any} args - The arguments to pass to the original function 197 | * @return {any} - The result of the original function 198 | */ 199 | return function(...args) { 200 | const resourceName = GetCurrentResourceName(); 201 | if (!IsDuplicityVersion() && isValidResource(resourceName)) { 202 | emitNet("SecureServe:Explosions:Whitelist", { 203 | source: GetPlayerServerId(PlayerId()), 204 | resource: resourceName 205 | }); 206 | } 207 | return originalFunction(...args); 208 | }; 209 | } 210 | 211 | const entityFunctions = [ 212 | "CreateObject", "CreateObjectNoOffset", "CreateVehicle", "CreatePed", 213 | "CreatePedInsideVehicle", "CreateRandomPed", "CreateRandomPedAsDriver" 214 | ]; 215 | 216 | for (const funcName of entityFunctions) { 217 | if (typeof global[funcName] === 'function') { 218 | const original = global[funcName]; 219 | global[funcName] = createEntityWrapper(original); 220 | } 221 | } 222 | 223 | const explosionFunctions = [ 224 | "AddExplosion", "AddExplosionWithUserVfx", "ExplodeVehicle", 225 | "NetworkExplodeVehicle", "ShootSingleBulletBetweenCoords", 226 | "AddOwnedExplosion", "StartScriptFire", "RemoveScriptFire" 227 | ]; 228 | 229 | if (!IsDuplicityVersion()) { 230 | for (const funcName of explosionFunctions) { 231 | if (typeof global[funcName] === 'function') { 232 | const original = global[funcName]; 233 | global[funcName] = handleExplosionEvent(original); 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /SecureServe/src/module/module.lua: -------------------------------------------------------------------------------- 1 | -- if GetCurrentResourceName() == "SecureServe" then 2 | -- return 3 | -- end 4 | local encryption_key = "" 5 | 6 | 7 | ---@return string The encryption key from secureserve.key file 8 | local function getEncryptionKey() 9 | local keyFile = LoadResourceFile("SecureServe", "secureserve.key") 10 | if not keyFile or keyFile == "" then 11 | print("^3[WARNING] Failed to load SecureServe encryption key. Using temporary key.^7") 12 | return "temp_key_" .. GetCurrentResourceName() 13 | end 14 | 15 | return keyFile:gsub("%s+", "") 16 | end 17 | 18 | encryption_key = getEncryptionKey() 19 | 20 | ---@param input string|number The input string or number to encrypt 21 | ---@return string The encrypted string 22 | function encryptDecrypt(input) 23 | local output = {} 24 | for i = 1, #tostring(input) do 25 | local char = tostring(input):byte(i) 26 | local keyChar = encryption_key:byte((i - 1) % #encryption_key + 1) 27 | local encryptedChar = (char + keyChar) % 256 28 | output[i] = string.char(encryptedChar) 29 | end 30 | return table.concat(output) 31 | end 32 | 33 | ---@param input string The encrypted string to decrypt 34 | ---@return string The decrypted string 35 | function decrypt(input) 36 | local output = {} 37 | for i = 1, #tostring(input) do 38 | local char = tostring(input):byte(i) 39 | local keyChar = encryption_key:byte((i - 1) % #encryption_key + 1) 40 | local decryptedChar = (char - keyChar) % 256 41 | output[i] = string.char(decryptedChar) 42 | end 43 | return table.concat(output) 44 | end 45 | 46 | ---@param originalFunction function The original entity creation function 47 | ---@return function The wrapped entity creation function 48 | local function createEntity(originalFunction, ...) 49 | local entity = originalFunction(...) 50 | 51 | if not IsDuplicityVersion() then 52 | while not DoesEntityExist(entity) do 53 | Wait(1) 54 | end 55 | TriggerServerEvent("SecureServe:Server:Methods:Entity:Create", entity, GetCurrentResourceName(), GetEntityModel(entity)) 56 | else 57 | Citizen.CreateThread(function() 58 | while not DoesEntityExist(entity) do 59 | Wait(1) 60 | end 61 | TriggerEvent("SecureServe:Server:Methods:Entity:CreateServer", entity, GetCurrentResourceName(), GetEntityModel(entity)) 62 | end) 63 | end 64 | 65 | return entity 66 | end 67 | 68 | local _CreateObject = CreateObject 69 | local _CreateObjectNoOffset = CreateObjectNoOffset 70 | local _CreateVehicle = CreateVehicle 71 | local _CreatePed = CreatePed 72 | local _CreatePedInsideVehicle = CreatePedInsideVehicle 73 | local _CreateRandomPed = CreateRandomPed 74 | local _CreateRandomPedAsDriver = CreateRandomPedAsDriver 75 | local _CreateScriptVehicleGenerator = CreateScriptVehicleGenerator 76 | local _CreateVehicleServerSetter = CreateVehicleServerSetter 77 | local _CreateAutomobile = CreateAutomobile 78 | 79 | _G.CreateObject = function(...) return createEntity(_CreateObject, ...) end 80 | _G.CreateObjectNoOffset = function(...) return createEntity(_CreateObjectNoOffset, ...) end 81 | _G.CreateVehicle = function(...) return createEntity(_CreateVehicle, ...) end 82 | _G.CreatePed = function(...) return createEntity(_CreatePed, ...) end 83 | _G.CreatePedInsideVehicle = function(...) return createEntity(_CreatePedInsideVehicle, ...) end 84 | _G.CreateRandomPed = function(...) return createEntity(_CreateRandomPed, ...) end 85 | _G.CreateRandomPedAsDriver = function(...) return createEntity(_CreateRandomPedAsDriver, ...) end 86 | _G.CreateScriptVehicleGenerator = function(...) return createEntity(_CreateScriptVehicleGenerator, ...) end 87 | _G.CreateVehicleServerSetter = function(...) return createEntity(_CreateVehicleServerSetter, ...) end 88 | _G.CreateAutomobile = function(...) return createEntity(_CreateAutomobile, ...) end 89 | 90 | if IsDuplicityVersion() then 91 | local _AddEventHandler = AddEventHandler 92 | local _RegisterNetEvent = RegisterNetEvent 93 | local events_to_listen = {} 94 | 95 | _G.RegisterNetEvent = function(event_name, ...) 96 | local enc_event_name = encryptDecrypt(event_name) 97 | events_to_listen[event_name] = enc_event_name 98 | 99 | _RegisterNetEvent(enc_event_name) 100 | return _RegisterNetEvent(event_name, ...) 101 | end 102 | 103 | _G.AddEventHandler = function(event_name, handler, ...) 104 | local enc_event_name = events_to_listen[event_name] 105 | local handler_ref = _AddEventHandler(event_name, handler, ...) 106 | 107 | if enc_event_name then 108 | _AddEventHandler(enc_event_name, handler, ...) 109 | end 110 | 111 | return handler_ref 112 | end 113 | 114 | Citizen.CreateThread(function() 115 | for event_name, _ in pairs(events_to_listen) do 116 | local enc_event_name = encryptDecrypt(event_name) 117 | if event_name ~= "check_trigger_list" then 118 | _AddEventHandler(event_name, function () 119 | local src = source 120 | if GetPlayerPing(src) > 0 then 121 | local resourceName = GetCurrentResourceName() 122 | local banMessage = ("Tried triggering a restricted event: %s in resource: %s."):format(event_name, resourceName) 123 | exports["SecureServe"]:module_punish(src, banMessage) 124 | end 125 | end) 126 | 127 | _AddEventHandler(enc_event_name, function () 128 | local src = source 129 | 130 | if GetPlayerPing(src) > 0 and decrypt(enc_event_name) ~= "add_to_trigger_list" and decrypt(enc_event_name) ~= "check_trigger_list" then 131 | -- TriggerEvent(encryptDecrypt("check_trigger_list"), src, decrypt(enc_event_name), GetCurrentResourceName()) 132 | end 133 | end) 134 | end 135 | end 136 | end) 137 | 138 | RegisterServerEvent = RegisterNetEvent 139 | else 140 | local _TriggerServerEvent = TriggerServerEvent 141 | 142 | _G.TriggerServerEvent = function(eventName, ...) 143 | local encryptedEvent = encryptDecrypt(eventName) 144 | return _TriggerServerEvent(encryptedEvent, ...) 145 | end 146 | 147 | ---@param resourceName string The name of the resource to check 148 | ---@return boolean Whether the resource is valid 149 | local function isValidResource(resourceName) 150 | local invalidResources = { 151 | nil, 152 | "fivem", 153 | "gta", 154 | "citizen", 155 | "system" 156 | } 157 | 158 | for _, invalid in ipairs(invalidResources) do 159 | if resourceName == invalid then 160 | return false 161 | end 162 | end 163 | 164 | return true 165 | end 166 | 167 | ---@param originalFunction function The original explosion function 168 | ---@return function The wrapped explosion function 169 | local handleExplosionEvent = function(originalFunction, ...) 170 | local resourceName = GetCurrentResourceName() 171 | if isValidResource(resourceName) then 172 | TriggerServerEvent("SecureServe:Explosions:Whitelist", { 173 | source = GetPlayerServerId(PlayerId()), 174 | resource = resourceName 175 | }) 176 | end 177 | return originalFunction(...) 178 | end 179 | 180 | local _AddExplosion = AddExplosion 181 | local _AddExplosionWithUserVfx = AddExplosionWithUserVfx 182 | local _ExplodeVehicle = ExplodeVehicle 183 | local _NetworkExplodeVehicle = NetworkExplodeVehicle 184 | local _ShootSingleBulletBetweenCoords = ShootSingleBulletBetweenCoords 185 | local _AddOwnedExplosion = AddOwnedExplosion 186 | local _StartScriptFire = StartScriptFire 187 | local _RemoveScriptFire = RemoveScriptFire 188 | 189 | _G.AddExplosion = function(...) return handleExplosionEvent(_AddExplosion, ...) end 190 | _G.AddExplosionWithUserVfx = function(...) return handleExplosionEvent(_AddExplosionWithUserVfx, ...) end 191 | _G.ExplodeVehicle = function(...) return handleExplosionEvent(_ExplodeVehicle, ...) end 192 | _G.NetworkExplodeVehicle = function(...) return handleExplosionEvent(_NetworkExplodeVehicle, ...) end 193 | _G.ShootSingleBulletBetweenCoords = function(...) return handleExplosionEvent(_ShootSingleBulletBetweenCoords, ...) end 194 | _G.AddOwnedExplosion = function(...) return handleExplosionEvent(_AddOwnedExplosion, ...) end 195 | _G.StartScriptFire = function(...) return handleExplosionEvent(_StartScriptFire, ...) end 196 | _G.RemoveScriptFire = function(...) return handleExplosionEvent(_RemoveScriptFire, ...) end 197 | 198 | 199 | 200 | local function handleWeaponEvent(originalFunction, weaponArgIndex, ...) 201 | local args = { ... } 202 | local weaponHash = nil 203 | 204 | if weaponArgIndex and args[weaponArgIndex] then 205 | local weaponArg = args[weaponArgIndex] 206 | weaponHash = type(weaponArg) == "string" and GetHashKey(weaponArg) or weaponArg 207 | end 208 | 209 | local resourceName = GetCurrentResourceName() 210 | if isValidResource(resourceName) then 211 | TriggerEvent("SecureServe:Weapons:Whitelist", { 212 | weapon = weaponHash, 213 | source = GetPlayerServerId(PlayerId()), 214 | resource = resourceName 215 | }) 216 | end 217 | 218 | return originalFunction(table.unpack(args)) 219 | end 220 | 221 | local weaponNatives = { 222 | { name = "GiveWeaponToPed", argIndex = 2 }, 223 | { name = "RemoveWeaponFromPed", argIndex = 2 }, 224 | { name = "RemoveAllPedWeapons", argIndex = nil }, 225 | { name = "SetCurrentPedWeapon", argIndex = 2 }, 226 | } 227 | 228 | for _, native in ipairs(weaponNatives) do 229 | local originalFunction = _G[native.name] 230 | if originalFunction then 231 | _G[native.name] = function(...) 232 | return handleWeaponEvent(originalFunction, native.argIndex, ...) 233 | end 234 | end 235 | end 236 | end 237 | -------------------------------------------------------------------------------- /SecureServe/src/server/core/config_manager.lua: -------------------------------------------------------------------------------- 1 | ---@class ConfigManagerModule 2 | local ConfigManager = {} 3 | 4 | local logger = require("server/core/logger") 5 | 6 | local function safe_get(table, key, default) 7 | if table and table[key] ~= nil then 8 | return table[key] 9 | end 10 | return default 11 | end 12 | 13 | local config = { 14 | Protections = {}, 15 | Settings = {}, 16 | Admins = {} 17 | } 18 | 19 | ---@description Loads and manages server-side configuration 20 | function ConfigManager.initialize() 21 | if not _G.SecureServe then 22 | _G.SecureServe = {} 23 | print("^1[WARNING] SecureServe config not found, using defaults^7") 24 | end 25 | 26 | config = _G.SecureServe 27 | 28 | ConfigManager.initialize_blacklist_lookups() 29 | 30 | RegisterNetEvent("requestConfig", function() 31 | local src = source 32 | TriggerClientEvent('receiveConfig', src, config) 33 | end) 34 | 35 | print("^5[SUCCESS] ^3Config Manager^7 initialized") 36 | end 37 | 38 | ---@description Get the entire config object 39 | ---@return table The configuration table 40 | function ConfigManager.get_config() 41 | return config 42 | end 43 | 44 | ---@param player_id number The player ID to check permissions for 45 | ---@param permission string The permission to check 46 | ---@return boolean has_permission Whether the player has the permission 47 | function ConfigManager.has_permission(player_id, permission) 48 | local identifiers = GetPlayerIdentifiers(player_id) 49 | local found = false 50 | 51 | for _, id in pairs(identifiers) do 52 | for _, admin in pairs(config.Admins or {}) do 53 | if id == admin.identifier and permission == admin.permission then 54 | found = true 55 | break 56 | end 57 | end 58 | 59 | if found then break end 60 | end 61 | 62 | return found 63 | end 64 | 65 | ---@description Get a specific config value by key 66 | ---@param key string The key to get from config 67 | ---@param default any Default value if key doesn't exist 68 | ---@return any The config value or default 69 | function ConfigManager.get(key, default) 70 | return safe_get(config, key, default) 71 | end 72 | 73 | ---@description Check if an event is whitelisted in the config 74 | ---@param event_name string The event name to check 75 | ---@return boolean is_whitelisted Whether the event is whitelisted 76 | function ConfigManager.is_event_whitelisted(event_name) 77 | if not config.EventWhitelist then return false end 78 | 79 | if config.EventWhitelist[event_name] then 80 | return true 81 | end 82 | 83 | for _, whitelisted_event in pairs(config.EventWhitelist) do 84 | if event_name == whitelisted_event then 85 | return true 86 | end 87 | end 88 | 89 | return false 90 | end 91 | 92 | ---@description Add an event to the whitelist 93 | ---@param event_name string The event name to whitelist 94 | ---@return boolean success Whether the operation was successful 95 | function ConfigManager.whitelist_event(event_name) 96 | if not event_name then return false end 97 | 98 | if not config.EventWhitelist then 99 | config.EventWhitelist = {} 100 | end 101 | 102 | if not ConfigManager.is_event_whitelisted(event_name) then 103 | config.EventWhitelist[event_name] = true 104 | return true 105 | end 106 | 107 | return false 108 | end 109 | 110 | ---@return boolean is_enabled Whether menu detection is enabled in config 111 | function ConfigManager.is_menu_detection_enabled() 112 | return true 113 | end 114 | 115 | ---@return boolean is_enabled Whether trigger protection is enabled in config 116 | function ConfigManager.is_trigger_protection_enabled() 117 | return true 118 | end 119 | 120 | ---@return boolean is_enabled Whether entity spam protection is enabled in config 121 | function ConfigManager.is_entity_spam_protection_enabled() 122 | return true 123 | end 124 | 125 | ---@return number max_entities The maximum number of entities allowed per second 126 | function ConfigManager.get_max_entities_per_second() 127 | return safe_get(SecureServe.Module.Entity.Limits, "Entities", 10) 128 | end 129 | 130 | -- Generic blacklist checker - checks if a model hash is in any blacklist 131 | ---@param modelHash number The model hash to check 132 | ---@return boolean isBlacklisted Whether the model is blacklisted in any category 133 | function ConfigManager.is_blacklisted_model(modelHash) 134 | return ConfigManager.is_vehicle_blacklisted(modelHash) or 135 | ConfigManager.is_ped_blacklisted(modelHash) or 136 | ConfigManager.is_object_blacklisted(modelHash) 137 | end 138 | 139 | local vehicle_hash_lookup = {} 140 | local ped_hash_lookup = {} 141 | local object_hash_lookup = {} 142 | 143 | function ConfigManager.initialize_blacklist_lookups() 144 | if config.Protection and config.Protection.BlacklistedVehicles then 145 | for _, vehicle in ipairs(config.Protection.BlacklistedVehicles) do 146 | if vehicle.name then 147 | local hash = type(vehicle.name) == "number" and vehicle.name or GetHashKey(vehicle.name) 148 | vehicle_hash_lookup[hash] = true 149 | end 150 | end 151 | end 152 | 153 | if config.Protection and config.Protection.BlacklistedPeds then 154 | for _, ped in ipairs(config.Protection.BlacklistedPeds) do 155 | if ped.hash then 156 | ped_hash_lookup[ped.hash] = true 157 | elseif ped.name then 158 | ped_hash_lookup[GetHashKey(ped.name)] = true 159 | end 160 | end 161 | end 162 | 163 | if config.Protection and config.Protection.BlacklistedObjects then 164 | for _, object in ipairs(config.Protection.BlacklistedObjects) do 165 | if object.name then 166 | local hash = type(object.name) == "number" and object.name or GetHashKey(object.name) 167 | object_hash_lookup[hash] = true 168 | end 169 | end 170 | end 171 | 172 | logger.info("^5[SUCCESS] ^3Blacklist lookups^7 initialized") 173 | end 174 | 175 | -- Type-specific blacklist checkers 176 | ---@param modelHash number The vehicle model hash to check 177 | ---@return boolean isBlacklisted Whether the vehicle model is blacklisted 178 | function ConfigManager.is_vehicle_blacklisted(modelHash) 179 | if not modelHash then return false end 180 | return vehicle_hash_lookup[modelHash] == true 181 | end 182 | 183 | ---@param modelHash number The ped model hash to check 184 | ---@return boolean isBlacklisted Whether the ped model is blacklisted 185 | function ConfigManager.is_ped_blacklisted(modelHash) 186 | if not modelHash then return false end 187 | return ped_hash_lookup[modelHash] == true 188 | end 189 | 190 | ---@param modelHash number The object model hash to check 191 | ---@return boolean isBlacklisted Whether the object model is blacklisted 192 | function ConfigManager.is_object_blacklisted(modelHash) 193 | if not modelHash then return false end 194 | return object_hash_lookup[modelHash] == true 195 | end 196 | 197 | ---@return boolean is_enabled Whether blacklisted vehicle protection is enabled 198 | function ConfigManager.is_blacklisted_vehicle_protection_enabled() 199 | return safe_get(config.Protections, "BlacklistedVehicles", false) 200 | end 201 | 202 | ---@return boolean is_enabled Whether mass vehicle spawn protection is enabled 203 | function ConfigManager.is_mass_vehicle_spawn_protection_enabled() 204 | return true 205 | end 206 | 207 | ---@return number max_vehicles The maximum number of vehicles allowed per player 208 | function ConfigManager.get_max_vehicles_per_player() 209 | return safe_get(SecureServe.Module.Entity.Limits, "Vehicles", 5) 210 | end 211 | 212 | ---@return boolean is_enabled Whether blacklisted ped protection is enabled 213 | function ConfigManager.is_blacklisted_ped_protection_enabled() 214 | return true 215 | end 216 | 217 | ---@return boolean is_enabled Whether mass ped spawn protection is enabled 218 | function ConfigManager.is_mass_ped_spawn_protection_enabled() 219 | return true 220 | end 221 | 222 | ---@return number max_peds The maximum number of peds allowed per player 223 | function ConfigManager.get_max_peds_per_player() 224 | return safe_get(SecureServe.Module.Entity.Limits, "Peds", 5) 225 | end 226 | 227 | ---@return boolean is_enabled Whether blacklisted object protection is enabled 228 | function ConfigManager.is_blacklisted_object_protection_enabled() 229 | return true 230 | end 231 | 232 | ---@return boolean is_enabled Whether mass object spawn protection is enabled 233 | function ConfigManager.is_mass_object_spawn_protection_enabled() 234 | return true 235 | end 236 | 237 | ---@return number max_objects The maximum number of objects allowed per player 238 | function ConfigManager.get_max_objects_per_player() 239 | return safe_get(SecureServe.Module.Entity.Limits, "Objects", 5) 240 | end 241 | 242 | ---@return boolean is_enabled Whether resource injection protection is enabled 243 | function ConfigManager.is_resource_injection_protection_enabled() 244 | return true 245 | end 246 | 247 | ---@return boolean is_enabled Whether weapon modifier protection is enabled 248 | function ConfigManager.is_weapon_modifier_protection_enabled() 249 | return true 250 | end 251 | 252 | ---@param weapon_hash number The weapon hash to get max damage for 253 | ---@return number|nil max_damage The maximum damage value for the weapon or nil if not defined 254 | function ConfigManager.get_weapon_max_damage(weapon_hash) 255 | if not config.WeaponDamages then return nil end 256 | return config.WeaponDamages[weapon_hash] 257 | end 258 | 259 | ---@return boolean is_enabled Whether explosion protection is enabled 260 | function ConfigManager.is_explosion_protection_enabled() 261 | return safe_get(SecureServe.Module.Explosions, "ModuleEnabled", false) 262 | end 263 | 264 | ---@todo fix this to acutally work 265 | ---@return boolean is_enabled Whether particle protection is enabled 266 | function ConfigManager.is_particle_protection_enabled() 267 | return safe_get(config.Protections, "ParticleProtection", false) 268 | end 269 | 270 | ---@todo fix this to acutally work 271 | ---@return number max_particles The maximum number of particles per second 272 | function ConfigManager.get_max_particles_per_second() 273 | return safe_get(config.Settings, "MaxParticlesPerSecond", 20) 274 | end 275 | 276 | ---@param effect_hash number The particle effect hash to check 277 | ---@return boolean is_blacklisted Whether the particle effect is blacklisted 278 | function ConfigManager.is_blacklisted_particle(effect_hash) 279 | if not config.BlacklistedParticles then return false end 280 | 281 | for _, blacklisted_particle in pairs(config.BlacklistedParticles) do 282 | if effect_hash == blacklisted_particle or effect_hash == GetHashKey(blacklisted_particle) then 283 | return true 284 | end 285 | end 286 | 287 | return false 288 | end 289 | 290 | ---@return boolean is_enabled Whether the debug mode is enabled in config 291 | function ConfigManager.is_debug_mode_enabled() 292 | return safe_get(config, "Debug", false) 293 | end 294 | 295 | ---@description Set the debug mode and update all connected clients 296 | ---@param enabled boolean Whether debug mode should be enabled 297 | function ConfigManager.set_debug_mode(enabled) 298 | if config.Debug ~= enabled then 299 | config.Debug = enabled 300 | TriggerClientEvent("SecureServe:UpdateDebugMode", -1, enabled) 301 | return true 302 | end 303 | return false 304 | end 305 | 306 | return ConfigManager -------------------------------------------------------------------------------- /SecureServe/src/server/core/debug_module.lua: -------------------------------------------------------------------------------- 1 | ---@class DebugModule 2 | local DebugModule = { 3 | enabled = false, 4 | error_count = 0, 5 | last_errors = {}, 6 | max_error_history = 20, 7 | is_dev_mode = false, 8 | current_error_handler = nil 9 | } 10 | 11 | -- Dependencies 12 | local logger = require("server/core/logger") 13 | 14 | ---@description Initialize the debug module 15 | ---@param config table Configuration options 16 | function DebugModule.initialize(config) 17 | if config then 18 | DebugModule.enabled = config.DebugEnabled or false 19 | DebugModule.max_error_history = config.MaxErrorHistory or 20 20 | DebugModule.is_dev_mode = config.DevMode or false 21 | end 22 | 23 | DebugModule.setup_error_handler() 24 | 25 | logger.info("Debug module initialized. Debug mode: " .. tostring(DebugModule.enabled)) 26 | end 27 | 28 | ---@description Setup global error handling 29 | function DebugModule.setup_error_handler() 30 | local original_error = error 31 | 32 | DebugModule.current_error_handler = function(err, level) 33 | DebugModule.handle_error(err, debug.traceback("", 2)) 34 | return original_error(err, level or 1) 35 | end 36 | 37 | error = DebugModule.current_error_handler 38 | 39 | AddEventHandler("onResourceError", function(resourceName, err, file, line) 40 | if resourceName == GetCurrentResourceName() then 41 | local trace = "File: " .. (file or "unknown") .. ", Line: " .. (line or "?") 42 | DebugModule.handle_error(err, trace) 43 | end 44 | end) 45 | 46 | logger.debug("Error handler has been set up") 47 | end 48 | 49 | ---@description Handle and log an error 50 | ---@param err string The error message 51 | ---@param trace string The stack trace 52 | function DebugModule.handle_error(err, trace) 53 | DebugModule.error_count = DebugModule.error_count + 1 54 | 55 | local error_entry = { 56 | message = err, 57 | trace = trace, 58 | timestamp = os.time(), 59 | resource = GetCurrentResourceName() 60 | } 61 | 62 | table.insert(DebugModule.last_errors, 1, error_entry) 63 | 64 | while #DebugModule.last_errors > DebugModule.max_error_history do 65 | table.remove(DebugModule.last_errors) 66 | end 67 | 68 | logger.error("Error detected: " .. err) 69 | logger.debug("Error trace: " .. trace) 70 | 71 | if DebugModule.is_dev_mode then 72 | DebugModule.print_detailed_error(error_entry) 73 | end 74 | end 75 | 76 | ---@description Print detailed error information 77 | ---@param error_entry table The error entry to print 78 | function DebugModule.print_detailed_error(error_entry) 79 | print("^1================= DETAILED ERROR =================^7") 80 | print("^1Error: ^7" .. error_entry.message) 81 | print("^1Resource: ^7" .. error_entry.resource) 82 | print("^1Time: ^7" .. os.date("%Y-%m-%d %H:%M:%S", error_entry.timestamp)) 83 | 84 | local trace_lines = DebugModule.format_stack_trace(error_entry.trace) 85 | print("^1Stack trace:^7") 86 | for i, line in ipairs(trace_lines) do 87 | print(line) 88 | end 89 | 90 | print("^1====================================================^7") 91 | end 92 | 93 | ---@description Format a stack trace for better readability 94 | ---@param trace string The stack trace to format 95 | ---@return table formatted_lines The formatted trace lines 96 | function DebugModule.format_stack_trace(trace) 97 | if not trace then return {"No trace available"} end 98 | 99 | local lines = {} 100 | for line in trace:gmatch("[^\r\n]+") do 101 | if not line:match("stack traceback:") then 102 | line = line:gsub("in function '([^']+)'", "in function '^3%1^7'") 103 | line = line:gsub("([^:]+):(%d+):", "^2%1^7:^5%2^7:") 104 | 105 | table.insert(lines, " " .. line) 106 | end 107 | end 108 | 109 | return lines 110 | end 111 | 112 | ---@description Get error statistics 113 | ---@return table stats Error statistics 114 | function DebugModule.get_error_stats() 115 | return { 116 | total_errors = DebugModule.error_count, 117 | recent_errors = #DebugModule.last_errors, 118 | debug_enabled = DebugModule.enabled, 119 | dev_mode = DebugModule.is_dev_mode 120 | } 121 | end 122 | 123 | ---@description Get the most recent errors 124 | ---@param count number Number of errors to retrieve (default: all) 125 | ---@return table errors The most recent errors 126 | function DebugModule.get_recent_errors(count) 127 | local result = {} 128 | local limit = count or #DebugModule.last_errors 129 | 130 | for i = 1, math.min(limit, #DebugModule.last_errors) do 131 | table.insert(result, DebugModule.last_errors[i]) 132 | end 133 | 134 | return result 135 | end 136 | 137 | ---@description Clear the error history 138 | function DebugModule.clear_errors() 139 | DebugModule.last_errors = {} 140 | logger.debug("Error history cleared") 141 | end 142 | 143 | ---@description Enable or disable debug mode 144 | ---@param enabled boolean Whether debug mode should be enabled 145 | function DebugModule.set_debug_mode(enabled) 146 | DebugModule.enabled = enabled 147 | logger.info("Debug mode " .. (enabled and "enabled" or "disabled")) 148 | end 149 | 150 | ---@description Enable or disable developer mode 151 | ---@param enabled boolean Whether developer mode should be enabled 152 | function DebugModule.set_dev_mode(enabled) 153 | DebugModule.is_dev_mode = enabled 154 | logger.info("Developer mode " .. (enabled and "enabled" or "disabled")) 155 | end 156 | 157 | ---@description Create a protected call that catches errors 158 | ---@param func function The function to call 159 | ---@param ... any Arguments to pass to the function 160 | ---@return boolean success Whether the call succeeded 161 | ---@return any result The result of the function call or the error message 162 | function DebugModule.protected_call(func, ...) 163 | if not func then 164 | return false, "No function provided" 165 | end 166 | 167 | local args = {...} 168 | local success, result = pcall(function() 169 | return func(table.unpack(args)) 170 | end) 171 | 172 | if not success then 173 | DebugModule.handle_error(result, debug.traceback("", 2)) 174 | return false, result 175 | end 176 | 177 | return true, result 178 | end 179 | 180 | return DebugModule -------------------------------------------------------------------------------- /SecureServe/src/server/core/logger.lua: -------------------------------------------------------------------------------- 1 | ---@class LoggerModule 2 | local Logger = { 3 | levels = { 4 | DEBUG = 0, 5 | INFO = 1, 6 | WARN = 2, 7 | ERROR = 3, 8 | FATAL = 4 9 | }, 10 | colors = { 11 | DEBUG = "^5", 12 | INFO = "^2", 13 | WARN = "^3", 14 | ERROR = "^1", 15 | FATAL = "^1", 16 | RESET = "^7" 17 | }, 18 | level = 1, 19 | use_webhook = false, 20 | log_webhook = "", 21 | history = {}, 22 | max_history = 100, 23 | debug_enabled = false 24 | } 25 | 26 | local config_manager 27 | 28 | ---@description Initialize the logger 29 | ---@param config table The configuration table 30 | function Logger.initialize(config) 31 | config_manager = require("server/core/config_manager") 32 | 33 | if config then 34 | Logger.level = config.LogLevel or Logger.level 35 | Logger.use_webhook = config.UseWebhook or Logger.use_webhook 36 | Logger.log_webhook = config.LogWebhook or Logger.log_webhook 37 | Logger.max_history = config.MaxLogHistory or Logger.max_history 38 | Logger.debug_enabled = config.Debug or false 39 | end 40 | 41 | Logger.info("Logger initialized with debug mode: " .. tostring(Logger.debug_enabled)) 42 | end 43 | 44 | ---@description Set debug mode 45 | ---@param enabled boolean Whether debug mode is enabled 46 | function Logger.set_debug_mode(enabled) 47 | Logger.debug_enabled = enabled 48 | Logger.info("Debug mode " .. (enabled and "enabled" or "disabled")) 49 | 50 | TriggerClientEvent("SecureServe:UpdateDebugMode", -1, enabled) 51 | end 52 | 53 | ---@description Format a log message 54 | ---@param level string The log level 55 | ---@param message string The message to log 56 | ---@param ... any Additional values to include in the log 57 | ---@return string formatted_message The formatted log message 58 | function Logger.format(level, message, ...) 59 | local timestamp = os.date("%Y-%m-%d %H:%M:%S") 60 | local color = Logger.colors[level] or Logger.colors.INFO 61 | local reset = Logger.colors.RESET 62 | 63 | local final_message = string.format("[%s] %s[%s]%s %s", 64 | timestamp, 65 | color, 66 | level, 67 | reset, 68 | message 69 | ) 70 | 71 | local args = {...} 72 | if #args > 0 then 73 | for i, v in ipairs(args) do 74 | if type(v) == "table" then 75 | final_message = final_message .. " " .. Logger.table_to_string(v) 76 | else 77 | final_message = final_message .. " " .. tostring(v) 78 | end 79 | end 80 | end 81 | 82 | return final_message 83 | end 84 | 85 | ---@description Convert a table to a string for logging 86 | ---@param t table The table to convert 87 | ---@param indent number The indentation level 88 | ---@return string result The string representation of the table 89 | function Logger.table_to_string(t, indent) 90 | if not t or type(t) ~= "table" then 91 | return tostring(t) 92 | end 93 | 94 | indent = indent or 0 95 | local result = "{\n" 96 | 97 | local keys = {} 98 | for k in pairs(t) do 99 | table.insert(keys, k) 100 | end 101 | table.sort(keys) 102 | 103 | for _, k in ipairs(keys) do 104 | local v = t[k] 105 | local indent_str = string.rep(" ", indent + 1) 106 | 107 | result = result .. indent_str 108 | 109 | if type(k) == "number" then 110 | result = result .. "[" .. k .. "] = " 111 | else 112 | result = result .. '["' .. tostring(k) .. '"] = ' 113 | end 114 | 115 | if type(v) == "table" then 116 | result = result .. Logger.table_to_string(v, indent + 1) .. ",\n" 117 | elseif type(v) == "string" then 118 | result = result .. '"' .. v .. '",\n' 119 | else 120 | result = result .. tostring(v) .. ",\n" 121 | end 122 | end 123 | 124 | result = result .. string.rep(" ", indent) .. "}" 125 | return result 126 | end 127 | 128 | ---@description Add a log entry to the history 129 | ---@param level string The log level 130 | ---@param message string The message to log 131 | function Logger.add_to_history(level, message) 132 | table.insert(Logger.history, { 133 | level = level, 134 | message = message, 135 | timestamp = os.time() 136 | }) 137 | 138 | while #Logger.history > Logger.max_history do 139 | table.remove(Logger.history, 1) 140 | end 141 | end 142 | 143 | ---@description Send a log to Discord webhook 144 | ---@param level string The log level 145 | ---@param message string The message to log 146 | function Logger.send_to_webhook(level, message) 147 | if not Logger.use_webhook or Logger.log_webhook == "" then 148 | return 149 | end 150 | 151 | local color 152 | if level == "ERROR" or level == "FATAL" then 153 | color = 16711680 -- Red 154 | elseif level == "WARN" then 155 | color = 16776960 -- Yellow 156 | elseif level == "INFO" then 157 | color = 65280 -- Green 158 | else 159 | color = 255 -- Blue 160 | end 161 | 162 | local embeds = { 163 | { 164 | title = "SecureServe Log", 165 | description = message, 166 | color = color, 167 | footer = { 168 | text = "SecureServe Anti-Cheat" 169 | }, 170 | timestamp = os.date("!%Y-%m-%dT%H:%M:%SZ") 171 | } 172 | } 173 | 174 | PerformHttpRequest(Logger.log_webhook, function() end, "POST", json.encode({ 175 | username = "SecureServe Logger", 176 | embeds = embeds 177 | }), {["Content-Type"] = "application/json"}) 178 | end 179 | 180 | ---@description Log a debug message 181 | ---@param message string The message to log 182 | ---@param ... any Additional values to include in the log 183 | function Logger.debug(message, ...) 184 | if Logger.levels.DEBUG < Logger.level then 185 | return 186 | end 187 | 188 | local formatted = Logger.format("DEBUG", message, ...) 189 | Logger.add_to_history("DEBUG", formatted) 190 | 191 | if Logger.debug_enabled then 192 | print(formatted) 193 | end 194 | end 195 | 196 | ---@description Log an info message 197 | ---@param message string The message to log 198 | ---@param ... any Additional values to include in the log 199 | function Logger.info(message, ...) 200 | if Logger.levels.INFO < Logger.level then 201 | return 202 | end 203 | 204 | local formatted = Logger.format("INFO", message, ...) 205 | Logger.add_to_history("INFO", formatted) 206 | 207 | if Logger.debug_enabled then 208 | print(formatted) 209 | end 210 | 211 | Logger.send_to_webhook("INFO", message) 212 | end 213 | 214 | ---@description Log a warning message 215 | ---@param message string The message to log 216 | ---@param ... any Additional values to include in the log 217 | function Logger.warn(message, ...) 218 | if Logger.levels.WARN < Logger.level then 219 | return 220 | end 221 | 222 | local formatted = Logger.format("WARN", message, ...) 223 | Logger.add_to_history("WARN", formatted) 224 | 225 | if Logger.debug_enabled then 226 | print(formatted) 227 | end 228 | 229 | Logger.send_to_webhook("WARN", message) 230 | end 231 | 232 | ---@description Log an error message 233 | ---@param message string The message to log 234 | ---@param ... any Additional values to include in the log 235 | function Logger.error(message, ...) 236 | if Logger.levels.ERROR < Logger.level then 237 | return 238 | end 239 | 240 | local formatted = Logger.format("ERROR", message, ...) 241 | Logger.add_to_history("ERROR", formatted) 242 | 243 | print(formatted) 244 | 245 | Logger.send_to_webhook("ERROR", message) 246 | end 247 | 248 | ---@description Log a fatal error message 249 | ---@param message string The message to log 250 | ---@param ... any Additional values to include in the log 251 | function Logger.fatal(message, ...) 252 | if Logger.levels.FATAL < Logger.level then 253 | return 254 | end 255 | 256 | local formatted = Logger.format("FATAL", message, ...) 257 | Logger.add_to_history("FATAL", formatted) 258 | 259 | print(formatted) 260 | 261 | Logger.send_to_webhook("FATAL", message) 262 | end 263 | 264 | ---@description Get the log history 265 | ---@param count number The number of entries to retrieve (default: all) 266 | ---@param level string Optional filter by log level 267 | ---@return table log_entries The log entries 268 | function Logger.get_history(count, level) 269 | local result = {} 270 | local start_index = count and (#Logger.history - count + 1) or 1 271 | start_index = math.max(1, start_index) 272 | 273 | for i = start_index, #Logger.history do 274 | local entry = Logger.history[i] 275 | if not level or entry.level == level then 276 | table.insert(result, entry) 277 | end 278 | end 279 | 280 | return result 281 | end 282 | 283 | ---@description Clear the log history 284 | function Logger.clear_history() 285 | Logger.history = {} 286 | Logger.debug("Log history cleared") 287 | end 288 | 289 | return Logger -------------------------------------------------------------------------------- /SecureServe/src/server/core/player_manager.lua: -------------------------------------------------------------------------------- 1 | local Encryption = require("shared/lib/encryption") 2 | 3 | ---@class PlayerManagerModule 4 | local PlayerManager = { 5 | connected_players = {}, 6 | whitelisted_explosions = {}, 7 | alive_players = {} 8 | } 9 | 10 | ---@description Initialize player manager functionality 11 | function PlayerManager.initialize() 12 | AddEventHandler("playerConnecting", function(name, setCallback, deferrals) 13 | local src = source 14 | local identifiers = GetPlayerIdentifiers(src) 15 | 16 | PlayerManager.connected_players[src] = { 17 | name = GetPlayerName(src), 18 | identifiers = identifiers, 19 | connected_at = os.time() 20 | } 21 | end) 22 | 23 | AddEventHandler("playerDropped", function(reason) 24 | local src = source 25 | PlayerManager.connected_players[src] = nil 26 | PlayerManager.alive_players[src] = nil 27 | PlayerManager.whitelisted_explosions[src] = nil 28 | end) 29 | end 30 | 31 | ---@param src number Source ID to validate 32 | ---@return boolean is_valid Whether the source is valid 33 | function PlayerManager.validate_source(src) 34 | if not src or src <= 0 then 35 | return false 36 | end 37 | 38 | return GetPlayerPing(src) > 0 39 | end 40 | 41 | ---@param player_id number The player ID to check permissions for 42 | ---@param permission string The permission to check 43 | ---@return boolean has_permission Whether the player has the permission 44 | function PlayerManager.has_permission(player_id, permission) 45 | local identifiers = GetPlayerIdentifiers(player_id) 46 | local found = false 47 | 48 | for _, id in pairs(identifiers) do 49 | for _, admin in pairs(SecureServe.Admins) do 50 | if id == admin.identifier and permission == admin.permission then 51 | found = true 52 | break 53 | end 54 | end 55 | 56 | if found then break end 57 | end 58 | 59 | return found 60 | end 61 | 62 | ---@param src number Source ID to get identifiers for 63 | ---@return table identifiers Table of player identifiers 64 | function PlayerManager.get_identifiers(src) 65 | if not PlayerManager.validate_source(src) then 66 | return {} 67 | end 68 | 69 | return GetPlayerIdentifiers(src) or {} 70 | end 71 | 72 | ---@param src number Source ID to check 73 | ---@return boolean is_explosion_whitelisted Whether the player's explosion is whitelisted 74 | function PlayerManager.is_whitelisted_explosion(src, explosion_type) 75 | return PlayerManager.whitelisted_explosions[src] ~= nil 76 | end 77 | 78 | ---@param src number Source ID to get explosion data for 79 | ---@return table|nil explosion_data The explosion data or nil if not found 80 | function PlayerManager.get_explosion_data(src) 81 | return PlayerManager.whitelisted_explosions[src] 82 | end 83 | 84 | ---@param src number Source ID to whitelist explosion for 85 | ---@param explosion_type number The explosion type to whitelist 86 | ---@return boolean success Whether the explosion was successfully whitelisted 87 | function PlayerManager.whitelist_explosion(src, explosion_type) 88 | if not src or not explosion_type then 89 | return false 90 | end 91 | 92 | PlayerManager.whitelisted_explosions[src] = { 93 | type = explosion_type, 94 | timestamp = os.time() 95 | } 96 | 97 | return true 98 | end 99 | 100 | ---@param src number Source ID to clear explosion whitelist for 101 | ---@param explosion_type number|nil Optional explosion type to clear 102 | function PlayerManager.clear_whitelisted_explosion(src, explosion_type) 103 | if explosion_type then 104 | if PlayerManager.whitelisted_explosions[src] and PlayerManager.whitelisted_explosions[src].type == explosion_type then 105 | PlayerManager.whitelisted_explosions[src] = nil 106 | end 107 | else 108 | PlayerManager.whitelisted_explosions[src] = nil 109 | end 110 | end 111 | 112 | ---@param src number Source to mark as alive 113 | function PlayerManager.mark_alive(src) 114 | PlayerManager.alive_players[src] = true 115 | end 116 | 117 | ---@description Get the count of currently connected players 118 | ---@return number count The number of players currently connected 119 | function PlayerManager.get_player_count() 120 | local count = 0 121 | for _ in pairs(PlayerManager.connected_players) do 122 | count = count + 1 123 | end 124 | return count 125 | end 126 | 127 | return PlayerManager -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_create_entity.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiCreateEntityModule 2 | local AntiCreateEntity = { 3 | entityRegistry = {}, 4 | allowedHashes = {}, 5 | resourceWhitelist = {} 6 | } 7 | 8 | local config_manager = require("server/core/config_manager") 9 | local ban_manager = require("server/core/ban_manager") 10 | local logger = require("server/core/logger") 11 | local DiscordLogger = require("server/core/discord_logger") 12 | 13 | ---@param modelHash number Hash of the model to check 14 | ---@return boolean isAllowed Whether the model hash is allowed 15 | function AntiCreateEntity.isHashAllowed(modelHash) 16 | return AntiCreateEntity.allowedHashes[modelHash] == true 17 | end 18 | 19 | ---@param hash number Hash to allow 20 | function AntiCreateEntity.allowHash(hash) 21 | AntiCreateEntity.allowedHashes[hash] = true 22 | end 23 | 24 | ---@param resourceName string Name of the resource 25 | ---@param modelHash number Hash of the model 26 | ---@return boolean isWhitelisted Whether the resource is whitelisted for the model 27 | function AntiCreateEntity.isResourceWhitelisted(resourceName, modelHash) 28 | if resourceName == GetCurrentResourceName() then 29 | return true 30 | end 31 | 32 | if AntiCreateEntity.resourceWhitelist[resourceName] then 33 | for _, hash in pairs(AntiCreateEntity.resourceWhitelist[resourceName]) do 34 | if hash == modelHash then 35 | return true 36 | end 37 | end 38 | end 39 | 40 | if AntiCreateEntity.isHashAllowed(modelHash) then 41 | return true 42 | end 43 | 44 | return false 45 | end 46 | 47 | function AntiCreateEntity.initialize() 48 | if SecureServe and SecureServe.Module and SecureServe.Module.Entity and SecureServe.Module.Entity.SecurityWhitelist then 49 | for _, entry in ipairs(SecureServe.Module.Entity.SecurityWhitelist) do 50 | AntiCreateEntity.resourceWhitelist[entry.resource] = entry.whitelist 51 | end 52 | logger.info("Loaded " .. #SecureServe.Module.Entity.SecurityWhitelist .. " whitelisted resources for entity security") 53 | end 54 | 55 | RegisterNetEvent("SecureServe:Server:Methods:ModulePunish", function(screenshot, reason, webhook, time) 56 | local src = source 57 | if not src or src <= 0 then return end 58 | 59 | logger.warn(string.format("[SecureServe] Entity Security: Player %s (%s) %s", 60 | GetPlayerName(src) or "Unknown", 61 | GetPlayerIdentifier(src, 0) or "Unknown", 62 | reason)) 63 | 64 | local details = { 65 | detection = reason, 66 | time = time or 0, 67 | screenshot = screenshot 68 | } 69 | 70 | print("[SecureServe] Incase this is a false ban go to config.lua and in it search SecureServe.Module incase this is an event ban go to Events and then to whitelist and add the event") 71 | print("[SecureServe] Incase its an entity ban go to Entity and SecurityWhitelist and add the resource name") 72 | if not screenshot and SecureServe.Module.Entity.TakeScreenshot then 73 | exports['screenshot-basic']:requestClientScreenshot(src, { 74 | fileName = 'entity_' .. src .. '_' .. os.time() .. '.jpg' 75 | }, function(err, data) 76 | details.screenshot = data 77 | ban_manager.ban_player(src, reason, details) 78 | end) 79 | else 80 | ban_manager.ban_player(src, reason, details) 81 | end 82 | 83 | if AntiCreateEntity.entityRegistry[src] then 84 | for entityId, _ in pairs(AntiCreateEntity.entityRegistry[src]) do 85 | if type(entityId) == "number" and DoesEntityExist(entityId) then 86 | DeleteEntity(entityId) 87 | end 88 | end 89 | end 90 | end) 91 | 92 | RegisterNetEvent("clearall", function() 93 | local src = source 94 | if not src or src <= 0 then return end 95 | 96 | if AntiCreateEntity.entityRegistry[src] then 97 | for entityId, _ in pairs(AntiCreateEntity.entityRegistry[src]) do 98 | if type(entityId) == "number" and DoesEntityExist(entityId) then 99 | DeleteEntity(entityId) 100 | end 101 | end 102 | end 103 | end) 104 | 105 | RegisterNetEvent("SecureServe:Server:Methods:Entity:CreateServer", function(entityId, resourceName, modelHash) 106 | local src = source 107 | AntiCreateEntity.allowHash(modelHash) 108 | end) 109 | 110 | RegisterNetEvent("SecureServe:Server:Methods:Entity:Create", function(entityId, resourceName, modelHash) 111 | local src = source 112 | if GetPlayerPing(tonumber(src)) <= tonumber(0) then return end 113 | if not AntiCreateEntity.entityRegistry[src] then 114 | AntiCreateEntity.entityRegistry[src] = {} 115 | end 116 | 117 | local serverEntityId = NetworkGetEntityFromNetworkId(entityId) 118 | if serverEntityId and DoesEntityExist(serverEntityId) then 119 | AntiCreateEntity.entityRegistry[src][serverEntityId] = { 120 | hash = modelHash, 121 | resource = resourceName, 122 | time = os.time() 123 | } 124 | end 125 | 126 | if not AntiCreateEntity.entityRegistry[src][modelHash] then 127 | AntiCreateEntity.entityRegistry[src][modelHash] = { 128 | hash = modelHash, 129 | resource = resourceName, 130 | time = os.time() 131 | } 132 | end 133 | end) 134 | 135 | AddEventHandler('entityCreated', function(entity) 136 | if not entity or not DoesEntityExist(entity) then return end 137 | 138 | local owner = NetworkGetFirstEntityOwner(entity) 139 | local population = GetEntityPopulationType(entity) 140 | local modelHash = GetEntityModel(entity) 141 | 142 | if (population == 7 or population == 0) and owner ~= 0 and owner ~= -1 then 143 | if AntiCreateEntity.isHashAllowed(modelHash) then 144 | return 145 | end 146 | 147 | if config_manager.is_debug_mode_enabled() then 148 | logger.info(json.encode(AntiCreateEntity.entityRegistry[owner])) 149 | end 150 | 151 | if AntiCreateEntity.entityRegistry[owner] and (AntiCreateEntity.entityRegistry[owner][entity] or AntiCreateEntity.entityRegistry[owner][modelHash]) then 152 | return 153 | elseif AntiCreateEntity.entityRegistry[0] and (AntiCreateEntity.entityRegistry[0][entity] or AntiCreateEntity.entityRegistry[0][modelHash]) then 154 | return 155 | elseif owner and modelHash then 156 | TriggerClientEvent("SecureServe:CheckEntityResource", owner, NetworkGetNetworkIdFromEntity(entity), modelHash) 157 | end 158 | end 159 | end) 160 | 161 | -- Function to get server entity data from registry 162 | ---@param playerId number The ID of the player 163 | ---@param entityId number The entity ID to look up 164 | ---@return table|nil entityData The entity data or nil if not found 165 | function AntiCreateEntity.getEntityData(playerId, entityId) 166 | if AntiCreateEntity.entityRegistry[playerId] and AntiCreateEntity.entityRegistry[playerId][entityId] then 167 | return AntiCreateEntity.entityRegistry[playerId][entityId] 168 | end 169 | return nil 170 | end 171 | 172 | Citizen.CreateThread(function() 173 | while true do 174 | Citizen.Wait(60000) 175 | local currentTime = os.time() 176 | for playerId, entities in pairs(AntiCreateEntity.entityRegistry) do 177 | for entityId, data in pairs(entities) do 178 | if type(data) == "table" and data.time and currentTime - data.time > 300 then 179 | entities[entityId] = nil 180 | end 181 | 182 | if type(entityId) == "number" and not DoesEntityExist(entityId) then 183 | entities[entityId] = nil 184 | end 185 | end 186 | 187 | if next(entities) == nil then 188 | AntiCreateEntity.entityRegistry[playerId] = nil 189 | end 190 | end 191 | end 192 | end) 193 | 194 | AddEventHandler("playerDropped", function() 195 | local src = source 196 | if AntiCreateEntity.entityRegistry[src] then 197 | for entityId, _ in pairs(AntiCreateEntity.entityRegistry[src]) do 198 | if type(entityId) == "number" and DoesEntityExist(entityId) then 199 | DeleteEntity(entityId) 200 | end 201 | end 202 | 203 | AntiCreateEntity.entityRegistry[src] = nil 204 | end 205 | end) 206 | end 207 | 208 | return AntiCreateEntity 209 | -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_entity_spam.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiEntitySpamModule 2 | local AntiEntitySpam = { 3 | vehicleTracker = {}, 4 | pedTracker = {}, 5 | objectTracker = {}, 6 | markedUsers = {} 7 | } 8 | 9 | local ban_manager = require("server/core/ban_manager") 10 | local config_manager = require("server/core/config_manager") 11 | 12 | ---@description Initialize anti-entity spam protection 13 | function AntiEntitySpam.initialize() 14 | AddEventHandler("entityCreating", function(entity) 15 | if not DoesEntityExist(entity) then return end 16 | 17 | local entityType = GetEntityType(entity) 18 | local owner = NetworkGetFirstEntityOwner(entity) 19 | local population = GetEntityPopulationType(entity) 20 | local modelHash = GetEntityModel(entity) 21 | local hwid = GetPlayerToken(owner, 0) 22 | 23 | if config_manager.is_blacklisted_model(modelHash) then 24 | if (entityType == 2 and config_manager.is_blacklisted_vehicle_protection_enabled()) or 25 | (entityType == 1 and config_manager.is_blacklisted_ped_protection_enabled()) or 26 | (entityType == 3 and config_manager.is_blacklisted_object_protection_enabled()) then 27 | 28 | CancelEvent() 29 | 30 | local entityTypeName = (entityType == 2 and "Vehicle") or (entityType == 1 and "Ped") or (entityType == 3 and "Object") or "Unknown" 31 | ban_manager.ban_player(owner, "Blacklisted " .. entityTypeName, 32 | "Tried to spawn a blacklisted " .. entityTypeName:lower() .. " (Hash: " .. modelHash .. ")") 33 | return 34 | end 35 | end 36 | 37 | if population == 7 or population == 0 then 38 | if entityType == 2 then 39 | AntiEntitySpam.handleAntiSpam(hwid, owner, AntiEntitySpam.vehicleTracker, "Vehicle", config_manager.get_max_vehicles_per_player()) 40 | elseif entityType == 1 then 41 | AntiEntitySpam.handleAntiSpam(hwid, owner, AntiEntitySpam.pedTracker, "Ped", config_manager.get_max_peds_per_player()) 42 | elseif entityType == 3 then 43 | AntiEntitySpam.handleAntiSpam(hwid, owner, AntiEntitySpam.objectTracker, "Object", config_manager.get_max_objects_per_player()) 44 | end 45 | end 46 | end) 47 | end 48 | 49 | ---@param hwid string Hardware ID of the player 50 | ---@param owner number Player server ID 51 | ---@param tracker table Tracking table for the entity type 52 | ---@param entityType string Type of entity being tracked 53 | ---@param maxEntities number Maximum allowed entities of this type 54 | function AntiEntitySpam.handleAntiSpam(hwid, owner, tracker, entityType, maxEntities) 55 | local COOLDOWN_TIME = 10 56 | 57 | if not hwid then return end 58 | 59 | if not tracker[hwid] then 60 | tracker[hwid] = { count = 1, time = os.time() } 61 | return 62 | end 63 | 64 | tracker[hwid].count = tracker[hwid].count + 1 65 | if os.time() - tracker[hwid].time >= COOLDOWN_TIME then 66 | tracker[hwid] = nil 67 | return 68 | end 69 | 70 | if tracker[hwid].count >= maxEntities then 71 | for _, entity in ipairs(AntiEntitySpam.getAllEntitiesByType(entityType)) do 72 | local entityOwner = NetworkGetFirstEntityOwner(entity) 73 | if entityOwner == owner and DoesEntityExist(entity) then 74 | DeleteEntity(entity) 75 | end 76 | end 77 | 78 | if not AntiEntitySpam.markedUsers[hwid] then 79 | AntiEntitySpam.markedUsers[hwid] = true 80 | AntiEntitySpam.clearSpamTracking() 81 | ban_manager.ban_player(owner, entityType .. " Spam", 82 | "Attempted to spam " .. entityType:lower() .. "s with count of: " .. tracker[hwid].count) 83 | CancelEvent() 84 | end 85 | end 86 | end 87 | 88 | ---@param entityType string Type of entity to get 89 | ---@return table entities List of entities of the specified type 90 | function AntiEntitySpam.getAllEntitiesByType(entityType) 91 | if entityType == "Vehicle" then return GetAllVehicles() end 92 | if entityType == "Ped" then return GetAllPeds() end 93 | if entityType == "Object" then return GetAllObjects() end 94 | return {} 95 | end 96 | 97 | ---@description Clears all spam tracking tables 98 | function AntiEntitySpam.clearSpamTracking() 99 | AntiEntitySpam.vehicleTracker = {} 100 | AntiEntitySpam.pedTracker = {} 101 | AntiEntitySpam.objectTracker = {} 102 | end 103 | 104 | return AntiEntitySpam -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_execution.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiExecutionModule 2 | local AntiExecution = {} 3 | 4 | local ban_manager = require("server/core/ban_manager") 5 | local config_manager = require("server/core/config_manager") 6 | 7 | local blocked_menus = { 8 | "rootMenu", 9 | "rootMenuv2", 10 | "rootMenuv3", 11 | "Wugr4yfgb" 12 | } 13 | 14 | local blacklisted_executors = { 15 | "Eulen", 16 | "EulenMenu", 17 | "EulenMenu2", 18 | "EulenMenu3", 19 | "SkidMenu", 20 | "AbsoluteEulen", 21 | "HamMafia", 22 | "LynxRevolution", 23 | "Lynx8", 24 | "LynxSeven", 25 | "TiagoMenu", 26 | "MarketMenu", 27 | "KoGuSzEk", 28 | "SentioMenu", 29 | "SwagMenu", 30 | "Dopamine", 31 | "Script Hook", 32 | "ScrHook", 33 | "d0pa1998", 34 | "HydroMenu", 35 | "D0paMenu", 36 | "Lux", 37 | "LuxuinityMenu", 38 | "OpenMenuV", 39 | "xAries", 40 | "Krepozz", 41 | "CiacaDasai", 42 | "GenesisV", 43 | "Deluxe Menu", 44 | "Ruby", 45 | "SwagCheats", 46 | "HudMenuX", 47 | "xseira", 48 | "SkazaMenu", 49 | "WADUI", 50 | "aries", 51 | "SidMenu", 52 | "AlwaysKaffa", 53 | "Lynx", 54 | "Maestro Menu", 55 | "NertigelFunc", 56 | "FendinX", 57 | "Root Menu", 58 | "Fuckingmenu", 59 | "Falcon", 60 | "Fallout Menu", 61 | "Redengine", 62 | "Executor", 63 | "DreamMenu", 64 | "Executor.lua", 65 | "RottenV", 66 | "Deer Menu", 67 | "Dopameme", 68 | "dopamine", 69 | "ICMENU", 70 | "Qlieplayer", 71 | "MaestroMenu", 72 | "Roblox Hack", 73 | "Nano", 74 | "SKRIPT.LUA", 75 | "Macias", 76 | "GrubyMenu", 77 | "Wolfi", 78 | "Ham", 79 | "luminous", 80 | "Absolute", 81 | "Mockingbird", 82 | "FlexSkazaMenu", 83 | "Nebula", 84 | "BellaMenu", 85 | "WaveMenu" 86 | } 87 | 88 | ---@description Initialize anti-execution module 89 | function AntiExecution.initialize() 90 | RegisterNetEvent("SecureServe:Server_Callbacks:Detections:RegisterKnownMenus", function(menus) 91 | for menu_name, _ in pairs(menus) do 92 | if config_manager.is_menu_detection_enabled() then 93 | for _, blocked_menu in ipairs(blocked_menus) do 94 | if string.lower(menu_name) == string.lower(blocked_menu) then 95 | ban_manager.ban_player(source, "Menu Detection", "Detected menu: " .. menu_name) 96 | return 97 | end 98 | end 99 | 100 | for _, blacklisted_executor in ipairs(blacklisted_executors) do 101 | if string.lower(menu_name) == string.lower(blacklisted_executor) then 102 | ban_manager.ban_player(source, "Executor Detection", "Detected executor: " .. menu_name) 103 | return 104 | end 105 | end 106 | end 107 | end 108 | end) 109 | 110 | RegisterNetEvent("__cfx_internal:handlePlayerTrigger", function(name, source) 111 | if config_manager.is_trigger_protection_enabled() then 112 | if name == "chat:addMessage" then 113 | ban_manager.ban_player(source, "Trigger Protection", "Tried executing chat:addMessage") 114 | end 115 | end 116 | end) 117 | 118 | AddEventHandler("playerConnecting", function(_, _, deferrals) 119 | local source = source 120 | deferrals.defer() 121 | 122 | Wait(100) 123 | 124 | if GetPlayerEndpoint(source) == nil then 125 | deferrals.done("SecureServe: Invalid connection detected.") 126 | CancelEvent() 127 | else 128 | deferrals.update("SecureServe: Checking connection...") 129 | deferrals.done() 130 | end 131 | end) 132 | end 133 | 134 | return AntiExecution -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_explosions.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiExplosions 2 | local AntiExplosions = {} 3 | 4 | local config_manager = require("server/core/config_manager") 5 | local ban_manager = require("server/core/ban_manager") 6 | local logger = require("server/core/logger") 7 | local debug_module = require("server/core/debug_module") 8 | 9 | ---@description Initialize anti-explosions protection 10 | function AntiExplosions.initialize() 11 | if not SecureServe.Module.Explosions.ModuleEnabled then 12 | return 13 | end 14 | 15 | local whitelist = {} 16 | local explosions = {} 17 | local detected = {} 18 | local false_explosions = { 19 | [11] = true, 20 | [12] = true, 21 | [13] = true, 22 | [24] = true, 23 | [30] = true, 24 | } 25 | 26 | RegisterNetEvent("SecureServe:Explosions:Whitelist", function(data) 27 | if (data.source == nil) then return end 28 | whitelist[data.source] = true 29 | logger.debug("Whitelisted explosion for player ID: " .. data.source) 30 | end) 31 | 32 | AddEventHandler('explosionEvent', function(sender, ev) 33 | explosions[sender] = explosions[sender] or {} 34 | 35 | if ev.ownerNetId == 0 then 36 | CancelEvent() 37 | return 38 | end 39 | 40 | local explosionType = ev.explosionType 41 | local explosionPos = ev.posX and ev.posY and ev.posZ and vector3(ev.posX, ev.posY, ev.posZ) or "Unknown" 42 | local explosionDamage = ev.damageScale or "Unknown" 43 | local explosionOwner = GetPlayerName(sender) or "Unknown" 44 | 45 | logger.debug(string.format("Explosion detected! Type: %s | Position: %s | Damage Scale: %s | Owner: %s", 46 | explosionType, explosionPos, explosionDamage, explosionOwner)) 47 | 48 | local resourceName = GetInvokingResource() 49 | if GetPlayerPing(sender) > 0 and SecureServe.ExplosionsModule then 50 | if whitelist[sender] or SecureServe.ExplosionsWhitelist[resourceName] then 51 | whitelist[sender] = false 52 | else 53 | ban_manager.ban_player(sender, "Explosions", string.format("Explosion Details: Type: %s, Position: %s, Damage Scale: %s", 54 | explosionType, explosionPos, explosionDamage)) 55 | CancelEvent() 56 | return 57 | end 58 | end 59 | 60 | for k, v in pairs(SecureServe.Protection.BlacklistedExplosions) do 61 | if ev.explosionType == v.id then 62 | local explosionInfo = string.format("Explosion Type: %d, Position: (%.2f, %.2f, %.2f)", ev.explosionType, ev.posX, ev.posY, ev.posZ) 63 | 64 | if v.limit and explosions[sender][v.id] and explosions[sender][v.id] >= v.limit then 65 | ban_manager.ban_player(sender, "Explosions", "Exceeded explosion limit at explosion: " .. v.id .. ". " .. explosionInfo) 66 | CancelEvent() 67 | return 68 | end 69 | 70 | explosions[sender][v.id] = (explosions[sender][v.id] or 0) + 1 71 | 72 | if v.limit and explosions[sender][v.id] > v.limit then 73 | ban_manager.ban_player(sender, "Explosions", "Exceeded explosion limit at explosion: " .. v.id .. ". " .. explosionInfo) 74 | CancelEvent() 75 | return 76 | end 77 | 78 | if v.limit then 79 | if explosions[sender][v.id] > v.limit then 80 | if false_explosions[ev.explosionType] then return end 81 | if not detected[sender] then 82 | detected[sender] = true 83 | CancelEvent() 84 | ban_manager.ban_player(sender, "Explosions", "Exceeded explosion limit at explosion: " .. v.id .. ". " .. explosionInfo) 85 | end 86 | end 87 | end 88 | 89 | if v.audio and ev.isAudible == false then 90 | ban_manager.ban_player(sender, "Explosions", "Used inaudible explosion. " .. explosionInfo) 91 | CancelEvent() 92 | return 93 | end 94 | 95 | if v.invisible and ev.isInvisible == true then 96 | ban_manager.ban_player(sender, "Explosions", "Used invisible explosion. " .. explosionInfo) 97 | CancelEvent() 98 | return 99 | end 100 | 101 | if v.damageScale and ev.damageScale > 1.0 then 102 | ban_manager.ban_player(sender, "Explosions", "Used boosted explosion. " .. explosionInfo) 103 | return 104 | end 105 | 106 | if SecureServe.Protection.CancelOtherExplosions then 107 | for k, v in pairs(SecureServe.Protection.BlacklistedExplosions) do 108 | if ev.explosionType ~= v.id then 109 | CancelEvent() 110 | end 111 | end 112 | end 113 | end 114 | end 115 | end) 116 | 117 | logger.info("Anti-Explosions protection initialized") 118 | end 119 | 120 | return AntiExplosions -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_explosive_damage.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiExplosiveDamageModule 2 | local AntiExplosiveDamage = {} 3 | ---@todo remove this 4 | 5 | local ban_manager = require("server/core/ban_manager") 6 | local config_manager = require("server/core/config_manager") 7 | 8 | ---@description Initialize anti-explosive damage protection 9 | function AntiExplosiveDamage.initialize() 10 | return 11 | end 12 | 13 | return AntiExplosiveDamage -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_particle_effects.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiParticleEffectsModule 2 | local AntiParticleEffects = { 3 | particle_tracking = {}, 4 | last_particle_reset = {} 5 | } 6 | 7 | local ban_manager = require("server/core/ban_manager") 8 | local config_manager = require("server/core/config_manager") 9 | 10 | 11 | ---@description Initialize anti-particle effects protection 12 | function AntiParticleEffects.initialize() 13 | AddEventHandler("ptFxEvent", function(sender, data) 14 | if not config_manager.is_particle_protection_enabled() then 15 | return 16 | end 17 | 18 | if sender <= 0 then 19 | return 20 | end 21 | 22 | local current_time = os.time() 23 | 24 | if not AntiParticleEffects.particle_tracking[sender] then 25 | AntiParticleEffects.particle_tracking[sender] = 0 26 | AntiParticleEffects.last_particle_reset[sender] = current_time 27 | end 28 | 29 | if current_time - AntiParticleEffects.last_particle_reset[sender] >= 5 then 30 | AntiParticleEffects.particle_tracking[sender] = 0 31 | AntiParticleEffects.last_particle_reset[sender] = current_time 32 | end 33 | 34 | AntiParticleEffects.particle_tracking[sender] = AntiParticleEffects.particle_tracking[sender] + 1 35 | 36 | if AntiParticleEffects.particle_tracking[sender] > config_manager.get_max_particles_per_second() * 5 then 37 | ban_manager.ban_player(sender, "Particle Effect Spam", "Too many particle effects: " .. AntiParticleEffects.particle_tracking[sender]) 38 | CancelEvent() 39 | return 40 | end 41 | 42 | if config_manager.is_blacklisted_particle(data.effectHash) then 43 | ban_manager.ban_player(sender, "Blacklisted Particle", "Used blacklisted particle effect: " .. data.effectHash) 44 | CancelEvent() 45 | return 46 | end 47 | end) 48 | 49 | AddEventHandler("playerDropped", function() 50 | local src = source 51 | 52 | AntiParticleEffects.particle_tracking[src] = nil 53 | AntiParticleEffects.last_particle_reset[src] = nil 54 | end) 55 | end 56 | 57 | ---@param player_id number The player ID to clear tracking for 58 | function AntiParticleEffects.clear_player_tracking(player_id) 59 | AntiParticleEffects.particle_tracking[player_id] = nil 60 | AntiParticleEffects.last_particle_reset[player_id] = nil 61 | end 62 | 63 | return AntiParticleEffects -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_resource_injection.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiResourceInjectionModule 2 | local AntiResourceInjection = { 3 | whitelisted_server_resources = {}, 4 | initial_resources_loaded = false 5 | } 6 | 7 | local ban_manager = require("server/core/ban_manager") 8 | local config_manager = require("server/core/config_manager") 9 | 10 | 11 | 12 | ---@description Initialize the resource injection protection 13 | function AntiResourceInjection.initialize() 14 | local resourceCount = GetNumResources() 15 | for i = 0, resourceCount - 1 do 16 | local resource_name = GetResourceByFindIndex(i) 17 | if resource_name then 18 | AntiResourceInjection.whitelisted_server_resources[resource_name] = true 19 | end 20 | end 21 | 22 | AntiResourceInjection.initial_resources_loaded = true 23 | end 24 | 25 | ---@param resource_name string The resource name to whitelist 26 | ---@return boolean success Whether the resource was successfully whitelisted 27 | function AntiResourceInjection.whitelist_resource(resource_name) 28 | if not resource_name or resource_name == "" then 29 | return false 30 | end 31 | 32 | AntiResourceInjection.whitelisted_server_resources[resource_name] = true 33 | return true 34 | end 35 | 36 | ---@param resource_name string The resource name to unwhitelist 37 | ---@return boolean success Whether the resource was successfully unwhitelisted 38 | function AntiResourceInjection.unwhitelist_resource(resource_name) 39 | if not resource_name or resource_name == "" or not AntiResourceInjection.whitelisted_server_resources[resource_name] then 40 | return false 41 | end 42 | 43 | AntiResourceInjection.whitelisted_server_resources[resource_name] = nil 44 | return true 45 | end 46 | 47 | ---@param resource_name string The resource name to check 48 | ---@return boolean is_whitelisted Whether the resource is whitelisted 49 | function AntiResourceInjection.is_resource_whitelisted(resource_name) 50 | return AntiResourceInjection.whitelisted_server_resources[resource_name] == true 51 | end 52 | 53 | return AntiResourceInjection -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_server_cfg_options.lua: -------------------------------------------------------------------------------- 1 | local logger = require("server/core/logger") 2 | local ban_manager = require("server/core/ban_manager") 3 | 4 | ---@class AntiServerCfgOptionsModule 5 | local AntiServerCfgOptions = {} 6 | 7 | ---@return void This function will apply the server security settings to the server 8 | function AntiServerCfgOptions.initialize() 9 | -- Check if server security settings are enabled 10 | if not SecureServe.ServerSecurity or not SecureServe.ServerSecurity.Enabled then 11 | logger.info("[SecureServe] Server security configuration not enabled") 12 | return 13 | end 14 | 15 | -- CONNECTION & AUTHENTICATION SETTINGS 16 | if SecureServe.ServerSecurity.Connection then 17 | -- Timeout settings 18 | SetConvar("sv_kick_players_cnl_timeout_sec", tostring(SecureServe.ServerSecurity.Connection.KickTimeout or 600)) 19 | SetConvar("sv_kick_players_cnl_update_rate_sec", tostring(SecureServe.ServerSecurity.Connection.UpdateRate or 60)) 20 | SetConvar("sv_kick_players_cnl_consecutive_failures", tostring(SecureServe.ServerSecurity.Connection.ConsecutiveFailures or 2)) 21 | 22 | -- Authentication settings 23 | SetConvar("sv_authMaxVariance", tostring(SecureServe.ServerSecurity.Connection.AuthMaxVariance or 1)) 24 | SetConvar("sv_authMinTrust", tostring(SecureServe.ServerSecurity.Connection.AuthMinTrust or 5)) 25 | 26 | -- Client verification 27 | SetConvar("sv_pure_verify_client_settings", SecureServe.ServerSecurity.Connection.VerifyClientSettings and "1" or "0") 28 | end 29 | 30 | -- NETWORK EVENT SECURITY 31 | if SecureServe.ServerSecurity.NetworkEvents then 32 | -- Block REQUEST_CONTROL_EVENT routing (supports values -1 to 4, 2 recommended for your use case) 33 | SetConvar("sv_filterRequestControl", tostring(SecureServe.ServerSecurity.NetworkEvents.FilterRequestControl or 0)) 34 | 35 | -- Block NETWORK_PLAY_SOUND_EVENT routing 36 | SetConvar("sv_enableNetworkedSounds", SecureServe.ServerSecurity.NetworkEvents.DisableNetworkedSounds and "false" or "true") 37 | 38 | -- Block REQUEST_PHONE_EXPLOSION_EVENT 39 | SetConvar("sv_enableNetworkedPhoneExplosions", SecureServe.ServerSecurity.NetworkEvents.DisablePhoneExplosions and "false" or "true") 40 | 41 | -- Block SCRIPT_ENTITY_STATE_CHANGE_EVENT 42 | SetConvar("sv_enableNetworkedScriptEntityStates", SecureServe.ServerSecurity.NetworkEvents.DisableScriptEntityStates and "false" or "true") 43 | end 44 | 45 | -- CLIENT MODIFICATION PROTECTION 46 | if SecureServe.ServerSecurity.ClientProtection then 47 | -- Pure level setting 48 | SetConvar("sv_pureLevel", tostring(SecureServe.ServerSecurity.ClientProtection.PureLevel or 2)) 49 | 50 | -- Disable client replays 51 | SetConvar("sv_disableClientReplays", SecureServe.ServerSecurity.ClientProtection.DisableClientReplays and "1" or "0") 52 | 53 | -- Script hook settings 54 | SetConvar("sv_scriptHookAllowed", SecureServe.ServerSecurity.ClientProtection.ScriptHookAllowed and "1" or "0") 55 | end 56 | 57 | -- MISC SECURITY SETTINGS 58 | if SecureServe.ServerSecurity.Misc then 59 | -- Enable chat sanitization 60 | SetConvar("sv_enableChatTextSanitization", SecureServe.ServerSecurity.Misc.EnableChatSanitization and "1" or "0") 61 | 62 | -- Rate limits 63 | if SecureServe.ServerSecurity.Misc.ResourceKvRateLimit then 64 | SetConvar("sv_defaultResourceKvRateLimit", tostring(SecureServe.ServerSecurity.Misc.ResourceKvRateLimit)) 65 | end 66 | 67 | if SecureServe.ServerSecurity.Misc.EntityKvRateLimit then 68 | SetConvar("sv_defaultEntityKvRateLimit", tostring(SecureServe.ServerSecurity.Misc.EntityKvRateLimit)) 69 | end 70 | end 71 | 72 | logger.info("[SecureServe] Server security configuration applied successfully") 73 | end 74 | 75 | return AntiServerCfgOptions -------------------------------------------------------------------------------- /SecureServe/src/server/protections/anti_weapon_damage_modifier.lua: -------------------------------------------------------------------------------- 1 | ---@class AntiWeaponDamageModifierModule 2 | local AntiWeaponDamageModifier = { 3 | weapon_damage_history = {}, 4 | weapon_damage_baseline = {} 5 | } 6 | 7 | local ban_manager = require("server/core/ban_manager") 8 | 9 | ---@description Initialize anti-weapon damage modifier protection 10 | function AntiWeaponDamageModifier.initialize() 11 | AddEventHandler("weaponDamageEvent", function(sender, data) 12 | if not sender or sender == 0 then 13 | return 14 | end 15 | 16 | local weapon_hash = data.weaponType 17 | local damage = data.weaponDamage 18 | local is_headshot = data.isHeadshot or false 19 | 20 | if not AntiWeaponDamageModifier.weapon_damage_history[sender] then 21 | AntiWeaponDamageModifier.weapon_damage_history[sender] = {} 22 | end 23 | 24 | if not AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash] then 25 | AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash] = {} 26 | end 27 | 28 | table.insert(AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash], damage) 29 | 30 | if #AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash] > 10 then 31 | table.remove(AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash], 1) 32 | end 33 | 34 | if not AntiWeaponDamageModifier.weapon_damage_baseline[weapon_hash] or damage > AntiWeaponDamageModifier.weapon_damage_baseline[weapon_hash] then 35 | AntiWeaponDamageModifier.weapon_damage_baseline[weapon_hash] = damage 36 | end 37 | 38 | if #AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash] >= 3 then 39 | local min_damage = 999999 40 | local max_damage = 0 41 | 42 | for _, dmg in ipairs(AntiWeaponDamageModifier.weapon_damage_history[sender][weapon_hash]) do 43 | if dmg < min_damage then 44 | min_damage = dmg 45 | end 46 | 47 | if dmg > max_damage then 48 | max_damage = dmg 49 | end 50 | end 51 | 52 | local max_normal_damage = AntiWeaponDamageModifier.weapon_damage_baseline[weapon_hash] or max_damage 53 | local allowed_overhead = is_headshot and 2.0 or 1.5 54 | 55 | if max_damage > max_normal_damage * allowed_overhead then 56 | ban_manager.ban_player(sender, "Weapon Damage Modifier", "Abnormal weapon damage: " .. max_damage .. " (expected max: " .. max_normal_damage .. ")") 57 | return 58 | end 59 | end 60 | end) 61 | end 62 | 63 | ---@param player_id number The player ID to clear history for 64 | function AntiWeaponDamageModifier.clear_player_history(player_id) 65 | AntiWeaponDamageModifier.weapon_damage_history[player_id] = nil 66 | end 67 | 68 | return AntiWeaponDamageModifier 69 | -------------------------------------------------------------------------------- /SecureServe/src/server/protections/heartbeat.lua: -------------------------------------------------------------------------------- 1 | local Utils = require("shared/lib/utils") 2 | local logger = require("server/core/logger") 3 | local ban_manager = require("server/core/ban_manager") 4 | 5 | ---@class HeartbeatModule 6 | local Heartbeat = { 7 | playerHeartbeats = {}, 8 | alive = {}, 9 | allowedStop = {}, 10 | failureCount = {}, 11 | checkInterval = 5000, 12 | maxFailures = 50 13 | } 14 | 15 | ---@description Initialize heartbeat protection 16 | function Heartbeat.initialize() 17 | logger.info("Initializing Heartbeat protection module") 18 | 19 | Heartbeat.playerHeartbeats = {} 20 | Heartbeat.alive = {} 21 | Heartbeat.allowedStop = {} 22 | Heartbeat.failureCount = {} 23 | 24 | Heartbeat.setupEventHandlers() 25 | 26 | Heartbeat.startMonitoringThreads() 27 | 28 | logger.info("Heartbeat protection module initialized") 29 | end 30 | 31 | ---@description Set up event handlers for heartbeat system 32 | function Heartbeat.setupEventHandlers() 33 | AddEventHandler("playerDropped", function() 34 | local playerId = source 35 | Heartbeat.playerHeartbeats[playerId] = nil 36 | Heartbeat.alive[playerId] = nil 37 | Heartbeat.allowedStop[playerId] = nil 38 | Heartbeat.failureCount[playerId] = nil 39 | end) 40 | 41 | RegisterNetEvent("mMkHcvct3uIg04STT16I:cbnF2cR9ZTt8NmNx2jQS", function(key) 42 | local playerId = source 43 | 44 | if string.len(key) < 15 or string.len(key) > 35 or key == nil then 45 | Heartbeat.banPlayer(playerId, "Invalid heartbeat key") 46 | else 47 | Heartbeat.playerHeartbeats[playerId] = os.time() 48 | end 49 | end) 50 | 51 | RegisterNetEvent('addalive', function() 52 | local playerId = source 53 | Heartbeat.alive[tonumber(playerId)] = true 54 | end) 55 | 56 | RegisterNetEvent('allowedStop', function() 57 | local playerId = source 58 | Heartbeat.allowedStop[playerId] = true 59 | end) 60 | 61 | RegisterNetEvent('playerLoaded', function() 62 | local playerId = source 63 | Heartbeat.playerHeartbeats[playerId] = os.time() 64 | end) 65 | 66 | RegisterNetEvent('playerSpawneda', function() 67 | local playerId = source 68 | Heartbeat.allowedStop[playerId] = true 69 | end) 70 | end 71 | 72 | ---@description Start the monitoring threads for heartbeat checks 73 | function Heartbeat.startMonitoringThreads() 74 | Citizen.CreateThread(function() 75 | while true do 76 | Citizen.Wait(10 * 1000) 77 | 78 | local currentTime = os.time() 79 | 80 | for playerId, lastHeartbeatTime in pairs(Heartbeat.playerHeartbeats) do 81 | if lastHeartbeatTime ~= nil then 82 | local timeSinceLastHeartbeat = currentTime - lastHeartbeatTime 83 | 84 | if timeSinceLastHeartbeat > 1500 then 85 | Heartbeat.banPlayer(playerId, "No heartbeat received") 86 | Heartbeat.playerHeartbeats[playerId] = nil 87 | end 88 | end 89 | end 90 | end 91 | end) 92 | 93 | Citizen.CreateThread(function() 94 | while true do 95 | local players = GetPlayers() 96 | 97 | for _, playerId in ipairs(players) do 98 | Heartbeat.alive[tonumber(playerId)] = false 99 | TriggerClientEvent('checkalive', tonumber(playerId)) 100 | end 101 | 102 | Citizen.Wait(Heartbeat.checkInterval) 103 | 104 | for _, playerId in ipairs(players) do 105 | local numPlayerId = tonumber(playerId) 106 | 107 | if not Heartbeat.alive[numPlayerId] and Heartbeat.allowedStop[numPlayerId] then 108 | Heartbeat.failureCount[numPlayerId] = (Heartbeat.failureCount[numPlayerId] or 0) + 1 109 | 110 | if Heartbeat.failureCount[numPlayerId] >= Heartbeat.maxFailures then 111 | Heartbeat.banPlayer(numPlayerId, "Failed to respond to alive checks") 112 | end 113 | else 114 | Heartbeat.failureCount[numPlayerId] = 0 115 | end 116 | end 117 | end 118 | end) 119 | end 120 | 121 | ---@description Ban a player for heartbeat violation 122 | ---@param playerId number The player ID to ban 123 | ---@param reason string The specific reason for the ban 124 | function Heartbeat.banPlayer(playerId, reason) 125 | logger.warn("Heartbeat violation detected for player " .. playerId .. ": " .. reason) 126 | 127 | if ban_manager then 128 | ban_manager.ban_player(playerId, 'Anticheat violation detected: ' .. reason, { 129 | admin = "Heartbeat System", 130 | time = 2147483647, 131 | detection = "Heartbeat System - " .. reason 132 | }) 133 | else 134 | DropPlayer(playerId, 'Anticheat violation detected') 135 | logger.error("Ban manager not available, player was only dropped") 136 | end 137 | end 138 | 139 | 140 | return Heartbeat -------------------------------------------------------------------------------- /SecureServe/src/server/protections/resource_manager.lua: -------------------------------------------------------------------------------- 1 | ---@class ResourceManagerModule 2 | local ResourceManager = { 3 | stopped_resources = {}, 4 | started_resources = {}, 5 | resource_states = {}, 6 | resources_restarted = {}, 7 | } 8 | 9 | ---@description Initialize the resource manager 10 | function ResourceManager.initialize() 11 | RegisterNetEvent("SecureServe:Server_Callbacks:Protections:GetResourceStatus", function() 12 | local src = source 13 | local stopped = ResourceManager.stopped_resources[src] and true or false 14 | local started = ResourceManager.started_resources[src] and true or false 15 | local restarted = ResourceManager.resources_restarted[src] and true or false 16 | 17 | TriggerClientEvent("SecureServe:Client_Callbacks:Protections:GetResourceStatus", src, stopped, started, restarted) 18 | end) 19 | 20 | AddEventHandler("onResourceStop", function(resource_name) 21 | for _, src in pairs(GetPlayers()) do 22 | ResourceManager.stopped_resources[tonumber(src)] = true 23 | end 24 | 25 | ResourceManager.resource_states[resource_name] = false 26 | 27 | Citizen.SetTimeout(5000, function() 28 | for _, src in pairs(GetPlayers()) do 29 | ResourceManager.stopped_resources[tonumber(src)] = false 30 | end 31 | end) 32 | end) 33 | 34 | AddEventHandler("onResourceStart", function(resource_name) 35 | for _, src in pairs(GetPlayers()) do 36 | ResourceManager.started_resources[tonumber(src)] = true 37 | end 38 | 39 | ResourceManager.resource_states[resource_name] = true 40 | 41 | Citizen.SetTimeout(5000, function() 42 | for _, src in pairs(GetPlayers()) do 43 | ResourceManager.started_resources[tonumber(src)] = false 44 | end 45 | end) 46 | end) 47 | 48 | AddEventHandler("onResourceListRefresh", function() 49 | ResourceManager.resources_restarted = {} 50 | for _, src in pairs(GetPlayers()) do 51 | ResourceManager.resources_restarted[tonumber(src)] = true 52 | end 53 | 54 | Citizen.SetTimeout(5000, function() 55 | for _, src in pairs(GetPlayers()) do 56 | ResourceManager.resources_restarted[tonumber(src)] = false 57 | end 58 | end) 59 | end) 60 | 61 | AddEventHandler("onResourceStop", function(resource_name) 62 | if resource_name == GetCurrentResourceName() then 63 | for _, player in pairs(GetPlayers()) do 64 | -- DropPlayer(player, "SecureServe anticheat was stopped.") 65 | end 66 | end 67 | end) 68 | end 69 | 70 | ---@param resource_name string Resource name to check 71 | ---@return boolean is_started Whether the resource is started 72 | function ResourceManager.is_resource_started(resource_name) 73 | return ResourceManager.resource_states[resource_name] == true 74 | end 75 | 76 | ---@param src number Source ID to check 77 | ---@return boolean resources_stopped Whether resources were stopped recently for this player 78 | function ResourceManager.were_resources_stopped(src) 79 | return ResourceManager.stopped_resources[src] == true 80 | end 81 | 82 | ---@param src number Source ID to check 83 | ---@return boolean resources_started Whether resources were started recently for this player 84 | function ResourceManager.were_resources_started(src) 85 | return ResourceManager.started_resources[src] == true 86 | end 87 | 88 | ---@param src number Source ID to check 89 | ---@return boolean resources_restarted Whether resources were restarted recently for this player 90 | function ResourceManager.were_resources_restarted(src) 91 | return resources_restarted[src] == true 92 | end 93 | 94 | return ResourceManager -------------------------------------------------------------------------------- /SecureServe/src/shared/init.lua: -------------------------------------------------------------------------------- 1 | local Require = require("shared/lib/require") 2 | 3 | ---@class SharedInit 4 | local SharedInit = {} 5 | 6 | ---@description Initialize all shared components 7 | function SharedInit.initialize() 8 | local Encryption = require("shared/lib/encryption") 9 | 10 | local Utils = require("shared/lib/utils") 11 | 12 | local Callbacks = require("shared/lib/callbacks") 13 | Callbacks.initialize(IsDuplicityVersion()) 14 | 15 | Encryption.initialize() 16 | 17 | print("^5[SUCCESS] ^3Shared Libraries^7 initialized") 18 | 19 | if GetCurrentResourceName() ~= "SecureServe" then 20 | print("^3SecureServe detected in resource: ^7" .. GetCurrentResourceName()) 21 | end 22 | end 23 | 24 | return SharedInit -------------------------------------------------------------------------------- /SecureServe/src/shared/lib/encryption.lua: -------------------------------------------------------------------------------- 1 | ---@class EncryptionLib 2 | ---@field encryption_key string The encryption key used for encryption/decryption 3 | local Encryption = { 4 | encryption_key = "", 5 | } 6 | 7 | 8 | function Encryption.initialize() 9 | local keyFile = LoadResourceFile("SecureServe", "secureserve.key") 10 | if not keyFile or keyFile == "" then 11 | print("^3[WARNING] Failed to load SecureServe encryption key. Using temporary key.^7") 12 | Encryption.encryption_key = "" 13 | else 14 | Encryption.encryption_key = keyFile:gsub("%s+", "") 15 | end 16 | end 17 | 18 | ---@param input string The string to encrypt/decrypt 19 | ---@return string The encrypted/decrypted string 20 | function Encryption.encrypt_decrypt(input) 21 | local output = {} 22 | for i = 1, #tostring(input) do 23 | local char = tostring(input):byte(i) 24 | local key_char = Encryption.encryption_key:byte((i - 1) % #Encryption.encryption_key + 1) 25 | local encrypted_char = (char + key_char) % 256 26 | output[i] = string.char(encrypted_char) 27 | end 28 | return table.concat(output) 29 | end 30 | 31 | ---@param input string The string to decrypt 32 | ---@return string The decrypted string 33 | function Encryption.decrypt(input) 34 | local output = {} 35 | for i = 1, #tostring(input) do 36 | local char = tostring(input):byte(i) 37 | local key_char = Encryption.encryption_key:byte((i - 1) % #Encryption.encryption_key + 1) 38 | local decrypted_char = (char - key_char) % 256 39 | output[i] = string.char(decrypted_char) 40 | end 41 | return table.concat(output) 42 | end 43 | 44 | return Encryption -------------------------------------------------------------------------------- /SecureServe/src/shared/lib/require.lua: -------------------------------------------------------------------------------- 1 | ---@class RequireLibrary 2 | ---@field loaded table Table of loaded modules 3 | ---@field paths table Paths to search for modules 4 | local Require = { 5 | loaded = {}, 6 | paths = { 7 | "./src/shared/", 8 | "./src/client/", 9 | "./src/server/", 10 | "./" 11 | } 12 | } 13 | 14 | ---@description Set a custom error handler that provides more detailed error information 15 | ---@param err string The error message 16 | ---@param module_name string The module name that caused the error 17 | ---@param trace_level number The level to start tracing from 18 | ---@return nil 19 | local function enhanced_error_handler(err, module_name, trace_level) 20 | local trace_level = trace_level or 2 21 | local trace = debug.traceback("", trace_level) 22 | 23 | local formatted_error = "\n^1============ SECURESERVE ERROR ============^7\n" 24 | formatted_error = formatted_error .. "^1Error in module: ^3" .. tostring(module_name) .. "^7\n" 25 | formatted_error = formatted_error .. "^1Message: ^3" .. tostring(err) .. "^7\n" 26 | formatted_error = formatted_error .. "^1Traceback: ^7\n" .. trace:gsub("stack traceback:", "^3Stack traceback:^7") 27 | formatted_error = formatted_error .. "\n^1==========================================^7\n" 28 | 29 | print(formatted_error) 30 | 31 | return err 32 | end 33 | 34 | ---@param module_name string The name of the module to require 35 | ---@return any The exported module content 36 | function Require.load(module_name) 37 | if Require.loaded[module_name] then 38 | return Require.loaded[module_name] 39 | end 40 | 41 | if module_name:match("^server/") then 42 | module_name = "src/" .. module_name 43 | elseif module_name:match("^client/") then 44 | module_name = "src/" .. module_name 45 | elseif module_name:match("^shared/") then 46 | module_name = "src/" .. module_name 47 | end 48 | 49 | local module_path = nil 50 | local code = nil 51 | 52 | for _, path in ipairs(Require.paths) do 53 | local full_path = path .. module_name .. ".lua" 54 | local success = pcall(function() 55 | code = LoadResourceFile(GetCurrentResourceName(), full_path) 56 | end) 57 | 58 | if success and code and code ~= "" then 59 | module_path = full_path 60 | break 61 | end 62 | 63 | full_path = path .. module_name .. "/init.lua" 64 | success = pcall(function() 65 | code = LoadResourceFile(GetCurrentResourceName(), full_path) 66 | end) 67 | 68 | if success and code and code ~= "" then 69 | module_path = full_path 70 | break 71 | end 72 | 73 | full_path = module_name .. ".lua" 74 | success = pcall(function() 75 | code = LoadResourceFile(GetCurrentResourceName(), full_path) 76 | end) 77 | 78 | if success and code and code ~= "" then 79 | module_path = full_path 80 | break 81 | end 82 | end 83 | 84 | if not module_path or not code then 85 | return enhanced_error_handler("Module not found: " .. module_name, module_name) 86 | end 87 | 88 | local module_env = setmetatable({ 89 | require = function(name) return Require.load(name) end, 90 | }, {__index = _G}) 91 | 92 | local module_func, err = load(code, module_path, "bt", module_env) 93 | if not module_func then 94 | return enhanced_error_handler("Error loading module: " .. tostring(err), module_name) 95 | end 96 | 97 | local success, result = pcall(module_func) 98 | if not success then 99 | return enhanced_error_handler("Error executing module: " .. tostring(result), module_name) 100 | end 101 | 102 | local module_exports = result or module_env.exports 103 | 104 | Require.loaded[module_name] = module_exports 105 | 106 | return module_exports 107 | end 108 | 109 | ---@param path string Path to add to the require paths 110 | function Require.add_path(path) 111 | table.insert(Require.paths, 1, path) 112 | end 113 | 114 | _G.SecureServeErrorHandler = function(err) 115 | local trace = debug.traceback("", 2) 116 | 117 | local formatted_error = "\n^1============ SECURESERVE RUNTIME ERROR ============^7\n" 118 | formatted_error = formatted_error .. "^1Error: ^3" .. tostring(err) .. "^7\n" 119 | formatted_error = formatted_error .. "^1Traceback: ^7\n" .. trace:gsub("stack traceback:", "^3Stack traceback:^7") 120 | formatted_error = formatted_error .. "\n^1================================================^7\n" 121 | 122 | print(formatted_error) 123 | 124 | return err 125 | end 126 | 127 | _G.require = function(module_name) 128 | return Require.load(module_name) 129 | end 130 | 131 | return Require -------------------------------------------------------------------------------- /SecureServe/src/shared/lib/utils.lua: -------------------------------------------------------------------------------- 1 | ---@class UtilsLib 2 | local Utils = {} 3 | 4 | ---@param length number The length of the random string to generate 5 | ---@return string The generated random string 6 | function Utils.random_key(length) 7 | local characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 8 | local random_string = "" 9 | 10 | for i = 1, length do 11 | local random_index = math.random(1, #characters) 12 | random_string = random_string .. characters:sub(random_index, random_index) 13 | end 14 | 15 | return random_string 16 | end 17 | 18 | local entity_enumerator = { 19 | __gc = function(enum) 20 | if enum.destructor and enum.handle then 21 | enum.destructor(enum.handle) 22 | end 23 | enum.destructor = nil 24 | enum.handle = nil 25 | end 26 | } 27 | 28 | ---@param init_func function Function to initialize enumeration 29 | ---@param move_func function Function to move to next entity 30 | ---@param dispose_func function Function to dispose enumeration 31 | ---@return function Iterator function 32 | function Utils.enumerate_entities(init_func, move_func, dispose_func) 33 | return coroutine.wrap(function() 34 | local iter, id = init_func() 35 | if not id or id == 0 then 36 | dispose_func(iter) 37 | return 38 | end 39 | 40 | local enum = { handle = iter, destructor = dispose_func } 41 | setmetatable(enum, entity_enumerator) 42 | 43 | local next = true 44 | repeat 45 | coroutine.yield(id) 46 | next, id = move_func(iter) 47 | until not next 48 | 49 | enum.destructor, enum.handle = nil, nil 50 | dispose_func(iter) 51 | end) 52 | end 53 | 54 | ---@return function Iterator function to enumerate objects 55 | function Utils.enumerate_objects() 56 | return Utils.enumerate_entities(FindFirstObject, FindNextObject, EndFindObject) 57 | end 58 | 59 | ---@return function Iterator function to enumerate peds 60 | function Utils.enumerate_peds() 61 | return Utils.enumerate_entities(FindFirstPed, FindNextPed, EndFindPed) 62 | end 63 | 64 | ---@return function Iterator function to enumerate vehicles 65 | function Utils.enumerate_vehicles() 66 | return Utils.enumerate_entities(FindFirstVehicle, FindNextVehicle, EndFindVehicle) 67 | end 68 | 69 | ---@return function Iterator function to enumerate pickups 70 | function Utils.enumerate_pickups() 71 | return Utils.enumerate_entities(FindFirstPickup, FindNextPickup, EndFindPickup) 72 | end 73 | 74 | ---@return table Table of entity enumeration functions 75 | function Utils.get_all_enumerators() 76 | return { 77 | vehicles = Utils.enumerate_vehicles, 78 | objects = Utils.enumerate_objects, 79 | peds = Utils.enumerate_peds, 80 | pickups = Utils.enumerate_pickups 81 | } 82 | end 83 | 84 | Utils.RandomKey = Utils.random_key 85 | Utils.EnumerateEntities = Utils.enumerate_entities 86 | Utils.EnumerateObjects = Utils.enumerate_objects 87 | Utils.EnumeratePeds = Utils.enumerate_peds 88 | Utils.EnumerateVehicles = Utils.enumerate_vehicles 89 | Utils.EnumeratePickups = Utils.enumerate_pickups 90 | Utils.GetAllEnumerators = Utils.get_all_enumerators 91 | 92 | 93 | return Utils -------------------------------------------------------------------------------- /keep-alive/client.lua: -------------------------------------------------------------------------------- 1 | AddEventHandler("playerSpawned", function () 2 | TriggerServerEvent('allowedStop') 3 | end) -------------------------------------------------------------------------------- /keep-alive/fxmanifest.lua: -------------------------------------------------------------------------------- 1 | 2 | fx_version "cerulean" 3 | 4 | shared_script "@SecureServe/src/module/module.lua" 5 | shared_script "@SecureServe/src/module/module.js" 6 | 7 | file "@SecureServe/secureserve.key" 8 | 9 | game "gta5" 10 | 11 | version "1.0.0" 12 | 13 | 14 | client_scripts { 15 | "client.lua", 16 | } 17 | 18 | dependencies { 19 | "/server:5181", 20 | "screenshot-basic" 21 | } 22 | 23 | lua54 "yes" 24 | 25 | --------------------------------------------------------------------------------