checkpoint: debug mode (untested)
parent
939b677300
commit
b9e8111929
|
@ -56,7 +56,7 @@ Some features of sban that the first release of Verbana will likely lack:
|
||||||
Requirements
|
Requirements
|
||||||
============
|
============
|
||||||
|
|
||||||
* Verbana must be listed as a trusted mod in minetest.conf (`secure.trusted_mods`)
|
* Verbana must be listed as a trusted mod in minetest.conf (`secure.trusted_mods`), in order to use a sqlite database.
|
||||||
* lsqlite3 (SQLite3 for Lua) must be installed and accessible to minetest's Lua.
|
* lsqlite3 (SQLite3 for Lua) must be installed and accessible to minetest's Lua.
|
||||||
* The easiest way I know how to do this: install luarocks, and execute `sudo luarocks --lua-version 5.1 install lsqlite3`
|
* The easiest way I know how to do this: install luarocks, and execute `sudo luarocks --lua-version 5.1 install lsqlite3`
|
||||||
* The minetest server must use IPv4 exclusively. I've made zero attempt to support IPv6.
|
* The minetest server must use IPv4 exclusively. I've made zero attempt to support IPv6.
|
||||||
|
|
2
TODO
2
TODO
|
@ -1,3 +1 @@
|
||||||
add a "report" command so that players can log issues w/ other players for the mods to peruse
|
|
||||||
|
|
||||||
in login_handling.lua: register_on_auth_fail should log
|
|
||||||
|
|
18
chat.lua
18
chat.lua
|
@ -1,8 +1,10 @@
|
||||||
verbana.chat = {}
|
verbana.chat = {}
|
||||||
|
|
||||||
local mod_priv = verbana.privs.moderator
|
local data = verbana.data
|
||||||
local admin_priv = verbana.privs.admin
|
local privs = verbana.privs
|
||||||
local unverified_priv = verbana.privs.unverified
|
|
||||||
|
local mod_priv = privs.moderator
|
||||||
|
local admin_priv = privs.admin
|
||||||
|
|
||||||
function verbana.chat.tell_mods(message)
|
function verbana.chat.tell_mods(message)
|
||||||
if minetest.global_exists('irc') then irc:say(message) end
|
if minetest.global_exists('irc') then irc:say(message) end
|
||||||
|
@ -10,20 +12,22 @@ function verbana.chat.tell_mods(message)
|
||||||
|
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local privs = minetest.get_player_privs(name)
|
if privs.is_privileged(name) then
|
||||||
if privs[mod_priv] or privs[admin_priv] then
|
|
||||||
minetest.chat_send_player(name, message)
|
minetest.chat_send_player(name, message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- make this the first chat message handler
|
-- make this the first chat message handler by inserting it at the start.
|
||||||
-- this has the effect of
|
-- this has the effect of
|
||||||
-- (1) pre-empting irc (and irc2)
|
-- (1) pre-empting irc (and irc2)
|
||||||
-- (2) disabling all server-side commands
|
-- (2) disabling all server-side commands
|
||||||
table.insert(minetest.registered_on_chat_messages, 1,
|
table.insert(minetest.registered_on_chat_messages, 1,
|
||||||
function(name, message)
|
function(name, message)
|
||||||
if minetest.check_player_privs(name, {[unverified_priv]=true}) then
|
local player_id = data.get_player_id(name)
|
||||||
|
local player_status = data.get_player_status(player_id)
|
||||||
|
local is_unverified = player_status.status_id == data.player_status.unverified.id
|
||||||
|
if is_unverified then
|
||||||
local cmsg = ('[unverified] <%s> %s'):format(name, message)
|
local cmsg = ('[unverified] <%s> %s'):format(name, message)
|
||||||
verbana.chat.tell_mods(cmsg)
|
verbana.chat.tell_mods(cmsg)
|
||||||
minetest.chat_send_player(name, cmsg)
|
minetest.chat_send_player(name, cmsg)
|
||||||
|
|
332
commands.lua
332
commands.lua
|
@ -1,9 +1,34 @@
|
||||||
verbana.commands = {}
|
verbana.commands = {}
|
||||||
|
|
||||||
|
local data = verbana.data
|
||||||
|
local lib_asn = verbana.lib_asn
|
||||||
|
local lib_ip = verbana.lib_ip
|
||||||
|
local log = verbana.log
|
||||||
|
local settings = verbana.settings
|
||||||
|
|
||||||
local mod_priv = verbana.privs.moderator
|
local mod_priv = verbana.privs.moderator
|
||||||
local admin_priv = verbana.privs.admin
|
local admin_priv = verbana.privs.admin
|
||||||
|
local debug_mode = settings.debug_mode
|
||||||
|
|
||||||
minetest.register_chatcommand('import_sban', {
|
local safe = verbana.util.safe
|
||||||
|
local safe_kick_player = verbana.util.safe_kick_player
|
||||||
|
|
||||||
|
local function register_chatcommand(name, def)
|
||||||
|
if debug_mode then name = ('verbana_%s'):format(name) end
|
||||||
|
def.func = safe(def.func)
|
||||||
|
minetest.register_chatcommand(name, def)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function override_chatcommand(name, def)
|
||||||
|
def.func = safe(def.func)
|
||||||
|
if debug_mode then
|
||||||
|
minetest.register_chatcommand(name, def)
|
||||||
|
else
|
||||||
|
minetest.override_chatcommand(name, def)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
register_chatcommand('import_sban', {
|
||||||
params='<filename>',
|
params='<filename>',
|
||||||
description='import records from sban',
|
description='import records from sban',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -13,7 +38,7 @@ minetest.register_chatcommand('import_sban', {
|
||||||
end
|
end
|
||||||
if not io.open(filename, 'r') then
|
if not io.open(filename, 'r') then
|
||||||
return false, ('Could not open file %q.'):format(filename)
|
return false, ('Could not open file %q.'):format(filename)
|
||||||
elseif verbana.data.import_from_sban(filename) then
|
elseif data.import_from_sban(filename) then
|
||||||
return true, 'Successfully imported.'
|
return true, 'Successfully imported.'
|
||||||
else
|
else
|
||||||
return false, 'Error importing SBAN db (see server log)'
|
return false, 'Error importing SBAN db (see server log)'
|
||||||
|
@ -21,14 +46,14 @@ minetest.register_chatcommand('import_sban', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('get_asn', {
|
register_chatcommand('get_asn', {
|
||||||
params='<name> | <IP>',
|
params='<name> | <IP>',
|
||||||
description='get the ASN associated with an IP or player name',
|
description='get the ASN associated with an IP or player name',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
func = function(_, name_or_ipstr)
|
func = function(_, name_or_ipstr)
|
||||||
local ipstr
|
local ipstr
|
||||||
|
|
||||||
if verbana.ip.is_valid_ip(name_or_ipstr) then
|
if lib_ip.is_valid_ip(name_or_ipstr) then
|
||||||
ipstr = name_or_ipstr
|
ipstr = name_or_ipstr
|
||||||
else
|
else
|
||||||
ipstr = minetest.get_player_ip(name_or_ipstr)
|
ipstr = minetest.get_player_ip(name_or_ipstr)
|
||||||
|
@ -38,7 +63,7 @@ minetest.register_chatcommand('get_asn', {
|
||||||
return false, ('"%s" is not a valid ip nor a connected player'):format(name_or_ipstr)
|
return false, ('"%s" is not a valid ip nor a connected player'):format(name_or_ipstr)
|
||||||
end
|
end
|
||||||
|
|
||||||
local asn, description = verbana.asn.lookup(ipstr)
|
local asn, description = lib_asn.lookup(ipstr)
|
||||||
if not asn or asn == 0 then
|
if not asn or asn == 0 then
|
||||||
return false, ('could not find ASN for "%s"'):format(ipstr)
|
return false, ('could not find ASN for "%s"'):format(ipstr)
|
||||||
end
|
end
|
||||||
|
@ -57,11 +82,11 @@ local function parse_status_params(params)
|
||||||
if not name or name:len() > 20 then
|
if not name or name:len() > 20 then
|
||||||
return nil, nil, nil, ('Invalid argument(s): %q'):format(params)
|
return nil, nil, nil, ('Invalid argument(s): %q'):format(params)
|
||||||
end
|
end
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name)
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return nil, nil, nil, ('Unknown player: %s'):format(name)
|
return nil, nil, nil, ('Unknown player: %s'):format(name)
|
||||||
end
|
end
|
||||||
local player_status = verbana.data.get_player_status(player_id, true)
|
local player_status = data.get_player_status(player_id, true)
|
||||||
return player_id, name, player_status, reason
|
return player_id, name, player_status, reason
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -77,33 +102,33 @@ local function parse_timed_status_params(params)
|
||||||
if not timespan then
|
if not timespan then
|
||||||
return nil, nil, nil, nil, ('Invalid argument(s): %q'):format(params)
|
return nil, nil, nil, nil, ('Invalid argument(s): %q'):format(params)
|
||||||
end
|
end
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name)
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return nil, nil, nil, nil, ('Unknown player: %s'):format(name)
|
return nil, nil, nil, nil, ('Unknown player: %s'):format(name)
|
||||||
end
|
end
|
||||||
local player_status = verbana.data.get_player_status(player_id, true)
|
local player_status = data.get_player_status(player_id, true)
|
||||||
local expires = os.time() + timespan
|
local expires = os.time() + timespan
|
||||||
return player_id, name, player_status, expires, reason
|
return player_id, name, player_status, expires, reason
|
||||||
end
|
end
|
||||||
|
|
||||||
local function has_suspicious_connection(player_name)
|
local function has_suspicious_connection(player_name)
|
||||||
local connection_log = verbana.data.get_player_connection_log(player_name, 1)
|
local connection_log = data.get_player_connection_log(player_name, 1)
|
||||||
if not connection_log or #connection_log ~= 1 then
|
if not connection_log or #connection_log ~= 1 then
|
||||||
verbana.log('warning', 'player %s exists but has no connection log?', player_name)
|
log('warning', 'player %s exists but has no connection log?', player_name)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
local last_login = connection_log[1]
|
local last_login = connection_log[1]
|
||||||
if last_login.ip_status_id == verbana.data.ip_status.trusted.id then
|
if last_login.ip_status_id == data.ip_status.trusted.id then
|
||||||
return false
|
return false
|
||||||
elseif last_login.ip_status_id ~= verbana.data.ip_status.default.id then
|
elseif last_login.ip_status_id ~= data.ip_status.default.id then
|
||||||
return true
|
return true
|
||||||
elseif last_login.asn_status_id == verbana.data.asn_status.default.id then
|
elseif last_login.asn_status_id == data.asn_status.default.id then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
----------------- SET PLAYER STATUS COMMANDS -----------------
|
----------------- SET PLAYER STATUS COMMANDS -----------------
|
||||||
minetest.register_chatcommand('verify', {
|
register_chatcommand('verify', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='verify a player',
|
description='verify a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -112,37 +137,43 @@ minetest.register_chatcommand('verify', {
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if player_status.status_id ~= verbana.data.player_status.unverified.id then
|
if player_status.status_id ~= data.player_status.unverified.id then
|
||||||
return false, ('Player %s is not unverified'):format(player_name)
|
return false, ('Player %s is not unverified'):format(player_name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
local status_id
|
local status_id
|
||||||
if has_suspicious_connection(player_name) then
|
if has_suspicious_connection(player_name) then
|
||||||
status_id = verbana.data.player_status.suspicious.id
|
status_id = data.player_status.suspicious.id
|
||||||
else
|
else
|
||||||
status_id = verbana.data.player_status.default.id
|
status_id = data.player_status.default.id
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, status_id, reason) then
|
if not data.set_player_status(player_id, executor_id, status_id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
minetest.set_player_privs(player_name, verbana.settings.verified_privs)
|
log('action', 'setting verified privs for %s', player_name)
|
||||||
|
if not debug_mode then
|
||||||
|
minetest.set_player_privs(player_name, settings.verified_privs)
|
||||||
|
end
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if player then
|
if player then
|
||||||
player:set_pos(verbana.settings.spawn_pos)
|
log('action', 'moving %s to spawn', player_name)
|
||||||
|
if not debug_mode then
|
||||||
|
player:set_pos(settings.spawn_pos)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s verified %s because %s', caller, player_name, reason)
|
log('action', '%s verified %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s verified %s', caller, player_name)
|
log('action', '%s verified %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Verified %s'):format(player_name)
|
return true, ('Verified %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('unverify', {
|
register_chatcommand('unverify', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='unverify a player',
|
description='unverify a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -152,34 +183,40 @@ minetest.register_chatcommand('unverify', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
verbana.data.player_status.suspicious.id,
|
data.player_status.suspicious.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot unverify %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot unverify %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.unverified.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.unverified.id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
minetest.set_player_privs(player_name, verbana.settings.unverified_privs)
|
log('action', 'setting unverified privs for %s', player_name)
|
||||||
|
if not debug_mode then
|
||||||
|
minetest.set_player_privs(player_name, settings.unverified_privs)
|
||||||
|
end
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if player then
|
if player then
|
||||||
player:set_pos(verbana.settings.unverified_spawn_pos)
|
log('action', 'moving %s to unverified area', player_name)
|
||||||
|
if not debug_mode then
|
||||||
|
player:set_pos(settings.unverified_spawn_pos)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s unverified %s because %s', caller, player_name, reason)
|
log('action', '%s unverified %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s unverified %s', caller, player_name)
|
log('action', '%s unverified %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Unverified %s'):format(player_name)
|
return true, ('Unverified %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.override_chatcommand('kick', {
|
override_chatcommand('kick', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='kick a player',
|
description='kick a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -191,31 +228,26 @@ minetest.override_chatcommand('kick', {
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if not player then
|
if not player then
|
||||||
return false, ("Player %s not in game!"):format(player_name)
|
return false, ("Player %s not in game!"):format(player_name)
|
||||||
end
|
|
||||||
if not minetest.kick_player(player_name, reason) then
|
|
||||||
player:set_detach()
|
|
||||||
if not minetest.kick_player(player_name, reason) then
|
|
||||||
verbana.log('warning', 'Failed to kick player %s after detaching!', player_name)
|
|
||||||
return false, ("Failed to kick player %s after detaching!"):format(player_name)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
log('action', 'kicking %s...', player_name)
|
||||||
|
safe_kick_player(caller, player, reason)
|
||||||
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.kicked.id, reason, nil, true) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.kicked.id, reason, nil, true) then
|
||||||
return false, 'ERROR logging player status'
|
return false, 'ERROR logging player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s kicked %s because %s', caller, player_name, reason)
|
log('action', '%s kicked %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s kicked %s', caller, player_name)
|
log('action', '%s kicked %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Kicked %s'):format(player_name)
|
return true, ('Kicked %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('lock', {
|
register_chatcommand('lock', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='lock a player\'s account',
|
description='lock a player\'s account',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -225,40 +257,34 @@ minetest.register_chatcommand('lock', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
verbana.data.player_status.unverified.id,
|
data.player_status.unverified.id,
|
||||||
verbana.data.player_status.suspicious.id,
|
data.player_status.suspicious.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot lock %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot lock %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if player then
|
if player then
|
||||||
if not minetest.kick_player(player_name, reason) then
|
safe_kick_player(caller, player, reason)
|
||||||
player:set_detach()
|
|
||||||
if not minetest.kick_player(player_name, reason) then
|
|
||||||
minetest.chat_send_player(caller, ('Failed to kick player %s after detaching!'):format(player_name))
|
|
||||||
verbana.log('warning', 'Failed to kick player %s after detaching!', player_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.locked.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.locked.id, reason) then
|
||||||
return false, 'ERROR logging player status'
|
return false, 'ERROR logging player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s locked %s because %s', caller, player_name, reason)
|
log('action', '%s locked %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s locked %s', caller, player_name)
|
log('action', '%s locked %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Locked %s'):format(player_name)
|
return true, ('Locked %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('unlock', {
|
register_chatcommand('unlock', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='unlock a player\'s account',
|
description='unlock a player\'s account',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -267,32 +293,32 @@ minetest.register_chatcommand('unlock', {
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if player_status.status_id ~= verbana.data.player_status.locked.id then
|
if player_status.status_id ~= data.player_status.locked.id then
|
||||||
return false, ('Player %s is not locked!'):format(player_name)
|
return false, ('Player %s is not locked!'):format(player_name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
local status_id
|
local status_id
|
||||||
if has_suspicious_connection(player_name) then
|
if has_suspicious_connection(player_name) then
|
||||||
status_id = verbana.data.player_status.suspicious.id
|
status_id = data.player_status.suspicious.id
|
||||||
else
|
else
|
||||||
status_id = verbana.data.player_status.default.id
|
status_id = data.player_status.default.id
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, status_id, reason) then
|
if not data.set_player_status(player_id, executor_id, status_id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s unlocked %s because %s', caller, player_name, reason)
|
log('action', '%s unlocked %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s unlocked %s', caller, player_name)
|
log('action', '%s unlocked %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Unlocked %s'):format(player_name)
|
return true, ('Unlocked %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.override_chatcommand('ban', {
|
override_chatcommand('ban', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='ban a player',
|
description='ban a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -308,40 +334,34 @@ minetest.override_chatcommand('ban', {
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
verbana.data.player_status.unverified.id,
|
data.player_status.unverified.id,
|
||||||
verbana.data.player_status.suspicious.id,
|
data.player_status.suspicious.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot ban %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot ban %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if player then
|
if player then
|
||||||
if not minetest.kick_player(player_name, reason) then
|
safe_kick_player(caller, player, reason)
|
||||||
player:set_detach()
|
|
||||||
if not minetest.kick_player(player_name, reason) then
|
|
||||||
minetest.chat_send_player(caller, ('Failed to kick player %s after detaching!'):format(player_name))
|
|
||||||
verbana.log('warning', 'Failed to kick player %s after detaching!', player_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.banned.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.banned.id, reason) then
|
||||||
return false, 'ERROR logging player status'
|
return false, 'ERROR logging player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s banned %s because %s', caller, player_name, reason)
|
log('action', '%s banned %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s banned %s', caller, player_name)
|
log('action', '%s banned %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Banned %s'):format(player_name)
|
return true, ('Banned %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('tempban', {
|
register_chatcommand('tempban', {
|
||||||
params='<name> <timespan> [<reason>]',
|
params='<name> <timespan> [<reason>]',
|
||||||
description='ban a player for a length of time',
|
description='ban a player for a length of time',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -351,41 +371,35 @@ minetest.register_chatcommand('tempban', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
verbana.data.player_status.unverified.id,
|
data.player_status.unverified.id,
|
||||||
verbana.data.player_status.suspicious.id,
|
data.player_status.suspicious.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot ban %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot ban %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local player = minetest.get_player_by_name(player_name)
|
local player = minetest.get_player_by_name(player_name)
|
||||||
if player then
|
if player then
|
||||||
if not minetest.kick_player(player_name, reason) then
|
safe_kick_player(caller, player, reason)
|
||||||
player:set_detach()
|
|
||||||
if not minetest.kick_player(player_name, reason) then
|
|
||||||
minetest.chat_send_player(caller, ('Failed to kick player %s after detaching!'):format(player_name))
|
|
||||||
verbana.log('warning', 'Failed to kick player %s after detaching!', player_name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.tempbanned.id, reason, expires) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.tempbanned.id, reason, expires) then
|
||||||
return false, 'ERROR logging player status'
|
return false, 'ERROR logging player status'
|
||||||
end
|
end
|
||||||
local expires_str = os.date("%c", expires)
|
local expires_str = os.date("%c", expires)
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s tempbanned %s until %s because %s', caller, player_name, expires_str, reason)
|
log('action', '%s tempbanned %s until %s because %s', caller, player_name, expires_str, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s tempbanned %s until %s', caller, player_name, expires_str)
|
log('action', '%s tempbanned %s until %s', caller, player_name, expires_str)
|
||||||
end
|
end
|
||||||
return true, ('Temporarily banned %s until %s'):format(player_name, expires_str)
|
return true, ('Temporarily banned %s until %s'):format(player_name, expires_str)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.override_chatcommand('unban', {
|
override_chatcommand('unban', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='unban a player',
|
description='unban a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -395,34 +409,34 @@ minetest.override_chatcommand('unban', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.banned.id,
|
data.player_status.banned.id,
|
||||||
verbana.data.player_status.tempbanned.id,
|
data.player_status.tempbanned.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Player %s is not banned!'):format(player_name)
|
return false, ('Player %s is not banned!'):format(player_name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
local status_id
|
local status_id
|
||||||
if has_suspicious_connection(player_name) then
|
if has_suspicious_connection(player_name) then
|
||||||
status_id = verbana.data.player_status.suspicious.id
|
status_id = data.player_status.suspicious.id
|
||||||
else
|
else
|
||||||
status_id = verbana.data.player_status.default.id
|
status_id = data.player_status.default.id
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, status_id, reason) then
|
if not data.set_player_status(player_id, executor_id, status_id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s unbanned %s because %s', caller, player_name, reason)
|
log('action', '%s unbanned %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s unbanned %s', caller, player_name)
|
log('action', '%s unbanned %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Unbanned %s'):format(player_name)
|
return true, ('Unbanned %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('whitelist', {
|
register_chatcommand('whitelist', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='whitelist a player',
|
description='whitelist a player',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -432,30 +446,30 @@ minetest.register_chatcommand('whitelist', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
verbana.data.player_status.unverified.id,
|
data.player_status.unverified.id,
|
||||||
verbana.data.player_status.suspicious.id,
|
data.player_status.suspicious.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot whitelist %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot whitelist %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.whitelisted.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.whitelisted.id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s whitelisted %s because %s', caller, player_name, reason)
|
log('action', '%s whitelisted %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s whitelisted %s', caller, player_name)
|
log('action', '%s whitelisted %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Whitelisted %s'):format(player_name)
|
return true, ('Whitelisted %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('unwhitelist', {
|
register_chatcommand('unwhitelist', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='whitelist a player',
|
description='whitelist a player',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -464,26 +478,26 @@ minetest.register_chatcommand('unwhitelist', {
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if player_status.status_id ~= verbana.data.player_status.whitelisted.id then
|
if player_status.status_id ~= data.player_status.whitelisted.id then
|
||||||
return false, ('Player %s is not locked!'):format(player_name)
|
return false, ('Player %s is not locked!'):format(player_name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.default.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.default.id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s unwhitelisted %s because %s', caller, player_name, reason)
|
log('action', '%s unwhitelisted %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s unwhitelisted %s', caller, player_name)
|
log('action', '%s unwhitelisted %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Unwhitelisted %s'):format(player_name)
|
return true, ('Unwhitelisted %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('suspect', {
|
register_chatcommand('suspect', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='mark a player as suspicious',
|
description='mark a player as suspicious',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -493,28 +507,28 @@ minetest.register_chatcommand('suspect', {
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if not verbana.util.table_contains({
|
if not verbana.util.table_contains({
|
||||||
verbana.data.player_status.unknown.id,
|
data.player_status.unknown.id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
}, player_status.status_id) then
|
}, player_status.status_id) then
|
||||||
return false, ('Cannot whitelist %s w/ status %s'):format(player_name, player_status.name)
|
return false, ('Cannot whitelist %s w/ status %s'):format(player_name, player_status.name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.suspicious.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.suspicious.id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s suspected %s because %s', caller, player_name, reason)
|
log('action', '%s suspected %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s suspected %s', caller, player_name)
|
log('action', '%s suspected %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Suspected %s'):format(player_name)
|
return true, ('Suspected %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('unsuspect', {
|
register_chatcommand('unsuspect', {
|
||||||
params='<name> [<reason>]',
|
params='<name> [<reason>]',
|
||||||
description='unmark a player as suspicious',
|
description='unmark a player as suspicious',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -523,26 +537,26 @@ minetest.register_chatcommand('unsuspect', {
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, reason
|
return false, reason
|
||||||
end
|
end
|
||||||
if player_status.status_id ~= verbana.data.player_status.suspicious.id then
|
if player_status.status_id ~= data.player_status.suspicious.id then
|
||||||
return false, ('Player %s is not suspicious!'):format(player_name)
|
return false, ('Player %s is not suspicious!'):format(player_name)
|
||||||
end
|
end
|
||||||
local executor_id = verbana.data.get_player_id(caller)
|
local executor_id = data.get_player_id(caller)
|
||||||
if not executor_id then
|
if not executor_id then
|
||||||
return false, 'ERROR: could not get executor ID?'
|
return false, 'ERROR: could not get executor ID?'
|
||||||
end
|
end
|
||||||
if not verbana.data.set_player_status(player_id, executor_id, verbana.data.player_status.default.id, reason) then
|
if not data.set_player_status(player_id, executor_id, data.player_status.default.id, reason) then
|
||||||
return false, 'ERROR setting player status'
|
return false, 'ERROR setting player status'
|
||||||
end
|
end
|
||||||
if reason then
|
if reason then
|
||||||
verbana.log('action', '%s unsuspected %s because %s', caller, player_name, reason)
|
log('action', '%s unsuspected %s because %s', caller, player_name, reason)
|
||||||
else
|
else
|
||||||
verbana.log('action', '%s unsuspected %s', caller, player_name)
|
log('action', '%s unsuspected %s', caller, player_name)
|
||||||
end
|
end
|
||||||
return true, ('Unsuspected %s'):format(player_name)
|
return true, ('Unsuspected %s'):format(player_name)
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
----------------- SET IP/ASN STATUS COMMANDS -----------------
|
----------------- SET IP/ASN STATUS COMMANDS -----------------
|
||||||
minetest.register_chatcommand('set_ip_status', {
|
register_chatcommand('set_ip_status', {
|
||||||
params='<asn> <status>',
|
params='<asn> <status>',
|
||||||
description='set the status of an IP (default, dangerous, blocked)',
|
description='set the status of an IP (default, dangerous, blocked)',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -551,7 +565,7 @@ minetest.register_chatcommand('set_ip_status', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('set_asn_status', {
|
register_chatcommand('set_asn_status', {
|
||||||
params='<asn> <status>',
|
params='<asn> <status>',
|
||||||
description='set the status of an ASN (default, dangerous, blocked)',
|
description='set the status of an ASN (default, dangerous, blocked)',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -560,7 +574,7 @@ minetest.register_chatcommand('set_asn_status', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
---------------- GET LOGS ---------------
|
---------------- GET LOGS ---------------
|
||||||
minetest.register_chatcommand('player_status_log', {
|
register_chatcommand('player_status_log', {
|
||||||
params='<name> [<number>]',
|
params='<name> [<number>]',
|
||||||
description='shows the status log of a player',
|
description='shows the status log of a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -572,11 +586,11 @@ minetest.register_chatcommand('player_status_log', {
|
||||||
if not name then
|
if not name then
|
||||||
return false, 'invalid arguments'
|
return false, 'invalid arguments'
|
||||||
end
|
end
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name)
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, 'unknown player'
|
return false, 'unknown player'
|
||||||
end
|
end
|
||||||
local rows = verbana.data.get_player_status_log(player_id)
|
local rows = data.get_player_status_log(player_id)
|
||||||
if not rows then
|
if not rows then
|
||||||
return false, 'An error occurred (see server logs)'
|
return false, 'An error occurred (see server logs)'
|
||||||
end
|
end
|
||||||
|
@ -607,7 +621,7 @@ minetest.register_chatcommand('player_status_log', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('ip_status_log', {
|
register_chatcommand('ip_status_log', {
|
||||||
params='<IP> [<number>]',
|
params='<IP> [<number>]',
|
||||||
description='shows the status log of an IP',
|
description='shows the status log of an IP',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -616,7 +630,7 @@ minetest.register_chatcommand('ip_status_log', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('asn_status_log', {
|
register_chatcommand('asn_status_log', {
|
||||||
params='<ASN> [<number>]',
|
params='<ASN> [<number>]',
|
||||||
description='shows the status log of an ASN',
|
description='shows the status log of an ASN',
|
||||||
privs={[admin_priv]=true},
|
privs={[admin_priv]=true},
|
||||||
|
@ -625,7 +639,7 @@ minetest.register_chatcommand('asn_status_log', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('login_record', {
|
register_chatcommand('login_record', {
|
||||||
params='<name> [<number>]',
|
params='<name> [<number>]',
|
||||||
description='shows the login record of a player',
|
description='shows the login record of a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -640,11 +654,11 @@ minetest.register_chatcommand('login_record', {
|
||||||
if not limit then
|
if not limit then
|
||||||
limit = 20
|
limit = 20
|
||||||
end
|
end
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name)
|
||||||
if not player_id then
|
if not player_id then
|
||||||
return false, 'unknown player'
|
return false, 'unknown player'
|
||||||
end
|
end
|
||||||
local rows = verbana.data.get_player_connection_log(player_id)
|
local rows = data.get_player_connection_log(player_id)
|
||||||
if not rows then
|
if not rows then
|
||||||
return false, 'An error occurred (see server logs)'
|
return false, 'An error occurred (see server logs)'
|
||||||
end
|
end
|
||||||
|
@ -655,11 +669,11 @@ minetest.register_chatcommand('login_record', {
|
||||||
local message = ('%s:%s from %s<%s> A%s<%s> (%s)'):format(
|
local message = ('%s:%s from %s<%s> A%s<%s> (%s)'):format(
|
||||||
os.date("%c", row.timestamp),
|
os.date("%c", row.timestamp),
|
||||||
(rows.success and ' failed!') or '',
|
(rows.success and ' failed!') or '',
|
||||||
verbana.ip.ipint_to_ipstr(row.ipint),
|
lib_ip.ipint_to_ipstr(row.ipint),
|
||||||
row.ip_status_name,
|
row.ip_status_name,
|
||||||
row.asn,
|
row.asn,
|
||||||
row.asn_status_name,
|
row.asn_status_name,
|
||||||
verbana.asn.get_description(row.asn)
|
lib_asn.get_description(row.asn)
|
||||||
)
|
)
|
||||||
minetest.chat_send_player(caller, message)
|
minetest.chat_send_player(caller, message)
|
||||||
end
|
end
|
||||||
|
@ -667,7 +681,7 @@ minetest.register_chatcommand('login_record', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('inspect_player', {
|
register_chatcommand('inspect_player', {
|
||||||
params='<name>',
|
params='<name>',
|
||||||
description='list ips, asns and statuses associated with a player',
|
description='list ips, asns and statuses associated with a player',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -676,7 +690,7 @@ minetest.register_chatcommand('inspect_player', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('inspect_ip', {
|
register_chatcommand('inspect_ip', {
|
||||||
params='<IP>',
|
params='<IP>',
|
||||||
description='list player accounts and statuses associated with an IP',
|
description='list player accounts and statuses associated with an IP',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -685,7 +699,7 @@ minetest.register_chatcommand('inspect_ip', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_chatcommand('inspect_asn', {
|
register_chatcommand('inspect_asn', {
|
||||||
params='<asn>',
|
params='<asn>',
|
||||||
description='list player accounts and statuses associated with an ASN',
|
description='list player accounts and statuses associated with an ASN',
|
||||||
privs={[mod_priv]=true},
|
privs={[mod_priv]=true},
|
||||||
|
@ -694,7 +708,9 @@ minetest.register_chatcommand('inspect_asn', {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
-- alias (for listing an account's primary, cascade status)
|
|
||||||
-- list recent bans/kicks/locks/etc
|
-- TODO: alias (for listing an account's primary, cascade status)
|
||||||
-- first_login (=b) for all players
|
-- TODO: list recent bans/kicks/locks/etc
|
||||||
-- asn statistics
|
-- TODO: first_login (=b) for all players
|
||||||
|
-- TODO: asn statistics
|
||||||
|
-- TODO: add a "report" command so that players can log issues w/ other players for the mods to peruse
|
||||||
|
|
45
data.lua
45
data.lua
|
@ -1,13 +1,11 @@
|
||||||
if not verbana then verbana = {} end
|
verbana.data = {}
|
||||||
if not verbana.modpath then verbana.modpath = '.' end
|
|
||||||
if not verbana.ip then dofile(verbana.modpath .. '/lib_ip.lua') end
|
local lib_asn = verbana.lib_asn
|
||||||
if not verbana.log then function verbana.log(_, message, ...) print(message:format(...)) end end
|
local lib_ip = verbana.lib_ip
|
||||||
|
|
||||||
local sql = verbana.sql
|
local sql = verbana.sql
|
||||||
local db = verbana.db
|
local db = verbana.db
|
||||||
|
|
||||||
verbana.data = {}
|
|
||||||
|
|
||||||
-- constants
|
-- constants
|
||||||
verbana.data.player_status = {
|
verbana.data.player_status = {
|
||||||
unknown={name='unknown', id=1},
|
unknown={name='unknown', id=1},
|
||||||
|
@ -207,11 +205,11 @@ function verbana.data.import_from_sban(filename)
|
||||||
if not insert_log_statement then return _error() end
|
if not insert_log_statement then return _error() end
|
||||||
for name, ipstr, created, last_login in sban_db:urows('SELECT name, ip, created, last_login FROM playerdata') do
|
for name, ipstr, created, last_login in sban_db:urows('SELECT name, ip, created, last_login FROM playerdata') do
|
||||||
local player_id = player_id_by_name[name]
|
local player_id = player_id_by_name[name]
|
||||||
if not verbana.ip.is_valid_ip(ipstr) then
|
if not lib_ip.is_valid_ip(ipstr) then
|
||||||
return _error('%s is not a valid IPv4 address', ipstr)
|
return _error('%s is not a valid IPv4 address', ipstr)
|
||||||
end
|
end
|
||||||
local ipint = verbana.ip.ipstr_to_ipint(ipstr)
|
local ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
local asn = verbana.asn.lookup(ipint)
|
local asn = lib_asn.lookup(ipint)
|
||||||
if not bind_and_step(insert_ip_statement, 'insert IP', ipint) then return _error() end
|
if not bind_and_step(insert_ip_statement, 'insert IP', ipint) then return _error() end
|
||||||
if not bind_and_step(insert_asn_statement, 'insert ASN', asn) then return _error() end
|
if not bind_and_step(insert_asn_statement, 'insert ASN', asn) then return _error() end
|
||||||
if not bind_and_step(insert_assoc_statement, 'insert assoc', player_id, ipint, asn, created, created) then return _error() end
|
if not bind_and_step(insert_assoc_statement, 'insert assoc', player_id, ipint, asn, created, created) then return _error() end
|
||||||
|
@ -285,16 +283,23 @@ function verbana.data.import_from_sban(filename)
|
||||||
end -- verbana.data.import_from_sban
|
end -- verbana.data.import_from_sban
|
||||||
|
|
||||||
|
|
||||||
|
local player_id_cache = {}
|
||||||
function verbana.data.get_player_id(name, create_if_new)
|
function verbana.data.get_player_id(name, create_if_new)
|
||||||
|
local cached_id = player_id_cache[name]
|
||||||
|
if cached_id then return cached_id end
|
||||||
if create_if_new then
|
if create_if_new then
|
||||||
if not execute_bind_one('INSERT OR IGNORE INTO player (name) VALUES (?)', 'insert player', name) then return nil end
|
if not execute_bind_one('INSERT OR IGNORE INTO player (name) VALUES (?)', 'insert player', name) then return nil end
|
||||||
end
|
end
|
||||||
local table = get_full_table('SELECT id FROM player WHERE name = ? LIMIT 1', 'get player id', name)
|
local table = get_full_table('SELECT id FROM player WHERE name = ? LIMIT 1', 'get player id', name)
|
||||||
if not (table and table[1]) then return nil end
|
if not (table and table[1]) then return nil end
|
||||||
|
player_id_cache[name] = table[1][1]
|
||||||
return table[1][1]
|
return table[1][1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local player_status_cache = {}
|
||||||
function verbana.data.get_player_status(player_id, create_if_new)
|
function verbana.data.get_player_status(player_id, create_if_new)
|
||||||
|
local cached_status = player_status_cache[player_id]
|
||||||
|
if cached_status then return cached_status end
|
||||||
local code = [[
|
local code = [[
|
||||||
SELECT executor.id executor_id
|
SELECT executor.id executor_id
|
||||||
, executor.name executor
|
, executor.name executor
|
||||||
|
@ -312,6 +317,7 @@ function verbana.data.get_player_status(player_id, create_if_new)
|
||||||
]]
|
]]
|
||||||
local table = get_full_ntable(code, 'get player status', player_id)
|
local table = get_full_ntable(code, 'get player status', player_id)
|
||||||
if #table == 1 then
|
if #table == 1 then
|
||||||
|
player_status_cache[player_id] = table[1]
|
||||||
return table[1]
|
return table[1]
|
||||||
elseif #table > 1 then
|
elseif #table > 1 then
|
||||||
verbana.log('error', 'somehow got more than 1 result when getting current player status for %s', player_id)
|
verbana.log('error', 'somehow got more than 1 result when getting current player status for %s', player_id)
|
||||||
|
@ -332,6 +338,7 @@ function verbana.data.get_player_status(player_id, create_if_new)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function verbana.data.set_player_status(player_id, executor_id, status_id, reason, expires, no_update_current)
|
function verbana.data.set_player_status(player_id, executor_id, status_id, reason, expires, no_update_current)
|
||||||
|
player_status_cache[player_id] = nil
|
||||||
local code = [[
|
local code = [[
|
||||||
INSERT INTO player_status_log (player_id, executor_id, status_id, reason, expires, timestamp)
|
INSERT INTO player_status_log (player_id, executor_id, status_id, reason, expires, timestamp)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
@ -345,7 +352,10 @@ function verbana.data.set_player_status(player_id, executor_id, status_id, reaso
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local ip_status_cache = {}
|
||||||
function verbana.data.get_ip_status(ipint, create_if_new)
|
function verbana.data.get_ip_status(ipint, create_if_new)
|
||||||
|
local cached_status = ip_status_cache[ipint]
|
||||||
|
if cached_status then return cached_status end
|
||||||
local code = [[
|
local code = [[
|
||||||
SELECT executor.id executor_id
|
SELECT executor.id executor_id
|
||||||
, executor.name executor
|
, executor.name executor
|
||||||
|
@ -363,6 +373,7 @@ function verbana.data.get_ip_status(ipint, create_if_new)
|
||||||
]]
|
]]
|
||||||
local table = get_full_ntable(code, 'get ip status', ipint)
|
local table = get_full_ntable(code, 'get ip status', ipint)
|
||||||
if #table == 1 then
|
if #table == 1 then
|
||||||
|
ip_status_cache[ipint] = table[1]
|
||||||
return table[1]
|
return table[1]
|
||||||
elseif #table > 1 then
|
elseif #table > 1 then
|
||||||
verbana.log('error', 'somehow got more than 1 result when getting current ip status for %s', ipint)
|
verbana.log('error', 'somehow got more than 1 result when getting current ip status for %s', ipint)
|
||||||
|
@ -383,6 +394,7 @@ function verbana.data.get_ip_status(ipint, create_if_new)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function verbana.data.set_ip_status(ipint, executor_id, status_id, reason, expires)
|
function verbana.data.set_ip_status(ipint, executor_id, status_id, reason, expires)
|
||||||
|
ip_status_cache[ipint] = nil
|
||||||
local code = [[
|
local code = [[
|
||||||
INSERT INTO ip_status_log (ip, executor_id, status_id, reason, expires, timestamp)
|
INSERT INTO ip_status_log (ip, executor_id, status_id, reason, expires, timestamp)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
@ -394,7 +406,10 @@ function verbana.data.set_ip_status(ipint, executor_id, status_id, reason, expir
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local asn_status_cache = {}
|
||||||
function verbana.data.get_asn_status(asn, create_if_new)
|
function verbana.data.get_asn_status(asn, create_if_new)
|
||||||
|
local cached_status = asn_status_cache[asn]
|
||||||
|
if cached_status then return cached_status end
|
||||||
local code = [[
|
local code = [[
|
||||||
SELECT executor.id executor_id
|
SELECT executor.id executor_id
|
||||||
, executor.name executor
|
, executor.name executor
|
||||||
|
@ -412,6 +427,7 @@ function verbana.data.get_asn_status(asn, create_if_new)
|
||||||
]]
|
]]
|
||||||
local table = get_full_ntable(code, 'get asn status', asn)
|
local table = get_full_ntable(code, 'get asn status', asn)
|
||||||
if #table == 1 then
|
if #table == 1 then
|
||||||
|
asn_status_cache[asn] = table[1]
|
||||||
return table[1]
|
return table[1]
|
||||||
elseif #table > 1 then
|
elseif #table > 1 then
|
||||||
verbana.log('error', 'somehow got more than 1 result when getting current asn status for %s', asn)
|
verbana.log('error', 'somehow got more than 1 result when getting current asn status for %s', asn)
|
||||||
|
@ -432,6 +448,7 @@ function verbana.data.get_asn_status(asn, create_if_new)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function verbana.data.set_asn_status(asn, executor_id, status_id, reason, expires)
|
function verbana.data.set_asn_status(asn, executor_id, status_id, reason, expires)
|
||||||
|
asn_status_cache[asn] = nil
|
||||||
local code = [[
|
local code = [[
|
||||||
INSERT INTO asn_status_log (asn, executor_id, status_id, reason, expires, timestamp)
|
INSERT INTO asn_status_log (asn, executor_id, status_id, reason, expires, timestamp)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
@ -672,7 +689,11 @@ function verbana.data.get_all_banned_players()
|
||||||
, player_status_log.expires expires
|
, player_status_log.expires expires
|
||||||
FROM player
|
FROM player
|
||||||
LEFT JOIN player_status_log ON player.id == player_status_log.player_id
|
LEFT JOIN player_status_log ON player.id == player_status_log.player_id
|
||||||
WHERE player_status_log.status_id IN (4, 5, 6)
|
WHERE player_status_log.status_id IN (?, ?, ?)
|
||||||
]] -- TODO: ... hard-coded values? ...
|
]]
|
||||||
return get_full_ntable(code, 'all banned')
|
return get_full_ntable(code, 'all banned',
|
||||||
|
verbana.data.player_status.banned,
|
||||||
|
verbana.data.player_status.tempbanned,
|
||||||
|
verbana.data.player_status.locked
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
irc?
|
irc?
|
||||||
irc2?
|
irc2?
|
||||||
|
sban?
|
||||||
|
verification?
|
||||||
|
|
10
init.lua
10
init.lua
|
@ -26,7 +26,7 @@ dofile(verbana.modpath .. '/lib_asn.lua')
|
||||||
-- connect to the DB - MAKE SURE TO CLEAN UP ALL "insecure" access points!
|
-- connect to the DB - MAKE SURE TO CLEAN UP ALL "insecure" access points!
|
||||||
local sql = verbana.ie.require('lsqlite3') -- TODO what happens if this isn't installed? ....
|
local sql = verbana.ie.require('lsqlite3') -- TODO what happens if this isn't installed? ....
|
||||||
verbana.sql = sql
|
verbana.sql = sql
|
||||||
local db_location = ('%s/verbana.sqlite'):format(minetest.get_worldpath()) -- TODO get path from settings
|
local db_location = verbana.settings.db_path
|
||||||
local db, _, errmsg = sql.open(db_location)
|
local db, _, errmsg = sql.open(db_location)
|
||||||
if not db then
|
if not db then
|
||||||
error(('Verbana could not open its database @ %q: %q'):format(db_location, errmsg))
|
error(('Verbana could not open its database @ %q: %q'):format(db_location, errmsg))
|
||||||
|
@ -34,16 +34,16 @@ else
|
||||||
verbana.db = db
|
verbana.db = db
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_shutdown(function()
|
minetest.register_on_shutdown(verbana.util.safe(function()
|
||||||
local ret_code = db:close()
|
local ret_code = db:close()
|
||||||
if ret_code ~= sql.OK then
|
if ret_code ~= sql.OK then
|
||||||
verbana.log('error', 'Error closing DB: %s', db:error_message())
|
verbana.log('error', 'Error closing DB: %s', db:error_message())
|
||||||
end
|
end
|
||||||
end)
|
end))
|
||||||
|
|
||||||
-- core
|
-- core
|
||||||
dofile(verbana.modpath .. '/chat.lua')
|
dofile(verbana.modpath .. '/data.lua') -- data must go first
|
||||||
dofile(verbana.modpath .. '/data.lua')
|
dofile(verbana.modpath .. '/chat.lua') -- chat must go before login_handling
|
||||||
dofile(verbana.modpath .. '/login_handling.lua')
|
dofile(verbana.modpath .. '/login_handling.lua')
|
||||||
dofile(verbana.modpath .. '/commands.lua')
|
dofile(verbana.modpath .. '/commands.lua')
|
||||||
|
|
||||||
|
|
40
lib_asn.lua
40
lib_asn.lua
|
@ -1,19 +1,15 @@
|
||||||
if not verbana then verbana = {} end
|
verbana.lib_asn = {}
|
||||||
if not verbana.modpath then verbana.modpath = '.' end
|
|
||||||
if not verbana.ip then dofile(verbana.modpath .. '/lib_ip.lua') end
|
|
||||||
if not verbana.log then function verbana.log(_, message, ...) print(message:format(...)) end end
|
|
||||||
verbana.asn = {}
|
|
||||||
|
|
||||||
local ASN_DESCRIPTION_FILE = 'data-used-autnums'
|
local lib_ip = verbana.lib_ip
|
||||||
local NETWORK_ASN_FILE = 'data-raw-table'
|
local settings = verbana.settings
|
||||||
|
|
||||||
local load_file = verbana.util.load_file
|
local load_file = verbana.util.load_file
|
||||||
|
|
||||||
-- map from ASN (integer) to description (string)
|
-- map from ASN (integer) to description (string)
|
||||||
verbana.asn.description = {}
|
verbana.lib_asn.description = {}
|
||||||
|
|
||||||
local function refresh_asn_descriptions()
|
local function refresh_asn_descriptions()
|
||||||
local contents = load_file(('%s/%s'):format(verbana.modpath, ASN_DESCRIPTION_FILE))
|
local contents = load_file(settings.asn_description_path)
|
||||||
if not contents then return end
|
if not contents then return end
|
||||||
local description = {}
|
local description = {}
|
||||||
|
|
||||||
|
@ -27,16 +23,16 @@ local function refresh_asn_descriptions()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verbana.asn.description = description
|
verbana.lib_asn.description = description
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- array of values like {starting_ip (integer), ending_ip (integer), ASN (integer)}
|
-- array of values like {starting_ip (integer), ending_ip (integer), ASN (integer)}
|
||||||
-- ip ranges should be sorted and not overlap.
|
-- ip ranges should be sorted and not overlap.
|
||||||
verbana.asn.network = {}
|
verbana.lib_asn.network = {}
|
||||||
|
|
||||||
local function refresh_asn_table()
|
local function refresh_asn_table()
|
||||||
local contents = load_file(('%s/%s'):format(verbana.modpath, NETWORK_ASN_FILE))
|
local contents = load_file(settings.asn_data_path)
|
||||||
if not contents then return end
|
if not contents then return end
|
||||||
|
|
||||||
local networks = {}
|
local networks = {}
|
||||||
|
@ -46,7 +42,7 @@ local function refresh_asn_table()
|
||||||
verbana.log('warning', 'could not interpret network line "%s"', line)
|
verbana.log('warning', 'could not interpret network line "%s"', line)
|
||||||
else
|
else
|
||||||
asn = tonumber(asn)
|
asn = tonumber(asn)
|
||||||
local start, end_ = verbana.ip.netstr_to_bounds(net)
|
local start, end_ = lib_ip.netstr_to_bounds(net)
|
||||||
|
|
||||||
if #networks == 0 then
|
if #networks == 0 then
|
||||||
table.insert(networks, {start, end_, asn})
|
table.insert(networks, {start, end_, asn})
|
||||||
|
@ -79,11 +75,11 @@ local function refresh_asn_table()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verbana.asn.network = networks
|
verbana.lib_asn.network = networks
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.asn.refresh()
|
function verbana.lib_asn.refresh()
|
||||||
local start = os.clock()
|
local start = os.clock()
|
||||||
if not refresh_asn_descriptions() then return false end
|
if not refresh_asn_descriptions() then return false end
|
||||||
if not refresh_asn_table() then return false end
|
if not refresh_asn_table() then return false end
|
||||||
|
@ -92,7 +88,7 @@ function verbana.asn.refresh()
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if not verbana.asn.refresh() then
|
if not verbana.lib_asn.refresh() then
|
||||||
error('Verbana could not load ASN data')
|
error('Verbana could not load ASN data')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -100,7 +96,7 @@ local function find(ipint)
|
||||||
-- binary search
|
-- binary search
|
||||||
-- TODO we could possibly weight the "middle" based in where ipint falls in [0,2**32).
|
-- TODO we could possibly weight the "middle" based in where ipint falls in [0,2**32).
|
||||||
-- TODO see e.g. https://en.wikipedia.org/wiki/Interpolation_search
|
-- TODO see e.g. https://en.wikipedia.org/wiki/Interpolation_search
|
||||||
local t = verbana.asn.network
|
local t = verbana.lib_asn.network
|
||||||
local low = 1
|
local low = 1
|
||||||
local high = #t
|
local high = #t
|
||||||
while low <= high do
|
while low <= high do
|
||||||
|
@ -120,21 +116,21 @@ local function find(ipint)
|
||||||
-- not found, return nil
|
-- not found, return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.asn.lookup(ipstr)
|
function verbana.lib_asn.lookup(ipstr)
|
||||||
local ipint
|
local ipint
|
||||||
if type(ipstr) == 'number' then
|
if type(ipstr) == 'number' then
|
||||||
ipint = ipstr
|
ipint = ipstr
|
||||||
else
|
else
|
||||||
ipint = verbana.ip.ipstr_to_ipint(ipstr)
|
ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
end
|
end
|
||||||
local asn = find(ipint)
|
local asn = find(ipint)
|
||||||
if asn then
|
if asn then
|
||||||
return asn, (verbana.asn.description[asn] or 'Not a known ASN')
|
return asn, (verbana.lib_asn.description[asn] or 'Not a known ASN')
|
||||||
else
|
else
|
||||||
return 0, 'Not a known ASN'
|
return 0, 'Not a known ASN'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.asn.get_description(asn)
|
function verbana.lib_asn.get_description(asn)
|
||||||
return verbana.asn.description[asn] or 'Not a known ASN'
|
return verbana.lib_asn.description[asn] or 'Not a known ASN'
|
||||||
end
|
end
|
||||||
|
|
12
lib_ip.lua
12
lib_ip.lua
|
@ -1,8 +1,8 @@
|
||||||
if not verbana then verbana = {} end
|
if not verbana then verbana = {} end
|
||||||
|
|
||||||
verbana.ip = {}
|
verbana.lib_ip = {}
|
||||||
|
|
||||||
function verbana.ip.is_valid_ip(ipstr)
|
function verbana.lib_ip.is_valid_ip(ipstr)
|
||||||
local a, b, c, d = ipstr:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')
|
local a, b, c, d = ipstr:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')
|
||||||
a = tonumber(a)
|
a = tonumber(a)
|
||||||
b = tonumber(b)
|
b = tonumber(b)
|
||||||
|
@ -12,12 +12,12 @@ function verbana.ip.is_valid_ip(ipstr)
|
||||||
return 0 <= a and a < 256 and 0 <= b and b < 256 and 0 <= c and c < 256 and 0 <= d and d < 256
|
return 0 <= a and a < 256 and 0 <= b and b < 256 and 0 <= c and c < 256 and 0 <= d and d < 256
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.ip.ipstr_to_ipint(ipstr)
|
function verbana.lib_ip.ipstr_to_ipint(ipstr)
|
||||||
local a, b, c, d = ipstr:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')
|
local a, b, c, d = ipstr:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')
|
||||||
return (tonumber(a) * 16777216) + (tonumber(b) * 65536) + (tonumber(c) * 256) + tonumber(d)
|
return (tonumber(a) * 16777216) + (tonumber(b) * 65536) + (tonumber(c) * 256) + tonumber(d)
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.ip.ipint_to_ipstr(number)
|
function verbana.lib_ip.ipint_to_ipstr(number)
|
||||||
local d = number % 256
|
local d = number % 256
|
||||||
number = math.floor(number / 256)
|
number = math.floor(number / 256)
|
||||||
local c = number % 256
|
local c = number % 256
|
||||||
|
@ -27,9 +27,9 @@ function verbana.ip.ipint_to_ipstr(number)
|
||||||
return ('%u.%u.%u.%u'):format(a, b, c, d)
|
return ('%u.%u.%u.%u'):format(a, b, c, d)
|
||||||
end
|
end
|
||||||
|
|
||||||
function verbana.ip.netstr_to_bounds(ipnet)
|
function verbana.lib_ip.netstr_to_bounds(ipnet)
|
||||||
local ip, net = ipnet:match('^(.*)/(%d+)$')
|
local ip, net = ipnet:match('^(.*)/(%d+)$')
|
||||||
local start = verbana.ip.ipstr_to_ipint(ip)
|
local start = verbana.lib_ip.ipstr_to_ipint(ip)
|
||||||
net = tonumber(net)
|
net = tonumber(net)
|
||||||
local end_ = start + (2 ^ (32 - net)) - 1
|
local end_ = start + (2 ^ (32 - net)) - 1
|
||||||
return start, end_
|
return start, end_
|
||||||
|
|
|
@ -3,43 +3,54 @@ local function table_is_empty(t)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local USING_VERIFICATION_JAIL = verbana.settings.verification_jail and verbana.settings.verification_jail_period
|
local data = verbana.data
|
||||||
|
local lib_asn = verbana.lib_asn
|
||||||
|
local lib_ip = verbana.lib_ip
|
||||||
|
local log = verbana.log
|
||||||
|
local privs = verbana.privs
|
||||||
|
local settings = verbana.settings
|
||||||
|
local util = verbana.util
|
||||||
|
|
||||||
|
local safe = util.safe
|
||||||
|
|
||||||
|
local USING_VERIFICATION_JAIL = settings.verification_jail and settings.verification_jail_period
|
||||||
|
local verification_jail = settings.verification_jail
|
||||||
|
local spawn_pos = settings.spawn_pos
|
||||||
|
local unverified_spawn_pos = settings.unverified_spawn_pos
|
||||||
|
local verification_jail_period = settings.verification_jail_period
|
||||||
|
|
||||||
local timer = 0
|
|
||||||
local verification_jail = verbana.settings.verification_jail
|
|
||||||
local check_player_privs = minetest.check_player_privs
|
local check_player_privs = minetest.check_player_privs
|
||||||
local spawn_pos = verbana.settings.spawn_pos
|
|
||||||
local unverified_spawn_pos = verbana.settings.unverified_spawn_pos
|
|
||||||
local verification_jail_period = verbana.settings.verification_jail_period
|
|
||||||
|
|
||||||
local function should_rejail(player, player_status)
|
local function should_rejail(player, player_status)
|
||||||
if player_status.status_id ~= verbana.data.player_status.unverified.id then
|
if player_status.status_id ~= data.player_status.unverified.id then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local pos = player:get_pos()
|
local pos = player:get_pos()
|
||||||
return not (
|
return not (
|
||||||
verification_jail.x[1] <= pos.x and pos.x <= verification_jail.x[2] and
|
verification_jail[1].x <= pos.x and pos.x <= verification_jail[2].x and
|
||||||
verification_jail.y[1] <= pos.y and pos.y <= verification_jail.y[2] and
|
verification_jail[1].y <= pos.y and pos.y <= verification_jail[2].y and
|
||||||
verification_jail.z[1] <= pos.z and pos.z <= verification_jail.z[2]
|
verification_jail[1].z <= pos.z and pos.z <= verification_jail[2].z
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function should_unjail(player, player_status)
|
local function should_unjail(player, player_status)
|
||||||
if player_status.status_id == verbana.data.player_status.unverified.id then
|
if player_status.status_id == data.player_status.unverified.id then
|
||||||
return false
|
return false
|
||||||
elseif verbana.privs.is_privileged(player:get_player_name()) then
|
elseif privs.is_privileged(player:get_player_name()) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local pos = player:get_pos()
|
local pos = player:get_pos()
|
||||||
return (
|
return (
|
||||||
verification_jail.x[1] <= pos.x and pos.x <= verification_jail.x[2] and
|
verification_jail[1].x <= pos.x and pos.x <= verification_jail[2].x and
|
||||||
verification_jail.y[1] <= pos.y and pos.y <= verification_jail.y[2] and
|
verification_jail[1].y <= pos.y and pos.y <= verification_jail[2].y and
|
||||||
verification_jail.z[1] <= pos.z and pos.z <= verification_jail.z[2]
|
verification_jail[1].z <= pos.z and pos.z <= verification_jail[2].z
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if USING_VERIFICATION_JAIL then
|
if USING_VERIFICATION_JAIL then
|
||||||
|
local timer = 0
|
||||||
minetest.register_globalstep(function(dtime)
|
minetest.register_globalstep(function(dtime)
|
||||||
timer = timer + dtime;
|
timer = timer + dtime;
|
||||||
if timer < verification_jail_period then
|
if timer < verification_jail_period then
|
||||||
|
@ -47,51 +58,56 @@ if USING_VERIFICATION_JAIL then
|
||||||
end
|
end
|
||||||
timer = 0
|
timer = 0
|
||||||
for _, player in ipairs(minetest.get_connected_players()) do
|
for _, player in ipairs(minetest.get_connected_players()) do
|
||||||
-- TODO this is pretty heavy
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name) -- cached, so not heavy
|
||||||
local player_status = verbana.data.get_player_status(player_id)
|
local player_status = data.get_player_status(player_id) -- cached, so not heavy
|
||||||
if should_rejail(player, player_status) then
|
if should_rejail(player, player_status) then
|
||||||
player:set_pos(unverified_spawn_pos)
|
log('action', 'rejailing %s', name)
|
||||||
|
if not settings.debug_mode then
|
||||||
|
player:set_pos(unverified_spawn_pos)
|
||||||
|
end
|
||||||
elseif should_unjail(player, player_status) then
|
elseif should_unjail(player, player_status) then
|
||||||
player:set_pos(spawn_pos)
|
log('action', 'unjailing %s', name)
|
||||||
|
if not settings.debug_mode then
|
||||||
|
player:set_pos(spawn_pos)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_prejoinplayer(function(name, ipstr)
|
minetest.register_on_prejoinplayer(safe(function(name, ipstr)
|
||||||
-- return a string w/ the reason for refusal; otherwise return nothing
|
-- return a string w/ the reason for refusal; otherwise return nothing
|
||||||
verbana.log('action', 'prejoin: %s %s', name, ipstr)
|
log('action', 'prejoin: %s %s', name, ipstr)
|
||||||
local ipint = verbana.ip.ipstr_to_ipint(ipstr)
|
local ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
local asn, asn_description = verbana.asn.lookup(ipint)
|
local asn, asn_description = lib_asn.lookup(ipint)
|
||||||
|
|
||||||
local player_id = verbana.data.get_player_id(name, true) -- will create one if none exists
|
local player_id = data.get_player_id(name, true) -- will create one if none exists
|
||||||
local player_status = verbana.data.get_player_status(player_id, true)
|
local player_status = data.get_player_status(player_id, true)
|
||||||
local ip_status = verbana.data.get_ip_status(ipint, true) -- will create one if none exists
|
local ip_status = data.get_ip_status(ipint, true) -- will create one if none exists
|
||||||
local asn_status = verbana.data.get_asn_status(asn, true) -- will create one if none exists
|
local asn_status = data.get_asn_status(asn, true) -- will create one if none exists
|
||||||
|
|
||||||
-- check and clear temporary statuses
|
-- check and clear temporary statuses
|
||||||
local now = os.time()
|
local now = os.time()
|
||||||
if player_status.name == 'tempbanned' then
|
if player_status.name == 'tempbanned' then
|
||||||
local expires = player_status.expires or now
|
local expires = player_status.expires or now
|
||||||
if now >= expires then
|
if now >= expires then
|
||||||
verbana.data.unban_player(player_id, player_status.executor_id, 'temp ban expired')
|
data.unban_player(player_id, player_status.executor_id, 'temp ban expired')
|
||||||
player_status = verbana.data.get_player_status(player_id) -- refresh player status
|
player_status = data.get_player_status(player_id) -- refresh player status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if ip_status.name == 'tempblocked' then
|
if ip_status.name == 'tempblocked' then
|
||||||
local expires = ip_status.expires or now
|
local expires = ip_status.expires or now
|
||||||
if now >= expires then
|
if now >= expires then
|
||||||
verbana.data.unblock_ip(ipint, ip_status.executor_id, 'temp block expired')
|
data.unblock_ip(ipint, ip_status.executor_id, 'temp block expired')
|
||||||
ip_status = verbana.data.get_ip_status(ipint) -- refresh ip status
|
ip_status = data.get_ip_status(ipint) -- refresh ip status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if asn_status.name == 'tempblocked' then
|
if asn_status.name == 'tempblocked' then
|
||||||
local expires = asn_status.expires or now
|
local expires = asn_status.expires or now
|
||||||
if now >= expires then
|
if now >= expires then
|
||||||
verbana.data.unblock_asn(asn, asn_status.executor_id, 'temp block expired')
|
data.unblock_asn(asn, asn_status.executor_id, 'temp block expired')
|
||||||
asn_status = verbana.data.get_asn_status(asn) -- refresh asn status
|
asn_status = data.get_asn_status(asn) -- refresh asn status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,7 +119,7 @@ minetest.register_on_prejoinplayer(function(name, ipstr)
|
||||||
|
|
||||||
if player_status.name == 'whitelisted' then
|
if player_status.name == 'whitelisted' then
|
||||||
-- if the player is whitelisted, let them in.
|
-- if the player is whitelisted, let them in.
|
||||||
elseif verbana.settings.privs_to_whitelist and minetest.check_player_privs(name, verbana.settings.privs_to_whitelist) then
|
elseif settings.whitelisted_privs and minetest.check_player_privs(name, settings.whitelisted_privs) then
|
||||||
-- if the player has a whitelisted priv, let them in.
|
-- if the player has a whitelisted priv, let them in.
|
||||||
elseif player_status.name == 'banned' then
|
elseif player_status.name == 'banned' then
|
||||||
local reason = player_status.reason
|
local reason = player_status.reason
|
||||||
|
@ -171,7 +187,7 @@ minetest.register_on_prejoinplayer(function(name, ipstr)
|
||||||
-- if the player is new, let them in (truly new players will require verification)
|
-- if the player is new, let them in (truly new players will require verification)
|
||||||
-- else if the player has never connected from this ip/asn, prevent them from connecting
|
-- else if the player has never connected from this ip/asn, prevent them from connecting
|
||||||
-- else let them in (mods will get an alert)
|
-- else let them in (mods will get an alert)
|
||||||
local has_assoc = verbana.data.has_asn_assoc(player_id, asn) or verbana.data.has_ip_assoc(player_id, ipint)
|
local has_assoc = data.has_asn_assoc(player_id, asn) or data.has_ip_assoc(player_id, ipint)
|
||||||
if not has_assoc then
|
if not has_assoc then
|
||||||
-- note: if 'suspicious' is true, then 'return_value' should be nil before this
|
-- note: if 'suspicious' is true, then 'return_value' should be nil before this
|
||||||
return_value = 'Suspicious activity detected.'
|
return_value = 'Suspicious activity detected.'
|
||||||
|
@ -179,15 +195,17 @@ minetest.register_on_prejoinplayer(function(name, ipstr)
|
||||||
end
|
end
|
||||||
|
|
||||||
if return_value then
|
if return_value then
|
||||||
verbana.data.log(player_id, ipint, asn, false)
|
data.log(player_id, ipint, asn, false)
|
||||||
verbana.log('action', 'Connection of %s from %s (A%s) denied because %q', name, ipstr, asn, return_value)
|
log('action', 'Connection of %s from %s (A%s) denied because %q', name, ipstr, asn, return_value)
|
||||||
return return_value
|
if not settings.debug_mode then
|
||||||
|
return return_value
|
||||||
|
end
|
||||||
else
|
else
|
||||||
verbana.log('action', 'Connection of %s from %s (A%s) allowed', name, ipstr, asn)
|
log('action', 'Connection of %s from %s (A%s) allowed', name, ipstr, asn)
|
||||||
verbana.data.log(player_id, ipint, asn, true)
|
data.log(player_id, ipint, asn, true)
|
||||||
verbana.data.assoc(player_id, ipint, asn)
|
data.assoc(player_id, ipint, asn)
|
||||||
end
|
end
|
||||||
end)
|
end))
|
||||||
|
|
||||||
local function move_to(name, pos, max_tries)
|
local function move_to(name, pos, max_tries)
|
||||||
max_tries = max_tries or 5
|
max_tries = max_tries or 5
|
||||||
|
@ -196,7 +214,10 @@ local function move_to(name, pos, max_tries)
|
||||||
-- get the player again here, in case they have disconnected
|
-- get the player again here, in case they have disconnected
|
||||||
local player = minetest.get_player_by_name(name)
|
local player = minetest.get_player_by_name(name)
|
||||||
if player then
|
if player then
|
||||||
player:set_pos(pos)
|
log('action', 'moving %s to %s', name, minetest.pos_to_string(pos))
|
||||||
|
if not settings.debug_mode then
|
||||||
|
player:set_pos(pos)
|
||||||
|
end
|
||||||
elseif tries < max_tries then
|
elseif tries < max_tries then
|
||||||
tries = tries + 1
|
tries = tries + 1
|
||||||
minetest.after(1, f)
|
minetest.after(1, f)
|
||||||
|
@ -205,63 +226,74 @@ local function move_to(name, pos, max_tries)
|
||||||
f()
|
f()
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.register_on_newplayer(function(player)
|
minetest.register_on_newplayer(safe(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
local ipstr = minetest.get_player_ip(name)
|
local ipstr = minetest.get_player_ip(name)
|
||||||
local ipint = verbana.ip.ipstr_to_ipint(ipstr)
|
local ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
local asn = verbana.asn.lookup(ipint)
|
local asn = lib_asn.lookup(ipint)
|
||||||
local player_id = verbana.data.get_player_id(name)
|
local player_id = data.get_player_id(name)
|
||||||
local ip_status = verbana.data.get_ip_status(ipint)
|
local ip_status = data.get_ip_status(ipint)
|
||||||
local asn_status = verbana.data.get_asn_status(asn)
|
local asn_status = data.get_asn_status(asn)
|
||||||
|
|
||||||
local need_to_verify = (
|
local need_to_verify = (
|
||||||
verbana.settings.universal_verification or
|
settings.universal_verification or
|
||||||
ip_status.name == 'suspicious' or
|
ip_status.name == 'suspicious' or
|
||||||
(asn_status.name == 'suspicious' and ip_status.name ~= 'trusted')
|
(asn_status.name == 'suspicious' and ip_status.name ~= 'trusted')
|
||||||
)
|
)
|
||||||
|
|
||||||
if need_to_verify then
|
if need_to_verify then
|
||||||
if not verbana.data.set_player_status(player_id, verbana.data.verbana_player_id, verbana.data.player_status.unverified.id, 'new player connected from suspicious network') then
|
if not data.set_player_status(player_id, data.verbana_player_id, data.player_status.unverified.id, 'new player connected from suspicious network') then
|
||||||
verbana.log('error', 'error setting unverified status on %s', name)
|
log('error', 'error setting unverified status on %s', name)
|
||||||
|
end
|
||||||
|
if not settings.debug_mode then
|
||||||
|
minetest.set_player_privs(name, settings.unverified_privs)
|
||||||
end
|
end
|
||||||
minetest.set_player_privs(name, verbana.settings.unverified_privs)
|
|
||||||
player:set_pos(unverified_spawn_pos)
|
|
||||||
-- wait a second before moving the player to the verification area
|
-- wait a second before moving the player to the verification area
|
||||||
-- because other mods sometimes try to move them around as well
|
-- because other mods sometimes try to move them around as well
|
||||||
minetest.after(1, function() move_to(name, unverified_spawn_pos) end)
|
minetest.after(1, move_to, name, unverified_spawn_pos)
|
||||||
verbana.log('action', 'new player %s sent to verification', name)
|
log('action', 'new player %s sent to verification', name)
|
||||||
else
|
else
|
||||||
verbana.data.set_player_status(
|
data.set_player_status(
|
||||||
player_id,
|
player_id,
|
||||||
verbana.data.verbana_player_id,
|
data.verbana_player_id,
|
||||||
verbana.data.player_status.default.id,
|
data.player_status.default.id,
|
||||||
'new player'
|
'new player'
|
||||||
)
|
)
|
||||||
verbana.log('action', 'new player %s', name)
|
log('action', 'new player %s', name)
|
||||||
end
|
end
|
||||||
end)
|
end))
|
||||||
|
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(safe(function(player)
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
local player_id = data.get_player_id(name)
|
||||||
|
local player_status = data.get_player_status(player_id)
|
||||||
local ipstr = minetest.get_player_ip(name)
|
local ipstr = minetest.get_player_ip(name)
|
||||||
local ipint = verbana.ip.ipstr_to_ipint(ipstr)
|
local ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
local asn, asn_description = verbana.asn.lookup(ipint)
|
local asn, asn_description = lib_asn.lookup(ipint)
|
||||||
if minetest.check_player_privs(name, {[verbana.privs.unverified]=true}) then
|
local is_unverified = player_status.status_id == data.player_status.unverified.id
|
||||||
|
if is_unverified then
|
||||||
verbana.chat.tell_mods(('*** Player %s from A%s (%s) is unverified.'):format(name, asn, asn_description))
|
verbana.chat.tell_mods(('*** Player %s from A%s (%s) is unverified.'):format(name, asn, asn_description))
|
||||||
end
|
end
|
||||||
if USING_VERIFICATION_JAIL then
|
if USING_VERIFICATION_JAIL then
|
||||||
local player_id = verbana.data.get_player_id(name)
|
|
||||||
local player_status = verbana.data.get_player_status(player_id)
|
|
||||||
|
|
||||||
if should_rejail(player, player_status) then
|
if should_rejail(player, player_status) then
|
||||||
player:set_pos(unverified_spawn_pos)
|
log('action', 'rejailing %s', name)
|
||||||
|
if not settings.debug_mode then
|
||||||
|
player:set_pos(unverified_spawn_pos)
|
||||||
|
end
|
||||||
elseif should_unjail(player, player_status) then
|
elseif should_unjail(player, player_status) then
|
||||||
player:set_pos(spawn_pos)
|
log('action', 'unjailing %s', name)
|
||||||
|
if not settings.debug_mode then
|
||||||
|
player:set_pos(spawn_pos)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end))
|
||||||
|
|
||||||
|
minetest.register_on_auth_fail(safe(function(name, ipstr)
|
||||||
|
log('action', 'auth failure: %s %s', name, ipstr)
|
||||||
|
local ipint = lib_ip.ipstr_to_ipint(ipstr)
|
||||||
|
local asn = lib_asn.lookup(ipint)
|
||||||
|
local player_id = data.get_player_id(name, true) -- will create one if none exists
|
||||||
|
|
||||||
minetest.register_on_auth_fail(function(name, ip)
|
data.log(player_id, ipint, asn, false)
|
||||||
-- TODO log failure
|
end))
|
||||||
end)
|
|
||||||
|
|
2
mod.conf
2
mod.conf
|
@ -1,4 +1,4 @@
|
||||||
name=verbana
|
name=verbana
|
||||||
description=Verification and Banning mod
|
description=Verification and Banning mod
|
||||||
depends=
|
depends=
|
||||||
optional_depends=irc,irc2
|
optional_depends=irc,irc2,sban,verification
|
||||||
|
|
12
privs.lua
12
privs.lua
|
@ -1,10 +1,16 @@
|
||||||
if not verbana then verbana = {} end
|
if not verbana then verbana = {} end
|
||||||
verbana.privs = {}
|
verbana.privs = {}
|
||||||
|
|
||||||
minetest.register_privilege('ban_admin', 'administrator for verification/bans')
|
verbana.privs.admin = verbana.settings.admin_priv
|
||||||
|
verbana.privs.moderator = verbana.settings.moderator_priv
|
||||||
|
|
||||||
verbana.privs.admin = 'ban_admin' -- TODO load from settings
|
if not minetest.registered_privileges[verbana.privs.admin] then
|
||||||
verbana.privs.moderator = 'basic_privs' -- TODO load from settings
|
minetest.register_privilege(verbana.privs.admin, 'Verbana administrator')
|
||||||
|
end
|
||||||
|
|
||||||
|
if not minetest.registered_privileges[verbana.privs.moderator] then
|
||||||
|
minetest.register_privilege(verbana.privs.moderator, 'Verbana moderator')
|
||||||
|
end
|
||||||
|
|
||||||
function verbana.privs.is_admin(name)
|
function verbana.privs.is_admin(name)
|
||||||
return minetest.check_player_privs(name, {[verbana.privs.admin] = true})
|
return minetest.check_player_privs(name, {[verbana.privs.admin] = true})
|
||||||
|
|
62
settings.lua
62
settings.lua
|
@ -2,20 +2,66 @@ verbana.settings = {}
|
||||||
|
|
||||||
local settings = minetest.settings
|
local settings = minetest.settings
|
||||||
|
|
||||||
|
function verbana.settings.set_universal_verification(value)
|
||||||
|
if type(value) == 'boolean' then
|
||||||
|
settings:set_bool('verbana.universal_verification', value)
|
||||||
|
else
|
||||||
|
verbana.log('warning', 'tried to set universal verification to %q', value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function get_setting(name, default)
|
||||||
|
local setting = settings:get('verbana.db_path')
|
||||||
|
if not setting or setting == '' then
|
||||||
|
return default
|
||||||
|
end
|
||||||
|
return setting
|
||||||
|
end
|
||||||
|
|
||||||
local function get_jail_bounds()
|
local function get_jail_bounds()
|
||||||
|
-- (x1,y1,z1),(x2,y2,z2)
|
||||||
local bounds = settings:get('verbana.jail_bounds')
|
local bounds = settings:get('verbana.jail_bounds')
|
||||||
if not bounds or bounds == '' then
|
if not bounds or bounds == '' then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
local x1, y1, z1, x2, y2, z2 = bounds:match(
|
||||||
|
'^%s*%(%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%),%(%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*%)%s*$'
|
||||||
|
)
|
||||||
|
if not x1 then
|
||||||
|
verbana.log('warning', 'The setting of verbana.jail_bounds %q is invalid, ignoring.')
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
x1 = tonumber(x1)
|
||||||
|
y1 = tonumber(y1)
|
||||||
|
z1 = tonumber(z1)
|
||||||
|
x2 = tonumber(x2)
|
||||||
|
y2 = tonumber(y2)
|
||||||
|
z2 = tonubmer(z2)
|
||||||
|
if x1 > x2 then x1, x2 = x2, x1 end
|
||||||
|
if y1 > y2 then y1, y2 = y2, y1 end
|
||||||
|
if z1 > z2 then z1, z2 = z2, z1 end
|
||||||
|
return {vector.new(x1, y1, z1), vector.new(x2, y2, z2)}
|
||||||
end
|
end
|
||||||
|
|
||||||
verbana.settings.verified_privs = minetest.string_to_privs(settings:get('default_privs') or '')
|
verbana.settings.db_path = get_setting('verbana.db_path', ('%s/verbana.sqlite'):format(minetest.get_worldpath()))
|
||||||
verbana.settings.unverified_privs = minetest.string_to_privs(settings:get('verbana.unverified_privs') or '')
|
verbana.settings.asn_description_path = get_setting('verbana.asn_description_path', ('%s/%s'):format(verbana.modpath, 'data-used-autnums'))
|
||||||
verbana.settings.privs_to_whitelist = minetest.string_to_privs(settings:get('verbana.privs_to_whitelist') or '')
|
verbana.settings.asn_data_path = get_setting('verbana.asn_data_path', ('%s/%s'):format(verbana.modpath, 'data-raw-table'))
|
||||||
verbana.settings.universal_verification = settings:get_bool('verbana.universal_verification', false)
|
|
||||||
|
|
||||||
verbana.settings.spawn_pos = minetest.string_to_pos(settings:get('static_spawnpoint') or '(0,0,0)')
|
verbana.settings.admin_priv = get_setting('verbana.admin_priv', 'ban_admin')
|
||||||
verbana.settings.unverified_spawn_pos = minetest.string_to_pos(settings:get('verbana.unverified_spawn_pos') or '(0,0,0)')
|
verbana.settings.moderator_priv = get_setting('verbana.moderator_priv', 'basic_privs')
|
||||||
|
|
||||||
|
verbana.settings.verified_privs = minetest.string_to_privs(get_setting('default_privs', 'shout,interact'))
|
||||||
|
verbana.settings.unverified_privs = minetest.string_to_privs(get_setting('verbana.unverified_privs', 'shout'))
|
||||||
|
verbana.settings.whitelisted_privs = minetest.string_to_privs(get_setting('verbana.whitelisted_privs', ''))
|
||||||
|
if #verbana.settings.whitelisted_privs == 0 then verbana.settings.whitelisted_privs = nil end
|
||||||
|
|
||||||
|
verbana.settings.spawn_pos = minetest.string_to_pos(get_setting('static_spawnpoint', '(0,0,0)'))
|
||||||
|
verbana.settings.unverified_spawn_pos = minetest.string_to_pos(get_setting('verbana.unverified_spawn_pos', '(0,0,0)'))
|
||||||
|
|
||||||
|
verbana.settings.universal_verification = settings:get_bool('verbana.universal_verification', false)
|
||||||
verbana.settings.jail_bounds = get_jail_bounds()
|
verbana.settings.jail_bounds = get_jail_bounds()
|
||||||
verbana.settings.jail_check_period = settings:get('static_spawnpoint')
|
verbana.settings.jail_check_period = get_setting('verbana.jail_check_period')
|
||||||
|
|
||||||
|
-- TODO: remove the default 'true' setting when we are ready
|
||||||
|
verbana.settings.debug_mode = get_setting('verbana.debug_mode', 'true') == 'true'
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
# The location of the DB (default: root of the world)
|
||||||
|
verbana.db_path (Location of the Verbana SQLite DB) string
|
||||||
|
|
||||||
|
# The location of the ASN description file (default: in the verbana mod folder)
|
||||||
|
verbana.asn_description_path (Location of the ASN description file) string
|
||||||
|
|
||||||
|
# The location of the ASN data file (default: in the verbana mod folder)
|
||||||
|
verbana.asn_data_path (Location of the ASN data file) string
|
||||||
|
|
||||||
# The privilege of the Verbana adminstrator(s)
|
# The privilege of the Verbana adminstrator(s)
|
||||||
verbana.admin_priv (Priv required for Verbana administration) string ban_admin
|
verbana.admin_priv (Priv required for Verbana administration) string ban_admin
|
||||||
|
|
||||||
|
@ -8,13 +17,13 @@ verbana.moderator_priv (Priv required for Verbana moderation) string basic_privs
|
||||||
verbana.unverified_privs (Privs for unverified users) string shout
|
verbana.unverified_privs (Privs for unverified users) string shout
|
||||||
|
|
||||||
# Comma delimited. If a player has all of the listed privileges, they skip suspicious network checks.
|
# Comma delimited. If a player has all of the listed privileges, they skip suspicious network checks.
|
||||||
verbana.privs_to_whitelist (Privs required to bypass suspicious network checks) string
|
verbana.whitelisted_privs (Privs required to bypass suspicious network checks) string
|
||||||
|
|
||||||
# Coordinates where unverified players spawn
|
# Coordinates where unverified players spawn
|
||||||
verbana.unverified_spawn_pos (Where unverified players spawn) string 0,0,0
|
verbana.unverified_spawn_pos (Where unverified players spawn) string 0,0,0
|
||||||
|
|
||||||
# Coordinates bounding the verification jail area, if it exists.
|
# Coordinates bounding the verification jail area, if it exists.
|
||||||
# Format: x1,x2,y1,y2,z1,z2
|
# Format: (x1,y1,z1),(x2,y2,z2)
|
||||||
verbana.jail_bounds (Bounding box of the verification jail) string
|
verbana.jail_bounds (Bounding box of the verification jail) string
|
||||||
|
|
||||||
# Period between checks that unverified players haven't escaped the verification area
|
# Period between checks that unverified players haven't escaped the verification area
|
||||||
|
|
27
util.lua
27
util.lua
|
@ -60,3 +60,30 @@ end
|
||||||
-- end
|
-- end
|
||||||
-- local TODO = 1 / nil
|
-- local TODO = 1 / nil
|
||||||
--end
|
--end
|
||||||
|
|
||||||
|
function verbana.util.safe(func)
|
||||||
|
-- wrap a function w/ logic to avoid crashing the game
|
||||||
|
return function(...)
|
||||||
|
local status, out = pcall(func, ...)
|
||||||
|
if status then
|
||||||
|
return out
|
||||||
|
else
|
||||||
|
verbana.log('warning', 'Error (func): %s', out)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function verbana.util.safe_kick_player(caller, player, reason)
|
||||||
|
local player_name = player:get_player_name()
|
||||||
|
verbana.log('action', 'kicking %s...', player_name)
|
||||||
|
if not verbana.settings.debug_mode then
|
||||||
|
if not minetest.kick_player(player_name, reason) then
|
||||||
|
player:set_detach()
|
||||||
|
if not minetest.kick_player(player_name, reason) then
|
||||||
|
minetest.chat_send_player(caller, ('Failed to kick player %s after detaching!'):format(player_name))
|
||||||
|
verbana.log('warning', 'Failed to kick player %s after detaching!', player_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
-- TODO: command line interface to manipulate the DB (e.g. for emergencies)
|
|
Loading…
Reference in New Issue