Parent : [[INDEX-FIVEM-FRAMEWORK]]
FiveM - Society / Billing / Invoice System : validation métier et comptes partagés
Problème
Un joueur peut usurper l'identité d'une entreprise pour envoyer des factures frauduleuses, ou retirer de l'argent d'un compte société sans être membre du job.
Solution
Validation server-side stricte du job de l'émetteur, comptes partagés par nom de société, et split de transaction entre joueur et société.
-- esx_billing : envoi de facture avec validation job
RegisterNetEvent('esx_billing:sendBill')
AddEventHandler('esx_billing:sendBill', function(targetId, sharedAccountName, label, amount)
local xPlayer = ESX.Player(source)
local jobName = string.gsub(sharedAccountName, 'society_', '')
if xPlayer.getJob().name ~= jobName then
print(('[^2ERROR^7] Player %s Attempted to Send bill from a society without correct Job - Possibly Cheats'):format(source))
return
end
-- Insertion base de données
MySQL.insert('INSERT INTO billing (identifier, sender, target_type, target, label, amount) VALUES (?, ?, ?, ?, ?, ?)', {
xPlayer.getIdentifier(),
xPlayer.getIdentifier(),
'society',
sharedAccountName,
label,
amount
})
end)
-- esx_society : enregistrement dynamique
local SocietiesByName = {}
function registerSociety(name, label, account, datastore, inventory, data)
if SocietiesByName[name] then
print(('[^3WARNING^7] society already registered: %s'):format(name))
return
end
SocietiesByName[name] = {
name = name,
label = label,
account = account,
datastore = datastore,
inventory = inventory,
data = data
}
end
function getSociety(name)
return SocietiesByName[name]
end
Pourquoi
- Le serveur vérifie que l'émetteur a bien le job correspondant à la société
- Les comptes partagés permettent de stocker l'argent d'une entreprise indépendamment des joueurs
- Le datastore/inventory lié à la société permet la gestion de stock commune
Quand l'utiliser
- Facturation métiers (police, EMS, mécanicien)
- Gestion d'entreprises avec trésorerie partagée
- Systèmes de salaires et retraites de société
Quand NE PAS l'utiliser
- Transferts P2P directs (pas besoin de compte société)
- Scripts standalone sans système de jobs
Exemples
Correct
-- Retrait société avec validation grade
RegisterNetEvent('society:withdraw')
AddEventHandler('society:withdraw', function(societyName, amount)
local xPlayer = ESX.Player(source)
local society = getSociety(societyName)
if not society then return end
if xPlayer.getJob().name ~= societyName then return end
if xPlayer.getJob().grade < Config.minGradeForWithdraw then return end
society.account.removeMoney(amount)
xPlayer.addMoney(amount)
end)
Incorrect
-- Le client envoie le nom de la société → spoof possible
RegisterNetEvent('billing:send')
AddEventHandler('billing:send', function(target, society, amount)
-- Aucune validation du job de l'émetteur
MySQL.insert('INSERT INTO billing ...', {target, society, amount})
end)
Références
- esx_billing/server/main.lua
- esx_society/server/main.lua
Liens connexes
- [[KNOW-ANT-FIVEM-002-client-side-validation-only|KNOW-ANT-FIVEM-002]]