Skip to content

Commit

Permalink
- Fix race condition bug in anticheat verification
Browse files Browse the repository at this point in the history
- Fix familysharing bug in singleplayer
  • Loading branch information
samuel committed Nov 20, 2024
1 parent 53f8e91 commit a8aa049
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lua/autorun/server/nova_sv_init.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Nova = Nova or {
["version"] = "1.9.0"
["version"] = "1.9.1"
}

Nova.extensions = Nova.extensions or {
Expand Down
3 changes: 2 additions & 1 deletion lua/nova/modules/admin/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ commands = {
PrintTable(protectedPlayers or {})
end,
},
//TODO: implement
/*["status"] = {
["category"] = "Server",
["description"] = "Prints the current status of Nova Defender",
Expand All @@ -237,7 +238,7 @@ commands = {
// bans total
end,
},*/
["detections"] = {
["detections"] = {
["category"] = "Detections",
["description"] = "List last 10 detections",
["callback"] = function(admin)
Expand Down
25 changes: 22 additions & 3 deletions lua/nova/modules/anticheat/anticheat.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local verificationLookup = {}
local rVerificationLookup = {}
local decryptionKey = ""
local playersVerified = {}
local verificationQueue = {}
Expand Down Expand Up @@ -323,7 +324,7 @@ hook.Add("nova_networking_playerauthenticated", "anticheat_sendpayload", functio
// if Nova.isProtected(ply) then return end

// we need to make sure that the player does not run the anticheat twice
if verificationLookup[steamID] or playersVerified[steamID] then
if rVerificationLookup[steamID] or playersVerified[steamID] then
Nova.log("d", string.format("Anticheat was already sent to %s", Nova.playerName(ply)))
return
end
Expand Down Expand Up @@ -351,6 +352,18 @@ timer.Create("nova_anticheat_verification", 60, 0, function()
Nova.log("d", string.format("Player %s is timing out, delay anticheat verification...", Nova.playerName(ply)))
continue
end
// skip if player has already an verification running
if rVerificationLookup[steamID] then
Nova.log("d", string.format("Verification for player %s already running. Skipping...", Nova.playerName(ply)))
continue
end
// skip if player has already been verified
if playersVerified[steamID] then
Nova.log("d", string.format("Player %s already verified... Removing from verification queue...", Nova.playerName(ply)))
verificationQueue[steamID] = nil
continue
end

Nova.verifyAnticheat(steamID, function(result)
verificationQueue[steamID] = nil
if result == "timeout" then
Expand Down Expand Up @@ -394,6 +407,7 @@ Nova.verifyAnticheat = function(ply_or_steamid, callback)
identifier = identifier,
duration = 0,
}
rVerificationLookup[steamID] = identifier

// start simple verification procedure
net.Start(Nova.netmessage("anticheat_verify_send"))
Expand Down Expand Up @@ -426,6 +440,7 @@ Nova.verifyAnticheat = function(ply_or_steamid, callback)
end

// player is not verified
rVerificationLookup[steamID] = nil
verificationLookup[identifier] = nil
return callback("timeout")
end
Expand Down Expand Up @@ -661,13 +676,17 @@ hook.Add("nova_init_loaded", "anticheat_createnetmessage", function()
Nova.log("s", string.format("Anticheat verification finished for %s", Nova.playerName(ply)))
verificationLookup[identifier].callback("success")
verificationLookup[identifier] = nil
rVerificationLookup[steamID] = nil
end)
end)

// Remove quarantine info when player disconnects
hook.Add("nova_base_playerdisconnect", "anticheat_verification", function(steamID)
Nova.log("d", string.format("Removing anticheat verification info for %s", steamID))
verificationLookup[steamID] = nil
if rVerificationLookup[steamID] then
verificationLookup[rVerificationLookup[steamID]] = nil
rVerificationLookup[steamID] = nil
end
playersVerified[steamID] = nil
verificationQueue[steamID] = nil
detectionQueue[steamID] = nil
Expand All @@ -676,7 +695,7 @@ end)
// Warning for known FProfiler issue
//hook.Run("nova_networking_onclientcommand", ply, steamID, command, "")
hook.Add("nova_networking_onclientcommand", "anticheat_fprofiler", function(ply, steamID, command, args)
if command == "FProfiler" and Nova.isStaff(ply) and (verificationQueue[steamID] or verificationLookup[steamID]) then
if command == "FProfiler" and Nova.isStaff(ply) and (verificationQueue[steamID] or rVerificationLookup[steamID]) then
Nova.notify({
["severity"] = "w",
["module"] = "anticheat",
Expand Down
11 changes: 9 additions & 2 deletions lua/nova/modules/banbypass/familyshare.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ Nova.isFamilyShared = function(ply)

// nowadays we don't need to make an api call to get the owner of the game anymore
// we can just use the (recently) added OwnerSteamID function
return ply:SteamID64() != ply:OwnerSteamID64()
local ownerSteamID64 = ply:OwnerSteamID64()

// returns "0" in singleplayer (undocumented)
if not ownerSteamID64 or ownerSteamID64 == "0" then
return false
end

return ply:SteamID64() != ownerSteamID64
end

Nova.getFamilyOwner = function(ply)
Expand All @@ -18,7 +25,7 @@ Nova.getFamilyOwner = function(ply)
local steamID = ply:SteamID()
local owner = ply:OwnerSteamID64()

if not owner then return false end
if not owner or owner == "0" then return false end

local ownerSteamID = Nova.convertSteamID(owner)

Expand Down
2 changes: 1 addition & 1 deletion lua/nova/modules/networking/sendlua.lua
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ timer.Create("nova_sendlua_authenticate", 5, 0, function()
timer.Adjust("nova_sendlua_authenticate", math.random(40, 60) / 10)

// if express is enabled, we fall back to regular netmessages if we get not response
local fallbackThreshold = math.floor(Nova.getSetting("networking_sendlua_maxAuthTries", 20) / 1.5)
local fallbackThreshold = math.floor(Nova.getSetting("networking_sendlua_maxAuthTries", 20) * 0.125)

for _, v in ipairs(player.GetHumans() or {}) do
if not IsValid(v) or not v:IsPlayer() then continue end
Expand Down

0 comments on commit a8aa049

Please sign in to comment.