Build 04
- general code cleanup of AuthFilter class - moved datasets into separate directory of world - added two more comparison operators for rulesets - tweaked pattern matching behavior in rulesets - changed database search method to use Lua regexes - removed hard-coded file names from database methods
This commit is contained in:
parent
a47562b251
commit
abaa02b036
10
README.txt
10
README.txt
@ -1,4 +1,4 @@
|
|||||||
Auth Redux Mod v2.2b
|
Auth Redux Mod v2.3b
|
||||||
By Leslie Krause
|
By Leslie Krause
|
||||||
|
|
||||||
Auth Redux is a drop-in replacement for the builtin authentication handler of Minetest.
|
Auth Redux is a drop-in replacement for the builtin authentication handler of Minetest.
|
||||||
@ -35,6 +35,14 @@ Version 2.2b (04-Jul-2018)
|
|||||||
- fixed type-checking of try statements in rulesets
|
- fixed type-checking of try statements in rulesets
|
||||||
- included mod.conf and description.txt files
|
- included mod.conf and description.txt files
|
||||||
|
|
||||||
|
Version 2.3b (08-Jul-2018)
|
||||||
|
- general code cleanup of AuthFilter class
|
||||||
|
- moved datasets into separate directory of world
|
||||||
|
- added two more comparison operators for rulesets
|
||||||
|
- tweaked pattern matching behavior in rulesets
|
||||||
|
- changed database search method to use Lua regexes
|
||||||
|
- removed hard-coded file names from database methods
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
63
filter.lua
63
filter.lua
@ -1,5 +1,5 @@
|
|||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
-- Minetest :: Auth Redux Mod v2.2 (auth_rx)
|
-- Minetest :: Auth Redux Mod v2.3 (auth_rx)
|
||||||
--
|
--
|
||||||
-- See README.txt for licensing and release notes.
|
-- See README.txt for licensing and release notes.
|
||||||
-- Copyright (c) 2017-2018, Leslie E. Krause
|
-- Copyright (c) 2017-2018, Leslie E. Krause
|
||||||
@ -22,8 +22,10 @@ FILTER_COND_FALSE = 40
|
|||||||
FILTER_COND_TRUE = 41
|
FILTER_COND_TRUE = 41
|
||||||
FILTER_COMP_EQ = 50
|
FILTER_COMP_EQ = 50
|
||||||
FILTER_COMP_GT = 51
|
FILTER_COMP_GT = 51
|
||||||
FILTER_COMP_LT = 52
|
FILTER_COMP_GTE = 52
|
||||||
FILTER_COMP_IS = 53
|
FILTER_COMP_LT = 53
|
||||||
|
FILTER_COMP_LTE = 54
|
||||||
|
FILTER_COMP_IS = 55
|
||||||
|
|
||||||
----------------------------
|
----------------------------
|
||||||
-- AuthFilter class
|
-- AuthFilter class
|
||||||
@ -77,10 +79,10 @@ function AuthFilter( path, name )
|
|||||||
t = vars[ var ].type
|
t = vars[ var ].type
|
||||||
v = vars[ var ].value
|
v = vars[ var ].value
|
||||||
end
|
end
|
||||||
elseif string.find( token, "^@[a-zA-Z._-]*$" ) then
|
elseif string.find( token, "^@[a-zA-Z0-9_]*%.txt$" ) then
|
||||||
t = FILTER_TYPE_SERIES
|
t = FILTER_TYPE_SERIES
|
||||||
v = { }
|
v = { }
|
||||||
local file = io.open( path .. "/" .. string.sub( token, 2 ), "rb" )
|
local file = io.open( path .. "/filters/" .. string.sub( token, 2 ), "rb" )
|
||||||
if not file then
|
if not file then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@ -91,24 +93,26 @@ function AuthFilter( path, name )
|
|||||||
-- sanitize search phrase and convert to regexp pattern
|
-- sanitize search phrase and convert to regexp pattern
|
||||||
local sanitizer =
|
local sanitizer =
|
||||||
{
|
{
|
||||||
["["] = "";
|
["["] = "",
|
||||||
["]"] = "";
|
["]"] = "",
|
||||||
["^"] = "%^";
|
["^"] = "%^",
|
||||||
["$"] = "%$";
|
["$"] = "%$",
|
||||||
["("] = "%(";
|
["("] = "%(",
|
||||||
[")"] = "%)";
|
[")"] = "%)",
|
||||||
["%"] = "%%";
|
["%"] = "%%",
|
||||||
["."] = "%.";
|
["-"] = "%-",
|
||||||
["-"] = "%-";
|
["."] = "[a-z]",
|
||||||
["*"] = "[a-zA-Z0-9_-]*";
|
["!"] = "[A-Z]",
|
||||||
["+"] = "[a-zA-Z0-9_-]+";
|
["*"] = "[a-zA-Z0-9_-]*",
|
||||||
["?"] = "[a-zA-Z0-9_-]";
|
["+"] = "[a-zA-Z0-9_-]+",
|
||||||
["#"] = "%d";
|
["?"] = "[a-zA-Z0-9_-]",
|
||||||
["~"] = "%a";
|
["#"] = "%d",
|
||||||
|
["~"] = "%a",
|
||||||
}
|
}
|
||||||
|
|
||||||
t = FILTER_TYPE_PATTERN
|
t = FILTER_TYPE_PATTERN
|
||||||
v = minetest.decode_base64( string.sub( token, 2 ) )
|
v = minetest.decode_base64( string.sub( token, 2 ) )
|
||||||
v = "^" .. string.gsub( string.upper( v ), ".", sanitizer ) .. "$"
|
v = "^" .. string.gsub( v, ".", sanitizer ) .. "$"
|
||||||
elseif string.find( token, "^'.*$" ) then
|
elseif string.find( token, "^'.*$" ) then
|
||||||
t = FILTER_TYPE_STRING
|
t = FILTER_TYPE_STRING
|
||||||
v = minetest.decode_base64( string.sub( token, 2 ) )
|
v = minetest.decode_base64( string.sub( token, 2 ) )
|
||||||
@ -235,15 +239,16 @@ function AuthFilter( path, name )
|
|||||||
-- TODO: might want to move the redundant operand type checks out of loop?
|
-- TODO: might want to move the redundant operand type checks out of loop?
|
||||||
|
|
||||||
local value2 = ( comp == FILTER_COMP_IS and oper2.type == FILTER_TYPE_STRING ) and string.upper( oper2.value ) or oper2.value
|
local value2 = ( comp == FILTER_COMP_IS and oper2.type == FILTER_TYPE_STRING ) and string.upper( oper2.value ) or oper2.value
|
||||||
|
local type2 = oper2.type
|
||||||
local expr = false
|
local expr = false
|
||||||
|
|
||||||
for i, value1 in ipairs( oper1.value ) do
|
for i, value1 in ipairs( oper1.value ) do
|
||||||
if comp == FILTER_COMP_EQ and oper2.type == FILTER_TYPE_STRING then
|
if comp == FILTER_COMP_EQ and type2 == FILTER_TYPE_STRING then
|
||||||
expr = ( value1 == value2 )
|
expr = ( value1 == value2 )
|
||||||
elseif comp == FILTER_COMP_IS and oper2.type == FILTER_TYPE_STRING then
|
elseif comp == FILTER_COMP_IS and type2 == FILTER_TYPE_STRING then
|
||||||
expr = ( string.upper( value1 ) == value2 )
|
expr = ( string.upper( value1 ) == value2 )
|
||||||
elseif comp == FILTER_COMP_IS and oper2.type == FILTER_TYPE_PATTERN then
|
elseif comp == FILTER_COMP_IS and type2 == FILTER_TYPE_PATTERN then
|
||||||
expr = ( string.find( string.upper( value1 ), value2 ) == 1 )
|
expr = ( string.find( value1, value2 ) == 1 )
|
||||||
else
|
else
|
||||||
return trace( "Mismatched operands in ruleset", num )
|
return trace( "Mismatched operands in ruleset", num )
|
||||||
end
|
end
|
||||||
@ -257,7 +262,7 @@ function AuthFilter( path, name )
|
|||||||
if #stmt ~= 4 then return trace( "Invalid 'if' or 'unless' statement in ruleset", num ) end
|
if #stmt ~= 4 then return trace( "Invalid 'if' or 'unless' statement in ruleset", num ) end
|
||||||
|
|
||||||
local cond = ( { ["if"] = FILTER_COND_TRUE, ["unless"] = FILTER_COND_FALSE } )[ stmt[ 1 ] ]
|
local cond = ( { ["if"] = FILTER_COND_TRUE, ["unless"] = FILTER_COND_FALSE } )[ stmt[ 1 ] ]
|
||||||
local comp = ( { ["eq"] = FILTER_COMP_EQ, ["gt"] = FILTER_COMP_GT, ["lt"] = FILTER_COMP_LT, ["is"] = FILTER_COMP_IS } )[ stmt[ 3 ] ]
|
local comp = ( { ["eq"] = FILTER_COMP_EQ, ["gt"] = FILTER_COMP_GT, ["lt"] = FILTER_COMP_LT, ["gte"] = FILTER_COMP_GTE, ["lte"] = FILTER_COMP_LTE, ["is"] = FILTER_COMP_IS } )[ stmt[ 3 ] ]
|
||||||
|
|
||||||
if not cond or not comp then
|
if not cond or not comp then
|
||||||
return trace( "Unrecognized keywords in ruleset", num )
|
return trace( "Unrecognized keywords in ruleset", num )
|
||||||
@ -270,19 +275,21 @@ function AuthFilter( path, name )
|
|||||||
return trace( "Unrecognized operands in ruleset", num )
|
return trace( "Unrecognized operands in ruleset", num )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FIXME: don't allow equality comparison of patterns or series
|
|
||||||
|
|
||||||
local expr
|
local expr
|
||||||
if comp == FILTER_COMP_EQ and oper1.type == oper2.type and oper1.type ~= FILTER_TYPE_SERIES and oper1.type ~= FILTER_TYPE_PATTERN then
|
if comp == FILTER_COMP_EQ and oper1.type == oper2.type and oper1.type ~= FILTER_TYPE_SERIES and oper1.type ~= FILTER_TYPE_PATTERN then
|
||||||
expr = ( oper1.value == oper2.value )
|
expr = ( oper1.value == oper2.value )
|
||||||
elseif comp == FILTER_COMP_IS and oper1.type == FILTER_TYPE_STRING and oper2.type == FILTER_TYPE_STRING then
|
elseif comp == FILTER_COMP_IS and oper1.type == FILTER_TYPE_STRING and oper2.type == FILTER_TYPE_STRING then
|
||||||
expr = ( string.upper( oper1.value ) == string.upper( oper2.value ) )
|
expr = ( string.upper( oper1.value ) == string.upper( oper2.value ) )
|
||||||
elseif comp == FILTER_COMP_IS and oper1.type == FILTER_TYPE_STRING and oper2.type == FILTER_TYPE_PATTERN then
|
elseif comp == FILTER_COMP_IS and oper1.type == FILTER_TYPE_STRING and oper2.type == FILTER_TYPE_PATTERN then
|
||||||
expr = ( string.find( string.upper( oper1.value ), oper2.value ) == 1 )
|
expr = ( string.find( oper1.value, oper2.value ) == 1 )
|
||||||
elseif comp == FILTER_COMP_GT and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
elseif comp == FILTER_COMP_GT and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
||||||
expr = ( oper1.value > oper2.value )
|
expr = ( oper1.value > oper2.value )
|
||||||
elseif comp == FILTER_COMP_LT and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
elseif comp == FILTER_COMP_LT and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
||||||
expr = ( oper1.value < oper2.value )
|
expr = ( oper1.value < oper2.value )
|
||||||
|
elseif comp == FILTER_COMP_GTE and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
||||||
|
expr = ( oper1.value >= oper2.value )
|
||||||
|
elseif comp == FILTER_COMP_LTE and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
||||||
|
expr = ( oper1.value <= oper2.value )
|
||||||
else
|
else
|
||||||
return trace( "Mismatched operands in ruleset", num )
|
return trace( "Mismatched operands in ruleset", num )
|
||||||
end
|
end
|
||||||
|
55
init.lua
55
init.lua
@ -1,5 +1,5 @@
|
|||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
-- Minetest :: Auth Redux Mod v2.1 (auth_rx)
|
-- Minetest :: Auth Redux Mod v2.3 (auth_rx)
|
||||||
--
|
--
|
||||||
-- See README.txt for licensing and release notes.
|
-- See README.txt for licensing and release notes.
|
||||||
-- Copyright (c) 2017-2018, Leslie E. Krause
|
-- Copyright (c) 2017-2018, Leslie E. Krause
|
||||||
@ -112,34 +112,12 @@ end
|
|||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
local AuthDatabase = function ( path, name )
|
local AuthDatabase = function ( path, name )
|
||||||
local data, size, users, index
|
local data, users, index
|
||||||
local self = { }
|
local self = { }
|
||||||
local journal = Journal( path, name .. "x" )
|
local journal = Journal( path, name .. "x" )
|
||||||
|
|
||||||
-- Private methods
|
-- Private methods
|
||||||
|
|
||||||
local find_phrase = function( source, phrase )
|
|
||||||
-- sanitize search phrase and convert to regexp pattern
|
|
||||||
local sanitizer =
|
|
||||||
{
|
|
||||||
["^"] = "%^";
|
|
||||||
["$"] = "%$";
|
|
||||||
["("] = "%(";
|
|
||||||
[")"] = "%)";
|
|
||||||
["%"] = "%%";
|
|
||||||
["."] = "%.";
|
|
||||||
["["] = "";
|
|
||||||
["]"] = "";
|
|
||||||
["*"] = "%w*";
|
|
||||||
["+"] = "%w+";
|
|
||||||
["-"] = "%-";
|
|
||||||
["?"] = "%w";
|
|
||||||
}
|
|
||||||
|
|
||||||
-- parens capture only first return value of gsub
|
|
||||||
return string.find( source, ( string.gsub( phrase, ".", sanitizer ) ) )
|
|
||||||
end
|
|
||||||
|
|
||||||
local db_update = function( meta, optime, opcode, ... )
|
local db_update = function( meta, optime, opcode, ... )
|
||||||
local fields = { ... }
|
local fields = { ... }
|
||||||
|
|
||||||
@ -205,9 +183,9 @@ local AuthDatabase = function ( path, name )
|
|||||||
local db_reload = function ( )
|
local db_reload = function ( )
|
||||||
minetest.log( "action", "Reading authentication data from disk..." )
|
minetest.log( "action", "Reading authentication data from disk..." )
|
||||||
|
|
||||||
local file, errmsg = io.open( path .. "/auth.db", "r+b" )
|
local file, errmsg = io.open( path .. "/" .. name, "r+b" )
|
||||||
if not file then
|
if not file then
|
||||||
minetest.log( "error", "Cannot open " .. path .. "/auth.db for reading." )
|
minetest.log( "error", "Cannot open " .. path .. "/" .. name .. " for reading." )
|
||||||
error( "Fatal exception in AuthDatabase:reload( ), aborting." )
|
error( "Fatal exception in AuthDatabase:reload( ), aborting." )
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -237,7 +215,6 @@ local AuthDatabase = function ( path, name )
|
|||||||
approved_addrs = string.split( fields[ 9 ], "," ),
|
approved_addrs = string.split( fields[ 9 ], "," ),
|
||||||
assigned_privs = string.split( fields[ 10 ], "," ),
|
assigned_privs = string.split( fields[ 10 ], "," ),
|
||||||
}
|
}
|
||||||
size = size + 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
file:close( )
|
file:close( )
|
||||||
@ -271,14 +248,13 @@ local AuthDatabase = function ( path, name )
|
|||||||
end
|
end
|
||||||
file:close( )
|
file:close( )
|
||||||
|
|
||||||
assert( os.remove( path .. "/auth.db" ) )
|
assert( os.remove( path .. "/" .. name ) )
|
||||||
assert( os.rename( path .. "/~auth.db", path .. "/auth.db" ) )
|
assert( os.rename( path .. "/~" .. name, path .. "/" .. name ) )
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Public methods
|
-- Public methods
|
||||||
|
|
||||||
self.connect = function ( )
|
self.connect = function ( )
|
||||||
size = 0
|
|
||||||
data = { }
|
data = { }
|
||||||
users = { }
|
users = { }
|
||||||
|
|
||||||
@ -296,7 +272,6 @@ local AuthDatabase = function ( path, name )
|
|||||||
journal.reset( )
|
journal.reset( )
|
||||||
|
|
||||||
data = nil
|
data = nil
|
||||||
size = nil
|
|
||||||
users = nil
|
users = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -317,7 +292,6 @@ local AuthDatabase = function ( path, name )
|
|||||||
assigned_privs = { },
|
assigned_privs = { },
|
||||||
}
|
}
|
||||||
data[ username ] = rec
|
data[ username ] = rec
|
||||||
size = size + 1
|
|
||||||
journal.record_raw( TX_CREATE, username, password )
|
journal.record_raw( TX_CREATE, username, password )
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -328,7 +302,6 @@ local AuthDatabase = function ( path, name )
|
|||||||
if not data[ username ] or users[ username ] then return false end
|
if not data[ username ] or users[ username ] then return false end
|
||||||
|
|
||||||
data[ username ] = nil
|
data[ username ] = nil
|
||||||
size = size - 1
|
|
||||||
journal.record_raw( TX_DELETE, username )
|
journal.record_raw( TX_DELETE, username )
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -392,15 +365,19 @@ local AuthDatabase = function ( path, name )
|
|||||||
return pairs( data )
|
return pairs( data )
|
||||||
end
|
end
|
||||||
|
|
||||||
self.records_match = function ( phrase )
|
self.records_match = function ( pattern )
|
||||||
local k
|
local k
|
||||||
return function ( )
|
return function ( )
|
||||||
local v
|
local v
|
||||||
local p = string.lower( phrase )
|
local p = string.lower( pattern )
|
||||||
|
|
||||||
k, v = next( data, k )
|
while true do
|
||||||
if find_phrase( string.lower( k ), p ) then
|
k, v = next( data, k )
|
||||||
return k, v
|
if not k then
|
||||||
|
return
|
||||||
|
elseif string.match( string.lower( k ), p ) then
|
||||||
|
return k, v
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -479,8 +456,6 @@ minetest.register_on_prejoinplayer( function ( player_name, player_ip )
|
|||||||
attempts = { type = FILTER_TYPE_NUMBER, value = rec and rec.total_attempts or 0 },
|
attempts = { type = FILTER_TYPE_NUMBER, value = rec and rec.total_attempts or 0 },
|
||||||
} )
|
} )
|
||||||
|
|
||||||
-- TODO: Add optional filter logging capabilities
|
|
||||||
|
|
||||||
return filter_err
|
return filter_err
|
||||||
end )
|
end )
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user