From c6c91787e0d04758bd93e6ca791b97d2aa2118b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20P=C3=A9rez-Cerezo?= Date: Sat, 29 Jun 2019 01:59:45 +0200 Subject: Various small improvements * Removal of old ip addresses (default: 1 Week old) * No display of IPv6 addresses in /xban_record * New /xkick command * Alt accounts always get shown when running /xban_record * /xban_record now requires kick priv, not ban. --- README.md | 12 ++++++++ init.lua | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 0f39ec3..1af1c84 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,18 @@ Unbans a player. **Example:** `/xunban Joe has promised not to grief again` +### `xnote` + +Adds a note to a player's record + +**Usage:** `/xnote ` + +**Example:** `/xunban Joe has behaved suspiciously + +### `xkick` + +Same as `xban`, only that it kicks the player instead of banning.` + ### `xban_record` Shows the ban record on chat. diff --git a/init.lua b/init.lua index 5df959e..5777fab 100644 --- a/init.lua +++ b/init.lua @@ -1,4 +1,3 @@ - xban = { MP = minetest.get_modpath(minetest.get_current_modname()) } dofile(xban.MP.."/serialize.lua") @@ -8,6 +7,8 @@ local tempbans = { } local DEF_SAVE_INTERVAL = 300 -- 5 minutes local DEF_DB_FILENAME = minetest.get_worldpath().."/xban.db" +local CLEAN_IP_SECONDS = 24*60*60*7 -- time after which innocent player IPs should get removed +local CLEAN_INTERVAL = 3600 -- interval at which the db should be purged of old IPs local DB_FILENAME = minetest.settings:get("xban.db_filename") local SAVE_INTERVAL = tonumber( @@ -40,6 +41,11 @@ local function parse_time(t) --> secs return secs end +function xban.is_ip(name) + -- checks if name is an ipv4 or ipv6 address + return string.match(name, "%.") or string.match(name, "%:") +end + function xban.find_entry(player, create) --> entry, index for index, e in ipairs(db) do for name in pairs(e.names) do @@ -177,17 +183,17 @@ function xban.add_whitelist(name_or_ip, source) end function xban.get_alt_accounts(player) - local e = xban.find_entry(player) - local names = {} - if not e then + local e = xban.find_entry(player) + local names = {} + if not e then return nil, ("No entry for `%s'"):format(player) - end - for name in pairs(e.names) do - if not string.match(name, "%.") and name ~= player then + end + for name in pairs(e.names) do + if not xban.is_ip(name) and name ~= player then table.insert(names, name) end - end - return names + end + return names end function xban.get_record(player) @@ -304,6 +310,28 @@ minetest.register_chatcommand("xnote", { end, }) +minetest.register_chatcommand("xkick", { + description = "Kicks a player", + params = " ", + privs = { kick=true }, + func = function(name, params) + local plname, note = params:match("(%S+)%s+(.+)") + if not (plname and note) then + return false, "Usage: /xkick " + end + local record = { + source = name, + time = os.time(), + expires = nil, + reason = note, + type = "kick", + } + xban.add_record(plname, record) + minetest.kick_player(plname) + return true, ("Kicked %s."):format(plname) + end, +}) + minetest.register_chatcommand("xunban", { @@ -325,27 +353,31 @@ minetest.register_chatcommand("xunban", { minetest.register_chatcommand("xban_record", { description = "Show the ban records of a player", params = "", - privs = { ban=true }, + privs = { kick=true }, func = function(name, params) local plname = params:match("%S+") if not plname then return false, "Usage: /xban_record " end local record, last_pos = xban.get_record(plname) + local alt_accounts = xban.get_alt_accounts(plname) + local msg + if alt_accounts then + msg = "Alt accounts: " .. table.concat(alt_accounts, ", ") + end if not record then local err = last_pos minetest.chat_send_player(name, "[xban] "..err) - return - end - for _, e in ipairs(record) do - minetest.chat_send_player(name, "[xban] "..e) + else + for _, e in ipairs(record) do + minetest.chat_send_player(name, "[xban] "..e) + end + if last_pos then + minetest.chat_send_player(name, "[xban] "..last_pos) + end end - local alt_accounts = xban.get_alt_accounts(plname) - local msg = "Alt accounts: " - msg = msg .. table.concat(alt_accounts, ", ") - minetest.chat_send_player(name, "[xban] "..msg) - if last_pos then - minetest.chat_send_player(name, "[xban] "..last_pos) + if msg then + minetest.chat_send_player(name, "[xban] "..msg) end return true, "Record listed." end, @@ -376,10 +408,33 @@ minetest.register_chatcommand("xban_wl", { end, }) +local function clean_db() + -- Removes old IP addresses for data protection and false positive + -- prevention + local cutoff = os.time() - CLEAN_IP_SECONDS + local cleaned = 0 + for _,entry in ipairs(db) do + if not entry.banned then + -- only remove innocent player's ip addresses, rest can be + -- kept to ensure server security + for name, time in pairs(entry.names) do + if xban.is_ip(name) and (time == true or time < cutoff ) then + entry.names[name] = nil + cleaned = cleaned + 1 + end + end + end + end + ACTION("Cleaned %d old IP addresses.", cleaned) +end local function check_temp_bans() minetest.after(60, check_temp_bans) local to_rm = { } local now = os.time() + if not db.nextclean or db.nextclean < now then + clean_db() + db.nextclean = now + CLEAN_INTERVAL + end for i, e in ipairs(tempbans) do if e.expires and (e.expires <= now) then table.insert(to_rm, i) @@ -394,6 +449,7 @@ local function check_temp_bans() end end + local function save_db() minetest.after(SAVE_INTERVAL, save_db) local f, e = io.open(DB_FILENAME, "wt") -- cgit v1.2.3