- 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:
Leslie Krause 2018-07-04 14:07:00 -04:00
parent 31875ec9e5
commit a47562b251
5 changed files with 111 additions and 46 deletions

View File

@ -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

72
convert.awk Executable file → Normal file
View File

@ -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)."
}

3
description.txt Normal file
View File

@ -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

View File

@ -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

4
mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = auth_rx
title = Auth Redux
author = sorcerykid
license = MIT