Build 03
- added install option to database import script - improved exception handling by AuthFilter class - fixed parsing of number literals in rulesets - fixed type-checking of try statements in rulesets - included mod.conf and description.txt files
This commit is contained in:
parent
31875ec9e5
commit
a47562b251
27
README.txt
27
README.txt
|
@ -1,5 +1,5 @@
|
|||
Auth Redux Mod v2.1b
|
||||
By Leslie E. Krause
|
||||
Auth Redux Mod v2.2b
|
||||
By Leslie Krause
|
||||
|
||||
Auth Redux is a drop-in replacement for the builtin authentication handler of Minetest.
|
||||
It is designed from the ground up to be robust and secure enough for use on high-traffic
|
||||
|
@ -10,6 +10,16 @@ Auth Redux is intended to be compatible with all versions of Minetest 0.4.14+.
|
|||
|
||||
https://forum.minetest.net/viewtopic.php?f=9&t=20393
|
||||
|
||||
Repository
|
||||
----------------------
|
||||
|
||||
Browse source code:
|
||||
https://bitbucket.org/sorcerykid/auth_rx
|
||||
|
||||
Download archive:
|
||||
https://bitbucket.org/sorcerykid/auth_rx/get/master.zip
|
||||
https://bitbucket.org/sorcerykid/auth_rx/get/master.tar.gz
|
||||
|
||||
Revision History
|
||||
----------------------
|
||||
|
||||
|
@ -18,21 +28,26 @@ Version 2.1b (30-Jun-2018)
|
|||
- included code samples for basic login filtering
|
||||
- included a command-line database import script
|
||||
|
||||
Version 2.2b (04-Jul-2018)
|
||||
- added install option to database import script
|
||||
- improved exception handling by AuthFilter class
|
||||
- fixed parsing of number literals in rulesets
|
||||
- fixed type-checking of try statements in rulesets
|
||||
- included mod.conf and description.txt files
|
||||
|
||||
Installation
|
||||
----------------------
|
||||
|
||||
1) Unzip the archive into the mods directory of your game
|
||||
2) Rename the auth_rx-master directory to "auth_rx"
|
||||
3) Create an empty file named "auth.dbx" within the respective world directory
|
||||
4) Create an empty file named "greenlist.mt" within the respective world directory
|
||||
5) Execute the provided "convert.awk" script (refer to instructions)
|
||||
3) Execute the "convert.awk" script (refer to instructions)
|
||||
|
||||
Source Code License
|
||||
----------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2018, Leslie E. Krause
|
||||
Copyright (c) 2016-2018, Leslie Krause (leslie@searstower.org)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
|
|
|
@ -1,16 +1,52 @@
|
|||
#!/bin/awk -f
|
||||
# Database Import Script for Auth Redux (by Leslie Krause)
|
||||
|
||||
################################################################################
|
||||
# Database Import Script for Auth Redux Mod
|
||||
# ------------------------------------------
|
||||
# This script will convert the specified 'auth.txt' file into a database format
|
||||
# required by the Auth Redux Mod. The output file will be generated in the same
|
||||
# world directory as the original 'auth.txt' file (which will be unchanged).
|
||||
#
|
||||
# STEP 1: Run this script from within the world directory and redirect output to "auth.db"
|
||||
# awk -f auth.txt > auth.db
|
||||
# STEP 2: Rename 'auth.txt' to 'auth.bak' or move to a different location for safekeeping
|
||||
# Setting the mode to 'install' will automatically install the required journal
|
||||
# and ruleset files into the world directory as well.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# awk -f convert.awk -v mode=convert ~/.minetest/worlds/world/auth.txt
|
||||
################################################################################
|
||||
|
||||
function error( msg ) {
|
||||
print( msg " at line " NR " in " FILENAME "." ) > "/dev/stderr"
|
||||
skipped++;
|
||||
print msg " at line " NR " in " FILENAME ".";
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
FS = ":";
|
||||
OFS = ":";
|
||||
checked = 0;
|
||||
skipped = 0;
|
||||
|
||||
db_file = "auth.db";
|
||||
journal_file = "auth.dbx";
|
||||
ruleset_file = "greenlist.mt";
|
||||
|
||||
# determine output file name from arguments
|
||||
|
||||
path = ARGV[ 1 ]
|
||||
if( sub( /[-_A-Za-z0-9]+\.txt$/, "", path ) == 0 ) {
|
||||
# sanity check for nonstandard input file
|
||||
path = "";
|
||||
}
|
||||
|
||||
# install required journal and ruleset files
|
||||
|
||||
if( mode == "install" ) {
|
||||
print "Installing the required journal and ruleset files...";
|
||||
print "" > path journal_file
|
||||
print "pass now" > path ruleset_file
|
||||
}
|
||||
else if( mode != "convert" ) {
|
||||
print "Unknown argument, defaulting to convert mode.";
|
||||
}
|
||||
|
||||
# set default values for new database fields
|
||||
|
||||
|
@ -21,15 +57,15 @@ BEGIN {
|
|||
total_attempts = 0;
|
||||
total_sessions = 0;
|
||||
|
||||
# output the database header
|
||||
# TODO: perhaps add? strftime( "%Y-%m-%d %H:%M:%S" )
|
||||
# print database headline to the output file
|
||||
|
||||
print "auth_rx/2.1 @0"
|
||||
print "Converting " ARGV[ 1 ] "...";
|
||||
print "auth_rx/2.1 @0" > path db_file;
|
||||
}
|
||||
|
||||
NF != 4 {
|
||||
error( "Malformed record" )
|
||||
next
|
||||
error( "Malformed record" );
|
||||
next;
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -39,12 +75,12 @@ NF != 4 {
|
|||
newlogin = $4;
|
||||
|
||||
if( !match( username, "^[a-zA-Z0-9_-]+$" ) ) {
|
||||
error( "Invalid username field" )
|
||||
next
|
||||
error( "Invalid username field" );
|
||||
next;
|
||||
}
|
||||
if( !match( newlogin, "^[0-9]+$" ) && newlogin != -1 ) {
|
||||
error( "Invalid last_login field" )
|
||||
next
|
||||
error( "Invalid last_login field" );
|
||||
next;
|
||||
}
|
||||
|
||||
# Database File Format
|
||||
|
@ -60,5 +96,11 @@ NF != 4 {
|
|||
# approved_addrs
|
||||
# assigned_privs
|
||||
|
||||
print( username ":" password ":" oldlogin ":" newlogin ":" lifetime ":" total_sessions ":" total_attempts ":" total_failures ":" approved_addrs ":" assigned_privs );
|
||||
print username, password, oldlogin, newlogin, lifetime, total_sessions, total_attempts, total_failures, approved_addrs, assigned_privs > path db_file;
|
||||
|
||||
checked++;
|
||||
}
|
||||
|
||||
END {
|
||||
print "Done! " checked " of " ( checked + skipped ) " total records were imported to " db_file " (" skipped " records skipped)."
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Auth Redux is a drop-in replacement for the builtin authentication handler of Minetest. It is designed from the ground up to be robust and secure enough for use on high-traffic Minetest servers, while also addressing a number of outstanding engine bugs.
|
||||
|
||||
For more information: https://forum.minetest.net/viewtopic.php?f=9&t=20393
|
51
filter.lua
51
filter.lua
|
@ -1,5 +1,5 @@
|
|||
--------------------------------------------------------
|
||||
-- Minetest :: Auth Redux Mod v2.1 (auth_rx)
|
||||
-- Minetest :: Auth Redux Mod v2.2 (auth_rx)
|
||||
--
|
||||
-- See README.txt for licensing and release notes.
|
||||
-- Copyright (c) 2017-2018, Leslie E. Krause
|
||||
|
@ -60,9 +60,10 @@ function AuthFilter( path, name )
|
|||
-- private methods
|
||||
----------------------------
|
||||
|
||||
local throw = function ( msg, num )
|
||||
-- minetest.log( "error", msg .. " (line " .. num .. ")" )
|
||||
error( msg .. " (line " .. num .. ")" )
|
||||
local trace = function ( msg, num )
|
||||
-- TODO: Use 'pcall' for more graceful exception handling?
|
||||
minetest.log( "error", string.format( "%s (%s/%s, line %d)", msg, path, name, num ) )
|
||||
return "The server encountered an internal error."
|
||||
end
|
||||
|
||||
local get_operand = function ( token, vars )
|
||||
|
@ -117,7 +118,7 @@ function AuthFilter( path, name )
|
|||
v = string.gsub( v, "%$([a-zA-Z_]+)", function ( var )
|
||||
return vars[ var ] and tostring( vars[ var ].value ) or "?"
|
||||
end )
|
||||
elseif string.find( token, "^%d+$" ) then
|
||||
elseif string.find( token, "^-?%d+$" ) or string.find( token, "^-?%d*%.%d+$" ) then
|
||||
t = FILTER_TYPE_NUMBER
|
||||
v = tonumber( token )
|
||||
else
|
||||
|
@ -167,10 +168,10 @@ function AuthFilter( path, name )
|
|||
-- TODO: these should be stripped on file import
|
||||
|
||||
elseif stmt[ 1 ] == "continue" then
|
||||
if #stmt ~= 1 then throw( "Invalid 'continue' statement in ruleset", num ) end
|
||||
if #stmt ~= 1 then return trace( "Invalid 'continue' statement in ruleset", num ) end
|
||||
|
||||
if rule == nil then
|
||||
throw( "No ruleset declared", num )
|
||||
return trace( "No ruleset declared", num )
|
||||
end
|
||||
|
||||
if evaluate( rule ) then
|
||||
|
@ -180,19 +181,19 @@ function AuthFilter( path, name )
|
|||
rule = nil
|
||||
|
||||
elseif stmt[ 1 ] == "try" then
|
||||
if rule then throw( "Missing 'continue' statement in ruleset", num ) end
|
||||
if #stmt ~= 2 then throw( "Invalid 'try' statement in ruleset", num ) end
|
||||
if rule then return trace( "Missing 'continue' statement in ruleset", num ) end
|
||||
if #stmt ~= 2 then return trace( "Invalid 'try' statement in ruleset", num ) end
|
||||
|
||||
local oper = get_operand( stmt[ 2 ], vars )
|
||||
if not oper then
|
||||
throw( "Unrecognized operand in ruleset", num )
|
||||
if not oper or oper.type ~= FILTER_TYPE_STRING then
|
||||
return trace( "Unrecognized operand in ruleset", num )
|
||||
end
|
||||
|
||||
note = oper.value
|
||||
|
||||
elseif stmt[ 1 ] == "pass" or stmt[ 1 ] == "fail" then
|
||||
if rule then throw( "Missing continue statement in ruleset", num ) end
|
||||
if #stmt ~= 2 then throw( "Invalid 'pass' or 'fail' statement in ruleset", num ) end
|
||||
if rule then return trace( "Missing continue statement in ruleset", num ) end
|
||||
if #stmt ~= 2 then return trace( "Invalid 'pass' or 'fail' statement in ruleset", num ) end
|
||||
|
||||
rule = { }
|
||||
|
||||
|
@ -200,7 +201,7 @@ function AuthFilter( path, name )
|
|||
local bool = ( { ["all"] = FILTER_BOOL_AND, ["any"] = FILTER_BOOL_OR, ["one"] = FILTER_BOOL_XOR, ["now"] = FILTER_BOOL_NOW } )[ stmt[ 2 ] ]
|
||||
|
||||
if not mode or not bool then
|
||||
throw( "Unrecognized keywords in ruleset", num )
|
||||
return trace( "Unrecognized keywords in ruleset", num )
|
||||
end
|
||||
|
||||
if bool == FILTER_BOOL_NOW then
|
||||
|
@ -212,22 +213,22 @@ function AuthFilter( path, name )
|
|||
rule.expr = { }
|
||||
|
||||
elseif stmt[ 1 ] == "when" or stmt[ 1 ] == "until" then
|
||||
if #stmt ~= 4 then throw( "Invalid 'when' or 'until' statement in ruleset", num ) end
|
||||
if #stmt ~= 4 then return trace( "Invalid 'when' or 'until' statement in ruleset", num ) end
|
||||
|
||||
local cond = ( { ["when"] = FILTER_COND_TRUE, ["until"] = FILTER_COND_FALSE } )[ stmt[ 1 ] ]
|
||||
local comp = ( { ["eq"] = FILTER_COMP_EQ, ["is"] = FILTER_COMP_IS } )[ stmt[ 3 ] ]
|
||||
|
||||
if not cond or not comp then
|
||||
throw( "Unrecognized keywords in ruleset", num )
|
||||
return trace( "Unrecognized keywords in ruleset", num )
|
||||
end
|
||||
|
||||
local oper1 = get_operand( stmt[ 2 ], vars )
|
||||
local oper2 = get_operand( stmt[ 4 ], vars )
|
||||
|
||||
if not oper1 or not oper2 then
|
||||
throw( "Unrecognized operands in ruleset", num )
|
||||
return trace( "Unrecognized operands in ruleset", num )
|
||||
elseif oper1.type ~= FILTER_TYPE_SERIES then
|
||||
throw( "Mismatched operands in ruleset", num )
|
||||
return trace( "Mismatched operands in ruleset", num )
|
||||
end
|
||||
|
||||
-- cache second operand value for efficiency
|
||||
|
@ -244,7 +245,7 @@ function AuthFilter( path, name )
|
|||
elseif comp == FILTER_COMP_IS and oper2.type == FILTER_TYPE_PATTERN then
|
||||
expr = ( string.find( string.upper( value1 ), value2 ) == 1 )
|
||||
else
|
||||
throw( "Mismatched operands in ruleset", num )
|
||||
return trace( "Mismatched operands in ruleset", num )
|
||||
end
|
||||
if expr then break end
|
||||
end
|
||||
|
@ -253,20 +254,20 @@ function AuthFilter( path, name )
|
|||
table.insert( rule.expr, expr )
|
||||
|
||||
elseif stmt[ 1 ] == "if" or stmt[ 1 ] == "unless" then
|
||||
if #stmt ~= 4 then throw( "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 comp = ( { ["eq"] = FILTER_COMP_EQ, ["gt"] = FILTER_COMP_GT, ["lt"] = FILTER_COMP_LT, ["is"] = FILTER_COMP_IS } )[ stmt[ 3 ] ]
|
||||
|
||||
if not cond or not comp then
|
||||
throw( "Unrecognized keywords in ruleset", num )
|
||||
return trace( "Unrecognized keywords in ruleset", num )
|
||||
end
|
||||
|
||||
local oper1 = get_operand( stmt[ 2 ], vars )
|
||||
local oper2 = get_operand( stmt[ 4 ], vars )
|
||||
|
||||
if not oper1 or not oper2 then
|
||||
throw( "Unrecognized operands in ruleset", num )
|
||||
return trace( "Unrecognized operands in ruleset", num )
|
||||
end
|
||||
|
||||
-- FIXME: don't allow equality comparison of patterns or series
|
||||
|
@ -283,7 +284,7 @@ function AuthFilter( path, name )
|
|||
elseif comp == FILTER_COMP_LT and oper1.type == FILTER_TYPE_NUMBER and oper2.type == FILTER_TYPE_NUMBER then
|
||||
expr = ( oper1.value < oper2.value )
|
||||
else
|
||||
throw( "Mismatched operands in ruleset", num )
|
||||
return trace( "Mismatched operands in ruleset", num )
|
||||
end
|
||||
if cond == FILTER_COND_FALSE then expr = not expr end
|
||||
|
||||
|
@ -293,10 +294,10 @@ function AuthFilter( path, name )
|
|||
-- but probably requires state table; efficiency vs complexity scenario
|
||||
|
||||
else
|
||||
throw( "Invalid statement in ruleset", num )
|
||||
return trace( "Invalid statement in ruleset", num )
|
||||
end
|
||||
end
|
||||
throw( "Unexpected end-of-file in ruleset", num )
|
||||
return trace( "Unexpected end-of-file in ruleset", 0 )
|
||||
end
|
||||
|
||||
return self
|
||||
|
|
Loading…
Reference in New Issue