-- When key not found in section, check key in global's section
function section_mt(section_name)
return { __index = function (t, k)
-- local section = rawget(global_config, section_name);
-- if not section then return nil; end
-- return section[k];
-- end
-- };
++ local section = rawget(global_config, section_name);
++ if not section then return nil; end
++ return section[k];
++ end };
end
function getconfig()
function parsers.lua.load(data, filename)
local env;
-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
-- env = setmetatable({
- Host = true, host = true, VirtualHost = true,
- Component = true, component = true,
- Host = true; host = true; Component = true, component = true,
-- Include = true, include = true, RunScript = dofile }, {
-- __index = function (t, k)
-- return rawget(_G, k) or
-- function (settings_table)
-- config[__currenthost or "*"][k] = settings_table;
-- end;
-- end,
-- __newindex = function (t, k, v)
-- set(env.__currenthost or "*", "core", k, v);
-- end
-- });
++ env = setmetatable({ Host = true, host = true, VirtualHost = true, Component = true, component = true,
++ Include = true, include = true, RunScript = dofile }, { __index = function (t, k)
++ return rawget(_G, k) or
++ function (settings_table)
++ config[__currenthost or "*"][k] = settings_table;
++ end;
++ end,
++ __newindex = function (t, k, v)
++ set(env.__currenthost or "*", "core", k, v);
++ end});
rawset(env, "__currenthost", "*") -- Default is global
- function env.Host(name)
+ function env.VirtualHost(name)
if rawget(config, name) and rawget(config[name].core, "component_module") then
error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
local config = require "core.configmanager";
local hosts = hosts;
--local prosody = _G.prosody;
--
module "usermanager"
--local new_default_provider;
--
- local function host_handler(host)
-prosody.events.add_handler("host-activated", function (host)
-- local host_session = hosts[host];
-- host_session.events.add_handler("item-added/auth-provider", function (provider)
-- if config.get(host, "core", "authentication") == provider.name then
-- host_session.users = provider;
-- end
-- end);
-- host_session.events.add_handler("item-removed/auth-provider", function (provider)
-- if host_session.users == provider then
-- host_session.users = new_default_provider(host);
-- end
-- end);
-- host_session.users = new_default_provider(host); -- Start with the default usermanager provider
- end
- prosody.events.add_handler("host-activated", host_handler);
- prosody.events.add_handler("component-activated", host_handler);
-end);
--
local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
--function new_default_provider(host)
-- local provider = { name = "default" };
--
-- function provider.test_password(username, password)
-- if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
-- local credentials = datamanager.load(username, host, "accounts") or {};
--
++function validate_credentials(host, username, password, method)
++ log("debug", "User '%s' is being validated", username);
++ if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
++ local credentials = datamanager.load(username, host, "accounts") or {};
++
++ if method == nil then method = "PLAIN"; end
++ if method == "PLAIN" and credentials.password then -- PLAIN, do directly
if password == credentials.password then
return true;
else
return nil, "Auth failed. Invalid username or password.";
end
++ end
++ -- must do md5
++ -- make credentials md5
++ local pwd = credentials.password;
++ if not pwd then pwd = credentials.md5; else pwd = hashes.md5(pwd, true); end
++ -- make password md5
++ if method == "PLAIN" then
++ password = hashes.md5(password or "", true);
++ elseif method ~= "DIGEST-MD5" then
++ return nil, "Unsupported auth method";
end
--
-- function provider.get_password(username)
-- if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
-- return (datamanager.load(username, host, "accounts") or {}).password;
- end
-
- function provider.set_password(username, password)
- if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
- local account = datamanager.load(username, host, "accounts");
- if account then
- account.password = password;
- return datamanager.store(username, host, "accounts", account);
- end
- return nil, "Account not available.";
- end
-
- function provider.user_exists(username)
- if is_cyrus(host) then return true; end
- return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
- end
-
- function provider.create_user(username, password)
- if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
- return datamanager.store(username, host, "accounts", {password = password});
- end
-
- function provider.get_supported_methods()
- return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
++ -- compare
++ if password == pwd then
++ return true;
++ else
++ return nil, "Auth failed. Invalid username or password.";
end
-
- function provider.set_password(username, password)
- if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
- local account = datamanager.load(username, host, "accounts");
- if account then
- account.password = password;
- return datamanager.store(username, host, "accounts", account);
- end
- return nil, "Account not available.";
- end
-
- function provider.user_exists(username)
- if is_cyrus(host) then return true; end
- return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
- end
-
- function provider.create_user(username, password)
- if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
- return datamanager.store(username, host, "accounts", {password = password});
- end
-
- function provider.get_supported_methods()
- return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
- end
--
-- function provider.is_admin(jid)
- host = host or "*";
-- local admins = config.get(host, "core", "admins");
- if admins ~= config.get("*", "core", "admins") then
- if type(admins) == "table" then
- jid = jid_bare(jid);
- for _,admin in ipairs(admins) do
- if admin == jid then return true; end
- end
- elseif admins then
- log("error", "Option 'admins' for host '%s' is not a table", host);
- if host ~= "*" and admins == config.get("*", "core", "admins") then
- return nil;
- end
- if type(admins) == "table" then
- jid = jid_bare(jid);
- for _,admin in ipairs(admins) do
- if admin == jid then return true; end
-- end
- elseif admins then
- log("warn", "Option 'admins' for host '%s' is not a table", host);
-- end
- return is_admin(jid); -- Test whether it's a global admin instead
- return nil;
-- end
-- return provider;
--end
--
--function validate_credentials(host, username, password, method)
-- return hosts[host].users.test_password(username, password);
end
function get_password(username, host)
-- return hosts[host].users.get_password(username);
++ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
++ return (datamanager.load(username, host, "accounts") or {}).password
end
--
function set_password(username, host, password)
-- return hosts[host].users.set_password(username, password);
++ if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
++ local account = datamanager.load(username, host, "accounts");
++ if account then
++ account.password = password;
++ return datamanager.store(username, host, "accounts", account);
++ end
++ return nil, "Account not available.";
end
function user_exists(username, host)
-- return hosts[host].users.user_exists(username);
++ if is_cyrus(host) then return true; end
++ return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
end
function create_user(username, password, host)
-- return hosts[host].users.create_user(username, password);
++ if is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
++ return datamanager.store(username, host, "accounts", {password = password});
end
function get_supported_methods(host)
-- return hosts[host].users.get_supported_methods();
++ return {["PLAIN"] = true, ["DIGEST-MD5"] = true}; -- TODO this should be taken from the config
end
function is_admin(jid, host)
- if host and host ~= "*" then
- return hosts[host].users.is_admin(jid);
- else -- Test only whether this JID is a global admin
- local admins = config.get("*", "core", "admins");
- if type(admins) == "table" then
- jid = jid_bare(jid);
- for _,admin in ipairs(admins) do
- if admin == jid then return true; end
- end
- elseif admins then
- log("error", "Option 'admins' for host '%s' is not a table", host);
- end
- return hosts[host].users.is_admin(jid);
++ host = host or "*";
++ local admins = config.get(host, "core", "admins");
++ if host ~= "*" and admins == config.get("*", "core", "admins") then
+ return nil;
+ end
++ if type(admins) == "table" then
++ jid = jid_bare(jid);
++ for _,admin in ipairs(admins) do
++ if admin == jid then return true; end
++ end
++ elseif admins then log("warn", "Option 'admins' for host '%s' is not a table", host); end
++ return nil;
end
- _M.new_default_provider = new_default_provider;
-
return _M;
return;
end
- -- If session was inactive, make sure it is now marked as not
- if #session.requests == 0 then
- (session.log or log)("debug", "BOSH client now active again at %d", os_time());
- inactive_sessions[session] = nil;
- end
-
if session.notopen then
local features = st.stanza("stream:features");
+ hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
fire_event("stream-features", session, features);
session.send(features);
session.notopen = nil;
local history = self._data['history'];
if not history then history = {}; self._data['history'] = history; end
stanza = st.clone(stanza);
-- stanza.attr.to = "";
-- local stamp = datetime.datetime();
-- local chars = #tostring(stanza);
-- stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):up(); -- XEP-0203
++ stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = datetime.datetime()}):up(); -- XEP-0203
stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
-- local entry = { stanza = stanza, stamp = stamp };
-- t_insert(history, entry);
++ t_insert(history, st.preserialize(stanza));
while #history > history_length do t_remove(history, 1) end
end
end
end
end
end
--function room_mt:send_history(to, stanza)
++function room_mt:send_history(to)
local history = self._data['history']; -- send discussion history
if history then
-- local x_tag = stanza and stanza:get_child("x", "http://jabber.org/protocol/muc");
-- local history_tag = x_tag and x_tag:get_child("history", "http://jabber.org/protocol/muc");
--
-- local maxchars = history_tag and tonumber(history_tag.attr.maxchars);
-- if maxchars then maxchars = math.floor(maxchars); end
--
-- local maxstanzas = math.floor(history_tag and tonumber(history_tag.attr.maxstanzas) or #history);
-- if not history_tag then maxstanzas = 20; end
--
-- local seconds = history_tag and tonumber(history_tag.attr.seconds);
-- if seconds then seconds = datetime.datetime(os.time() - math.floor(seconds)); end
--
-- local since = history_tag and history_tag.attr.since;
-- if since and not since:match("^%d%d%d%d%-%d%d%-%d%dT%d%d:%d%d:%d%dZ$") then since = nil; end -- FIXME timezone support
-- if seconds and (not since or since < seconds) then since = seconds; end
--
-- local n = 0;
-- local charcount = 0;
-- local stanzacount = 0;
--
-- for i=#history,1,-1 do
-- local entry = history[i];
-- if maxchars then
-- if not entry.chars then
-- entry.stanza.attr.to = "";
-- entry.chars = #tostring(entry.stanza);
-- end
-- charcount = charcount + entry.chars + #to;
-- if charcount > maxchars then break; end
-- end
-- if since and since > entry.stamp then break; end
-- if n + 1 > maxstanzas then break; end
-- n = n + 1;
-- end
-- for i=#history-n+1,#history do
-- local msg = history[i].stanza;
-- msg.attr.to = to;
++ for _, msg in ipairs(history) do
++ msg = st.deserialize(msg);
++ msg.attr.to=to;
self:_route_stanza(msg);
end
end
:tag("item", {affiliation=affiliation or "none", role=role or "none"}):up()
:tag("status", {code='110'}));
end
-- self:send_history(from, stanza);
++ if self._data.whois == 'anyone' then -- non-anonymous?
++ self:_route_stanza(st.stanza("message", {from=to, to=from, type='groupchat'})
++ :tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
++ :tag("status", {code='100'}));
++ end
++ self:send_history(from);
else -- banned
local reply = st.error_reply(stanza, "auth", "forbidden"):up();
reply.tags[1].attr.code = "403";
function room_mt:set_role(actor, occupant_jid, role, callback, reason)
if role == "none" then role = nil; end
if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end
-- if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
++ if self:get_role(self._jid_nick[actor]) ~= "moderator" then return nil, "cancel", "not-allowed"; end
local occupant = self._occupants[occupant_jid];
if not occupant then return nil, "modify", "not-acceptable"; end
if occupant.affiliation == "owner" or occupant.affiliation == "admin" then return nil, "cancel", "not-allowed"; end
end
end
end
-- if self._data.whois == 'anyone' then
-- muc_child:tag('status', { code = '100' });
-- end
end
self:route_stanza(stanza);
if muc_child then
package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath;
end
++package.path = package.path..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.lua";
++package.cpath = package.cpath..";"..(CFG_SOURCEDIR or ".").."/fallbacks/?.so";
++
-- Substitute ~ with path to home directory in data path
if CFG_DATADIR then
if os.getenv("HOME") then
end
end
---- Global 'prosody' object
--prosody = { events = require "util.events".new(); };
--local prosody = prosody;
--
-- Load the config-parsing module
config = require "core.configmanager"
full_sessions = {};
hosts = {};
++ -- Global 'prosody' object
++ prosody = {};
++ local prosody = prosody;
++
prosody.bare_sessions = bare_sessions;
prosody.full_sessions = full_sessions;
prosody.hosts = hosts;
prosody.arg = _G.arg;
++ prosody.events = require "util.events".new();
++
prosody.platform = "unknown";
if os.getenv("WINDIR") then
prosody.platform = "windows";
-- Function to reopen logfiles
function prosody.reopen_logfiles()
log("info", "Re-opening log files");
++ eventmanager.fire_event("reopen-log-files"); -- Handled by appropriate log sinks
prosody.events.fire_event("reopen-log-files");
end
function load_secondary_libraries()
--- Load and initialise core modules
require "util.import"
- require "util.xmppstream"
require "core.xmlhandlers"
require "core.rostermanager"
++ require "core.eventmanager"
require "core.hostmanager"
require "core.modulemanager"
require "core.usermanager"
end
function prepare_to_start()
- log("debug", "Prosody is using the %s backend for connection handling", server.get_backend());
+ log("info", "Prosody is using the %s backend for connection handling", server.get_backend());
-- Signal to modules that we are ready to start
++ eventmanager.fire_event("server-starting");
prosody.events.fire_event("server-starting");
-- start listening on sockets
init_global_protection();
prepare_to_start();
++eventmanager.fire_event("server-started");
prosody.events.fire_event("server-started");
loop();
log("info", "Shutting down...");
cleanup();
++eventmanager.fire_event("server-stopped");
prosody.events.fire_event("server-stopped");
log("info", "Shutdown complete");
state = false : disabled
state = true : enabled
state = nil : non-existant
++
++plain:
++ function(username, realm)
++ return password, state;
++ end
++
++plain-test:
++ function(username, realm, password)
++ return true or false, state;
++ end
++
++digest-md5:
++ function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken
++ -- implementations it's not
++ return digesthash, state;
++ end
++
++digest-md5-test:
++ function(username, domain, realm, encoding, digesthash)
++ return true or false, state;
++ end
]]
local method = {};
-- sasl.lua v0.4
---- Copyright (C) 2008-2010 Tobias Markmann
++-- Copyright (C) 2008-2009 Tobias Markmann
--
-- All rights reserved.
--
--=========================
--SASL ANONYMOUS according to RFC 4505
--
----[[
--Supported Authentication Backends
--
--anonymous:
-- function(username, realm)
-- return true; --for normal usage just return true; if you don't like the supplied username you can return false.
-- end
--]]
--
local function anonymous(self, message)
local username;
repeat
-- sasl.lua v0.4
---- Copyright (C) 2008-2010 Tobias Markmann
++-- Copyright (C) 2008-2009 Tobias Markmann
--
-- All rights reserved.
--
--=========================
--SASL DIGEST-MD5 according to RFC 2831
----[[
--Supported Authentication Backends
--
--digest-md5:
-- function(username, domain, realm, encoding) -- domain and realm are usually the same; for some broken
-- -- implementations it's not
-- return digesthash, state;
-- end
--
--digest-md5-test:
-- function(username, domain, realm, encoding, digesthash)
-- return true or false, state;
-- end
--]]
--
local function digest(self, message)
--TODO complete support for authzid
-- sasl.lua v0.4
---- Copyright (C) 2008-2010 Tobias Markmann
++-- Copyright (C) 2008-2009 Tobias Markmann
--
-- All rights reserved.
--
-- ================================
-- SASL PLAIN according to RFC 4616
--
----[[
--Supported Authentication Backends
--
--plain:
-- function(username, realm)
-- return password, state;
-- end
--
--plain-test:
-- function(username, realm, password)
-- return true or false, state;
-- end
--
--plain-hashed:
-- function(username, realm)
-- return hashed_password, hash_function, state;
-- end
--]]
--
local function plain(self, message)
if not message then
return "failure", "malformed-request";
if correct_password == password then correct = true; else correct = false; end
elseif self.profile.plain_test then
correct, state = self.profile.plain_test(authentication, self.realm, password);
-- elseif self.profile.plain_hashed then
-- local hashed_password, hash_f;
-- hashed_password, hash_f, state = self.profile.plain_hashed(authentication, self.realm);
-- if hashed_password == hash_f(password) then correct = true; else correct = false; end
end
self.username = authentication
end
function init(registerMechanism)
-- registerMechanism("PLAIN", {"plain", "plain_test", "plain_hashed"}, plain);
++ registerMechanism("PLAIN", {"plain", "plain_test"}, plain);
end
return _M;
-- sasl.lua v0.4
---- Copyright (C) 2008-2010 Tobias Markmann
++-- Copyright (C) 2008-2009 Tobias Markmann
--
-- All rights reserved.
--
--=========================
--SASL SCRAM-SHA-1 according to draft-ietf-sasl-scram-10
--
----[[
--Supported Authentication Backends
--
--scram-{MECH}:
-- function(username, realm)
-- return salted_password, iteration_count, salt, state;
-- end
--]]
--
local default_i = 4096
local function bp( b )
return username;
end
--local function scram_gen(hash_name, H_f, HMAC_f)
-- local function scram_hash(self, message)
-- if not self.state then self["state"] = {} end
++local function scram_sha_1(self, message)
++ if not self.state then self["state"] = {} end
-- if not self.state.name then
-- -- we are processing client_first_message
-- local client_first_message = message;
-- self.state["client_first_message"] = client_first_message;
-- self.state["name"] = client_first_message:match("n=(.+),r=")
-- self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
++ if not self.state.name then
++ -- we are processing client_first_message
++ local client_first_message = message;
++ self.state["client_first_message"] = client_first_message;
++ self.state["name"] = client_first_message:match("n=(.+),r=")
++ self.state["clientnonce"] = client_first_message:match("r=([^,]+)")
-- if not self.state.name or not self.state.clientnonce then
-- return "failure", "malformed-request";
-- end
++ if not self.state.name or not self.state.clientnonce then
++ return "failure", "malformed-request";
++ end
-- self.state.name = validate_username(self.state.name);
-- if not self.state.name then
-- log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
-- return "failure", "malformed-request", "Invalid username.";
-- end
++ self.state.name = validate_username(self.state.name);
++ if not self.state.name then
++ log("debug", "Username violates either SASLprep or contains forbidden character sequences.")
++ return "failure", "malformed-request", "Invalid username.";
++ end
-- self.state["servernonce"] = generate_uuid();
--
-- -- retreive credentials
-- if self.profile.plain then
- local password, state = self.profile.plain(self.state.name, self.realm)
- password, state = self.profile.plain(self.state.name, self.realm)
-- if state == nil then return "failure", "not-authorized"
-- elseif state == false then return "failure", "account-disabled" end
--
-- password = saslprep(password);
-- if not password then
-- log("debug", "Password violates SASLprep.");
-- return "failure", "not-authorized", "Invalid password."
-- end
-- self.state.salt = generate_uuid();
-- self.state.iteration_count = default_i;
-- self.state.salted_password = Hi(HMAC_f, password, self.state.salt, default_i);
-- elseif self.profile["scram_"..hash_name] then
- local salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm);
- salted_password, iteration_count, salt, state = self.profile["scram-"..hash_name](self.state.name, self.realm);
-- if state == nil then return "failure", "not-authorized"
-- elseif state == false then return "failure", "account-disabled" end
--
-- self.state.salted_password = salted_password;
-- self.state.iteration_count = iteration_count;
-- self.state.salt = salt
-- end
++ self.state["servernonce"] = generate_uuid();
++ self.state["salt"] = generate_uuid();
-- local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..self.state.iteration_count;
-- self.state["server_first_message"] = server_first_message;
-- return "challenge", server_first_message
-- else
-- if type(message) ~= "string" then return "failure", "malformed-request" end
-- -- we are processing client_final_message
-- local client_final_message = message;
++ local server_first_message = "r="..self.state.clientnonce..self.state.servernonce..",s="..base64.encode(self.state.salt)..",i="..default_i;
++ self.state["server_first_message"] = server_first_message;
++ return "challenge", server_first_message
++ else
++ if type(message) ~= "string" then return "failure", "malformed-request" end
++ -- we are processing client_final_message
++ local client_final_message = message;
-- self.state["proof"] = client_final_message:match("p=(.+)");
-- self.state["nonce"] = client_final_message:match("r=(.+),p=");
-- self.state["channelbinding"] = client_final_message:match("c=(.+),r=");
-- if not self.state.proof or not self.state.nonce or not self.state.channelbinding then
-- return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
++ self.state["proof"] = client_final_message:match("p=(.+)");
++ self.state["nonce"] = client_final_message:match("r=(.+),p=");
++ self.state["channelbinding"] = client_final_message:match("c=(.+),r=");
++ if not self.state.proof or not self.state.nonce or not self.state.channelbinding then
++ return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message.";
++ end
++
++ local password, state;
++ if self.profile.plain then
++ password, state = self.profile.plain(self.state.name, self.realm)
++ if state == nil then return "failure", "not-authorized"
++ elseif state == false then return "failure", "account-disabled" end
++ password = saslprep(password);
++ if not password then
++ log("debug", "Password violates SASLprep.");
++ return "failure", "not-authorized", "Invalid password."
end
++ end
-- local SaltedPassword = self.state.salted_password;
-- local ClientKey = HMAC_f(SaltedPassword, "Client Key")
-- local ServerKey = HMAC_f(SaltedPassword, "Server Key")
-- local StoredKey = H_f(ClientKey)
-- local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
-- local ClientSignature = HMAC_f(StoredKey, AuthMessage)
-- local ClientProof = binaryXOR(ClientKey, ClientSignature)
-- local ServerSignature = HMAC_f(ServerKey, AuthMessage)
++ local SaltedPassword = Hi(hmac_sha1, password, self.state.salt, default_i)
++ local ClientKey = hmac_sha1(SaltedPassword, "Client Key")
++ local ServerKey = hmac_sha1(SaltedPassword, "Server Key")
++ local StoredKey = sha1(ClientKey)
++ local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+")
++ local ClientSignature = hmac_sha1(StoredKey, AuthMessage)
++ local ClientProof = binaryXOR(ClientKey, ClientSignature)
++ local ServerSignature = hmac_sha1(ServerKey, AuthMessage)
-- if base64.encode(ClientProof) == self.state.proof then
-- local server_final_message = "v="..base64.encode(ServerSignature);
-- self["username"] = self.state.name;
-- return "success", server_final_message;
-- else
-- return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";
-- end
++ if base64.encode(ClientProof) == self.state.proof then
++ local server_final_message = "v="..base64.encode(ServerSignature);
++ self["username"] = self.state.name;
++ return "success", server_final_message;
++ else
++ return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated.";
end
end
-- return scram_hash;
end
function init(registerMechanism)
-- local function registerSCRAMMechanism(hash_name, hash, hmac_hash)
-- registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hash_name:lower())}, scram_gen(hash_name:lower(), hash, hmac_hash));
-- end
--
-- registerSCRAMMechanism("SHA-1", sha1, hmac_sha1);
++ registerMechanism("SCRAM-SHA-1", {"plain"}, scram_sha_1);
end
return _M;