Giter VIP home page Giter VIP logo

sauth's Introduction

sauth v2.0

Build status License: MIT

IMPORTANT: Version 2 changes the DB schema inline with the core auth schema. The existing sauth.sqlite will be converted so make a backup! ONLY USE with minetest version 0.5 or greater.

Sauth is an alternative sqlite3 auth handler for minetest. Capable of handling large player databases and provides mitigation of auth entry request load by use of memory caching. Fine tune your servers auth memory load by caching clients who play regularly to reduce join event load on the server, resulting in a better playability experience on servers with many player accounts.

Requires:

I suggest you use luarocks (https://luarocks.org/) to install lsqlite3.

sudo apt install luarocks
luarocks install lsqlite3

Your server should always run mods in secure mode, you must add sauth to the list of trusted mods in minetest.conf for example:

secure.trusted_mods = irc,sauth

You can and should use your existing auth db, make a copy of auth.sqlite renaming it to sauth.sqlite BEFORE starting the server.

To enable the mod for singleplayer add:

sauth.enable_singleplayer = true

to minetest.conf before starting the server.

Caching comes at the expense of memory consumption. During server startup sauth initialises the cache with up to 500 players who logged in to the server in the last 24 hours before the last player to login prior to shutdown. You can manage the cache by adding these settings to minetest.conf and modifying the values otherwise the mod will use the hard coded defaults.

sauth.cache_max = 500 -- default maximum number of memory cached entries on startup
sauth.cache_ttl = 86400 -- default seconds deducted from last login

Uninstalling

If/when you want to remove sauth just delete the mod and minetest will default back to using the internal auth handler on the same db, it's as simple as that!

sauth's People

Contributors

rubenwardy avatar shivajiva101 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

rubenwardy sofar

sauth's Issues

Crash with IRC auto-login

I recently realized my auto-update script was broken, I fixed it and was greeted with a crash.

Error line: https://github.com/shivajiva101/sauth/blob/0.5/init.lua#L305
Backtrace #1: https://github.com/MT-CTF/irc_commands/blob/master/init.lua#L163

I added some debug to see what index was nil, it appears to be cache[name] with name being Thomas-S (A valid player)

2022-08-27 16:12:56: ACTION[Main]: Server for gameid="capturetheflag" listening on [::]:30001.
2022-08-27 16:13:04: ACTION[Server]: IRC: Connected!
2022-08-27 16:13:10: ACTION[Server]: IRC CHAT: -!- CTF_Bot joined ##minetest-ctf
2022-08-27 16:13:11: ACTION[Server]: User Thomas-S from IRC logs in as Thomas-S
2022-08-27 16:13:11: ERROR[Server]: _missing "Thomas-S" | nil
2022-08-27 16:13:11: ACTION[Main]: Server: Shutting down
2022-08-27 16:13:11: ACTION[Main]: IRC: Disconnected.
2022-08-27 16:13:11: ERROR[Main]: ServerError: AsyncErr: Lua: Runtime error from mod 'irc' in callback environment_Step(): ...st/bin/../worlds/ctf/worldmods/servermods/sauth/init.lua:308: attempt to index a nil value
2022-08-27 16:13:11: ERROR[Main]: stack traceback:
2022-08-27 16:13:11: ERROR[Main]: 	...st/bin/../worlds/ctf/worldmods/servermods/sauth/init.lua:308: in function 'record_login'
2022-08-27 16:13:11: ERROR[Main]: 	...../worlds/ctf/worldmods/servermods/irc_commands/init.lua:163: in function 'check_host_login'
2022-08-27 16:13:11: ERROR[Main]: 	...../worlds/ctf/worldmods/servermods/irc_commands/init.lua:171: in function 'func'
2022-08-27 16:13:11: ERROR[Main]: 	/home/minetest/minetest/bin/../builtin/common/after.lua:20: in function </home/minetest/minetest/bin/../builtin/common/after.lua:5>
2022-08-27 16:13:11: ERROR[Main]: 	/home/minetest/minetest/bin/../builtin/game/register.lua:429: in function </home/minetest/minetest/bin/../builtin/game/register.lua:415>

Thomas-S logged in through the irc_host feature added to our fork of irc_commands https://github.com/MT-CTF/irc_commands/
I'm not familiar with the IRC code so this might be an issue on our side

Cache creation crashes the server if the auth database is empty (new server)

Hello,

I just created a new server (empty auth db) and I get this error when trying to start it:

2022-04-29 18:10:18: ERROR[Main]: ModError: Failed to load and run script from /home/minetest/mt2/bin/../mods/sauth/init.lua:
2022-04-29 18:10:18: ERROR[Main]: /home/minetest/mt2/bin/../mods/sauth/init.lua:63: attempt to perform arithmetic on field 'result' (a nil value)
2022-04-29 18:10:18: ERROR[Main]: stack traceback:
2022-04-29 18:10:18: ERROR[Main]:       /home/minetest/mt2/bin/../mods/sauth/init.lua:63: in function 'create_cache'
2022-04-29 18:10:18: ERROR[Main]:       /home/minetest/mt2/bin/../mods/sauth/init.lua:106: in main chunk

I should mention that I am using the minetest tagged version 5.5.0, and latest available sauth on the 0.5 branch.

As a test, I tried to copy the sauth.sqlite database from another servers and indeed the crash does not happen. I suspect a missing nil check, perhaps?

Changing password of offline player results in crash.

It seems sauth.auth_handler.set_password will attempt to add password to empty cache table of offline player resulting in a crash. I only tested on online players yesterday.

A quick and likely dirty fix confirms and seems to resolve this:

	set_password = function(name, password)
		assert(type(name) == 'string')
		assert(type(password) == 'string')
		-- get player record
		if get_record(name) == nil then
			sauth.auth_handler.create_auth(name, password)
		else
			-- if player offline, don't touch cash or crash
			if auth_table[name] == nil then
				update_password(name, password)
			else			
				update_password(name, password)
				auth_table[name].password = password
			end
		end
		return true
	end,

Mods using auth_table (default auth handler) may lag server with sauth handler.

This isn't a issue you will likely be able to avoid with this mod, but I thought you would like to know.
One of our reasons for sauth being unusable on our server was that we used the Name Restrictions mod.

The name restriction mod goes through the entire auth_table supplied by the auth.txt with several intensive searches. As sauth's auth_table is cached, many hundreds of records are queried and compared for lots of things. As this happens on minetest.register_on_prejoinplayer, the cause of the lag isn't easily discovered.
As I depend on the name_restrictions mod. I made use of sauth's sqlite3 connection and made a custom query to load all names into a table on startup. Then I modified the name_restrictions mod to use that name cache rather than hit the auth_table.

Now that we are actually able to use sauth, and have the luxury of working with a database rather than a text file, we are thrilled with all the hard work you've done on sauth.
Thanks!

auth.sql doesn't update _s import correctly

When trying to populate the sauth.sqlite with .read auth.sql, I noted a syntax error message from sqlite3 cli.
I found that column "import" in table "_s" would not update from false to true as a result of the error.

I'm sure there's a prettier way, but changing:
stmt = "UPDATE _s (import) VALUES ('true');\n"
to

stmt = "UPDATE _s SET import='true';\n"
Resolved this for me.

One reason database was getting hit hard with massive requests on our server.

You may remember I was having issues with massive lag on our server that was resolved by removing sauth and reverting to the original auth_handler.
I could not duplicate on a dev server that was a exact clone of our server without first trying out sauth again multiple times on the production server with added "debug" lines in the sauth code.
I found that the call to the function "get_record(name)" within the "get_auth" was repeatedly trying to get a record without a player name.
I found that protector_redo checks the privs of a "digger" with any digging. This also applies to mobs. Like sheep eating grass. The sheeps privs are checked, and they don't have a player name :D
This can also be confirmed when using TNT. One TNT will cause 9 get_records to occur without a player name. 9 TNT's made 2098 queries. At nearly the same time!

My work around was to reject requests for records without a player name. With a few days in production it seems to work without any known (so far) bad side affects. I think I'd rather prevent the protection mod from making the priv checks to begin with, but my attempt broke TNT from doing damage to surrounding nodes (ooops)

This is what I did to reject the requests, and give a message about the no name record request:

		-- Return password,privileges,last_login
		assert(type(name) == 'string')

		if name == nil or name == '' or name == ' ' then
			minetest.log("sauth_handler: Name was missing in call to get_auth. Rejected.")
			return nil
		end

		add_to_cache = add_to_cache or true -- Assert caching on missing param
		local r = auth_table[name]
		-- Check and load db record if reqd
		if r == nil then
			minetest.log("get_record from get_auth: "..name)
			r = get_record(name)
	  	else
		  	return auth_table[name]	-- cached copy			
	  	end
		-- Return nil on missing entry

Hope this is useful to someone.

For posterity: A script to migrate *away* from `sauth` to regular sqlite3 auth

I used this script to migrate my server from sauth to auth. There's not enough reason for me right now to maintain a server with a very uncommon auth backend. More people may be interested in this, so I'm leaving it here as-is. Could be maybe merged, or posted on the wiki, or something. Don't really care :).

#!/bin/env python3

# copy all auth entries from an sauth.sqlite file into an existing
# (but empty) auth.sqlite from minetest's normal sqlite3 auth backend

# You'll need an auth.sqlite file from just any minetest world. This
# script will delete all the entries from it. Or you can manually create
# an empty auth.sqlite.

# sauth has a small bug where there may be duplicate `name` entries in the
# auth table, and this script works around them with a `try: except:`
# block. Otherwise it's a very straight copy over of auth and privileges.

# make sure to edit `world.mt` after this runs to assure `auth_backend = sqlite3`
# and `load_mod_sauth = false`

import sqlite3
import sys

try:
    from_name = sys.argv[1]
    to_name = sys.argv[2]
except:
    print("Usage: $0 from_db.sqlite3 to_db.sqlite3")
    exit();

try:
    from_db = sqlite3.connect(from_name)
except:
    print("$1 must be the path to sauth.sqlite3")
    exit();

try:
    to_db = sqlite3.connect(to_name)
except:
    print("$2 must be the path to auth.sqlite3")
    exit();


print("This program will import all auth entries from " + from_name)
print("and import them into " + to_name + ".")
print("to do this, it has to delete all the entries in " + to_name)
print("if you don't want this, press ^C now")

input("Press Enter to continue...")

from_cur = from_db.cursor()
to_cur = to_db.cursor()

print("Deleting all content from " + to_name)
to_cur.execute("delete from auth;")
to_db.commit()
to_cur.execute("delete from user_privileges;")
to_db.commit()

count = 0
last_id = 0

print("Copying entries...")
for row in from_cur.execute("SELECT id, name, password, privileges, last_login FROM auth;"):
    count += 1
    if count % 100 == 0:
        print(count)

    last_id = row[0]

    try:
        to_cur.execute("INSERT INTO auth (id, name, password, last_login) VALUES ("
                       + str(row[0]) + ", \"" + row[1] + "\", \"" + row[2] + "\", "
                       + str(row[4]) + ");")
        to_db.commit()
    except:
        print("An error occured for id " + str(row[0]) + " - skipping")
        continue

    try:
        for priv in row[3].replace(" ", "").split(","):
            to_cur.execute("INSERT INTO user_privileges (id, privilege) VALUES ("
                           + str(row[0]) + ", \"" + priv + "\");")
            to_db.commit()
    except:
        print("An error occured for id " + str(row[0]) + " - skipping")
        continue

print(str(count) + " records written, last id = " + str(last_id)) 

# end
from_db.close()
to_db.commit()
to_db.close()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.