------------------------------------ ------------------------------------ ---- DONT TOUCH ANY OF THIS IF YOU DON'T KNOW WHAT YOU ARE DOING ---- THESE ARE **NOT** CONFIG VALUES, USE THE CONVARS IF YOU WANT TO CHANGE SOMETHING ---- ---- ---- If you are a developer and want to change something, consider writing a plugin instead: ---- https://easyadmin.readthedocs.io/en/latest/plugins/ ---- ------------------------------------ ------------------------------------ blacklist = {} ---Handles the banning of a player ---@param playerId number @The ID of the player to ban ---@param reason string @The reason for the ban ---@param expires number @The timestamp when the ban should expire ---@return nil RegisterServerEvent("EasyAdmin:banPlayer", function(playerId,reason,expires) -- Validate playerId before proceeding if not playerId or not CachedPlayers[playerId] or CachedPlayers[playerId].dropped then TriggerClientEvent("EasyAdmin:showNotification", source, GetLocalisedText("invalidplayer")) return end if playerId ~= nil and CheckAdminCooldown(source, "ban") then if (DoesPlayerHavePermission(source, "player.ban.temporary") or DoesPlayerHavePermission(source, "player.ban.permanent")) and CachedPlayers[playerId] and not CachedPlayers[playerId].immune then SetAdminCooldown(source, "ban") local bannedIdentifiers = CachedPlayers[playerId].identifiers or getAllPlayerIdentifiers(playerId) local username = CachedPlayers[playerId].name or getName(playerId, true) if expires and expires < os.time() then expires = os.time()+expires elseif not expires then expires = 10444633200 end if expires >= 10444633200 and not DoesPlayerHavePermission(source, "player.ban.permanent") then return false end reason = formatShortcuts(reason).. string.format(GetLocalisedText("reasonadd"), CachedPlayers[playerId].name, getName(source) ) local ban = {banid = GetFreshBanId(), name = username,identifiers = bannedIdentifiers, banner = getName(source, true), reason = reason, expire = expires, expireString = formatDateString(expires) } updateBlacklist( ban ) PrintDebugMessage("Player "..getName(source,true).." banned player "..CachedPlayers[playerId].name.." for "..reason, 3) SendWebhookMessage(moderationNotification,string.format(GetLocalisedText("adminbannedplayer"), getName(source, false, true), CachedPlayers[playerId].name, reason, formatDateString( expires ), tostring(ban.banid) ), "ban", 16711680) DropPlayer(playerId, string.format(GetLocalisedText("banned"), reason, formatDateString( expires ) ) ) elseif CachedPlayers[playerId].immune then TriggerClientEvent("EasyAdmin:showNotification", source, GetLocalisedText("adminimmune")) end end end) ---Handles the banning of an offline player ---@param playerId number @The ID of the offline player to ban ---@param reason string @The reason for the ban ---@param expires number @The timestamp when the ban should expire ---@return nil RegisterServerEvent("EasyAdmin:offlinebanPlayer", function(playerId,reason,expires) if playerId ~= nil and not CachedPlayers[playerId].immune and CheckAdminCooldown(source, "ban") then if (DoesPlayerHavePermission(source, "player.ban.temporary") or DoesPlayerHavePermission(source, "player.ban.permanent")) and not CachedPlayers[playerId].immune then SetAdminCooldown(source, "ban") local bannedIdentifiers = CachedPlayers[playerId].identifiers or getAllPlayerIdentifiers(playerId) local username = CachedPlayers[playerId].name or getName(playerId, true) if expires and expires < os.time() then expires = os.time()+expires elseif not expires then expires = 10444633200 end if expires >= 10444633200 and not DoesPlayerHavePermission(source, "player.ban.permanent") then return false end reason = formatShortcuts(reason).. string.format(GetLocalisedText("reasonadd"), CachedPlayers[playerId].name, getName(source) ) local ban = {banid = GetFreshBanId(), name = username,identifiers = bannedIdentifiers, banner = getName(source), reason = reason, expire = expires } updateBlacklist( ban ) PrintDebugMessage("Player "..getName(source,true).." offline banned player "..CachedPlayers[playerId].name.." for "..reason, 3) SendWebhookMessage(moderationNotification,string.format(GetLocalisedText("adminofflinebannedplayer"), getName(source, false, true), CachedPlayers[playerId].name, reason, formatDateString( expires ) ), "ban", 16711680) end elseif CachedPlayers[playerId].immune then TriggerClientEvent("EasyAdmin:showNotification", source, GetLocalisedText("adminimmune")) end end) AddEventHandler('banCheater', function(playerId,reason) Citizen.Trace("^1EasyAdmin^7: the banCheater event is ^1deprecated^7 and has been removed! Please adjust your ^3"..GetInvokingResource().."^7 Resource to use EasyAdmin:addBan instead.") end) ---Adds a ban to the banlist, either for an online or offline player ---@param playerId number|string|table @The ID of the player or a table of identifiers if the player is offline ---@param reason string @The reason for the ban ---@param expires number @The timestamp when the ban should expire ---@param banner string @The name of the administrator who issued the ban ---@return table @The created ban entry function addBanExport(playerId,reason,expires,banner) local bannedIdentifiers = {} local bannedUsername = "Unknown" if type(playerId) == "table" then -- if playerId is a table of identifiers offline = true bannedIdentifiers = playerId elseif CachedPlayers[playerId] then if CachedPlayers[playerId].dropped then offline = true end if CachedPlayers[playerId].immune then return false end bannedIdentifiers = CachedPlayers[playerId].identifiers bannedUsername = CachedPlayers[playerId].name or getName(playerId, true) else PrintDebugMessage("Couldn't find any Infos about Player "..playerId..", no ban issued.", 1) return false end if expires and expires < os.time() then expires = os.time()+expires elseif not expires then expires = 10444633200 end reason = formatShortcuts(reason).. string.format(GetLocalisedText("reasonadd"), getName(tostring(playerId) or "?"), banner or "Unknown" ) local ban = {banid = GetFreshBanId(), name = bannedUsername,identifiers = bannedIdentifiers, banner = banner or "Unknown", reason = reason, expire = expires, expireString = formatDateString(expires) } updateBlacklist( ban ) if source then PrintDebugMessage("Player "..getName(source,true).." added ban "..reason, 3) end SendWebhookMessage(moderationNotification,string.format(GetLocalisedText("adminbannedplayer"), banner or "Unknown", getName(tostring(playerId) or "?", false, true), reason, formatDateString( expires ), tostring(ban.banid) ), "ban", 16711680) if not offline then DropPlayer(playerId, string.format(GetLocalisedText("banned"), reason, formatDateString( expires ) ) ) end return ban end exports('addBan', addBanExport) AddEventHandler("EasyAdmin:addBan", addBanExport) RegisterServerEvent("EasyAdmin:updateBanlist", function(playerId) local src = source if DoesPlayerHavePermission(source, "player.ban.view") then updateBlacklist(false,true) Citizen.Wait(300) TriggerLatentClientEvent("EasyAdmin:fillBanlist", src, 100000, blacklist) PrintDebugMessage("Banlist Refreshed by "..getName(src,true), 3) end end) RegisterServerEvent("EasyAdmin:requestBanlist", function() local src = source if DoesPlayerHavePermission(source, "player.ban.view") then TriggerLatentClientEvent("EasyAdmin:fillBanlist", src, 100000, blacklist) PrintDebugMessage("Banlist Requested by "..getName(src,true), 3) end end) RegisterCommand("unban", function(source, args, rawCommand) if args[1] and DoesPlayerHavePermission(source, "player.ban.remove") and CheckAdminCooldown(source, "unban") then SetAdminCooldown(source, "unban") PrintDebugMessage("Player "..getName(source,true).." Unbanned "..args[1], 3) if tonumber(args[1]) then UnbanId(tonumber(args[1])) else UnbanIdentifier(args[1]) end if (source ~= 0) then TriggerClientEvent("EasyAdmin:showNotification", source, GetLocalisedText("done")) else Citizen.Trace(GetLocalisedText("done")) end SendWebhookMessage(moderationNotification,string.format(GetLocalisedText("adminunbannedplayer"), getName(source, false, true), args[1], "Unbanned via Command"), "ban", 16711680) end end, false) RegisterServerEvent("EasyAdmin:editBan", function(ban) if DoesPlayerHavePermission(source, "player.ban.edit") then updateBan(ban.banid,ban) -- TODO Webhook end end) ---Unbans a player using their ban ID ---@param banId number @The ID of the ban to be removed ---@return boolean @True if the unban was successful, false otherwise function unbanPlayer(banId) local thisBan = nil for i,ban in ipairs(blacklist) do if ban.banid == banId then thisBan = ban break end end if thisBan == nil then return false end UnbanId(banId) return true end exports('unbanPlayer', unbanPlayer) ---Fetches a ban entry by its ID ---@param banId number @The ID of the ban to fetch ---@return table|false @The ban entry if found, false otherwise function fetchBan(banId) for i,ban in ipairs(blacklist) do if ban.banid == banId then return ban end end return false end exports('fetchBan', fetchBan) RegisterServerEvent("EasyAdmin:unbanPlayer", function(banId) if DoesPlayerHavePermission(source, "player.ban.remove") and CheckAdminCooldown(source, "unban") then SetAdminCooldown(source, "unban") local thisBan = fetchBan(banId) local ret = unbanPlayer(banId) if ret then PrintDebugMessage("Player "..getName(source,true).." unbanned "..banId, 3) SendWebhookMessage(moderationNotification,string.format(GetLocalisedText("adminunbannedplayer"), getName(source, false, true), banId, thisBan.reason), "ban", 16711680) end end end) ---Generates a new unique ban ID ---@return number @The next available ban ID function GetFreshBanId() if blacklist[#blacklist] then return blacklist[#blacklist].banid+1 else return 1 end end exports('GetFreshBanId', GetFreshBanId) RegisterCommand("convertbanlist", function(source, args, rawCommand) if GetConvar("ea_custombanlist", "false") == "true" then local content = LoadResourceFile(GetCurrentResourceName(), "banlist.json") local ob = json.decode(content) for i,theBan in ipairs(ob) do TriggerEvent("ea_data:addBan", theBan) print("processed ban: "..i.."\n") end content=nil else print("Custom Banlist is not enabled, converting back to json.") TriggerEvent('ea_data:retrieveBanlist', function(banlist) blacklist = banlist for i,theBan in ipairs(blacklist) do if not theBan.identifiers then theBan.identifiers = {} end if theBan.steam then table.insert(theBan.identifiers, theBan.steam) theBan.steam=nil end if theBan.identifier then table.insert(theBan.identifiers, theBan.identifier) theBan.identifier=nil end if theBan.discord then table.insert(theBan.identifiers, theBan.discord) theBan.discord=nil end end local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode(blacklist, {indent = true}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end end) end end, true) ---Updates a ban entry in the banlist ---@param id number @The ID of the ban to update ---@param newData table @The new data to apply to the ban ---@return nil function updateBan(id,newData) if id and newData and newData.identifiers and newData.banid and newData.reason and newData.expire then for i, ban in pairs(blacklist) do if ban.banid == newData.banid then blacklist[i] = newData local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode(blacklist, {indent = true}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end if GetConvar("ea_custombanlist", "false") == "true" then TriggerEvent("ea_data:updateBan", newData) end break end end end end ---Adds a new ban entry to the banlist ---@param data table @The data of the ban to be added ---@return nil function addBan(data) if data then table.insert(blacklist, data) end end ---Synchronizes the in-memory banlist with the stored file or external system ---@param data table @Optional data to add or remove from the banlist ---@param remove boolean @Whether this is a remove operation ---@param forceChange boolean @Whether to force a save regardless of changes ---@return nil function updateBlacklist(data,remove, forceChange) local change = (forceChange or false) --mark if file was changed to save up on disk writes. if GetConvar("ea_custombanlist", "false") == "true" then PrintDebugMessage("You are using a Custom Banlist System, this is ^3not currently supported^7 and WILL cause issues! Only use this if you know what you are doing, otherwise, disable ea_custombanlist.", 1) if data and not remove then addBan(data) TriggerEvent("ea_data:addBan", data) elseif data and remove then UnbanId(data.banid) elseif not data then TriggerEvent('ea_data:retrieveBanlist', function(banlist) blacklist = banlist PrintDebugMessage("updated banlist custom banlist", 4) for i,theBan in ipairs(blacklist) do if theBan.expire < os.time() then table.remove(blacklist,i) PrintDebugMessage("removing old ban custom banlist", 4) TriggerEvent("ea_data:removeBan", theBan) end end end) end return end local content = LoadResourceFile(GetCurrentResourceName(), "banlist.json") if not content then PrintDebugMessage("banlist.json file was missing, we created a new one.", 2) local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode({}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end content = json.encode({}) end blacklist = json.decode(content) if not blacklist then PrintDebugMessage("^1-^2-^3-^4-^5-^6-^8-^9-^1-^2-^3-^4-^5-^6-^8-^9-^1-^2-^3-^3!^1FATAL ERROR^3!^3-^2-^1-^9-^8-^6-^5-^4-^3-^2-^1-^9-^8-^6-^5-^4-^3-^2-^7\n") PrintDebugMessage("^1Failed^7 to load Banlist!\n") PrintDebugMessage("Please check your banlist file for errors, ^1Bans *will not* work!^7\n") PrintDebugMessage("^1-^2-^3-^4-^5-^6-^8-^9-^1-^2-^3-^4-^5-^6-^8-^9-^1-^2-^3-^3!^1FATAL ERROR^3!^3-^2-^1-^9-^8-^6-^5-^4-^3-^2-^1-^9-^8-^6-^5-^4-^3-^2-^7\n") return end upgraded = performBanlistUpgrades(blacklist) if upgraded then change = true end if data and not remove then addBan(data) PrintDebugMessage("Added the following data to banlist:\n"..table_to_string(data), 4) change=true elseif not data then for i,theBan in ipairs(blacklist) do theBan.id = nil if not theBan.banid then if i==1 then theBan.banid = 1 else theBan.banid = blacklist[i].banid or i end PrintDebugMessage("Ban "..theBan.banid.." did not have an ID, assigned one.", 4) change=true end if not theBan.expire then PrintDebugMessage("Ban "..theBan.banid.." did not have an expiry time, removing..", 4) table.remove(blacklist,i) change=true elseif not theBan.identifiers then -- make sure 1 identifier is given, otherwise its a broken ban PrintDebugMessage("Ban "..theBan.banid.." did not have any identifiers, removing..", 4) table.remove(blacklist,i) change=true elseif not theBan.identifiers[1] then PrintDebugMessage("Ban "..theBan.banid.." did not have one identifier, removing..", 4) table.remove(blacklist,i) change=true elseif theBan.expire < os.time() then PrintDebugMessage("Ban "..theBan.banid.." expired, removing..", 4) table.remove(blacklist,i) change=true elseif theBan.expire == 1924300800 then PrintDebugMessage("Ban "..theBan.banid.." had legacy expiry time, we fixed it", 4) blacklist[i].expire = 10444633200 change=true end end end if data and remove then PrintDebugMessage("Removed the following data from banlist:\n"..table_to_string(data), 4) UnbanId(data.banid) change = true end if change then PrintDebugMessage("Banlist changed, saving..", 4) local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode(blacklist, {indent = true}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end end PrintDebugMessage("Completed Banlist Update.", 4) end ---Bans a player using their identifier ---@param identifier string @The identifier of the player to ban ---@param reason string @The reason for the ban ---@return nil function BanIdentifier(identifier,reason) updateBlacklist( {identifiers = {identifier} , banner = "Unknown", reason = reason, expire = 10444633200} ) end ---Bans a player using multiple identifiers ---@param identifier table @A table of identifiers for the player to ban ---@param reason string @The reason for the ban ---@return nil function BanIdentifiers(identifier,reason) updateBlacklist( {identifiers = identifier , banner = "Unknown", reason = reason, expire = 10444633200} ) end ---Unbans a player using their identifier ---@param identifier string @The identifier of the player to unban ---@return nil function UnbanIdentifier(identifier) if identifier then for i,ban in pairs(blacklist) do for index,id in pairs(ban.identifiers) do if identifier == id then table.remove(blacklist,i) local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode(blacklist, {indent = true}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end if GetConvar("ea_custombanlist", "false") == "true" then TriggerEvent("ea_data:removeBan", ban) end PrintDebugMessage("removed ban as per unbanidentifier func", 4) return end end end end end ---Unbans a player using their ban ID ---@param id number @The ID of the ban to remove ---@return nil function UnbanId(id) for i,ban in pairs(blacklist) do if ban.banid == id then table.remove(blacklist,i) local saved = SaveResourceFile(GetCurrentResourceName(), "banlist.json", json.encode(blacklist, {indent = true}), -1) if not saved then PrintDebugMessage("^1Saving banlist.json failed! Please check if EasyAdmin has Permission to write in its own folder!^7", 1) end if GetConvar("ea_custombanlist", "false") == "true" then TriggerEvent("ea_data:removeBan", ban) end end end end ---Performs upgrades on the banlist format if necessary ---@return boolean @True if the banlist was upgraded, false otherwise function performBanlistUpgrades() local upgraded = false local takenIds = {} for i,b in pairs(blacklist) do if takenIds[b.banid] then local freshId = GetFreshBanId() PrintDebugMessage("ID "..b.banid.." was assigned twice, reassigned to "..freshId, 4) blacklist[i].banid = freshId upgraded = true end takenIds[b.banid] = true end takenIds=nil for i,ban in pairs(blacklist) do if type(i) == "string" then PrintDebugMessage("Ban "..ban.banid.." had a string as indice, fixed it.", 4) blacklist[i] = nil table.insert(blacklist,ban) upgraded = true end end for i,ban in ipairs(blacklist) do if ban.identifiers then for k, identifier in pairs(ban.identifiers) do if identifier == "" then PrintDebugMessage("Ban "..ban.banid.." had an empty identifier, removed it.", 4) ban.identifiers[k] = nil upgraded = true end end end if not ban.expireString then upgraded = true ban.expireString = formatDateString(ban.expire) end end if blacklist[1] and (blacklist[1].identifier or blacklist[1].steam or blacklist[1].discord) then Citizen.Trace("Upgrading Banlist...\n", 4) for i,ban in ipairs(blacklist) do if not ban.identifiers then ban.identifiers = {} PrintDebugMessage("Ban "..ban.banid.." had no identifiers, added one.", 4) upgraded=true end if ban.identifier then table.insert(ban.identifiers, ban.identifier) PrintDebugMessage("Ban "..ban.banid.." had identifier, converted to identifiers table", 4) ban.identifier = nil upgraded=true end if ban.steam then table.insert(ban.identifiers, ban.steam) PrintDebugMessage("Ban "..ban.banid.." had seperate steam identifier, converted to identifiers table", 4) ban.steam = nil upgraded=true end if ban.discord and ban.discord ~= "" then table.insert(ban.identifiers, ban.discord) PrintDebugMessage("Ban "..ban.banid.." had seperate discord identifier, converted to identifiers table", 4) ban.discord = nil upgraded=true end end Citizen.Trace("Banlist Upgraded.\n", 4) end return upgraded end ---Checks if a given identifier is banned ---@param theIdentifier string @The identifier to check ---@return boolean @True if the identifier is banned, false otherwise function IsIdentifierBanned(theIdentifier) local identifierfound = false for index,value in ipairs(blacklist) do for i,identifier in ipairs(value.identifiers) do if theIdentifier == identifier then identifierfound = true end end end return identifierfound end exports('IsIdentifierBanned', IsIdentifierBanned)