settings.define("auth_server.salt", { description = "Salt for hashing passwords", type = "string", default = "3m&LmNm7" }) local data = { users = {} } -- Schema: -- data = { -- users = { -- ["username"] = { -- token = "token", -- password = "hashed password", -- groups = { -- ["group"] = true -- }, -- }, -- } function save_data() db = fs.open("auth.db", "w") db.write(textutils.serialize(data)) db.close() end function load_data() if fs.exists("auth.db") then db = fs.open("auth.db", "r") db_contents = db.readAll() db.close() data = textutils.unserialize(db_contents) end end function generate_token(user) local token = sha256.sha256(user .. os.time() .. math.random()) data.users[user].token = token return token end function convert_password(password) local salt = settings.get("auth_server.salt") return sha256.sha256(password .. salt) end function log(str) io.write("[" .. os.time() .. "] " .. str .. "\n") end function countElements(table) local count = 0 for key, value in pairs(table) do count = count + 1 end return count end load_data() math.randomseed(os.time()) while true do client_id, msg = rednet.receive("auth") request = msg if request.action == nil then rednet.send(client_id, "invalid request", "auth") end if request.action == "register" then if request.username == nil or request.password == nil then rednet.send(client_id, "invalid request", "auth") end if data.users[request.username] ~= nil then rednet.send(client_id, "user already exists", "auth") end data.users[request.username] = { password = convert_password(request.password) } local user_count = countElements(data.users) if user_count == 1 then log("Promoting " .. request.username .. " to admin") data.users[request.username].groups = { ["admin"] = true } end save_data() rednet.send(client_id, "ok", "auth") log(request.username .. " registered") end if request.action == "login" then if request.username == nil or request.password == nil then rednet.send(client_id, "invalid request", "auth") elseif data.users[request.username] == nil then rednet.send(client_id, "user not found", "auth") log(request.username .. " failed log in attempt") elseif convert_password(request.password) == data.users[request.username].password then local token = generate_token(request.username) rednet.send(client_id, token, "auth") log(request.username .. " logged in") else rednet.send(client_id, "invalid password", "auth") end end if request.action == "token" then if request.token == nil or request.token == "" or request.token == -1 then rednet.send(client_id, "invalid request", "auth") else local found = false for user, userdata in pairs(data.users) do if userdata.token == request.token then rednet.send(client_id, user, "auth") found = true end end if not found then rednet.send(client_id, "invalid token", "auth") end end end if request.action == "profile" then if request.username == nil then rednet.send(client_id, "invalid request", "auth") end local profile = {} if data.users[request.username].profile_data ~= nil then profile = data.users[request.username].profile_data else profile.display_name = request.username end profile.username = request.username rednet.send(client_id, data.users[request.username], "auth") end if request.action == "update_profile" then if request.username == nil or request.token == nil then rednet.send(client_id, "invalid request", "auth") end if data.users[request.username].token == request.token then if request.profile_data ~= nil then data.users[request.username].profile_data = request.profile_data end save_data() rednet.send(client_id, "ok") log(request.username .. " updated their profile", "auth") else rednet.send(client_id, "invalid token", "auth") end end if request.action == "check_group" then if request.username == nil or request.group == nil then rednet.send(client_id, "invalid request", "auth") end if data.users[request.username].groups == nil or data.users[request.username].groups[request.group] == nil or data.users[request.username].groups[request.group] == false then rednet.send(client_id, false, "auth") else rednet.send(client_id, true, "auth") end end if request.action == "list_groups" then if request.username == nil then rednet.send(client_id, "invalid request", "auth") end if data.users[request.username].groups == nil then rednet.send(client_id, {}, "auth") else rednet.send(client_id, data.users[request.username].groups, "auth") end end -- Only if in group admin if request.action == "add_group" then if request.username == nil or request.group == nil or request.token == nil then rednet.send(client_id, "invalid request", "auth") else local found = false local acting_user = nil for user, userdata in pairs(data.users) do if userdata.token == request.token then acting_user = user found = true end end if not found then rednet.send(client_id, "invalid token", "auth") elseif data.users[acting_user]["groups"] == nil or data.users[acting_user].groups["admin"] == nil then rednet.send(client_id, "invalid privileges", "auth") else if data.users[request.username].groups == nil then data.users[request.username].groups = {} end data.users[request.username].groups[request.group] = true save_data() rednet.send(client_id, "ok", "auth") log(request.username .. " added to group " .. request.group, "auth") end end end end