-- stuff to handle users users = { god = { password = "a4757d7419ff3b48e92e90596f0e7548", -- god's default password is "god" privs = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", site = "", talktime = 0, } } -- the users table is keyed by lower-case username. The values are -- a table describing that user, in the following form: -- .password = [string] an md5 hash of their password -- .password2 = [string] new style password - md5 of their username concatenated with their password -- .privs = [string] a list of the user's priviledges. -- .site = [string] site the user last connected from -- .talktime = [number] how many minutes the user has been connected -- .name = [string] real name of the user -- .birthday = [string] date of birth in ISO format -- .location = [string] where the user is based -- .homepage = [string] url to user's homepage -- .email = [string] user's email address -- .sex = [stirng] male/female/etc -- .around = [string] when the user is next around -- .restrict = [string] list of restrictions (eg, G) -- .timeon = [number] seconds of online time. -- .connected = [number] time of their connection, if they're connected now, otherwise nil. function escapeUserData(data) -- does stuff to a string so it can be safely saved... -- strings are assumed to only be sensitive to the double quote chartacter. local p, l = 1; local r = '" .. strchar(34) .. "'; local rl = strlen(r); local dl = 0; repeat l = strfind(data, '"', p, 1); if (l) then data = strsub(data, 1, l - 1) .. r .. strsub(data, l + 1, - 1); p = l + rl; dl = strlen(data); end; until l == nil or p > dl return data; end; function saveUsers(filename) -- dumps the users table to file in an executable form local f; if (filename ~= "dump") then f = openfile(filename, "w"); else f = "(dump) "; end; local indent = 0; write(f, "users = "); saveTable(users, f, indent); if (f ~= "(dump) ") then closefile(f) end; end; function saveTable(table, f, indent) local i, v; write(f, "{\n"); indent = indent + 2; for i, v in table do if (i ~= "n") then write(f, strrep(" ", indent) .. i .. " = {\n"); indent = indent + 2; local j, k, t; for j, k in v do if (j ~= "n" and j ~= "connected") then write(f, strrep(" ", indent) .. j .. " = "); t = type(k); if (t == "string") then k = format("%q", k); write(f, k, ",", "\n"); elseif (t == "number") then write(f, k .. ",\n"); elseif (t == "table") then saveTable(k, f, indent); end; end; end; indent = indent - 2; write(f, strrep(" ", indent) .. "},\n"); end; end; write(f, "}\n"); end; function loadUsers(filename) dofile(filename); end; function checkPasswordWithAuthenticator(authenticator, user, password) local null, null, rUser, host, port = strfind(authenticator, "^([^%@]-)%@([^%:]-):(.-)$"); if (not null) then return nil, "Invalid authenticator field."; end; local s = connect(host, port); if (not s) then return nil, "Unable to connect to authenticator."; end; s:send(format("auth %s %s\n", rUser, password)); local r = s:receive("*l"); s:close(); if (not r) then return nil, "Unable to get response from authenticator."; end; local null, null, code, message = strfind(r, "^auth (.-) (.-)$"); if (not null) then return nil, "Invalid response from authenticator."; end; if (code == "1") then return 1, message; else return nil, message; end; end; function checkPassword(user, password) user = strlower(user); if (users[user].authenticator) then -- they have an authenticator! return checkPasswordWithAuthenticator(users[user].authenticator, user, password); elseif (users[user].password2) then -- they have a new-style password if (users[user].password2 == crypt(user .. password)) then return 1, ""; else return nil, "Incorrect password."; end; else -- they have an old-style password. Check it, if it's correct, -- generate a password2 from it, and delete the old one. if (users[user].password == crypt(password)) then users[user].password2 = crypt(user .. password); users[user].password = nil; return 1, ""; else return nil, "Incorrect password."; end; end end; function changePassword(user, old, new) user = strlower(user); if (users[user].authenticator) then local null, null, rUser, host, port = strfind(users[user].authenticator, "^([^%@]-)%@([^%:]-):(.-)$"); if (not null) then return nil, "Invalid authenticator field."; end; local s = connect(host, port); if (not s) then return nil, "Unable to connect to authenticator."; end; s:send(format("pass %s %s %s\n", rUser, old, new)); local r = s:receive("*l"); s:close(); if (not r) then return nil, "Unable to get response from authenticator."; end; local null, null, code, message = strfind(r, "^pass (.-) (.-)$"); if (not null) then return nil, "Invalid response from authenticator."; end; if (code == "1") then return 1, message; else return nil, message; end; else local pr, message = checkPassword(user, old); if (not pr) then return nil, (message or "Incorrect old password"); end; users[user].password2 = crypt(user .. new); users[user].password = nil; saveUsers(colloquy.users); return 1, "Password changed."; end; end;