1 -- Minetest: builtin/auth.lua
4 -- Authentication handler
7 function core.string_to_privs(str, delim)
8 assert(type(str) == "string")
11 for _, priv in pairs(string.split(str, delim)) do
12 privs[priv:trim()] = true
17 function core.privs_to_string(privs, delim)
18 assert(type(privs) == "table")
21 for priv, bool in pairs(privs) do
23 table.insert(list, priv)
26 return table.concat(list, delim)
29 assert(core.string_to_privs("a,b").b == true)
30 assert(core.privs_to_string({a=true,b=true}) == "a,b")
32 core.auth_file_path = core.get_worldpath().."/auth.txt"
35 local function read_auth_file()
37 local file, errmsg = io.open(core.auth_file_path, 'rb')
39 core.log("info", core.auth_file_path.." could not be opened for reading ("..errmsg.."); assuming new world")
42 for line in file:lines() do
44 local fields = line:split(":", true)
45 local name, password, privilege_string, last_login = unpack(fields)
46 last_login = tonumber(last_login)
47 if not (name and password and privilege_string) then
48 error("Invalid line in auth.txt: "..dump(line))
50 local privileges = core.string_to_privs(privilege_string)
51 newtable[name] = {password=password, privileges=privileges, last_login=last_login}
55 core.auth_table = newtable
56 core.notify_authentication_modified()
59 local function save_auth_file()
61 -- Check table for validness before attempting to save
62 for name, stuff in pairs(core.auth_table) do
63 assert(type(name) == "string")
65 assert(type(stuff) == "table")
66 assert(type(stuff.password) == "string")
67 assert(type(stuff.privileges) == "table")
68 assert(stuff.last_login == nil or type(stuff.last_login) == "number")
70 local file, errmsg = io.open(core.auth_file_path, 'w+b')
72 error(core.auth_file_path.." could not be opened for writing: "..errmsg)
74 for name, stuff in pairs(core.auth_table) do
75 local priv_string = core.privs_to_string(stuff.privileges)
76 local parts = {name, stuff.password, priv_string, stuff.last_login or ""}
77 file:write(table.concat(parts, ":").."\n")
84 core.builtin_auth_handler = {
85 get_auth = function(name)
86 assert(type(name) == "string")
87 -- Figure out what password to use for a new player (singleplayer
88 -- always has an empty password, otherwise use default, which is
90 local new_password_hash = ""
91 -- If not in authentication table, return nil
92 if not core.auth_table[name] then
95 -- Figure out what privileges the player should have.
96 -- Take a copy of the privilege table
98 for priv, _ in pairs(core.auth_table[name].privileges) do
99 privileges[priv] = true
101 -- If singleplayer, give all privileges except those marked as give_to_singleplayer = false
102 if core.is_singleplayer() then
103 for priv, def in pairs(core.registered_privileges) do
104 if def.give_to_singleplayer then
105 privileges[priv] = true
108 -- For the admin, give everything
109 elseif name == core.setting_get("name") then
110 for priv, def in pairs(core.registered_privileges) do
111 privileges[priv] = true
116 password = core.auth_table[name].password,
117 privileges = privileges,
118 -- Is set to nil if unknown
119 last_login = core.auth_table[name].last_login,
122 create_auth = function(name, password)
123 assert(type(name) == "string")
124 assert(type(password) == "string")
125 core.log('info', "Built-in authentication handler adding player '"..name.."'")
126 core.auth_table[name] = {
128 privileges = core.string_to_privs(core.setting_get("default_privs")),
129 last_login = os.time(),
133 set_password = function(name, password)
134 assert(type(name) == "string")
135 assert(type(password) == "string")
136 if not core.auth_table[name] then
137 core.builtin_auth_handler.create_auth(name, password)
139 core.log('info', "Built-in authentication handler setting password of player '"..name.."'")
140 core.auth_table[name].password = password
145 set_privileges = function(name, privileges)
146 assert(type(name) == "string")
147 assert(type(privileges) == "table")
148 if not core.auth_table[name] then
149 core.builtin_auth_handler.create_auth(name,
150 core.get_password_hash(name,
151 core.setting_get("default_password")))
153 core.auth_table[name].privileges = privileges
154 core.notify_authentication_modified(name)
161 record_login = function(name)
162 assert(type(name) == "string")
163 assert(core.auth_table[name]).last_login = os.time()
168 function core.register_authentication_handler(handler)
169 if core.registered_auth_handler then
170 error("Add-on authentication handler already registered by "..core.registered_auth_handler_modname)
172 core.registered_auth_handler = handler
173 core.registered_auth_handler_modname = core.get_current_modname()
176 function core.get_auth_handler()
177 return core.registered_auth_handler or core.builtin_auth_handler
180 local function auth_pass(name)
182 local auth_handler = core.get_auth_handler()
183 if auth_handler[name] then
184 return auth_handler[name](...)
190 core.set_player_password = auth_pass("set_password")
191 core.set_player_privs = auth_pass("set_privileges")
192 core.auth_reload = auth_pass("reload")
195 local record_login = auth_pass("record_login")
197 core.register_on_joinplayer(function(player)
198 record_login(player:get_player_name())