From b73cbae8a5e49f7f3300e7c028e570ad8a58e46d Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Wed, 12 Jan 2011 21:29:37 +0100 Subject: Adding some code for channel binding advertising. --- util/sasl/scram.lua | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 530ef5a0..fbe3547b 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -14,6 +14,7 @@ local s_match = string.match; local type = type local string = string +local tostring = tostring; local base64 = require "util.encodings".base64; local hmac_sha1 = require "util.hmac".sha1; local sha1 = require "util.hashes".sha1; @@ -110,6 +111,8 @@ function getAuthenticationDatabaseSHA1(password, salt, iteration_count) return true, stored_key, server_key end +local support_channel_binding = true; + local function scram_gen(hash_name, H_f, HMAC_f) local function scram_hash(self, message) if not self.state then self["state"] = {} end @@ -118,15 +121,26 @@ local function scram_gen(hash_name, H_f, HMAC_f) if not self.state.name then -- we are processing client_first_message local client_first_message = message; - + log("debug", client_first_message); -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; - self.state["gs2_cbind_flag"], self.state["authzid"], self.state["name"], self.state["clientnonce"] - = client_first_message:match("^(%a),(.*),n=(.*),r=([^,]*).*"); + self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] + = client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); -- we don't do any channel binding yet - if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then - return "failure", "malformed-request"; + log("debug", "Decoded: cbind_flag: %s, cbind_name: %s, authzid: %s, name: %s, clientnonce: %s", tostring(self.state.gs2_cbind_flag), + tostring(self.state.gs2_cbind_name), + tostring(self.state.authzid), + tostring(self.state.name), + tostring(self.state.clientnonce)); + if support_channel_binding then + if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then + return "failure", "malformed-request"; + end + else + if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then + return "failure", "malformed-request"; + end end if not self.state.name or not self.state.clientnonce then @@ -179,7 +193,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) else -- we are processing client_final_message local client_final_message = message; - + log("debug", "client_final_message: %s", client_final_message); self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); if not self.state.proof or not self.state.nonce or not self.state.channelbinding then @@ -213,6 +227,9 @@ end function init(registerMechanism) local function registerSCRAMMechanism(hash_name, hash, hmac_hash) registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); + + -- register channel binding equivalent + registerMechanism("SCRAM-"..hash_name.."-PLUS", {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); end registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); -- cgit v1.2.3 From 1e72875d5263b9478b257b27a3784dcd7fc4dcc3 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sat, 15 Jan 2011 17:59:15 +0100 Subject: Check whether we support the proposed channel binding type. --- util/sasl.lua | 11 +++++++++++ util/sasl/scram.lua | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/util/sasl.lua b/util/sasl.lua index 93b79a86..37a234c9 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -27,6 +27,17 @@ Authentication Backend Prototypes: state = false : disabled state = true : enabled state = nil : non-existant + +Channel Binding: + +To enable support of channel binding in some mechanisms you need to provide appropriate callbacks in a table +at profile.cb. + +Example: + profile.cb["tls-unique"] = function(self) + return self.user + end + ]] local method = {}; diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index fbe3547b..76e9c152 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -137,6 +137,11 @@ local function scram_gen(hash_name, H_f, HMAC_f) if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then return "failure", "malformed-request"; end + + -- check whether we support the proposed channel binding type + if not self.profile.cb[self.state.gs2_cbind_name] then + return "failure", "malformed-request", "Proposed channel binding type isn't supported."; + end else if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then return "failure", "malformed-request"; -- cgit v1.2.3 From 1fbe88e5c40b9a48ea35aedaaaee9152991b8e65 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: Run with own LuaSec. --- prosody | 3 +++ util/dependencies.lua | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/prosody b/prosody index 7c819214..c86eea42 100755 --- a/prosody +++ b/prosody @@ -16,6 +16,9 @@ CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR"); CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR"); CFG_DATADIR=os.getenv("PROSODY_DATADIR"); +package.path = "/Users/tfar/share/lua/5.1/?.lua;"..package.path; +package.cpath = "/Users/tfar/lib/lua/5.1/?.so;"..package.cpath; + -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Tell Lua where to find our libraries diff --git a/util/dependencies.lua b/util/dependencies.lua index 9371521c..9258be88 100644 --- a/util/dependencies.lua +++ b/util/dependencies.lua @@ -11,9 +11,9 @@ module("dependencies", package.seeall) function softreq(...) local ok, lib = pcall(require, ...); if ok then return lib; else return nil, lib; end end -- Required to be able to find packages installed with luarocks -if not softreq "luarocks.loader" then -- LuaRocks 2.x - softreq "luarocks.require"; -- LuaRocks <1.x -end +--if not softreq "luarocks.loader" then -- LuaRocks 2.x +-- softreq "luarocks.require"; -- LuaRocks <1.x +--end function missingdep(name, sources, msg) print(""); -- cgit v1.2.3 From 0435f611fd9e7794b8f42699c35ceee01dd28d1f Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: util.sasl: New method to add channel binding handler to a SASL instance. --- util/sasl.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/sasl.lua b/util/sasl.lua index 37a234c9..cd0a1d64 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -70,6 +70,15 @@ function new(realm, profile) return setmetatable({ profile = profile, realm = realm, mechs = mechanisms }, method); end +-- add a channel binding handler +function method:add_cb_handler(name, f) + if type(self.profile.cb) ~= "table" then + self.profile.cb = {}; + end + self.profile.cb[name] = f; + return self; +end + -- get a fresh clone with the same realm and profile function method:clean_clone() return new(self.realm, self.profile) -- cgit v1.2.3 From 3dc5c26703b55ae5a24ba7757e18282e351425fd Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: mod_saslauth: Set secure socket as SASL object user data for secure sessions. --- plugins/mod_saslauth.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 1c0d0673..2b3b59a9 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -246,6 +246,10 @@ module:hook("stream-features", function(event) return; end origin.sasl_handler = usermanager_get_sasl_handler(module.host); + + if origin.secure then + origin.sasl_handler["userdata"] = origin.conn:socket(); + end features:tag("mechanisms", mechanisms_attr); for mechanism in pairs(origin.sasl_handler:mechanisms()) do if mechanism ~= "PLAIN" or origin.secure or allow_unencrypted_plain_auth then -- cgit v1.2.3 From e7a197972565c5a0e3f1fa538c693f115ebdb7e8 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: util.sasl.scram: Use self.profile.cb for detection whether channel binding is supported or not. --- util/sasl/scram.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 76e9c152..cb50390d 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -111,12 +111,12 @@ function getAuthenticationDatabaseSHA1(password, salt, iteration_count) return true, stored_key, server_key end -local support_channel_binding = true; - 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 support_channel_binding = false; + if self.profile.cb then support_channel_binding = true; end + if type(message) ~= "string" or #message == 0 then return "failure", "malformed-request" end if not self.state.name then -- we are processing client_first_message -- cgit v1.2.3 From a1c646ad48267cdfaefb27e77f335969c7c4cc3f Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: mod_saslauth: Add channel binding handler for tls-unique channel binding. --- plugins/mod_saslauth.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 2b3b59a9..822be62b 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -246,8 +246,10 @@ module:hook("stream-features", function(event) return; end origin.sasl_handler = usermanager_get_sasl_handler(module.host); - if origin.secure then + origin.sasl_handler:add_cb_handler("tls-unique", function(self) + return self.userdata:getpeerfinished(); + end); origin.sasl_handler["userdata"] = origin.conn:socket(); end features:tag("mechanisms", mechanisms_attr); -- cgit v1.2.3 From 9e938f0e7c47c76bef0734195c4384e1239a087b Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: util.sasl.scram: Validate channel binding data of client final message. --- util/sasl/scram.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index cb50390d..66cc941d 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -200,9 +200,18 @@ local function scram_gen(hash_name, H_f, HMAC_f) local client_final_message = message; log("debug", "client_final_message: %s", client_final_message); self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); - - 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."; + + if self.state.gs2_cbind_name then + local client_gs2_header = base64.decode(self.state.channelbinding) + local our_client_gs2_header = "p="..self.state.gs2_cbind_name..","..self.state["authzid"]..","..self.profile.cb[self.state.gs2_cbind_name](self); + + if client_gs2_header ~= our_client_gs2_header then + return "failure", "malformed-request", "Invalid channel binding value."; + end + else + 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 end if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then -- cgit v1.2.3 From dd1571b3905d0c388c78920c20bbaa15c709445f Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: util.sasl.scram: Adding reference to RFC 5929 'Channel Bindings for TLS'. --- util/sasl/scram.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 66cc941d..74854619 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -38,6 +38,10 @@ scram_{MECH}: function(username, realm) return stored_key, server_key, iteration_count, salt, state; end + +Supported Channel Binding Backends + +'tls-unique' according to RFC 5929 ]] local default_i = 4096 -- cgit v1.2.3 From bd085514c5801265370efd4d044cb8f992e67170 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: util.sasl.scram: Remove some debugging output. --- util/sasl/scram.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 74854619..1b6d56c8 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -131,12 +131,6 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] = client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); - -- we don't do any channel binding yet - log("debug", "Decoded: cbind_flag: %s, cbind_name: %s, authzid: %s, name: %s, clientnonce: %s", tostring(self.state.gs2_cbind_flag), - tostring(self.state.gs2_cbind_name), - tostring(self.state.authzid), - tostring(self.state.name), - tostring(self.state.clientnonce)); if support_channel_binding then if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then return "failure", "malformed-request"; -- cgit v1.2.3 From d07446041f3c2c72077de003db171bd2b5ecd0c6 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 17 Jan 2011 16:50:21 +0100 Subject: mod_saslauth: Check whether LuaSec supports getpeerfinished() binding. --- plugins/mod_saslauth.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 822be62b..422bc187 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -247,10 +247,14 @@ module:hook("stream-features", function(event) end origin.sasl_handler = usermanager_get_sasl_handler(module.host); if origin.secure then - origin.sasl_handler:add_cb_handler("tls-unique", function(self) - return self.userdata:getpeerfinished(); - end); - origin.sasl_handler["userdata"] = origin.conn:socket(); + -- check wether LuaSec has the nifty binding to the function needed for tls-unique + -- FIXME: would be nice to have this check only once and not for every socket + if origin.conn:socket().getpeerfinished then + origin.sasl_handler:add_cb_handler("tls-unique", function(self) + return self.userdata:getpeerfinished(); + end); + origin.sasl_handler["userdata"] = origin.conn:socket(); + end end features:tag("mechanisms", mechanisms_attr); for mechanism in pairs(origin.sasl_handler:mechanisms()) do -- cgit v1.2.3 From 051ca76fbe398f3e177386c212dafd78bc6ecbe4 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 6 Feb 2011 13:20:17 +0100 Subject: util.sasl.scram: Checking the GS2 header for valid start flag. --- util/sasl/scram.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 1b6d56c8..19d0bf7b 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -131,6 +131,12 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] = client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); + -- check for invalid gs2_flag_type start + local gs2_flag_type == string.sub(self.state.gs2_cbind_flag, 0, 1) + if gs2_flag_type ~= "y" and gs2_flag_type ~= "n" and gs2_flag_type ~= "p" then + return "failure", "malformed-request", "The GS2 header has to start with 'y', 'n', or 'p'." + end + if support_channel_binding then if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then return "failure", "malformed-request"; @@ -141,6 +147,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) return "failure", "malformed-request", "Proposed channel binding type isn't supported."; end else + -- we don't support channelbinding, if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then return "failure", "malformed-request"; end -- cgit v1.2.3 From f575f1eb40aef2e7196badfe41d217b6f7fbf350 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Sun, 6 Feb 2011 13:39:32 +0100 Subject: sasl.util.scarm: Rearrage some code so it makes more sense. --- util/sasl/scram.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 19d0bf7b..ad26658b 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -132,7 +132,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) = client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); -- check for invalid gs2_flag_type start - local gs2_flag_type == string.sub(self.state.gs2_cbind_flag, 0, 1) + local gs2_flag_type = string.sub(self.state.gs2_cbind_flag, 0, 1) if gs2_flag_type ~= "y" and gs2_flag_type ~= "n" and gs2_flag_type ~= "p" then return "failure", "malformed-request", "The GS2 header has to start with 'y', 'n', or 'p'." end @@ -206,17 +206,18 @@ local function scram_gen(hash_name, H_f, HMAC_f) log("debug", "client_final_message: %s", client_final_message); self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); + 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 + if self.state.gs2_cbind_name then + -- we support channelbinding, so check if the value is valid local client_gs2_header = base64.decode(self.state.channelbinding) local our_client_gs2_header = "p="..self.state.gs2_cbind_name..","..self.state["authzid"]..","..self.profile.cb[self.state.gs2_cbind_name](self); if client_gs2_header ~= our_client_gs2_header then return "failure", "malformed-request", "Invalid channel binding value."; end - else - 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 end if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then -- cgit v1.2.3 From 0a2715f365f2dc28c33933d486fecdb64daf7a89 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 7 Feb 2011 13:24:42 +0100 Subject: Only advertise mechanisms needing channel binding if a channel binding backend is avaliable. --- util/sasl.lua | 27 +++++++++++++++++++++++++-- util/sasl/scram.lua | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/util/sasl.lua b/util/sasl.lua index cd0a1d64..393a0919 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -18,6 +18,7 @@ local type = type local setmetatable = setmetatable; local assert = assert; local require = require; +local print = print module "sasl" @@ -44,13 +45,21 @@ local method = {}; method.__index = method; local mechanisms = {}; local backend_mechanism = {}; +local mechanism_channelbindings = {}; -- register a new SASL mechanims -local function registerMechanism(name, backends, f) +local function registerMechanism(name, backends, f, cb_backends) assert(type(name) == "string", "Parameter name MUST be a string."); assert(type(backends) == "string" or type(backends) == "table", "Parameter backends MUST be either a string or a table."); assert(type(f) == "function", "Parameter f MUST be a function."); + if cb_backends then assert(type(cb_backends) == "table"); end mechanisms[name] = f + if cb_backends then + mechanism_channelbindings[name] = {}; + for _, cb_name in ipairs(cb_backends) do + mechanism_channelbindings[name][cb_name] = true; + end + end for _, backend_name in ipairs(backends) do if backend_mechanism[backend_name] == nil then backend_mechanism[backend_name] = {}; end t_insert(backend_mechanism[backend_name], name); @@ -86,7 +95,21 @@ end -- get a list of possible SASL mechanims to use function method:mechanisms() - return self.mechs; + local current_mechs = {}; + for mech, _ in pairs(self.mechs) do + if mechanism_channelbindings[mech] and self.profile.cb then + local ok = false; + for cb_name, _ in pairs(self.profile.cb) do + if mechanism_channelbindings[mech][cb_name] then + ok = true; + end + end + if ok == true then current_mechs[mech] = true; end + else + current_mechs[mech] = true; + end + end + return current_mechs; end -- select a mechanism to use diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index ad26658b..071de505 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -249,7 +249,7 @@ function init(registerMechanism) registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); -- register channel binding equivalent - registerMechanism("SCRAM-"..hash_name.."-PLUS", {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); + registerMechanism("SCRAM-"..hash_name.."-PLUS", {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash), {"tls-unique"}); end registerSCRAMMechanism("SHA-1", sha1, hmac_sha1); -- cgit v1.2.3 From cfe10e6fa474e0c5d94d04d65663e774627d64a0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 15:12:18 +0200 Subject: mod_admin_adhoc: Add commands for activating and deactivating hosts --- plugins/mod_admin_adhoc.lua | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index a13c7312..aa1af3ff 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -17,6 +17,8 @@ local usermanager_create_user = require "core.usermanager".create_user; local usermanager_delete_user = require "core.usermanager".delete_user; local usermanager_get_password = require "core.usermanager".get_password; local usermanager_set_password = require "core.usermanager".set_password; +local hostmanager_activate = require "core.hostmanager".activate; +local hostmanager_deactivate = require "core.hostmanager".deactivate; local is_admin = require "core.usermanager".is_admin; local rm_load_roster = require "core.rostermanager".load_roster; local st, jid, uuid = require "util.stanza", require "util.jid", require "util.uuid"; @@ -606,6 +608,63 @@ function unload_modules_handler(self, data, state) end end +function activate_host_handler(self, data, state) + local layout = dataforms_new { + title = "Activate host"; + instructions = ""; + + { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/hosts#activate" }; + { name = "host", type = "text-single", required = true, label = "Host:"}; + }; + if state then + if data.action == "cancel" then + return { status = "canceled" }; + end + local fields, err = layout:data(data.form); + if err then + return generate_error_message(err); + end + local ok, err = hostmanager_activate(fields.host); + + if ok then + return { status = "completed", info = fields.host .. " activated" }; + else + return { status = "canceled", error = err } + end + else + return { status = "executing", actions = {"next", "complete", default = "complete"}, form = { layout = layout } }, "executing"; + end +end + +function deactivate_host_handler(self, data, state) + local layout = dataforms_new { + title = "Deactivate host"; + instructions = ""; + + { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/hosts#activate" }; + { name = "host", type = "text-single", required = true, label = "Host:"}; + }; + if state then + if data.action == "cancel" then + return { status = "canceled" }; + end + local fields, err = layout:data(data.form); + if err then + return generate_error_message(err); + end + local ok, err = hostmanager_deactivate(fields.host); + + if ok then + return { status = "completed", info = fields.host .. " deactivated" }; + else + return { status = "canceled", error = err } + end + else + return { status = "executing", actions = {"next", "complete", default = "complete"}, form = { layout = layout } }, "executing"; + end +end + + local add_user_desc = adhoc_new("Add User", "http://jabber.org/protocol/admin#add-user", add_user_command_handler, "admin"); local change_user_password_desc = adhoc_new("Change User Password", "http://jabber.org/protocol/admin#change-user-password", change_user_password_command_handler, "admin"); local config_reload_desc = adhoc_new("Reload configuration", "http://prosody.im/protocol/config#reload", config_reload_handler, "global_admin"); @@ -620,6 +679,8 @@ local load_module_desc = adhoc_new("Load module", "http://prosody.im/protocol/mo local reload_modules_desc = adhoc_new("Reload modules", "http://prosody.im/protocol/modules#reload", reload_modules_handler, "admin"); local shut_down_service_desc = adhoc_new("Shut Down Service", "http://jabber.org/protocol/admin#shutdown", shut_down_service_handler, "global_admin"); local unload_modules_desc = adhoc_new("Unload modules", "http://prosody.im/protocol/modules#unload", unload_modules_handler, "admin"); +local activate_host_desc = adhoc_new("Activate host", "http://prosody.im/protocol/hosts#activate", activate_host_handler, "global_admin"); +local deactivate_host_desc = adhoc_new("Deactivate host", "http://prosody.im/protocol/hosts#deactivate", deactivate_host_handler, "global_admin"); module:provides("adhoc", add_user_desc); module:provides("adhoc", change_user_password_desc); @@ -635,3 +696,5 @@ module:provides("adhoc", load_module_desc); module:provides("adhoc", reload_modules_desc); module:provides("adhoc", shut_down_service_desc); module:provides("adhoc", unload_modules_desc); +module:provides("adhoc", activate_host_desc); +module:provides("adhoc", deactivate_host_desc); -- cgit v1.2.3 From e0e7541f02faa5df74a151e3fe64d9323a12ebe7 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 16:39:19 +0200 Subject: storagemanager: Fix argument (Thanks Maranda) --- core/storagemanager.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index d744700a..97ff084f 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -123,7 +123,7 @@ function datamanager.stores(username, host, typ) return get_driver(host):stores(username, typ); end function datamanager.purge(username, host) - return purge(username); + return purge(username, host); end return _M; -- cgit v1.2.3 From 93cde32b80d341ff10c2a1bae4344199486389bc Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 16:40:38 +0200 Subject: storagemanager: Remove unused variable --- core/storagemanager.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 97ff084f..5a7bb7bd 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -96,7 +96,6 @@ end function purge(user, host) local storage = config.get(host, "storage"); - local driver_name; if type(storage) == "table" then -- multiple storage backends in use that we need to purge local purged = {}; -- cgit v1.2.3 From 8d9a04088f11349c430002cf6f56ce2337228b20 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 23:24:40 +0200 Subject: prosodyctl: Set $HOME to data path. Fixes issue with openssl and random state (Thanks Florob) --- prosodyctl | 1 + 1 file changed, 1 insertion(+) diff --git a/prosodyctl b/prosodyctl index d4aa6d5e..52b734f7 100755 --- a/prosodyctl +++ b/prosodyctl @@ -161,6 +161,7 @@ if ok and pposix then -- Set our umask to protect data files pposix.umask(config.get("*", "core", "umask") or "027"); + pposix.setenv("HOME", data_path); else print("Error: Unable to load pposix module. Check that Prosody is installed correctly.") print("For more help send the below error to us through http://prosody.im/discuss"); -- cgit v1.2.3 From eae1e0b03e4c3b9cabc93537f036121496d1e6a5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 23:25:10 +0200 Subject: prosodyctl: Abort if unable to load util.pposix --- prosodyctl | 1 + 1 file changed, 1 insertion(+) diff --git a/prosodyctl b/prosodyctl index 52b734f7..12117c0f 100755 --- a/prosodyctl +++ b/prosodyctl @@ -166,6 +166,7 @@ else print("Error: Unable to load pposix module. Check that Prosody is installed correctly.") print("For more help send the below error to us through http://prosody.im/discuss"); print(tostring(pposix)) + os.exit(1); end local function test_writeable(filename) -- cgit v1.2.3 From 4a423e63859ba5be2ff19dd5d5d17dd75ad19f59 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 23:26:38 +0200 Subject: prosodyctl: Set stricter umask while generating key (thanks darkrain) --- prosodyctl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 12117c0f..93eac3f2 100755 --- a/prosodyctl +++ b/prosodyctl @@ -686,11 +686,13 @@ function cert_commands.key(arg) if ask_overwrite(key_filename) then return nil, key_filename; end - os.remove(key_filename); -- We chmod this file to not have write permissions + os.remove(key_filename); -- This file, if it exists is unlikely to have write permissions local key_size = tonumber(arg[2] or show_prompt("Choose key size (2048):") or 2048); + local old_umask = pposix.umask("0377"); if openssl.genrsa{out=key_filename, key_size} then os.execute(("chmod 400 '%s'"):format(key_filename)); show_message("Key written to ".. key_filename); + pposix.umask(old_umask); return nil, key_filename; end show_message("There was a problem, see OpenSSL output"); -- cgit v1.2.3 From c586bcd596d47bf6cca6439d3eb96ba8d6a681f4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Sep 2012 23:29:25 +0200 Subject: prosodyctl: Fix copypaste error --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 93eac3f2..e26339e2 100755 --- a/prosodyctl +++ b/prosodyctl @@ -724,7 +724,7 @@ function cert_commands.generate(arg) if #arg >= 1 and arg[1] ~= "--help" then local cert_filename = (CFG_DATADIR or ".") .. "/" .. arg[1] .. ".cert"; if ask_overwrite(cert_filename) then - return nil, conf_filename; + return nil, cert_filename; end local _, key_filename = cert_commands.key({arg[1]}); local _, conf_filename = cert_commands.config(arg); -- cgit v1.2.3 From b47879e18077b22d5cbace5ed8bb7362ec087d33 Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Thu, 28 Mar 2013 12:49:19 +0100 Subject: mod_privacy: Drop stanzas of type groupchat, so users aren't kicked from their chatrooms when blocking specific MUC occupants. --- plugins/mod_privacy.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/mod_privacy.lua b/plugins/mod_privacy.lua index 7ec94922..dc6b153a 100644 --- a/plugins/mod_privacy.lua +++ b/plugins/mod_privacy.lua @@ -366,6 +366,10 @@ function checkIfNeedToBeBlocked(e, session) end if apply then if block then + -- drop and not bounce groupchat messages, otherwise users will get kicked + if stanza.attr.type == "groupchat" then + return true; + end module:log("debug", "stanza blocked: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from)); if stanza.name == "message" then origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- cgit v1.2.3 From d5457e36492d72a959b12b466ba92b21374e7417 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 9 Apr 2013 15:50:46 +0200 Subject: prosodyctl: Bump util.pposix version for API change --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 71b99f9e..24d28157 100755 --- a/prosodyctl +++ b/prosodyctl @@ -135,7 +135,7 @@ dependencies.log_warnings(); -- Switch away from root and into the prosody user -- local switched_user, current_uid; -local want_pposix_version = "0.3.5"; +local want_pposix_version = "0.3.6"; local ok, pposix = pcall(require, "util.pposix"); if ok and pposix then -- cgit v1.2.3 -- cgit v1.2.3 -- cgit v1.2.3 -- cgit v1.2.3 From f6f9dae378f74717d52ba03e880d84cca606d833 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 16 May 2013 10:47:22 +0100 Subject: mod_admin_telnet: Add server:memory() command to view details of Prosody's memory usage --- plugins/mod_admin_telnet.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 753e2d2c..b67ba576 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -236,6 +236,7 @@ function commands.help(session, data) elseif section == "server" then print [[server:version() - Show the server's version number]] print [[server:uptime() - Show how long the server has been running]] + print [[server:memory() - Show details about the server's memory usage]] print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]] elseif section == "port" then print [[port:list() - Lists all network ports prosody currently listens on]] @@ -300,6 +301,26 @@ function def_env.server:shutdown(reason) return true, "Shutdown initiated"; end +local function human(kb) + local unit = "K"; + if kb > 1024 then + kb, unit = kb/1024, "M"; + end + return ("%0.2f%sB"):format(kb, unit); +end + +function def_env.server:memory() + if not pposix.meminfo then + return true, "Lua is using "..collectgarbage("count"); + end + local mem, lua_mem = pposix.meminfo(), collectgarbage("count"); + local print = self.session.print; + print("Process: "..human((mem.allocated+mem.allocated_mmap)/1024)); + print(" Used: "..human(mem.used/1024).." ("..human(lua_mem).." by Lua)"); + print(" Free: "..human(mem.unused/1024).." ("..human(mem.returnable/1024).." returnable)"); + return true, "OK"; +end + def_env.module = {}; local function get_hosts_set(hosts, module) -- cgit v1.2.3 From 42be754bb20ba65af1a3b311b82f5765b8985234 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 16 May 2013 14:17:25 +0100 Subject: mod_muc: Refactor config form handling, and allow for clients to submit incomplete forms. Fixes #246 --- plugins/muc/mod_muc.lua | 2 +- plugins/muc/muc.lib.lua | 125 +++++++++++++++++------------------------------- 2 files changed, 46 insertions(+), 81 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 0f1beb0e..47809964 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -115,7 +115,7 @@ end local function get_disco_items(stanza) local reply = st.iq({type='result', id=stanza.attr.id, from=muc_host, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#items"); for jid, room in pairs(rooms) do - if not room:is_hidden() then + if not room:get_hidden() then reply:tag("item", {jid=jid, name=room:get_name()}):up(); end end diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 1ea231f3..833b1154 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -98,8 +98,8 @@ function room_mt:get_default_role(affiliation) elseif affiliation == "member" then return "participant"; elseif not affiliation then - if not self:is_members_only() then - return self:is_moderated() and "visitor" or "participant"; + if not self:get_members_only() then + return self:get_moderated() and "visitor" or "participant"; end end end @@ -218,10 +218,10 @@ function room_mt:get_disco_info(stanza) :tag("identity", {category="conference", type="text", name=self:get_name()}):up() :tag("feature", {var="http://jabber.org/protocol/muc"}):up() :tag("feature", {var=self:get_password() and "muc_passwordprotected" or "muc_unsecured"}):up() - :tag("feature", {var=self:is_moderated() and "muc_moderated" or "muc_unmoderated"}):up() - :tag("feature", {var=self:is_members_only() and "muc_membersonly" or "muc_open"}):up() - :tag("feature", {var=self:is_persistent() and "muc_persistent" or "muc_temporary"}):up() - :tag("feature", {var=self:is_hidden() and "muc_hidden" or "muc_public"}):up() + :tag("feature", {var=self:get_moderated() and "muc_moderated" or "muc_unmoderated"}):up() + :tag("feature", {var=self:get_members_only() and "muc_membersonly" or "muc_open"}):up() + :tag("feature", {var=self:get_persistent() and "muc_persistent" or "muc_temporary"}):up() + :tag("feature", {var=self:get_hidden() and "muc_hidden" or "muc_public"}):up() :tag("feature", {var=self._data.whois ~= "anyone" and "muc_semianonymous" or "muc_nonanonymous"}):up() :add_child(dataform.new({ { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" }, @@ -296,7 +296,7 @@ function room_mt:set_moderated(moderated) if self.save then self:save(true); end end end -function room_mt:is_moderated() +function room_mt:get_moderated() return self._data.moderated; end function room_mt:set_members_only(members_only) @@ -306,7 +306,7 @@ function room_mt:set_members_only(members_only) if self.save then self:save(true); end end end -function room_mt:is_members_only() +function room_mt:get_members_only() return self._data.members_only; end function room_mt:set_persistent(persistent) @@ -316,7 +316,7 @@ function room_mt:set_persistent(persistent) if self.save then self:save(true); end end end -function room_mt:is_persistent() +function room_mt:get_persistent() return self._data.persistent; end function room_mt:set_hidden(hidden) @@ -326,9 +326,15 @@ function room_mt:set_hidden(hidden) if self.save then self:save(true); end end end -function room_mt:is_hidden() +function room_mt:get_hidden() return self._data.hidden; end +function room_mt:get_public() + return not self:get_hidden(); +end +function room_mt:set_public(public) + return self:set_hidden(not public); +end function room_mt:set_changesubject(changesubject) changesubject = changesubject and true or nil; if self._data.changesubject ~= changesubject then @@ -604,13 +610,13 @@ function room_mt:get_form_layout() name = 'muc#roomconfig_persistentroom', type = 'boolean', label = 'Make Room Persistent?', - value = self:is_persistent() + value = self:get_persistent() }, { name = 'muc#roomconfig_publicroom', type = 'boolean', label = 'Make Room Publicly Searchable?', - value = not self:is_hidden() + value = not self:get_hidden() }, { name = 'muc#roomconfig_changesubject', @@ -637,13 +643,13 @@ function room_mt:get_form_layout() name = 'muc#roomconfig_moderatedroom', type = 'boolean', label = 'Make Room Moderated?', - value = self:is_moderated() + value = self:get_moderated() }, { name = 'muc#roomconfig_membersonly', type = 'boolean', label = 'Make Room Members-Only?', - value = self:is_members_only() + value = self:get_members_only() }, { name = 'muc#roomconfig_historylength', @@ -655,10 +661,7 @@ function room_mt:get_form_layout() return module:fire_event("muc-config-form", { room = self, form = form }) or form; end -local valid_whois = { - moderators = true, - anyone = true, -} +local valid_whois = { moderators = true, anyone = true }; function room_mt:process_form(origin, stanza) local query = stanza.tags[1]; @@ -671,81 +674,43 @@ function room_mt:process_form(origin, stanza) local fields = self:get_form_layout():data(form); if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); return; end - local dirty = false - local event = { room = self, fields = fields, changed = dirty }; - module:fire_event("muc-config-submitted", event); - dirty = event.changed or dirty; - - local name = fields['muc#roomconfig_roomname']; - if name ~= self:get_name() then - self:set_name(name); - end + local changed = {}; - local description = fields['muc#roomconfig_roomdesc']; - if description ~= self:get_description() then - self:set_description(description); + local function handle_option(name, field, allowed) + local new = fields[field]; + if new == nil then return; end + if allowed and not allowed[new] then return; end + if new == self["get_"..name](self) then return; end + changed[name] = true; + self["set_"..name](self, new); end - local persistent = fields['muc#roomconfig_persistentroom']; - dirty = dirty or (self:is_persistent() ~= persistent) - module:log("debug", "persistent=%s", tostring(persistent)); - - local moderated = fields['muc#roomconfig_moderatedroom']; - dirty = dirty or (self:is_moderated() ~= moderated) - module:log("debug", "moderated=%s", tostring(moderated)); - - local membersonly = fields['muc#roomconfig_membersonly']; - dirty = dirty or (self:is_members_only() ~= membersonly) - module:log("debug", "membersonly=%s", tostring(membersonly)); - - local public = fields['muc#roomconfig_publicroom']; - dirty = dirty or (self:is_hidden() ~= (not public and true or nil)) - - local changesubject = fields['muc#roomconfig_changesubject']; - dirty = dirty or (self:get_changesubject() ~= (not changesubject and true or nil)) - module:log('debug', 'changesubject=%s', changesubject and "true" or "false") - - local historylength = tonumber(fields['muc#roomconfig_historylength']); - dirty = dirty or (historylength and (self:get_historylength() ~= historylength)); - module:log('debug', 'historylength=%s', historylength) + local event = { room = self, fields = fields, changed = changed, stanza = stanza, origin = origin, update_option = handle_option }; + module:fire_event("muc-config-submitted", event); - - local whois = fields['muc#roomconfig_whois']; - if not valid_whois[whois] then - origin.send(st.error_reply(stanza, 'cancel', 'bad-request', "Invalid value for 'whois'")); - return; - end - local whois_changed = self._data.whois ~= whois - self._data.whois = whois - module:log('debug', 'whois=%s', whois) - - local password = fields['muc#roomconfig_roomsecret']; - if self:get_password() ~= password then - self:set_password(password); - end - self:set_moderated(moderated); - self:set_members_only(membersonly); - self:set_persistent(persistent); - self:set_hidden(not public); - self:set_changesubject(changesubject); - self:set_historylength(historylength); + handle_option("name", "muc#roomconfig_roomname"); + handle_option("description", "muc#roomconfig_roomdesc"); + handle_option("persistent", "muc#roomconfig_persistentroom"); + handle_option("moderated", "muc#roomconfig_moderatedroom"); + handle_option("members_only", "muc#roomconfig_membersonly"); + handle_option("public", "muc#roomconfig_publicroom"); + handle_option("changesubject", "muc#roomconfig_changesubject"); + handle_option("historylength", "muc#roomconfig_historylength"); + handle_option("whois", "muc#roomconfig_whois", valid_whois); + handle_option("password", "muc#roomconfig_roomsecret"); if self.save then self:save(true); end origin.send(st.reply(stanza)); - if dirty or whois_changed then + if next(changed) then local msg = st.message({type='groupchat', from=self.jid}) :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up() - - if dirty then - msg.tags[1]:tag('status', {code = '104'}):up(); - end - if whois_changed then + :tag('status', {code = '104'}):up(); + if changed.whois then local code = (whois == 'moderators') and "173" or "172"; msg.tags[1]:tag('status', {code = code}):up(); end - self:broadcast_message(msg, false) end end @@ -943,7 +908,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha :tag('body') -- Add a plain message for clients which don't support invites :text(_from..' invited you to the room '.._to..(_reason and (' ('.._reason..')') or "")) :up(); - if self:is_members_only() and not self:get_affiliation(_invitee) then + if self:get_members_only() and not self:get_affiliation(_invitee) then log("debug", "%s invited %s into members only room %s, granting membership", _from, _invitee, _to); self:set_affiliation(_from, _invitee, "member", nil, "Invited by " .. self._jid_nick[_from]) end -- cgit v1.2.3 From 61ccc4463ded21290bd964409597bbade9781108 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 08:30:28 +0100 Subject: util.iterators: Various fixes and improvements, primarily use pack() where it should be used. --- util/iterators.lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/util/iterators.lua b/util/iterators.lua index 1f6aacb8..8f521fc4 100644 --- a/util/iterators.lua +++ b/util/iterators.lua @@ -10,6 +10,10 @@ local it = {}; +local t_insert = table.insert; +local select, unpack, next = select, unpack, next; +local function pack(...) return { n = select("#", ...), ... }; end + -- Reverse an iterator function it.reverse(f, s, var) local results = {}; @@ -19,7 +23,7 @@ function it.reverse(f, s, var) local ret = { f(s, var) }; var = ret[1]; if var == nil then break; end - table.insert(results, 1, ret); + t_insert(results, 1, ret); end -- Then return our reverse one @@ -55,12 +59,12 @@ function it.unique(f, s, var) return function () while true do - local ret = { f(s, var) }; + local ret = pack(f(s, var)); var = ret[1]; if var == nil then break; end if not set[var] then set[var] = true; - return var; + return unpack(ret, 1, ret.n); end end end; @@ -71,8 +75,7 @@ function it.count(f, s, var) local x = 0; while true do - local ret = { f(s, var) }; - var = ret[1]; + local var = f(s, var); if var == nil then break; end x = x + 1; end @@ -104,7 +107,7 @@ end function it.tail(n, f, s, var) local results, count = {}, 0; while true do - local ret = { f(s, var) }; + local ret = pack(f(s, var)); var = ret[1]; if var == nil then break; end results[(count%n)+1] = ret; @@ -117,7 +120,8 @@ function it.tail(n, f, s, var) return function () pos = pos + 1; if pos > n then return nil; end - return unpack(results[((count-1+pos)%n)+1]); + local ret = results[((count-1+pos)%n)+1]; + return unpack(ret, 1, ret.n); end --return reverse(head(n, reverse(f, s, var))); end @@ -139,7 +143,7 @@ function it.to_array(f, s, var) while true do var = f(s, var); if var == nil then break; end - table.insert(t, var); + t_insert(t, var); end return t; end -- cgit v1.2.3 From d7f5ff243ecc816cad86b5e49ec4ad7c2ceaf83d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 08:31:03 +0100 Subject: util.iterators: Add filter() to run results through a filter function --- util/iterators.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/util/iterators.lua b/util/iterators.lua index 8f521fc4..bcda48b4 100644 --- a/util/iterators.lua +++ b/util/iterators.lua @@ -123,7 +123,21 @@ function it.tail(n, f, s, var) local ret = results[((count-1+pos)%n)+1]; return unpack(ret, 1, ret.n); end - --return reverse(head(n, reverse(f, s, var))); + --return reverse(head(n, reverse(f, s, var))); -- ! +end + +function it.filter(filter, f, s, var) + if type(filter) ~= "function" then + local filter_value = filter; + function filter(x) return x ~= filter_value; end + end + return function (s, var) + local ret; + repeat ret = pack(f(s, var)); + var = ret[1]; + until var == nil or filter(unpack(ret, 1, ret.n)); + return unpack(ret, 1, ret.n); + end, s, var; end local function _ripairs_iter(t, key) if key > 1 then return key-1, t[key-1]; end end -- cgit v1.2.3 From f74284d013a5ffc1b9c5508d4fd0d5b292da29a3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 08:42:21 +0100 Subject: util.iterators: Small fix for variable scoping issue --- util/iterators.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/iterators.lua b/util/iterators.lua index bcda48b4..4b429163 100644 --- a/util/iterators.lua +++ b/util/iterators.lua @@ -75,7 +75,7 @@ function it.count(f, s, var) local x = 0; while true do - local var = f(s, var); + var = f(s, var); if var == nil then break; end x = x + 1; end -- cgit v1.2.3 From 99a110b625c997a25dded7dcadba921fad8560d4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 09:01:11 +0100 Subject: prosodyctl: Add 'check' command, which currently checks the config file for some common mistakes --- prosodyctl | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/prosodyctl b/prosodyctl index 247b099a..262be676 100755 --- a/prosodyctl +++ b/prosodyctl @@ -776,6 +776,58 @@ function commands.cert(arg) show_usage("cert config|request|generate|key", "Helpers for generating X.509 certificates and keys.") end +function commands.check(arg) + local what = table.remove(arg, 1); + local array, set = require "util.array", require "util.set"; + local it = require "util.iterators"; + local ok = true; + if not what or what == "config" then + print("Checking config..."); + local known_global_options = set.new({ + "pidfile", "log", "plugin_paths", "prosody_user", "prosody_group", "daemonize", + "umask", "prosodyctl_timeout", "use_ipv6", "use_libevent", "network_settings" + }); + local config = config.getconfig(); + -- Check that we have any global options (caused by putting a host at the top) + if it.count(it.filter("log", pairs(config["*"]))) == 0 then + ok = false; + print(""); + print(" No global options defined. Perhaps you have put a host definition at the top") + print(" of the config file? They should be at the bottom, see http://prosody.im/doc/configure#overview"); + end + -- Check for global options under hosts + local global_options = set.new(it.to_array(it.keys(config["*"]))); + for host, options in it.filter("*", pairs(config)) do + local host_options = set.new(it.to_array(it.keys(options))); + local misplaced_options = set.intersection(host_options, known_global_options); + for name in pairs(options) do + if name:match("^interfaces?") + or name:match("_ports?$") or name:match("_interfaces?$") + or name:match("_ssl$") then + misplaced_options:add(name); + end + end + if not misplaced_options:empty() then + ok = false; + print(""); + local n = it.count(misplaced_options); + print(" You have "..n.." option"..(n>1 and "s " or " ").."set under "..host.." that should be"); + print(" in the global section of the config file, above any VirtualHost or Component definitions,") + print(" see http://prosody.im/doc/configure#overview for more information.") + print(""); + print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); + end + end + print("Done."); + end + if not ok then + print("Problems found, see above."); + else + print("All checks passed, congratulations!"); + end + return ok and 0 or 2; +end + --------------------- if command and command:match("^mod_") then -- Is a command in a module -- cgit v1.2.3 From a4bd217da1874b9e0837bbda638d7b42eeb7a0e2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 13:35:12 +0100 Subject: prosodyctl: Add 'prosodyctl check dns' to make an attempt at verifying the server's DNS records --- prosodyctl | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 262be676..d3ba8932 100755 --- a/prosodyctl +++ b/prosodyctl @@ -818,7 +818,148 @@ function commands.check(arg) print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); end end - print("Done."); + print("Done.\n"); + end + if not what or what == "dns" then + local dns = require "net.dns"; + local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222}); + local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269}); + + local c2s_srv_required, s2s_srv_required; + if not c2s_ports:contains(5222) then + c2s_srv_required = true; + end + if not s2s_ports:contains(5269) then + s2s_srv_required = true; + end + + local problem_hosts = set.new(); + + local external_addresses = set.new(); + + local fqdn = socket.dns.tohostname(socket.dns.gethostname()); + if fqdn then + local res = dns.lookup(fqdn, "A"); + if res then + for _, record in ipairs(res) do + external_addresses:add(record.a); + end + end + local res = dns.lookup(fqdn, "AAAA"); + if res then + for _, record in ipairs(res) do + external_addresses:add(record.aaaa); + end + end + end + + if external_addresses:empty() then + print(""); + print(" Failed to determine the external addresses of this server. Checks may be inaccurate."); + c2s_srv_required, s2s_srv_required = true, true; + end + + local v6_supported = not not socket.tcp6; + + for host, host_options in it.filter("*", pairs(config.getconfig())) do + local all_targets_ok, some_targets_ok = true, false; + + local is_component = not not host_options.component_module; + print("Checking DNS for "..(is_component and "component" or "host").." "..host.."..."); + local target_hosts = set.new(); + if not is_component then + local res = dns.lookup("_xmpp-client._tcp."..host..".", "SRV"); + if res then + for _, record in ipairs(res) do + target_hosts:add(record.srv.target); + if not c2s_ports:contains(record.srv.port) then + print(" SRV target "..record.srv.target.." contains unknown client port: "..record.srv.port); + end + end + else + if c2s_srv_required then + print(" No _xmpp-client SRV record found for "..host..", but it looks like you need one."); + else + target_hosts:add(host); + end + end + end + local res = dns.lookup("_xmpp-server._tcp."..host..".", "SRV"); + if res then + for _, record in ipairs(res) do + target_hosts:add(record.srv.target); + if not s2s_ports:contains(record.srv.port) then + print(" SRV target "..record.srv.target.." contains unknown server port: "..record.srv.port); + end + end + else + if s2s_srv_required then + print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one."); + else + target_hosts:add(host); + end + end + if target_hosts:empty() then + target_hosts:add(host); + end + + if target_hosts:contains("localhost") then + print(" Target 'localhost' cannot be accessed from other servers"); + target_hosts:remove("localhost"); + end + + for host in target_hosts do + local host_ok_v4, host_ok_v6; + local res = dns.lookup(host, "A"); + if res then + for _, record in ipairs(res) do + if external_addresses:contains(record.a) then + some_targets_ok = true; + host_ok_v4 = true; + else + print(" "..host.." A record points to unknown address "..record.a); + all_targets_ok = false; + end + end + end + local res = dns.lookup(host, "AAAA"); + if res then + for _, record in ipairs(res) do + if external_addresses:contains(record.aaaa) then + some_targets_ok = true; + host_ok_v6 = true; + else + print(" "..host.." AAAA record points to unknown address "..record.aaaa); + all_targets_ok = false; + end + end + end + + if not host_ok_v4 then + print(" Host "..host.." does not seem to resolve to this server for IPv4"); + end + if not host_ok_v6 and v6_supported then + print(" Host "..host.." does not seem to resolve to this server for IPv6"); + elseif host_ok_v6 and not v6_supported then + print(" Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6."); + print(" Please see http://prosody.im/doc/ipv6 for more information."); + end + end + if not all_targets_ok then + print(" "..(some_targets_ok and "Only some" or "No").." targets for "..host.." appear to resolve to this server."); + if is_component then + print(" DNS records are necessary if you want users on other servers to access this component."); + end + print(""); + problem_hosts:add(host); + end + end + if not problem_hosts:empty() then + print(""); + print("For more information about DNS configuration please see http://prosody.im/doc/dns"); + print(""); + ok = false; + end end if not ok then print("Problems found, see above."); -- cgit v1.2.3 From 12da21e1b07b79f4e72902b5da27550d9051d691 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 17 May 2013 14:56:06 +0200 Subject: mod_admin_telnet: List session flags (encryption, compression etc) the same way for c2s as s2s --- plugins/mod_admin_telnet.lua | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index b67ba576..08fe57c0 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -484,6 +484,25 @@ end function def_env.hosts:add(name) end +local function session_flags(session, line) + line = line or {}; + if session.cert_identity_status == "valid" then + line[#line+1] = "(secure)"; + elseif session.secure then + line[#line+1] = "(encrypted)"; + end + if session.compressed then + line[#line+1] = "(compressed)"; + end + if session.smacks then + line[#line+1] = "(sm)"; + end + if (session.ip or session.conn and session.conn:ip()):match(":") then + line[#line+1] = "(IPv6)"; + end + return table.concat(line, " "); +end + def_env.c2s = {}; local function show_c2s(callback) @@ -526,7 +545,7 @@ function def_env.c2s:show(match_jid) status = "available"; end end - print(" "..jid.." - "..status.."("..priority..")"); + print(session_flags(session, { " "..jid.." - "..status.."("..priority..")" })); end end); return true, "Total: "..count.." clients"; @@ -565,23 +584,6 @@ function def_env.c2s:close(match_jid) return true, "Total: "..count.." sessions closed"; end -local function session_flags(session, line) - if session.cert_identity_status == "valid" then - line[#line+1] = "(secure)"; - elseif session.secure then - line[#line+1] = "(encrypted)"; - end - if session.compressed then - line[#line+1] = "(compressed)"; - end - if session.smacks then - line[#line+1] = "(sm)"; - end - if session.conn and session.conn:ip():match(":") then - line[#line+1] = "(IPv6)"; - end - return table.concat(line, " "); -end def_env.s2s = {}; function def_env.s2s:show(match_jid) -- cgit v1.2.3 From 4d630bbd3cb0478ca5b90f0d27d6b801751c4472 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:52:52 +0100 Subject: util.ip: Automatically determine protocol of IP address if none specified. Return error if invalid. --- util/ip.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/util/ip.lua b/util/ip.lua index de287b16..9e668d1b 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -12,7 +12,15 @@ local ip_mt = { __index = function (ip, key) return (ip_methods[key])(ip); end, local hex2bits = { ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111" }; local function new_ip(ipStr, proto) - if proto ~= "IPv4" and proto ~= "IPv6" then + if not proto then + local sep = ipStr:match("^%x+(.)"); + if sep == ":" then proto = "IPv6" + elseif sep == "." then proto = "IPv4" + end + if not proto then + return nil, "invalid address"; + end + elseif proto ~= "IPv4" and proto ~= "IPv6" then return nil, "invalid protocol"; end -- cgit v1.2.3 From e082db3cf78c91b937a996cae2c71511df616e84 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:53:51 +0100 Subject: util.ip: Add 'private' method/property to determine whether an IP address is generally expected to be internet-routeable (YMMV) --- util/ip.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/util/ip.lua b/util/ip.lua index 9e668d1b..6ebc023b 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -193,5 +193,20 @@ function ip_methods:scope() return value; end +function ip_methods:private() + local private = self.scope ~= 0xE; + if not private and self.proto == "IPv4" then + local ip = self.addr; + local fields = {}; + ip:gsub("([^.]*).?", function (c) fields[#fields + 1] = tonumber(c) end); + if fields[1] == 127 or fields[1] == 10 or (fields[1] == 192 and fields[2] == 168) + or (fields[1] == 172 and (fields[2] >= 16 or fields[2] <= 32)) then + private = true; + end + end + self.private = private; + return private; +end + return {new_ip = new_ip, commonPrefixLength = commonPrefixLength}; -- cgit v1.2.3 From 3d22661def97ba52851d798e6795fd8f2460b61e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:55:05 +0100 Subject: prosodyctl: check dns: Correctly mark host as failed if expected SRV records are not found --- prosodyctl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prosodyctl b/prosodyctl index d3ba8932..11c6296b 100755 --- a/prosodyctl +++ b/prosodyctl @@ -879,6 +879,7 @@ function commands.check(arg) else if c2s_srv_required then print(" No _xmpp-client SRV record found for "..host..", but it looks like you need one."); + all_targst_ok = false; else target_hosts:add(host); end @@ -895,6 +896,7 @@ function commands.check(arg) else if s2s_srv_required then print(" No _xmpp-server SRV record found for "..host..", but it looks like you need one."); + all_targets_ok = false; else target_hosts:add(host); end -- cgit v1.2.3 From 45e58c98b5e4602efaf1d24ec6d23d07d67b006a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:55:57 +0100 Subject: prosodyctl: check dns: More concise output (merged separate v4/v6 warnings) --- prosodyctl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/prosodyctl b/prosodyctl index 11c6296b..e0114e3a 100755 --- a/prosodyctl +++ b/prosodyctl @@ -937,12 +937,17 @@ function commands.check(arg) end end + local bad_protos = {} if not host_ok_v4 then - print(" Host "..host.." does not seem to resolve to this server for IPv4"); + table.insert(bad_protos, "IPv4"); end - if not host_ok_v6 and v6_supported then - print(" Host "..host.." does not seem to resolve to this server for IPv6"); - elseif host_ok_v6 and not v6_supported then + if not host_ok_v6 then + table.insert(bad_protos, "IPv6"); + end + if #bad_protos > 0 then + print(" Host "..host.." does not seem to resolve to this server ("..table.concat(bad_protos, "/")..")"); + end + if host_ok_v6 and not v6_supported then print(" Host "..host.." has AAAA records, but your version of LuaSocket does not support IPv6."); print(" Please see http://prosody.im/doc/ipv6 for more information."); end -- cgit v1.2.3 From ad9525152440cec194c1c3f8effae68a27e719d6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:56:18 +0100 Subject: prosodyctl: check dns: Whitespace fix in output --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index e0114e3a..f5763f92 100755 --- a/prosodyctl +++ b/prosodyctl @@ -957,9 +957,9 @@ function commands.check(arg) if is_component then print(" DNS records are necessary if you want users on other servers to access this component."); end - print(""); problem_hosts:add(host); end + print(""); end if not problem_hosts:empty() then print(""); -- cgit v1.2.3 From 87c32db77c63f9ada68a7d612a1379286cf0f8c8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 17 May 2013 14:56:36 +0100 Subject: prosodyctl: check dns: Use socket.local_addresses() if available --- prosodyctl | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index f5763f92..41f3b8dc 100755 --- a/prosodyctl +++ b/prosodyctl @@ -822,6 +822,7 @@ function commands.check(arg) end if not what or what == "dns" then local dns = require "net.dns"; + local ip = require "util.ip"; local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222}); local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269}); @@ -835,7 +836,7 @@ function commands.check(arg) local problem_hosts = set.new(); - local external_addresses = set.new(); + local external_addresses, internal_addresses = set.new(), set.new(); local fqdn = socket.dns.tohostname(socket.dns.gethostname()); if fqdn then @@ -853,6 +854,16 @@ function commands.check(arg) end end + local local_addresses = socket.local_addresses and socket.local_addresses() or {}; + + for addr in it.values(local_addresses) do + if not ip.new_ip(addr).private then + external_addresses:add(addr); + else + internal_addresses:add(addr); + end + end + if external_addresses:empty() then print(""); print(" Failed to determine the external addresses of this server. Checks may be inaccurate."); @@ -918,6 +929,10 @@ function commands.check(arg) if external_addresses:contains(record.a) then some_targets_ok = true; host_ok_v4 = true; + elseif internal_addresses:contains(record.a) then + host_ok_v4 = true; + some_targets_ok = true; + print(" "..host.." A record points to internal address, external connections might fail"); else print(" "..host.." A record points to unknown address "..record.a); all_targets_ok = false; @@ -930,6 +945,10 @@ function commands.check(arg) if external_addresses:contains(record.aaaa) then some_targets_ok = true; host_ok_v6 = true; + elseif internal_addresses:contains(record.aaaa) then + host_ok_v6 = true; + some_targets_ok = true; + print(" "..host.." AAAA record points to internal address, external connections might fail"); else print(" "..host.." AAAA record points to unknown address "..record.aaaa); all_targets_ok = false; -- cgit v1.2.3 From 73fe0d54714b34a0a202f1d1e9f2390ad9a54ad6 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 17 May 2013 18:28:05 +0200 Subject: mod_admin_telnet: Use stanza:get_child_text() --- plugins/mod_admin_telnet.lua | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 08fe57c0..2056f1e2 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -538,12 +538,7 @@ function def_env.c2s:show(match_jid) count = count + 1; local status, priority = "unavailable", tostring(session.priority or "-"); if session.presence then - status = session.presence:child_with_name("show"); - if status then - status = status:get_text() or "[invalid!]"; - else - status = "available"; - end + status = session.presence:get_child_text("show") or "available"; end print(session_flags(session, { " "..jid.." - "..status.."("..priority..")" })); end -- cgit v1.2.3 From 5950b8bdd2cf6554204090fa6a69867d8236e749 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 15:28:00 +0100 Subject: mod_muc: Add getter/setter for 'whois' (fixes traceback) --- plugins/muc/muc.lib.lua | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 833b1154..6b3bdcb0 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -357,6 +357,19 @@ function room_mt:set_historylength(length) end +local valid_whois = { moderators = true, anyone = true }; + +function room_mt:set_whois(whois) + if valid_whois[whois] and self._data.whois ~= whois then + self._data.whois = whois; + if self.save then self:save(true); end + end +end + +function room_mt:get_whois() + return self._data.whois; +end + local function construct_stanza_id(room, stanza) local from_jid, to_nick = stanza.attr.from, stanza.attr.to; local from_nick = room._jid_nick[from_jid]; @@ -661,8 +674,6 @@ function room_mt:get_form_layout() return module:fire_event("muc-config-form", { room = self, form = form }) or form; end -local valid_whois = { moderators = true, anyone = true }; - function room_mt:process_form(origin, stanza) local query = stanza.tags[1]; local form; @@ -708,7 +719,7 @@ function room_mt:process_form(origin, stanza) :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up() :tag('status', {code = '104'}):up(); if changed.whois then - local code = (whois == 'moderators') and "173" or "172"; + local code = (self:get_whois() == 'moderators') and "173" or "172"; msg.tags[1]:tag('status', {code = code}):up(); end self:broadcast_message(msg, false) -- cgit v1.2.3 From 5cea0b157002bff872b559c59aa77b30ec2634df Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 15:29:10 +0100 Subject: mod_muc: Pass actor (requesting JID) when generating the config form, and to the muc-config-form event handler --- plugins/muc/muc.lib.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 6b3bdcb0..68e36e83 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -594,11 +594,11 @@ end function room_mt:send_form(origin, stanza) origin.send(st.reply(stanza):query("http://jabber.org/protocol/muc#owner") - :add_child(self:get_form_layout():form()) + :add_child(self:get_form_layout(stanza.attr.from):form()) ); end -function room_mt:get_form_layout() +function room_mt:get_form_layout(actor) local form = dataform.new({ title = "Configuration for "..self.jid, instructions = "Complete and submit this form to configure the room.", @@ -671,7 +671,7 @@ function room_mt:get_form_layout() value = tostring(self:get_historylength()) } }); - return module:fire_event("muc-config-form", { room = self, form = form }) or form; + return module:fire_event("muc-config-form", { room = self, actor = actor, form = form }) or form; end function room_mt:process_form(origin, stanza) @@ -682,7 +682,7 @@ function room_mt:process_form(origin, stanza) if form.attr.type == "cancel" then origin.send(st.reply(stanza)); return; end if form.attr.type ~= "submit" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); return; end - local fields = self:get_form_layout():data(form); + local fields = self:get_form_layout(stanza.attr.from):data(form); if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); return; end -- cgit v1.2.3 From 62a1d8a2d312c61673f868878efdcb747c63f772 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 16:45:29 +0100 Subject: util.ip: Add CIDR notation parsing and matching --- util/ip.lua | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/util/ip.lua b/util/ip.lua index 20ea3dd7..8cf0076e 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -215,5 +215,28 @@ function ip_methods:private() return private; end +local function parse_cidr(cidr) + local bits; + local ip_len = cidr:find("/", 1, true); + if ip_len then + bits = tonumber(cidr:sub(ip_len+1, -1)); + cidr = cidr:sub(1, ip_len-1); + end + return new_ip(cidr), bits; +end + +local function match(ipA, ipB, bits) + local common_bits = commonPrefixLength(ipA, ipB); + if not bits then + return ipA == ipB; + end + if bits and ipB.proto == "IPv4" then + common_bits = common_bits - 96; -- v6 mapped addresses always share these bits + end + return common_bits >= bits; +end + return {new_ip = new_ip, - commonPrefixLength = commonPrefixLength}; + commonPrefixLength = commonPrefixLength, + parse_cidr = parse_cidr, + match=match}; -- cgit v1.2.3 From e491b17e6f0187c419ac9a4d7178d9b1b9ac88be Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 17:14:30 +0100 Subject: tests: Some much-needed cleanup... --- tests/test.lua | 16 ++++++++---- tests/test_core_modulemanager.lua | 48 ------------------------------------ tests/test_core_s2smanager.lua | 3 +++ tests/test_net_http.lua | 37 ---------------------------- tests/test_util_http.lua | 37 ++++++++++++++++++++++++++++ tests/test_util_ip.lua | 7 ++++++ tests/test_util_rfc3484.lua | 51 --------------------------------------- tests/test_util_rfc6724.lua | 51 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 109 insertions(+), 141 deletions(-) delete mode 100644 tests/test_core_modulemanager.lua delete mode 100644 tests/test_net_http.lua create mode 100644 tests/test_util_http.lua create mode 100644 tests/test_util_ip.lua delete mode 100644 tests/test_util_rfc3484.lua create mode 100644 tests/test_util_rfc6724.lua diff --git a/tests/test.lua b/tests/test.lua index db727ce1..b6728061 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -12,12 +12,12 @@ function run_all_tests() package.loaded["net.connlisteners"] = { get = function () return {} end }; dotest "util.jid" dotest "util.multitable" - dotest "util.rfc3484" - dotest "net.http" - dotest "core.modulemanager" + dotest "util.rfc6724" + dotest "util.http" dotest "core.stanza_router" dotest "core.s2smanager" dotest "core.configmanager" + dotest "util.ip" dotest "util.stanza" dotest "util.sasl.scram" @@ -136,15 +136,21 @@ function dotest(unitname) end local oldmodule, old_M = _fakeG.module, _fakeG._M; - _fakeG.module = function () _M = _G end + _fakeG.module = function () _M = unit end setfenv(chunk, unit); - local success, err = pcall(chunk); + local success, ret = pcall(chunk); _fakeG.module, _fakeG._M = oldmodule, old_M; if not success then print("WARNING: ", "Failed to initialise module: "..unitname, err); return; end + if type(ret) == "table" then + for k,v in pairs(ret) do + unit[k] = v; + end + end + for name, f in pairs(unit) do local test = rawget(tests, name); if type(f) ~= "function" then diff --git a/tests/test_core_modulemanager.lua b/tests/test_core_modulemanager.lua deleted file mode 100644 index 9498875a..00000000 --- a/tests/test_core_modulemanager.lua +++ /dev/null @@ -1,48 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -local config = require "core.configmanager"; -local helpers = require "util.helpers"; -local set = require "util.set"; - -function load_modules_for_host(load_modules_for_host, mm) - local test_num = 0; - local function test_load(global_modules_enabled, global_modules_disabled, host_modules_enabled, host_modules_disabled, expected_modules) - test_num = test_num + 1; - -- Prepare - hosts = { ["example.com"] = {} }; - config.set("*", "core", "modules_enabled", global_modules_enabled); - config.set("*", "core", "modules_disabled", global_modules_disabled); - config.set("example.com", "core", "modules_enabled", host_modules_enabled); - config.set("example.com", "core", "modules_disabled", host_modules_disabled); - - expected_modules = set.new(expected_modules); - expected_modules:add_list(helpers.get_upvalue(load_modules_for_host, "autoload_modules")); - - local loaded_modules = set.new(); - function mm.load(host, module) - assert_equal(host, "example.com", test_num..": Host isn't example.com but "..tostring(host)); - assert_equal(expected_modules:contains(module), true, test_num..": Loading unexpected module '"..tostring(module).."'"); - loaded_modules:add(module); - end - load_modules_for_host("example.com"); - assert_equal((expected_modules - loaded_modules):empty(), true, test_num..": Not all modules loaded: "..tostring(expected_modules - loaded_modules)); - end - - test_load({ "one", "two", "three" }, nil, nil, nil, { "one", "two", "three" }); - test_load({ "one", "two", "three" }, {}, nil, nil, { "one", "two", "three" }); - test_load({ "one", "two", "three" }, { "two" }, nil, nil, { "one", "three" }); - test_load({ "one", "two", "three" }, { "three" }, nil, nil, { "one", "two" }); - test_load({ "one", "two", "three" }, nil, nil, { "three" }, { "one", "two" }); - test_load({ "one", "two", "three" }, nil, { "three" }, { "three" }, { "one", "two", "three" }); - - test_load({ "one", "two" }, nil, { "three" }, nil, { "one", "two", "three" }); - test_load({ "one", "two", "three" }, nil, { "three" }, nil, { "one", "two", "three" }); - test_load({ "one", "two", "three" }, { "three" }, { "three" }, nil, { "one", "two", "three" }); - test_load({ "one", "two" }, { "three" }, { "three" }, nil, { "one", "two", "three" }); -end diff --git a/tests/test_core_s2smanager.lua b/tests/test_core_s2smanager.lua index b49c7da6..7194d201 100644 --- a/tests/test_core_s2smanager.lua +++ b/tests/test_core_s2smanager.lua @@ -6,6 +6,9 @@ -- COPYING file in the source package for more information. -- +env = { + prosody = { events = require "util.events".new() }; +}; function compare_srv_priorities(csp) local r1 = { priority = 10, weight = 0 } diff --git a/tests/test_net_http.lua b/tests/test_net_http.lua deleted file mode 100644 index e68f96e9..00000000 --- a/tests/test_net_http.lua +++ /dev/null @@ -1,37 +0,0 @@ --- Prosody IM --- Copyright (C) 2008-2010 Matthew Wild --- Copyright (C) 2008-2010 Waqas Hussain --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -function urlencode(urlencode) - assert_equal(urlencode("helloworld123"), "helloworld123", "Normal characters not escaped"); - assert_equal(urlencode("hello world"), "hello%20world", "Spaces escaped"); - assert_equal(urlencode("This & that = something"), "This%20%26%20that%20%3d%20something", "Important URL chars escaped"); -end - -function urldecode(urldecode) - assert_equal("helloworld123", urldecode("helloworld123"), "Normal characters not escaped"); - assert_equal("hello world", urldecode("hello%20world"), "Spaces escaped"); - assert_equal("This & that = something", urldecode("This%20%26%20that%20%3d%20something"), "Important URL chars escaped"); - assert_equal("This & that = something", urldecode("This%20%26%20that%20%3D%20something"), "Important URL chars escaped"); -end - -function formencode(formencode) - assert_equal(formencode({ { name = "one", value = "1"}, { name = "two", value = "2" } }), "one=1&two=2", "Form encoded"); - assert_equal(formencode({ { name = "one two", value = "1"}, { name = "two one&", value = "2" } }), "one+two=1&two+one%26=2", "Form encoded"); -end - -function formdecode(formdecode) - local t = formdecode("one=1&two=2"); - assert_table(t[1]); - assert_equal(t[1].name, "one"); assert_equal(t[1].value, "1"); - assert_table(t[2]); - assert_equal(t[2].name, "two"); assert_equal(t[2].value, "2"); - - local t = formdecode("one+two=1&two+one%26=2"); - assert_equal(t[1].name, "one two"); assert_equal(t[1].value, "1"); - assert_equal(t[2].name, "two one&"); assert_equal(t[2].value, "2"); -end diff --git a/tests/test_util_http.lua b/tests/test_util_http.lua new file mode 100644 index 00000000..e68f96e9 --- /dev/null +++ b/tests/test_util_http.lua @@ -0,0 +1,37 @@ +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +function urlencode(urlencode) + assert_equal(urlencode("helloworld123"), "helloworld123", "Normal characters not escaped"); + assert_equal(urlencode("hello world"), "hello%20world", "Spaces escaped"); + assert_equal(urlencode("This & that = something"), "This%20%26%20that%20%3d%20something", "Important URL chars escaped"); +end + +function urldecode(urldecode) + assert_equal("helloworld123", urldecode("helloworld123"), "Normal characters not escaped"); + assert_equal("hello world", urldecode("hello%20world"), "Spaces escaped"); + assert_equal("This & that = something", urldecode("This%20%26%20that%20%3d%20something"), "Important URL chars escaped"); + assert_equal("This & that = something", urldecode("This%20%26%20that%20%3D%20something"), "Important URL chars escaped"); +end + +function formencode(formencode) + assert_equal(formencode({ { name = "one", value = "1"}, { name = "two", value = "2" } }), "one=1&two=2", "Form encoded"); + assert_equal(formencode({ { name = "one two", value = "1"}, { name = "two one&", value = "2" } }), "one+two=1&two+one%26=2", "Form encoded"); +end + +function formdecode(formdecode) + local t = formdecode("one=1&two=2"); + assert_table(t[1]); + assert_equal(t[1].name, "one"); assert_equal(t[1].value, "1"); + assert_table(t[2]); + assert_equal(t[2].name, "two"); assert_equal(t[2].value, "2"); + + local t = formdecode("one+two=1&two+one%26=2"); + assert_equal(t[1].name, "one two"); assert_equal(t[1].value, "1"); + assert_equal(t[2].name, "two one&"); assert_equal(t[2].value, "2"); +end diff --git a/tests/test_util_ip.lua b/tests/test_util_ip.lua new file mode 100644 index 00000000..ce7c397f --- /dev/null +++ b/tests/test_util_ip.lua @@ -0,0 +1,7 @@ + +function test_match(match_ip) + assert(match_ip("10.20.30.40", "10.0.0.0/8")); + assert(match_ip("80.244.94.84", "80.244.94.84")); + assert(match_ip("8.8.8.8", "8.8.0.0/16")); + assert(match_ip("8.8.4.4", "8.8.0.0/16")); +end diff --git a/tests/test_util_rfc3484.lua b/tests/test_util_rfc3484.lua deleted file mode 100644 index 18ae310e..00000000 --- a/tests/test_util_rfc3484.lua +++ /dev/null @@ -1,51 +0,0 @@ --- Prosody IM --- Copyright (C) 2011 Florian Zeitz --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- - -function source(source) - local new_ip = require"util.ip".new_ip; - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("3ffe::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr, "3ffe::1", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); - assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "2001::1", "prefer appropriate scope"); - assert_equal(source(new_ip("ff05::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::1", "IPv6"), new_ip("2002::1", "IPv6")}).addr, "2001::1", "prefer same address"); - assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fec0::2", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::2", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::2", "IPv6"), new_ip("3ffe::2", "IPv6")}).addr, "2001::2", "longest matching prefix"); - assert_equal(source(new_ip("2002:836b:2179::1", "IPv6"), {new_ip("2002:836b:2179::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001::2", "IPv6")}).addr, "2002:836b:2179::d5e3:7953:13eb:22e8", "prefer matching label"); -end - -function destination(dest) - local order; - local new_ip = require"util.ip".new_ip; - order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")}) - assert_equal(order[1].addr, "2001::1", "prefer matching scope"); - assert_equal(order[2].addr, "131.107.65.121", "prefer matching scope") - - order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("fe80::1", "IPv6"), new_ip("131.107.65.117", "IPv4")}) - assert_equal(order[1].addr, "131.107.65.121", "prefer matching scope") - assert_equal(order[2].addr, "2001::1", "prefer matching scope") - - order = dest({new_ip("2001::1", "IPv6"), new_ip("10.1.2.3", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")}) - assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); - assert_equal(order[2].addr, "10.1.2.3", "prefer higher precedence"); - - order = dest({new_ip("2001::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "fe80::1", "prefer smaller scope"); - assert_equal(order[2].addr, "fec0::1", "prefer smaller scope"); - assert_equal(order[3].addr, "2001::1", "prefer smaller scope"); - - order = dest({new_ip("2001::1", "IPv6"), new_ip("3ffe::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2001::1", "longest matching prefix"); - assert_equal(order[2].addr, "3ffe::1", "longest matching prefix"); - - order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2002:836b:4179::1", "prefer matching label"); - assert_equal(order[2].addr, "2001::1", "prefer matching label"); - - order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("2001::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); - assert_equal(order[2].addr, "2002:836b:4179::1", "prefer higher precedence"); -end diff --git a/tests/test_util_rfc6724.lua b/tests/test_util_rfc6724.lua new file mode 100644 index 00000000..18ae310e --- /dev/null +++ b/tests/test_util_rfc6724.lua @@ -0,0 +1,51 @@ +-- Prosody IM +-- Copyright (C) 2011 Florian Zeitz +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +function source(source) + local new_ip = require"util.ip".new_ip; + assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("3ffe::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr, "3ffe::1", "prefer appropriate scope"); + assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); + assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "2001::1", "prefer appropriate scope"); + assert_equal(source(new_ip("ff05::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); + assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::1", "IPv6"), new_ip("2002::1", "IPv6")}).addr, "2001::1", "prefer same address"); + assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fec0::2", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::2", "prefer appropriate scope"); + assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::2", "IPv6"), new_ip("3ffe::2", "IPv6")}).addr, "2001::2", "longest matching prefix"); + assert_equal(source(new_ip("2002:836b:2179::1", "IPv6"), {new_ip("2002:836b:2179::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001::2", "IPv6")}).addr, "2002:836b:2179::d5e3:7953:13eb:22e8", "prefer matching label"); +end + +function destination(dest) + local order; + local new_ip = require"util.ip".new_ip; + order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")}) + assert_equal(order[1].addr, "2001::1", "prefer matching scope"); + assert_equal(order[2].addr, "131.107.65.121", "prefer matching scope") + + order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("fe80::1", "IPv6"), new_ip("131.107.65.117", "IPv4")}) + assert_equal(order[1].addr, "131.107.65.121", "prefer matching scope") + assert_equal(order[2].addr, "2001::1", "prefer matching scope") + + order = dest({new_ip("2001::1", "IPv6"), new_ip("10.1.2.3", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")}) + assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); + assert_equal(order[2].addr, "10.1.2.3", "prefer higher precedence"); + + order = dest({new_ip("2001::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "fe80::1", "prefer smaller scope"); + assert_equal(order[2].addr, "fec0::1", "prefer smaller scope"); + assert_equal(order[3].addr, "2001::1", "prefer smaller scope"); + + order = dest({new_ip("2001::1", "IPv6"), new_ip("3ffe::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001::1", "longest matching prefix"); + assert_equal(order[2].addr, "3ffe::1", "longest matching prefix"); + + order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2002:836b:4179::1", "prefer matching label"); + assert_equal(order[2].addr, "2001::1", "prefer matching label"); + + order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("2001::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); + assert_equal(order[2].addr, "2002:836b:4179::1", "prefer higher precedence"); +end -- cgit v1.2.3 From 75fe955f7d00be12e57b7beca24f3ed0ab5d384f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 17:17:56 +0100 Subject: tests/test_core_configmanager.lua: Update to remove tests based on sections (now removed) --- tests/test_core_configmanager.lua | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/test_core_configmanager.lua b/tests/test_core_configmanager.lua index 132dfc74..d7919965 100644 --- a/tests/test_core_configmanager.lua +++ b/tests/test_core_configmanager.lua @@ -9,27 +9,23 @@ function get(get, config) - config.set("example.com", "test", "testkey", 123); - assert_equal(get("example.com", "test", "testkey"), 123, "Retrieving a set key"); + config.set("example.com", "testkey", 123); + assert_equal(get("example.com", "testkey"), 123, "Retrieving a set key"); - config.set("*", "test", "testkey1", 321); - assert_equal(get("*", "test", "testkey1"), 321, "Retrieving a set global key"); - assert_equal(get("example.com", "test", "testkey1"), 321, "Retrieving a set key of undefined host, of which only a globally set one exists"); + config.set("*", "testkey1", 321); + assert_equal(get("*", "testkey1"), 321, "Retrieving a set global key"); + assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key of undefined host, of which only a globally set one exists"); - config.set("example.com", "test", ""); -- Creates example.com host in config - assert_equal(get("example.com", "test", "testkey1"), 321, "Retrieving a set key, of which only a globally set one exists"); + config.set("example.com", ""); -- Creates example.com host in config + assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key, of which only a globally set one exists"); assert_equal(get(), nil, "No parameters to get()"); assert_equal(get("undefined host"), nil, "Getting for undefined host"); - assert_equal(get("undefined host", "undefined section"), nil, "Getting for undefined host & section"); - assert_equal(get("undefined host", "undefined section", "undefined key"), nil, "Getting for undefined host & section & key"); - - assert_equal(get("example.com", "undefined section", "testkey"), nil, "Defined host, undefined section"); + assert_equal(get("undefined host", "undefined key"), nil, "Getting for undefined host & key"); end function set(set, u) - assert_equal(set("*"), false, "Set with no section/key"); - assert_equal(set("*", "set_test"), false, "Set with no key"); + assert_equal(set("*"), false, "Set with no key"); assert_equal(set("*", "set_test", "testkey"), true, "Setting a nil global value"); assert_equal(set("*", "set_test", "testkey", 123), true, "Setting a global value"); -- cgit v1.2.3 From afd634ee6c958694a1cef66f22334b4ee0b87c9d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 17:44:01 +0100 Subject: test_util_ip: Add tests for IP matching --- tests/test_util_ip.lua | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/tests/test_util_ip.lua b/tests/test_util_ip.lua index ce7c397f..e30b30b6 100644 --- a/tests/test_util_ip.lua +++ b/tests/test_util_ip.lua @@ -1,7 +1,30 @@ -function test_match(match_ip) - assert(match_ip("10.20.30.40", "10.0.0.0/8")); - assert(match_ip("80.244.94.84", "80.244.94.84")); - assert(match_ip("8.8.8.8", "8.8.0.0/16")); - assert(match_ip("8.8.4.4", "8.8.0.0/16")); +function match(match) + local _ = require "util.ip".new_ip; + local ip = _"10.20.30.40"; + assert_equal(match(ip, _"10.0.0.0", 8), true); + assert_equal(match(ip, _"10.0.0.0", 16), false); + assert_equal(match(ip, _"10.0.0.0", 24), false); + assert_equal(match(ip, _"10.0.0.0", 32), false); + + assert_equal(match(ip, _"10.20.0.0", 8), true); + assert_equal(match(ip, _"10.20.0.0", 16), true); + assert_equal(match(ip, _"10.20.0.0", 24), false); + assert_equal(match(ip, _"10.20.0.0", 32), false); + + assert_equal(match(ip, _"0.0.0.0", 32), false); + assert_equal(match(ip, _"0.0.0.0", 0), true); + assert_equal(match(ip, _"0.0.0.0"), false); + + assert_equal(match(ip, _"10.0.0.0", 255), false, "excessive number of bits"); + assert_equal(match(ip, _"10.0.0.0", -8), true, "negative number of bits"); + assert_equal(match(ip, _"10.0.0.0", -32), true, "negative number of bits"); + assert_equal(match(ip, _"10.0.0.0", 0), true, "zero bits"); + assert_equal(match(ip, _"10.0.0.0"), false, "no specified number of bits (differing ip)"); + assert_equal(match(ip, _"10.20.30.40"), true, "no specified number of bits (same ip)"); + + assert_equal(match(_"80.244.94.84", _"80.244.94.84"), true, "simple ip"); + + assert_equal(match(_"8.8.8.8", _"8.8.0.0", 16), true); + assert_equal(match(_"8.8.4.4", _"8.8.0.0", 16), true); end -- cgit v1.2.3 From 7f6333bd83cec64412862e4c49dce81e9873fa96 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 21:40:40 +0100 Subject: test_util_ip.lua: Add more tests for util.ip --- tests/test_util_ip.lua | 65 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/tests/test_util_ip.lua b/tests/test_util_ip.lua index e30b30b6..410f1da2 100644 --- a/tests/test_util_ip.lua +++ b/tests/test_util_ip.lua @@ -1,6 +1,6 @@ -function match(match) - local _ = require "util.ip".new_ip; +function match(match, _M) + local _ = _M.new_ip; local ip = _"10.20.30.40"; assert_equal(match(ip, _"10.0.0.0", 8), true); assert_equal(match(ip, _"10.0.0.0", 16), false); @@ -23,8 +23,67 @@ function match(match) assert_equal(match(ip, _"10.0.0.0"), false, "no specified number of bits (differing ip)"); assert_equal(match(ip, _"10.20.30.40"), true, "no specified number of bits (same ip)"); - assert_equal(match(_"80.244.94.84", _"80.244.94.84"), true, "simple ip"); + assert_equal(match(_"127.0.0.1", _"127.0.0.1"), true, "simple ip"); assert_equal(match(_"8.8.8.8", _"8.8.0.0", 16), true); assert_equal(match(_"8.8.4.4", _"8.8.0.0", 16), true); end + +function parse_cidr(parse_cidr, _M) + local new_ip = _M.new_ip; + + assert_equal(new_ip"0.0.0.0", new_ip"0.0.0.0") + + local function assert_cidr(cidr, ip, bits) + local parsed_ip, parsed_bits = parse_cidr(cidr); + assert_equal(new_ip(ip), parsed_ip, cidr.." parsed ip is "..ip); + assert_equal(bits, parsed_bits, cidr.." parsed bits is "..tostring(bits)); + end + assert_cidr("0.0.0.0", "0.0.0.0", nil); + assert_cidr("127.0.0.1", "127.0.0.1", nil); + assert_cidr("127.0.0.1/0", "127.0.0.1", 0); + assert_cidr("127.0.0.1/8", "127.0.0.1", 8); + assert_cidr("127.0.0.1/32", "127.0.0.1", 32); + assert_cidr("127.0.0.1/256", "127.0.0.1", 256); + assert_cidr("::/48", "::", 48); +end + +function new_ip(new_ip) + local v4, v6 = "IPv4", "IPv6"; + local function assert_proto(s, proto) + local ip = new_ip(s); + if proto then + assert_equal(ip and ip.proto, proto, "protocol is correct for "..("%q"):format(s)); + else + assert_equal(ip, nil, "address is invalid"); + end + end + assert_proto("127.0.0.1", v4); + assert_proto("::1", v6); + assert_proto("", nil); + assert_proto("abc", nil); + assert_proto(" ", nil); +end + +function commonPrefixLength(cpl, _M) + local new_ip = _M.new_ip; + local function assert_cpl6(a, b, len, v4) + local ipa, ipb = new_ip(a), new_ip(b); + if v4 then len = len+96; end + assert_equal(cpl(ipa, ipb), len, "common prefix length of "..a.." and "..b.." is "..len); + assert_equal(cpl(ipb, ipa), len, "common prefix length of "..b.." and "..a.." is "..len); + end + local function assert_cpl4(a, b, len) + return assert_cpl6(a, b, len, "IPv4"); + end + assert_cpl4("0.0.0.0", "0.0.0.0", 32); + assert_cpl4("255.255.255.255", "0.0.0.0", 0); + assert_cpl4("255.255.255.255", "255.255.0.0", 16); + assert_cpl4("255.255.255.255", "255.255.255.255", 32); + assert_cpl4("255.255.255.255", "255.255.255.255", 32); + + assert_cpl6("::1", "::1", 128); + assert_cpl6("abcd::1", "abcd::1", 128); + assert_cpl6("abcd::abcd", "abcd::", 112); + assert_cpl6("abcd::abcd", "abcd::abcd:abcd", 96); +end -- cgit v1.2.3 From 97cef2740ba76cc8fb2c0f33983f02dc1d5d4fc5 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 18 May 2013 21:41:17 +0100 Subject: util.ip: Fix protocol detection of IPv6 addresses beginning with : --- util/ip.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/ip.lua b/util/ip.lua index 8cf0076e..62649c9b 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -14,8 +14,10 @@ local hex2bits = { ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011 local function new_ip(ipStr, proto) if not proto then local sep = ipStr:match("^%x+(.)"); - if sep == ":" then proto = "IPv6" - elseif sep == "." then proto = "IPv4" + if sep == ":" or (not(sep) and ipStr:sub(1,1) == ":") then + proto = "IPv6" + elseif sep == "." then + proto = "IPv4" end if not proto then return nil, "invalid address"; -- cgit v1.2.3 From 582360b3b27b1f2ed4a11ec47d84e80600e1ed2f Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Mon, 20 May 2013 00:28:02 +0200 Subject: test_util_rfc6724: Update with new test vectors from RFC 6724 --- tests/test_util_rfc6724.lua | 104 ++++++++++++++++++++++++++++++++------------ 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/tests/test_util_rfc6724.lua b/tests/test_util_rfc6724.lua index 18ae310e..bb73e921 100644 --- a/tests/test_util_rfc6724.lua +++ b/tests/test_util_rfc6724.lua @@ -1,5 +1,5 @@ -- Prosody IM --- Copyright (C) 2011 Florian Zeitz +-- Copyright (C) 2011-2013 Florian Zeitz -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. @@ -7,45 +7,91 @@ function source(source) local new_ip = require"util.ip".new_ip; - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("3ffe::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr, "3ffe::1", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); - assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "2001::1", "prefer appropriate scope"); - assert_equal(source(new_ip("ff05::1", "IPv6"), {new_ip("fe80::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::1", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::1", "IPv6"), new_ip("2002::1", "IPv6")}).addr, "2001::1", "prefer same address"); - assert_equal(source(new_ip("fec0::1", "IPv6"), {new_ip("fec0::2", "IPv6"), new_ip("2001::1", "IPv6")}).addr, "fec0::2", "prefer appropriate scope"); - assert_equal(source(new_ip("2001::1", "IPv6"), {new_ip("2001::2", "IPv6"), new_ip("3ffe::2", "IPv6")}).addr, "2001::2", "longest matching prefix"); - assert_equal(source(new_ip("2002:836b:2179::1", "IPv6"), {new_ip("2002:836b:2179::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001::2", "IPv6")}).addr, "2002:836b:2179::d5e3:7953:13eb:22e8", "prefer matching label"); + assert_equal(source(new_ip("2001:db8:1::1", "IPv6"), + {new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr, + "2001:db8:3::1", + "prefer appropriate scope"); + assert_equal(source(new_ip("ff05::1", "IPv6"), + {new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::1", "IPv6")}).addr, + "2001:db8:3::1", + "prefer appropriate scope"); + assert_equal(source(new_ip("2001:db8:1::1", "IPv6"), + {new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:2::1", "IPv6")}).addr, + "2001:db8:1::1", + "prefer same address"); -- "2001:db8:1::1" should be marked "deprecated" here, we don't handle that right now + assert_equal(source(new_ip("fe80::1", "IPv6"), + {new_ip("fe80::2", "IPv6"), new_ip("2001:db8:1::1", "IPv6")}).addr, + "fe80::2", + "prefer appropriate scope"); -- "fe80::2" should be marked "deprecated" here, we don't handle that right now + assert_equal(source(new_ip("2001:db8:1::1", "IPv6"), + {new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr, + "2001:db8:1::2", + "longest matching prefix"); +--[[ "2001:db8:1::2" should be a care-of address and "2001:db8:3::2" a home address, we can't handle this and would fail + assert_equal(source(new_ip("2001:db8:1::1", "IPv6"), + {new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::2", "IPv6")}).addr, + "2001:db8:3::2", + "prefer home address"); +]] + assert_equal(source(new_ip("2002:c633:6401::1", "IPv6"), + {new_ip("2002:c633:6401::d5e3:7953:13eb:22e8", "IPv6"), new_ip("2001:db8:1::2", "IPv6")}).addr, + "2002:c633:6401::d5e3:7953:13eb:22e8", + "prefer matching label"); -- "2002:c633:6401::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now + assert_equal(source(new_ip("2001:db8:1::d5e3:0:0:1", "IPv6"), + {new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:1::d5e3:7953:13eb:22e8", "IPv6")}).addr, + "2001:db8:1::d5e3:7953:13eb:22e8", + "prefer temporary address") -- "2001:db8:1::2" should be marked "public" and "2001:db8:1::d5e3:7953:13eb:22e8" should be marked "temporary" here, we don't handle that right now end function destination(dest) local order; local new_ip = require"util.ip".new_ip; - order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")}) - assert_equal(order[1].addr, "2001::1", "prefer matching scope"); - assert_equal(order[2].addr, "131.107.65.121", "prefer matching scope") + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("169.254.13.78", "IPv4")}) + assert_equal(order[1].addr, "2001:db8:1::1", "prefer matching scope"); + assert_equal(order[2].addr, "198.51.100.121", "prefer matching scope"); - order = dest({new_ip("2001::1", "IPv6"), new_ip("131.107.65.121", "IPv4")}, {new_ip("fe80::1", "IPv6"), new_ip("131.107.65.117", "IPv4")}) - assert_equal(order[1].addr, "131.107.65.121", "prefer matching scope") - assert_equal(order[2].addr, "2001::1", "prefer matching scope") + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("198.51.100.121", "IPv4")}, + {new_ip("fe80::1", "IPv6"), new_ip("198.51.100.117", "IPv4")}) + assert_equal(order[1].addr, "198.51.100.121", "prefer matching scope"); + assert_equal(order[2].addr, "2001:db8:1::1", "prefer matching scope"); - order = dest({new_ip("2001::1", "IPv6"), new_ip("10.1.2.3", "IPv4")}, {new_ip("2001::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")}) - assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("10.1.2.3", "IPv4")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::1", "IPv6"), new_ip("10.1.2.4", "IPv4")}) + assert_equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence"); assert_equal(order[2].addr, "10.1.2.3", "prefer higher precedence"); - order = dest({new_ip("2001::1", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("fec0::1", "IPv6"), new_ip("fe80::2", "IPv6")}) + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")}) assert_equal(order[1].addr, "fe80::1", "prefer smaller scope"); - assert_equal(order[2].addr, "fec0::1", "prefer smaller scope"); - assert_equal(order[3].addr, "2001::1", "prefer smaller scope"); + assert_equal(order[2].addr, "2001:db8:1::1", "prefer smaller scope"); - order = dest({new_ip("2001::1", "IPv6"), new_ip("3ffe::1", "IPv6")}, {new_ip("2001::2", "IPv6"), new_ip("3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2001::1", "longest matching prefix"); - assert_equal(order[2].addr, "3ffe::1", "longest matching prefix"); +--[[ "2001:db8:1::2" and "fe80::2" should be marked "care-of address", while "2001:db8:3::1" should be marked "home address", we can't currently handle this and would fail the test + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3::1", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001:db8:1::1", "prefer home address"); + assert_equal(order[2].addr, "fe80::1", "prefer home address"); +]] - order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2002:836b:4179::1", "prefer matching label"); - assert_equal(order[2].addr, "2001::1", "prefer matching label"); +--[[ "fe80::2" should be marked "deprecated", we can't currently handle this and would fail the test + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("fe80::1", "IPv6")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001:db8:1::1", "avoid deprecated addresses"); + assert_equal(order[2].addr, "fe80::1", "avoid deprecated addresses"); +]] - order = dest({new_ip("2002:836b:4179::1", "IPv6"), new_ip("2001::1", "IPv6")}, {new_ip("2002:836b:4179::2", "IPv6"), new_ip("2001::2", "IPv6"), new_ip("fe80::2", "IPv6")}) - assert_equal(order[1].addr, "2001::1", "prefer higher precedence"); - assert_equal(order[2].addr, "2002:836b:4179::1", "prefer higher precedence"); + order = dest({new_ip("2001:db8:1::1", "IPv6"), new_ip("2001:db8:3ffe::1", "IPv6")}, + {new_ip("2001:db8:1::2", "IPv6"), new_ip("2001:db8:3f44::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001:db8:1::1", "longest matching prefix"); + assert_equal(order[2].addr, "2001:db8:3ffe::1", "longest matching prefix"); + + order = dest({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")}, + {new_ip("2002:c633:6401::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2002:c633:6401::1", "prefer matching label"); + assert_equal(order[2].addr, "2001:db8:1::1", "prefer matching label"); + + order = dest({new_ip("2002:c633:6401::1", "IPv6"), new_ip("2001:db8:1::1", "IPv6")}, + {new_ip("2002:c633:6401::2", "IPv6"), new_ip("2001:db8:1::2", "IPv6"), new_ip("fe80::2", "IPv6")}) + assert_equal(order[1].addr, "2001:db8:1::1", "prefer higher precedence"); + assert_equal(order[2].addr, "2002:c633:6401::1", "prefer higher precedence"); end -- cgit v1.2.3 From 8c3cb3971b29f84e8831f5ded9863cc282bfcde5 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 20 May 2013 15:33:57 +0100 Subject: prosodyctl: Use jid.split() to parse parameter to adduser/deluser/passwd --- prosodyctl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/prosodyctl b/prosodyctl index 41f3b8dc..780821be 100755 --- a/prosodyctl +++ b/prosodyctl @@ -274,11 +274,12 @@ local commands = {}; local command = arg[1]; function commands.adduser(arg) + local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[adduser JID]], [[Create the specified user account in Prosody]]); return 1; end - local user, host = arg[1]:match("([^@]+)@(.+)"); + local user, host = jid_split(arg[1]); if not user and host then show_message [[Failed to understand JID, please supply the JID you want to create]] show_usage [[adduser user@host]] @@ -313,11 +314,12 @@ function commands.adduser(arg) end function commands.passwd(arg) + local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[passwd JID]], [[Set the password for the specified user account in Prosody]]); return 1; end - local user, host = arg[1]:match("([^@]+)@(.+)"); + local user, host = jid_split(arg[1]); if not user and host then show_message [[Failed to understand JID, please supply the JID you want to set the password for]] show_usage [[passwd user@host]] @@ -352,11 +354,12 @@ function commands.passwd(arg) end function commands.deluser(arg) + local jid_split = require "util.jid".split; if not arg[1] or arg[1] == "--help" then show_usage([[deluser JID]], [[Permanently remove the specified user account from Prosody]]); return 1; end - local user, host = arg[1]:match("([^@]+)@(.+)"); + local user, host = jid_split(arg[1]); if not user and host then show_message [[Failed to understand JID, please supply the JID you want to set the password for]] show_usage [[passwd user@host]] -- cgit v1.2.3 From efe217c73fdae21c90ab0c5533f6829f36b6a274 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 09:48:59 +0100 Subject: mod_muc: Replace getText() with get_child_text(), 1 insertion, 12 deletions! --- plugins/muc/muc.lib.lua | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 68e36e83..4867b941 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -72,17 +72,6 @@ local function is_kickable_error(stanza) local cond = get_error_condition(stanza); return kickable_error_conditions[cond] and cond; end -local function getUsingPath(stanza, path, getText) - local tag = stanza; - for _, name in ipairs(path) do - if type(tag) ~= 'table' then return; end - tag = tag:child_with_name(name); - end - if tag and getText then tag = table.concat(tag); end - return tag; -end -local function getTag(stanza, path) return getUsingPath(stanza, path); end -local function getText(stanza, path) return getUsingPath(stanza, path, true); end ----------- local room_mt = {}; @@ -867,7 +856,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha else local from = stanza.attr.from; stanza.attr.from = current_nick; - local subject = getText(stanza, {"subject"}); + local subject = stanza:get_child_text("subject"); if subject then if occupant.role == "moderator" or ( self._data.changesubject and occupant.role == "participant" ) then -- and participant -- cgit v1.2.3 From 719dba768b24f8179d0fa47d5d046127bceb3242 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 09:57:36 +0100 Subject: mod_muc: Use stanza:maptags() instead of custom filtering functions, 7 insertions, 19 deletions! --- plugins/muc/muc.lib.lua | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 4867b941..4c398b57 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -27,28 +27,16 @@ local muc_domain = nil; --module:get_host(); local default_history_length, max_history_length = 20, math.huge; ------------ -local function filter_xmlns_from_array(array, filters) - local count = 0; - for i=#array,1,-1 do - local attr = array[i].attr; - if filters[attr and attr.xmlns] then - t_remove(array, i); - count = count + 1; - end - end - return count; -end -local function filter_xmlns_from_stanza(stanza, filters) - if filters then - if filter_xmlns_from_array(stanza.tags, filters) ~= 0 then - return stanza, filter_xmlns_from_array(stanza, filters); - end +local presence_filters = {["http://jabber.org/protocol/muc"]=true;["http://jabber.org/protocol/muc#user"]=true}; +local function presence_filter(tag) + if presence_filters[tag.attr.xmlns] then + return nil; end - return stanza, 0; + return tag; end -local presence_filters = {["http://jabber.org/protocol/muc"]=true;["http://jabber.org/protocol/muc#user"]=true}; + local function get_filtered_presence(stanza) - return filter_xmlns_from_stanza(st.clone(stanza):reset(), presence_filters); + return st.clone(stanza):maptags(presence_filter); end local kickable_error_conditions = { ["gone"] = true; -- cgit v1.2.3 From 9cfd06fd2bc1312b40a226f0b9432df7ee314060 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 10:10:09 +0100 Subject: mod_muc: Remove unused variable --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 4c398b57..ed9f554b 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -834,7 +834,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end elseif stanza.name == "message" and type == "groupchat" then - local from, to = stanza.attr.from, stanza.attr.to; + local from = stanza.attr.from; local current_nick = self._jid_nick[from]; local occupant = self._occupants[current_nick]; if not occupant then -- not in room -- cgit v1.2.3 From 19dc1c3cae56d365119af4b4976061ea78d965ce Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 10:10:28 +0100 Subject: mod_muc: Fix incorrect variable name --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index ed9f554b..e1deab99 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1008,7 +1008,7 @@ function room_mt:get_role(nick) end function room_mt:can_set_role(actor_jid, occupant_jid, role) local occupant = self._occupants[occupant_jid]; - if not occupant or not actor then return nil, "modify", "not-acceptable"; end + if not occupant or not actor_jid then return nil, "modify", "not-acceptable"; end if actor_jid == true then return true; end -- cgit v1.2.3 From 26c72e66f2b134aa8d547531417cd3f6c6a73f35 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 12:58:57 +0100 Subject: prosody.cfg.lua.dist: Suggest 'prosodyctl check config' instead of 'luac -p' --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 23032932..3f440067 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -4,7 +4,7 @@ -- website at http://prosody.im/doc/configure -- -- Tip: You can check that the syntax of this file is correct --- when you have finished by running: luac -p prosody.cfg.lua +-- when you have finished by running: prosodyctl check config -- If there are any errors, it will let you know what and where -- they are, otherwise it will keep quiet. -- -- cgit v1.2.3 From e0476bb4f1b46631ed4f71e1614f403bb87420da Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 13:18:56 +0100 Subject: prosodyctl: check config: Show a suggestion to change hosts that begin with jabber/xmpp/chat/im subdomains, and link to DNS documentation --- prosodyctl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/prosodyctl b/prosodyctl index 780821be..de7c09c5 100755 --- a/prosodyctl +++ b/prosodyctl @@ -820,7 +820,15 @@ function commands.check(arg) print(""); print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); end + local subdomain = host:match("^[^.]+"); + if not(is_component) and (subdomain == "jabber" or subdomain == "xmpp" + or subdomain == "chat" or subdomain == "im") then + print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to"); + print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host.."."); + print(" For more information see: http://prosody.im/doc/dns"); + end end + print("Done.\n"); end if not what or what == "dns" then -- cgit v1.2.3 From b0c86fe0553fdd69b150ee50e6265313f8b08f01 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 13:21:12 +0100 Subject: prosodyctl: check config: whitespace fix --- prosodyctl | 1 + 1 file changed, 1 insertion(+) diff --git a/prosodyctl b/prosodyctl index de7c09c5..5441b2b3 100755 --- a/prosodyctl +++ b/prosodyctl @@ -823,6 +823,7 @@ function commands.check(arg) local subdomain = host:match("^[^.]+"); if not(is_component) and (subdomain == "jabber" or subdomain == "xmpp" or subdomain == "chat" or subdomain == "im") then + print(""); print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to"); print(" "..host:gsub("^[^.]+%.", "")..". You can use SRV records to redirect XMPP clients and servers to "..host.."."); print(" For more information see: http://prosody.im/doc/dns"); -- cgit v1.2.3 From e09c12782cfe310c0456b758ea879ff7cb0af565 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 21 May 2013 13:21:30 +0100 Subject: mod_muc: Remove some old TODO comments --- plugins/muc/muc.lib.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index e1deab99..483b0812 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -215,7 +215,6 @@ function room_mt:get_disco_items(stanza) return reply; end function room_mt:set_subject(current_nick, subject) - -- TODO check nick's authority if subject == "" then subject = nil; end self._data['subject'] = subject; self._data['subject_from'] = current_nick; @@ -848,7 +847,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha if subject then if occupant.role == "moderator" or ( self._data.changesubject and occupant.role == "participant" ) then -- and participant - self:set_subject(current_nick, subject); -- TODO use broadcast_message_stanza + self:set_subject(current_nick, subject); else stanza.attr.from = from; origin.send(st.error_reply(stanza, "auth", "forbidden")); -- cgit v1.2.3 From e6533b846352a28dd37578f1e366d8d61cd11622 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 22 May 2013 13:32:38 +0100 Subject: prosodyctl: check config: Fix check for whether host is a component --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index 5441b2b3..c0f5dd92 100755 --- a/prosodyctl +++ b/prosodyctl @@ -821,7 +821,7 @@ function commands.check(arg) print(" You need to move the following option"..(n>1 and "s" or "")..": "..table.concat(it.to_array(misplaced_options), ", ")); end local subdomain = host:match("^[^.]+"); - if not(is_component) and (subdomain == "jabber" or subdomain == "xmpp" + if not(host_options:contains("component_module")) and (subdomain == "jabber" or subdomain == "xmpp" or subdomain == "chat" or subdomain == "im") then print(""); print(" Suggestion: If "..host.. " is a new host with no real users yet, consider renaming it now to"); -- cgit v1.2.3 From a8da45a1b9aca9dae8e2d9ceeb491815716df340 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 22 May 2013 13:33:33 +0100 Subject: prosodyctl: check dns: Add check that proxy65 addresses resolve correctly --- prosodyctl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/prosodyctl b/prosodyctl index c0f5dd92..4d7f678f 100755 --- a/prosodyctl +++ b/prosodyctl @@ -933,6 +933,25 @@ function commands.check(arg) target_hosts:remove("localhost"); end + local modules = set.new(it.to_array(it.values(host_options.modules_enabled))) + + set.new(it.to_array(it.values(config.get("*", "modules_enabled")))) + + set.new({ config.get(host, "component_module") }); + + if modules:contains("proxy65") then + local proxy65_target = config.get(host, "proxy65_address") or host; + local A, AAAA = dns.lookup(proxy65_target, "A"), dns.lookup(proxy65_target, "AAAA"); + local prob = {}; + if not A then + table.insert(prob, "A"); + end + if v6_supported and not AAAA then + table.insert(prob, "AAAA"); + end + if #prob > 0 then + print(" File transfer proxy "..proxy65_target.." has no "..table.concat(prob, "/").." record. Create one or set 'proxy65_address' to the correct host/IP."); + end + end + for host in target_hosts do local host_ok_v4, host_ok_v6; local res = dns.lookup(host, "A"); -- cgit v1.2.3 From 7b3aac0e5d17681af0956ac2c42e5ccaca612fd8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 13:55:28 +0100 Subject: prosody.cfg.lua.dist: Remove unnecessary ';' from default config (thanks Vincent) --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 3f440067..a662adcd 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -78,7 +78,7 @@ modules_disabled = { -- "offline"; -- Store offline messages -- "c2s"; -- Handle client connections -- "s2s"; -- Handle server-to-server connections -}; +} -- Disable account creation by default, for security -- For more information see http://prosody.im/doc/creating_accounts -- cgit v1.2.3 From d1920dc560eb1e71b59c9500fb0ad8dec81a3a3f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 13:59:59 +0100 Subject: prosody.cfg.lua: Remove some more sneaky ';' characters from the config --- prosody.cfg.lua.dist | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index a662adcd..30221da9 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -24,7 +24,7 @@ admins = { } -- Enable use of libevent for better performance under high load -- For more information see: http://prosody.im/doc/libevent ---use_libevent = true; +--use_libevent = true -- This is the list of modules Prosody will load on startup. -- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. @@ -70,7 +70,7 @@ modules_enabled = { --"watchregistrations"; -- Alert admins of registrations --"motd"; -- Send a message to users when they log in --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. -}; +} -- These modules are auto-loaded, but should you want -- to disable them then uncomment them here: @@ -82,7 +82,7 @@ modules_disabled = { -- Disable account creation by default, for security -- For more information see http://prosody.im/doc/creating_accounts -allow_registration = false; +allow_registration = false -- These are the SSL/TLS-related settings. If you don't want -- to use SSL/TLS, you may comment or remove this -- cgit v1.2.3 From 99eea8313f1b497d6a4b644929ce19b69276d602 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 14:46:16 +0100 Subject: net.server_event: Add support for listener.onreadtimeout(conn), which can return true to prevent the connection from being closed when a read timeout occurs --- net/server_event.lua | 101 ++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/net/server_event.lua b/net/server_event.lua index 5eae95a9..dc48e338 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -437,10 +437,11 @@ do end function interface_mt:setlistener(listener) - self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout, self.onstatus - = listener.onconnect, listener.ondisconnect, listener.onincoming, listener.ontimeout, listener.onstatus; + self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout, self.onreadtimeout, self.onstatus + = listener.onconnect, listener.ondisconnect, listener.onincoming, + listener.ontimeout, listener.onreadtimeout, listener.onstatus; end - + -- Stub handlers function interface_mt:onconnect() end @@ -450,6 +451,12 @@ do end function interface_mt:ontimeout() end + function interface_mt:onreadtimeout() + self.fatalerror = "timeout during receiving" + debug( "connection failed:", self.fatalerror ) + self:_close() + self.eventread = nil + end function interface_mt:ondrain() end function interface_mt:onstatus() @@ -477,6 +484,7 @@ do ondisconnect = listener.ondisconnect; -- will be called when client disconnects onincoming = listener.onincoming; -- will be called when client sends data ontimeout = listener.ontimeout; -- called when fatal socket timeout occurs + onreadtimeout = listener.onreadtimeout; -- called when socket inactivity timeout occurs onstatus = listener.onstatus; -- called for status changes (e.g. of SSL/TLS) eventread = false, eventwrite = false, eventclose = false, eventhandshake = false, eventstarthandshake = false; -- event handler @@ -574,61 +582,56 @@ do interface.eventread = nil return -1 end - if EV_TIMEOUT == event then -- took too long to get some data from client -> disconnect - interface.fatalerror = "timeout during receiving" - debug( "connection failed:", interface.fatalerror ) + if EV_TIMEOUT == event and interface:onreadtimeout() ~= true then + return -1 -- took too long to get some data from client -> disconnect + end + if interface._usingssl then -- handle luasec + if interface.eventwritetimeout then -- ok, in the past writecallback was regged + local ret = interface.writecallback( ) -- call it + --vdebug( "tried to write in readcallback, result:", tostring(ret) ) + end + if interface.eventreadtimeout then + interface.eventreadtimeout:close( ) + interface.eventreadtimeout = nil + end + end + local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern" + --vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) ) + buffer = buffer or part + if buffer and #buffer > cfg.MAX_READ_LENGTH then -- check buffer length + interface.fatalerror = "receive buffer exceeded" + debug( "fatal error:", interface.fatalerror ) interface:_close() interface.eventread = nil return -1 - else -- can read - if interface._usingssl then -- handle luasec - if interface.eventwritetimeout then -- ok, in the past writecallback was regged - local ret = interface.writecallback( ) -- call it - --vdebug( "tried to write in readcallback, result:", tostring(ret) ) - end - if interface.eventreadtimeout then - interface.eventreadtimeout:close( ) - interface.eventreadtimeout = nil + end + if err and ( err ~= "timeout" and err ~= "wantread" ) then + if "wantwrite" == err then -- need to read on write event + if not interface.eventwrite then -- register new write event if needed + interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT ) end - end - local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern" - --vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) ) - buffer = buffer or part - if buffer and #buffer > cfg.MAX_READ_LENGTH then -- check buffer length - interface.fatalerror = "receive buffer exceeded" - debug( "fatal error:", interface.fatalerror ) + interface.eventreadtimeout = addevent( base, nil, EV_TIMEOUT, + function( ) + interface:_close() + end, cfg.READ_TIMEOUT + ) + debug( "wantwrite during read attempt, reg it in writecallback but dont know what really happens next..." ) + -- to be honest i dont know what happens next, if it is allowed to first read, the write etc... + else -- connection was closed or fatal error + interface.fatalerror = err + debug( "connection failed in read event:", interface.fatalerror ) interface:_close() interface.eventread = nil return -1 end - if err and ( err ~= "timeout" and err ~= "wantread" ) then - if "wantwrite" == err then -- need to read on write event - if not interface.eventwrite then -- register new write event if needed - interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT ) - end - interface.eventreadtimeout = addevent( base, nil, EV_TIMEOUT, - function( ) - interface:_close() - end, cfg.READ_TIMEOUT - ) - debug( "wantwrite during read attempt, reg it in writecallback but dont know what really happens next..." ) - -- to be honest i dont know what happens next, if it is allowed to first read, the write etc... - else -- connection was closed or fatal error - interface.fatalerror = err - debug( "connection failed in read event:", interface.fatalerror ) - interface:_close() - interface.eventread = nil - return -1 - end - else - interface.onincoming( interface, buffer, err ) -- send new data to listener - end - if interface.noreading then - interface.eventread = nil; - return -1; - end - return EV_READ, cfg.READ_TIMEOUT + else + interface.onincoming( interface, buffer, err ) -- send new data to listener + end + if interface.noreading then + interface.eventread = nil; + return -1; end + return EV_READ, cfg.READ_TIMEOUT end client:settimeout( 0 ) -- set non blocking -- cgit v1.2.3 From bb5dfce88b39f2a7211c4877afb1fcda0cf2d874 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Fri, 17 May 2013 18:33:32 +0200 Subject: mod_pubsub: Split out handlers into a module library --- plugins/mod_pubsub.lua | 463 -------------------------------------- plugins/mod_pubsub/mod_pubsub.lua | 251 +++++++++++++++++++++ plugins/mod_pubsub/pubsub.lib.lua | 225 ++++++++++++++++++ 3 files changed, 476 insertions(+), 463 deletions(-) delete mode 100644 plugins/mod_pubsub.lua create mode 100644 plugins/mod_pubsub/mod_pubsub.lua create mode 100644 plugins/mod_pubsub/pubsub.lib.lua diff --git a/plugins/mod_pubsub.lua b/plugins/mod_pubsub.lua deleted file mode 100644 index 926ed4f2..00000000 --- a/plugins/mod_pubsub.lua +++ /dev/null @@ -1,463 +0,0 @@ -local pubsub = require "util.pubsub"; -local st = require "util.stanza"; -local jid_bare = require "util.jid".bare; -local uuid_generate = require "util.uuid".generate; -local usermanager = require "core.usermanager"; - -local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; -local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors"; -local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event"; -local xmlns_pubsub_owner = "http://jabber.org/protocol/pubsub#owner"; - -local autocreate_on_publish = module:get_option_boolean("autocreate_on_publish", false); -local autocreate_on_subscribe = module:get_option_boolean("autocreate_on_subscribe", false); -local pubsub_disco_name = module:get_option("name"); -if type(pubsub_disco_name) ~= "string" then pubsub_disco_name = "Prosody PubSub Service"; end - -local service; - -local handlers = {}; - -function handle_pubsub_iq(event) - local origin, stanza = event.origin, event.stanza; - local pubsub = stanza.tags[1]; - local action = pubsub.tags[1]; - if not action then - return origin.send(st.error_reply(stanza, "cancel", "bad-request")); - end - local handler = handlers[stanza.attr.type.."_"..action.name]; - if handler then - handler(origin, stanza, action); - return true; - end -end - -local pubsub_errors = { - ["conflict"] = { "cancel", "conflict" }; - ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; - ["jid-required"] = { "modify", "bad-request", nil, "jid-required" }; - ["nodeid-required"] = { "modify", "bad-request", nil, "nodeid-required" }; - ["item-not-found"] = { "cancel", "item-not-found" }; - ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" }; - ["forbidden"] = { "cancel", "forbidden" }; -}; -function pubsub_error_reply(stanza, error) - local e = pubsub_errors[error]; - local reply = st.error_reply(stanza, unpack(e, 1, 3)); - if e[4] then - reply:tag(e[4], { xmlns = xmlns_pubsub_errors }):up(); - end - return reply; -end - -function handlers.get_items(origin, stanza, items) - local node = items.attr.node; - local item = items:get_child("item"); - local id = item and item.attr.id; - - if not node then - return origin.send(pubsub_error_reply(stanza, "nodeid-required")); - end - local ok, results = service:get_items(node, stanza.attr.from, id); - if not ok then - return origin.send(pubsub_error_reply(stanza, results)); - end - - local data = st.stanza("items", { node = node }); - for _, entry in pairs(results) do - data:add_child(entry); - end - local reply; - if data then - reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :add_child(data); - else - reply = pubsub_error_reply(stanza, "item-not-found"); - end - return origin.send(reply); -end - -function handlers.get_subscriptions(origin, stanza, subscriptions) - local node = subscriptions.attr.node; - local ok, ret = service:get_subscriptions(node, stanza.attr.from, stanza.attr.from); - if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); - end - local reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :tag("subscriptions"); - for _, sub in ipairs(ret) do - reply:tag("subscription", { node = sub.node, jid = sub.jid, subscription = 'subscribed' }):up(); - end - return origin.send(reply); -end - -function handlers.set_create(origin, stanza, create) - local node = create.attr.node; - local ok, ret, reply; - if node then - ok, ret = service:create(node, stanza.attr.from); - if ok then - reply = st.reply(stanza); - else - reply = pubsub_error_reply(stanza, ret); - end - else - repeat - node = uuid_generate(); - ok, ret = service:create(node, stanza.attr.from); - until ok or ret ~= "conflict"; - if ok then - reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :tag("create", { node = node }); - else - reply = pubsub_error_reply(stanza, ret); - end - end - return origin.send(reply); -end - -function handlers.set_delete(origin, stanza, delete) - local node = delete.attr.node; - - local reply, notifier; - if not node then - return origin.send(pubsub_error_reply(stanza, "nodeid-required")); - end - local ok, ret = service:delete(node, stanza.attr.from); - if ok then - reply = st.reply(stanza); - else - reply = pubsub_error_reply(stanza, ret); - end - return origin.send(reply); -end - -function handlers.set_subscribe(origin, stanza, subscribe) - local node, jid = subscribe.attr.node, subscribe.attr.jid; - if not (node and jid) then - return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); - end - --[[ - local options_tag, options = stanza.tags[1]:get_child("options"), nil; - if options_tag then - options = options_form:data(options_tag.tags[1]); - end - --]] - local options_tag, options; -- FIXME - local ok, ret = service:add_subscription(node, stanza.attr.from, jid, options); - local reply; - if ok then - reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :tag("subscription", { - node = node, - jid = jid, - subscription = "subscribed" - }):up(); - if options_tag then - reply:add_child(options_tag); - end - else - reply = pubsub_error_reply(stanza, ret); - end - origin.send(reply); -end - -function handlers.set_unsubscribe(origin, stanza, unsubscribe) - local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid; - if not (node and jid) then - return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); - end - local ok, ret = service:remove_subscription(node, stanza.attr.from, jid); - local reply; - if ok then - reply = st.reply(stanza); - else - reply = pubsub_error_reply(stanza, ret); - end - return origin.send(reply); -end - -function handlers.set_publish(origin, stanza, publish) - local node = publish.attr.node; - if not node then - return origin.send(pubsub_error_reply(stanza, "nodeid-required")); - end - local item = publish:get_child("item"); - local id = (item and item.attr.id); - if not id then - id = uuid_generate(); - if item then - item.attr.id = id; - end - end - local ok, ret = service:publish(node, stanza.attr.from, id, item); - local reply; - if ok then - reply = st.reply(stanza) - :tag("pubsub", { xmlns = xmlns_pubsub }) - :tag("publish", { node = node }) - :tag("item", { id = id }); - else - reply = pubsub_error_reply(stanza, ret); - end - return origin.send(reply); -end - -function handlers.set_retract(origin, stanza, retract) - local node, notify = retract.attr.node, retract.attr.notify; - notify = (notify == "1") or (notify == "true"); - local item = retract:get_child("item"); - local id = item and item.attr.id - if not (node and id) then - return origin.send(pubsub_error_reply(stanza, node and "item-not-found" or "nodeid-required")); - end - local reply, notifier; - if notify then - notifier = st.stanza("retract", { id = id }); - end - local ok, ret = service:retract(node, stanza.attr.from, id, notifier); - if ok then - reply = st.reply(stanza); - else - reply = pubsub_error_reply(stanza, ret); - end - return origin.send(reply); -end - -function handlers.set_purge(origin, stanza, purge) - local node, notify = purge.attr.node, purge.attr.notify; - notify = (notify == "1") or (notify == "true"); - local reply; - if not node then - return origin.send(pubsub_error_reply(stanza, "nodeid-required")); - end - local ok, ret = service:purge(node, stanza.attr.from, notify); - if ok then - reply = st.reply(stanza); - else - reply = pubsub_error_reply(stanza, ret); - end - return origin.send(reply); -end - -function simple_broadcast(kind, node, jids, item) - if item then - item = st.clone(item); - item.attr.xmlns = nil; -- Clear the pubsub namespace - end - local message = st.message({ from = module.host, type = "headline" }) - :tag("event", { xmlns = xmlns_pubsub_event }) - :tag(kind, { node = node }) - :add_child(item); - for jid in pairs(jids) do - module:log("debug", "Sending notification to %s", jid); - message.attr.to = jid; - module:send(message); - end -end - -module:hook("iq/host/"..xmlns_pubsub..":pubsub", handle_pubsub_iq); -module:hook("iq/host/"..xmlns_pubsub_owner..":pubsub", handle_pubsub_iq); - -local disco_info; - -local feature_map = { - create = { "create-nodes", "instant-nodes", "item-ids" }; - retract = { "delete-items", "retract-items" }; - purge = { "purge-nodes" }; - publish = { "publish", autocreate_on_publish and "auto-create" }; - delete = { "delete-nodes" }; - get_items = { "retrieve-items" }; - add_subscription = { "subscribe" }; - get_subscriptions = { "retrieve-subscriptions" }; -}; - -local function add_disco_features_from_service(disco, service) - for method, features in pairs(feature_map) do - if service[method] then - for _, feature in ipairs(features) do - if feature then - disco:tag("feature", { var = xmlns_pubsub.."#"..feature }):up(); - end - end - end - end - for affiliation in pairs(service.config.capabilities) do - if affiliation ~= "none" and affiliation ~= "owner" then - disco:tag("feature", { var = xmlns_pubsub.."#"..affiliation.."-affiliation" }):up(); - end - end -end - -local function build_disco_info(service) - local disco_info = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" }) - :tag("identity", { category = "pubsub", type = "service", name = pubsub_disco_name }):up() - :tag("feature", { var = "http://jabber.org/protocol/pubsub" }):up(); - add_disco_features_from_service(disco_info, service); - return disco_info; -end - -module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function (event) - local origin, stanza = event.origin, event.stanza; - local node = stanza.tags[1].attr.node; - if not node then - return origin.send(st.reply(stanza):add_child(disco_info)); - else - local ok, ret = service:get_nodes(stanza.attr.from); - if ok and not ret[node] then - ok, ret = false, "item-not-found"; - end - if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); - end - local reply = st.reply(stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#info", node = node }) - :tag("identity", { category = "pubsub", type = "leaf" }); - return origin.send(reply); - end -end); - -local function handle_disco_items_on_node(event) - local stanza, origin = event.stanza, event.origin; - local query = stanza.tags[1]; - local node = query.attr.node; - local ok, ret = service:get_items(node, stanza.attr.from); - if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); - end - - local reply = st.reply(stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#items", node = node }); - - for id, item in pairs(ret) do - reply:tag("item", { jid = module.host, name = id }):up(); - end - - return origin.send(reply); -end - - -module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function (event) - if event.stanza.tags[1].attr.node then - return handle_disco_items_on_node(event); - end - local ok, ret = service:get_nodes(event.stanza.attr.from); - if not ok then - event.origin.send(pubsub_error_reply(event.stanza, ret)); - else - local reply = st.reply(event.stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); - for node, node_obj in pairs(ret) do - reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); - end - event.origin.send(reply); - end - return true; -end); - -local admin_aff = module:get_option_string("default_admin_affiliation", "owner"); -local function get_affiliation(jid) - local bare_jid = jid_bare(jid); - if bare_jid == module.host or usermanager.is_admin(bare_jid, module.host) then - return admin_aff; - end -end - -function set_service(new_service) - service = new_service; - module.environment.service = service; - disco_info = build_disco_info(service); -end - -function module.save() - return { service = service }; -end - -function module.restore(data) - set_service(data.service); -end - -set_service(pubsub.new({ - capabilities = { - none = { - create = false; - publish = false; - retract = false; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - subscribe_other = false; - unsubscribe_other = false; - get_subscription_other = false; - get_subscriptions_other = false; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = false; - }; - publisher = { - create = false; - publish = true; - retract = true; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - subscribe_other = false; - unsubscribe_other = false; - get_subscription_other = false; - get_subscriptions_other = false; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = false; - }; - owner = { - create = true; - publish = true; - retract = true; - delete = true; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - - subscribe_other = true; - unsubscribe_other = true; - get_subscription_other = true; - get_subscriptions_other = true; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = true; - }; - }; - - autocreate_on_publish = autocreate_on_publish; - autocreate_on_subscribe = autocreate_on_subscribe; - - broadcaster = simple_broadcast; - get_affiliation = get_affiliation; - - normalize_jid = jid_bare; -})); diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua new file mode 100644 index 00000000..ad20c6a7 --- /dev/null +++ b/plugins/mod_pubsub/mod_pubsub.lua @@ -0,0 +1,251 @@ +local pubsub = require "util.pubsub"; +local st = require "util.stanza"; +local jid_bare = require "util.jid".bare; +local usermanager = require "core.usermanager"; + +local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; +local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event"; +local xmlns_pubsub_owner = "http://jabber.org/protocol/pubsub#owner"; + +local autocreate_on_publish = module:get_option_boolean("autocreate_on_publish", false); +local autocreate_on_subscribe = module:get_option_boolean("autocreate_on_subscribe", false); +local pubsub_disco_name = module:get_option("name"); +if type(pubsub_disco_name) ~= "string" then pubsub_disco_name = "Prosody PubSub Service"; end + +local service; + +local lib_pubsub = module:require "pubsub"; +local handlers = lib_pubsub.handlers; +local pubsub_error_reply = lib_pubsub.pubsub_error_reply; + +function handle_pubsub_iq(event) + local origin, stanza = event.origin, event.stanza; + local pubsub = stanza.tags[1]; + local action = pubsub.tags[1]; + if not action then + return origin.send(st.error_reply(stanza, "cancel", "bad-request")); + end + local handler = handlers[stanza.attr.type.."_"..action.name]; + if handler then + handler(origin, stanza, action, service); + return true; + end +end + +function simple_broadcast(kind, node, jids, item) + if item then + item = st.clone(item); + item.attr.xmlns = nil; -- Clear the pubsub namespace + end + local message = st.message({ from = module.host, type = "headline" }) + :tag("event", { xmlns = xmlns_pubsub_event }) + :tag(kind, { node = node }) + :add_child(item); + for jid in pairs(jids) do + module:log("debug", "Sending notification to %s", jid); + message.attr.to = jid; + module:send(message); + end +end + +module:hook("iq/host/"..xmlns_pubsub..":pubsub", handle_pubsub_iq); +module:hook("iq/host/"..xmlns_pubsub_owner..":pubsub", handle_pubsub_iq); + +local disco_info; + +local feature_map = { + create = { "create-nodes", "instant-nodes", "item-ids" }; + retract = { "delete-items", "retract-items" }; + purge = { "purge-nodes" }; + publish = { "publish", autocreate_on_publish and "auto-create" }; + delete = { "delete-nodes" }; + get_items = { "retrieve-items" }; + add_subscription = { "subscribe" }; + get_subscriptions = { "retrieve-subscriptions" }; +}; + +local function add_disco_features_from_service(disco, service) + for method, features in pairs(feature_map) do + if service[method] then + for _, feature in ipairs(features) do + if feature then + disco:tag("feature", { var = xmlns_pubsub.."#"..feature }):up(); + end + end + end + end + for affiliation in pairs(service.config.capabilities) do + if affiliation ~= "none" and affiliation ~= "owner" then + disco:tag("feature", { var = xmlns_pubsub.."#"..affiliation.."-affiliation" }):up(); + end + end +end + +local function build_disco_info(service) + local disco_info = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" }) + :tag("identity", { category = "pubsub", type = "service", name = pubsub_disco_name }):up() + :tag("feature", { var = "http://jabber.org/protocol/pubsub" }):up(); + add_disco_features_from_service(disco_info, service); + return disco_info; +end + +module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function (event) + local origin, stanza = event.origin, event.stanza; + local node = stanza.tags[1].attr.node; + if not node then + return origin.send(st.reply(stanza):add_child(disco_info)); + else + local ok, ret = service:get_nodes(stanza.attr.from); + if ok and not ret[node] then + ok, ret = false, "item-not-found"; + end + if not ok then + return origin.send(pubsub_error_reply(stanza, ret)); + end + local reply = st.reply(stanza) + :tag("query", { xmlns = "http://jabber.org/protocol/disco#info", node = node }) + :tag("identity", { category = "pubsub", type = "leaf" }); + return origin.send(reply); + end +end); + +local function handle_disco_items_on_node(event) + local stanza, origin = event.stanza, event.origin; + local query = stanza.tags[1]; + local node = query.attr.node; + local ok, ret = service:get_items(node, stanza.attr.from); + if not ok then + return origin.send(pubsub_error_reply(stanza, ret)); + end + + local reply = st.reply(stanza) + :tag("query", { xmlns = "http://jabber.org/protocol/disco#items", node = node }); + + for id, item in pairs(ret) do + reply:tag("item", { jid = module.host, name = id }):up(); + end + + return origin.send(reply); +end + + +module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function (event) + if event.stanza.tags[1].attr.node then + return handle_disco_items_on_node(event); + end + local ok, ret = service:get_nodes(event.stanza.attr.from); + if not ok then + event.origin.send(pubsub_error_reply(event.stanza, ret)); + else + local reply = st.reply(event.stanza) + :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); + for node, node_obj in pairs(ret) do + reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); + end + event.origin.send(reply); + end + return true; +end); + +local admin_aff = module:get_option_string("default_admin_affiliation", "owner"); +local function get_affiliation(jid) + local bare_jid = jid_bare(jid); + if bare_jid == module.host or usermanager.is_admin(bare_jid, module.host) then + return admin_aff; + end +end + +function set_service(new_service) + service = new_service; + module.environment.service = service; + disco_info = build_disco_info(service); +end + +function module.save() + return { service = service }; +end + +function module.restore(data) + set_service(data.service); +end + +set_service(pubsub.new({ + capabilities = { + none = { + create = false; + publish = false; + retract = false; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = false; + unsubscribe_other = false; + get_subscription_other = false; + get_subscriptions_other = false; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = false; + }; + publisher = { + create = false; + publish = true; + retract = true; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = false; + unsubscribe_other = false; + get_subscription_other = false; + get_subscriptions_other = false; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = false; + }; + owner = { + create = true; + publish = true; + retract = true; + delete = true; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + + subscribe_other = true; + unsubscribe_other = true; + get_subscription_other = true; + get_subscriptions_other = true; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = true; + }; + }; + + autocreate_on_publish = autocreate_on_publish; + autocreate_on_subscribe = autocreate_on_subscribe; + + broadcaster = simple_broadcast; + get_affiliation = get_affiliation; + + normalize_jid = jid_bare; +})); diff --git a/plugins/mod_pubsub/pubsub.lib.lua b/plugins/mod_pubsub/pubsub.lib.lua new file mode 100644 index 00000000..2b015e34 --- /dev/null +++ b/plugins/mod_pubsub/pubsub.lib.lua @@ -0,0 +1,225 @@ +local st = require "util.stanza"; +local uuid_generate = require "util.uuid".generate; + +local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; +local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors"; + +local _M = {}; + +local handlers = {}; +_M.handlers = handlers; + +local pubsub_errors = { + ["conflict"] = { "cancel", "conflict" }; + ["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" }; + ["jid-required"] = { "modify", "bad-request", nil, "jid-required" }; + ["nodeid-required"] = { "modify", "bad-request", nil, "nodeid-required" }; + ["item-not-found"] = { "cancel", "item-not-found" }; + ["not-subscribed"] = { "modify", "unexpected-request", nil, "not-subscribed" }; + ["forbidden"] = { "cancel", "forbidden" }; +}; +local function pubsub_error_reply(stanza, error) + local e = pubsub_errors[error]; + local reply = st.error_reply(stanza, unpack(e, 1, 3)); + if e[4] then + reply:tag(e[4], { xmlns = xmlns_pubsub_errors }):up(); + end + return reply; +end +_M.pubsub_error_reply = pubsub_error_reply; + +function handlers.get_items(origin, stanza, items, service) + local node = items.attr.node; + local item = items:get_child("item"); + local id = item and item.attr.id; + + if not node then + return origin.send(pubsub_error_reply(stanza, "nodeid-required")); + end + local ok, results = service:get_items(node, stanza.attr.from, id); + if not ok then + return origin.send(pubsub_error_reply(stanza, results)); + end + + local data = st.stanza("items", { node = node }); + for _, entry in pairs(results) do + data:add_child(entry); + end + local reply; + if data then + reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :add_child(data); + else + reply = pubsub_error_reply(stanza, "item-not-found"); + end + return origin.send(reply); +end + +function handlers.get_subscriptions(origin, stanza, subscriptions, service) + local node = subscriptions.attr.node; + local ok, ret = service:get_subscriptions(node, stanza.attr.from, stanza.attr.from); + if not ok then + return origin.send(pubsub_error_reply(stanza, ret)); + end + local reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :tag("subscriptions"); + for _, sub in ipairs(ret) do + reply:tag("subscription", { node = sub.node, jid = sub.jid, subscription = 'subscribed' }):up(); + end + return origin.send(reply); +end + +function handlers.set_create(origin, stanza, create, service) + local node = create.attr.node; + local ok, ret, reply; + if node then + ok, ret = service:create(node, stanza.attr.from); + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + else + repeat + node = uuid_generate(); + ok, ret = service:create(node, stanza.attr.from); + until ok or ret ~= "conflict"; + if ok then + reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :tag("create", { node = node }); + else + reply = pubsub_error_reply(stanza, ret); + end + end + return origin.send(reply); +end + +function handlers.set_delete(origin, stanza, delete, service) + local node = delete.attr.node; + + local reply, notifier; + if not node then + return origin.send(pubsub_error_reply(stanza, "nodeid-required")); + end + local ok, ret = service:delete(node, stanza.attr.from); + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + +function handlers.set_subscribe(origin, stanza, subscribe, service) + local node, jid = subscribe.attr.node, subscribe.attr.jid; + if not (node and jid) then + return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); + end + --[[ + local options_tag, options = stanza.tags[1]:get_child("options"), nil; + if options_tag then + options = options_form:data(options_tag.tags[1]); + end + --]] + local options_tag, options; -- FIXME + local ok, ret = service:add_subscription(node, stanza.attr.from, jid, options); + local reply; + if ok then + reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :tag("subscription", { + node = node, + jid = jid, + subscription = "subscribed" + }):up(); + if options_tag then + reply:add_child(options_tag); + end + else + reply = pubsub_error_reply(stanza, ret); + end + origin.send(reply); +end + +function handlers.set_unsubscribe(origin, stanza, unsubscribe, service) + local node, jid = unsubscribe.attr.node, unsubscribe.attr.jid; + if not (node and jid) then + return origin.send(pubsub_error_reply(stanza, jid and "nodeid-required" or "invalid-jid")); + end + local ok, ret = service:remove_subscription(node, stanza.attr.from, jid); + local reply; + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + +function handlers.set_publish(origin, stanza, publish, service) + local node = publish.attr.node; + if not node then + return origin.send(pubsub_error_reply(stanza, "nodeid-required")); + end + local item = publish:get_child("item"); + local id = (item and item.attr.id); + if not id then + id = uuid_generate(); + if item then + item.attr.id = id; + end + end + local ok, ret = service:publish(node, stanza.attr.from, id, item); + local reply; + if ok then + reply = st.reply(stanza) + :tag("pubsub", { xmlns = xmlns_pubsub }) + :tag("publish", { node = node }) + :tag("item", { id = id }); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + +function handlers.set_retract(origin, stanza, retract, service) + local node, notify = retract.attr.node, retract.attr.notify; + notify = (notify == "1") or (notify == "true"); + local item = retract:get_child("item"); + local id = item and item.attr.id + if not (node and id) then + return origin.send(pubsub_error_reply(stanza, node and "item-not-found" or "nodeid-required")); + end + local reply, notifier; + if notify then + notifier = st.stanza("retract", { id = id }); + end + local ok, ret = service:retract(node, stanza.attr.from, id, notifier); + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + +function handlers.set_purge(origin, stanza, purge, service) + local node, notify = purge.attr.node, purge.attr.notify; + notify = (notify == "1") or (notify == "true"); + local reply; + if not node then + return origin.send(pubsub_error_reply(stanza, "nodeid-required")); + end + local ok, ret = service:purge(node, stanza.attr.from, notify); + if ok then + reply = st.reply(stanza); + else + reply = pubsub_error_reply(stanza, ret); + end + return origin.send(reply); +end + +return _M; -- cgit v1.2.3 From 421bdc43997ee9215ce57ee73616f90ce695f601 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Fri, 17 May 2013 18:35:50 +0200 Subject: mod_disco: Emit events for disco requests, which contain a node, on user accounts --- plugins/mod_disco.lua | 30 ++++++++++++++++++++++++++---- plugins/mod_pep.lua | 12 ++++++------ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index 72c9a34c..b8df0bd6 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -133,12 +133,23 @@ module:hook("iq/bare/http://jabber.org/protocol/disco#info:query", function(even local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "get" then return; end local node = stanza.tags[1].attr.node; - if node and node ~= "" then return; end -- TODO fire event? local username = jid_split(stanza.attr.to) or origin.username; if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then + if node and node ~= "" then + local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#info', node=node}); + if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false} + module:fire_event("account-disco-info-node", event); + if event.exists then + origin.send(reply); + else + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Node does not exist")); + end + return true; + end local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#info'}); if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account - module:fire_event("account-disco-info", { origin = origin, stanza = reply }); + module:fire_event("account-disco-info", { origin = origin, reply = reply }); origin.send(reply); return true; end @@ -147,12 +158,23 @@ module:hook("iq/bare/http://jabber.org/protocol/disco#items:query", function(eve local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "get" then return; end local node = stanza.tags[1].attr.node; - if node and node ~= "" then return; end -- TODO fire event? local username = jid_split(stanza.attr.to) or origin.username; if not stanza.attr.to or is_contact_subscribed(username, module.host, jid_bare(stanza.attr.from)) then + if node and node ~= "" then + local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#items', node=node}); + if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false} + module:fire_event("account-disco-items-node", event); + if event.exists then + origin.send(reply); + else + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Node does not exist")); + end + return true; + end local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#items'}); if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account - module:fire_event("account-disco-items", { origin = origin, stanza = reply }); + module:fire_event("account-disco-items", { origin = origin, stanza = stanza, reply = reply }); origin.send(reply); return true; end diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index a65ee903..d59bd2a2 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -262,19 +262,19 @@ module:hook("iq-result/bare/disco", function(event) end); module:hook("account-disco-info", function(event) - local stanza = event.stanza; - stanza:tag('identity', {category='pubsub', type='pep'}):up(); - stanza:tag('feature', {var='http://jabber.org/protocol/pubsub#publish'}):up(); + local reply = event.reply; + reply:tag('identity', {category='pubsub', type='pep'}):up(); + reply:tag('feature', {var='http://jabber.org/protocol/pubsub#publish'}):up(); end); module:hook("account-disco-items", function(event) - local stanza = event.stanza; - local bare = stanza.attr.to; + local reply = event.reply; + local bare = reply.attr.to; local user_data = data[bare]; if user_data then for node, _ in pairs(user_data) do - stanza:tag('item', {jid=bare, node=node}):up(); -- TODO we need to handle queries to these nodes + reply:tag('item', {jid=bare, node=node}):up(); -- TODO we need to handle queries to these nodes end end end); -- cgit v1.2.3 From b5eff9a9018c37698bbb850452a5c8bf504051a4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 18:14:09 +0100 Subject: net.server_select: Support for listener.onreadtimeout() [see also e67891ad18d6] --- net/server_select.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/server_select.lua b/net/server_select.lua index 7eb330a8..0e7f41f8 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -861,16 +861,16 @@ loop = function(once) -- this is the main loop of the program _starttime = _currenttime for handler, timestamp in pairs( _writetimes ) do if os_difftime( _currenttime - timestamp ) > _sendtimeout then - --_writetimes[ handler ] = nil handler.disconnect( )( handler, "send timeout" ) handler:force_close() -- forced disconnect end end for handler, timestamp in pairs( _readtimes ) do if os_difftime( _currenttime - timestamp ) > _readtimeout then - --_readtimes[ handler ] = nil - handler.disconnect( )( handler, "read timeout" ) - handler:close( ) -- forced disconnect? + if not(handler.onreadtimeout) or handler:onreadtimeout() ~= true then + handler.disconnect( )( handler, "read timeout" ) + handler:close( ) -- forced disconnect? + end end end end -- cgit v1.2.3 From 8c7ccc03685804776dfc90cba17ec3d766479740 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 18:33:16 +0100 Subject: net.server_select: Default checkinterval to 30s, so that read timeouts are actually detected --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/server_select.lua b/net/server_select.lua index 0e7f41f8..1665524f 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -145,7 +145,7 @@ _tcpbacklog = 128 -- some kind of hint to the OS _maxsendlen = 51000 * 1024 -- max len of send buffer _maxreadlen = 25000 * 1024 -- max len of read buffer -_checkinterval = 1200000 -- interval in secs to check idle clients +_checkinterval = 30 -- interval in secs to check idle clients _sendtimeout = 60000 -- allowed send idle time in secs _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs -- cgit v1.2.3 From aa2c7c578a713f6a6de80508badb2b832b968108 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 18:37:07 +0100 Subject: mod_bosh: Some very minor whitespace/layout fixes --- plugins/mod_bosh.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 19f191c8..bd39daa5 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -218,7 +218,7 @@ local function bosh_close_stream(session, reason) held_request.headers = default_headers; held_request:send(response_body); end - sessions[session.sid] = nil; + sessions[session.sid] = nil; inactive_sessions[session] = nil; sm_destroy_session(session); end @@ -291,7 +291,8 @@ function stream_callbacks.streamopened(context, attr) body_attr.hold = tostring(session.bosh_hold); body_attr.authid = sid; body_attr.secure = "true"; - body_attr.ver = '1.6'; from = session.host; + body_attr.ver = '1.6'; + body_attr.from = session.host; body_attr["xmlns:xmpp"] = "urn:xmpp:xbosh"; body_attr["xmpp:version"] = "1.0"; end -- cgit v1.2.3 From de91cf38b186b4cd02863e84f69c513b83c85ebb Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 24 May 2013 18:38:36 +0100 Subject: mod_bosh: rename variable for clarity --- plugins/mod_bosh.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index bd39daa5..57abebb2 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -364,8 +364,8 @@ function stream_callbacks.handlestanza(context, stanza) end end -function stream_callbacks.streamclosed(request) - local session = sessions[request.sid]; +function stream_callbacks.streamclosed(context) + local session = sessions[context.sid]; if session then session.bosh_processing = false; if #session.send_buffer > 0 then -- cgit v1.2.3 From 2e3f198799b27ea3b6d5a9e90b08bff23c42ac62 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 28 May 2013 16:10:22 +0100 Subject: mod_s2s: Remove unnecessary debug message --- plugins/mod_s2s/mod_s2s.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 5a2af968..ab5b7232 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -616,7 +616,6 @@ function listener.ondisconnect(conn, err) if err and session.direction == "outgoing" and session.notopen then (session.log or log)("debug", "s2s connection attempt failed: %s", err); if s2sout.attempt_connection(session, err) then - (session.log or log)("debug", "...so we're going to try another target"); return; -- Session lives for now end end -- cgit v1.2.3 From eeb633659f244fdcd3a6b1e132e8969e3266603a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 28 May 2013 18:32:51 +0200 Subject: mod_register: get_child_text()! --- plugins/mod_register.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 141a4997..3d7a068c 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -115,8 +115,8 @@ local function handle_registration_stanza(event) module:log("info", "User removed their account: %s@%s", username, host); module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session }); else - local username = nodeprep(query:get_child("username"):get_text()); - local password = query:get_child("password"):get_text(); + local username = nodeprep(query:get_child_text("username")); + local password = query:get_child_text("password"); if username and password then if username == session.username then if usermanager_set_password(username, password, session.host) then -- cgit v1.2.3 From 8d85647c37f3b1fd49e0d639d5646745672391bd Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 30 May 2013 14:32:40 +0200 Subject: mod_c2s, mod_c2s: Send a whitespace on read timeout, to prod TCP into detecting if the connection died --- plugins/mod_c2s.lua | 7 +++++++ plugins/mod_s2s/mod_s2s.lua | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 1d2dd6dd..f9a270c7 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -262,6 +262,13 @@ function listener.ondisconnect(conn, err) end end +function listener.onreadtimeout(conn) + local session = sessions[conn]; + if session then + return session.send(' '); + end +end + function listener.associate_session(conn, session) sessions[conn] = session; end diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index ab5b7232..309940cf 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -624,6 +624,13 @@ function listener.ondisconnect(conn, err) end end +function listener.onreadtimeout(conn) + local session = sessions[conn]; + if session then + return session.sends2s(' '); + end +end + function listener.register_outgoing(conn, session) session.direction = "outgoing"; sessions[conn] = session; -- cgit v1.2.3 From 3389da653e5eaff6f8c78a7c56323732cfd6abe3 Mon Sep 17 00:00:00 2001 From: James Callahan Date: Mon, 3 Jun 2013 12:50:37 -0400 Subject: configure: Fix poor layout --- configure | 53 ++++++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/configure b/configure index ecf77a86..87fd870b 100755 --- a/configure +++ b/configure @@ -94,32 +94,31 @@ do --ostype=*) OSTYPE="$value" OSTYPE_SET=yes - if [ "$OSTYPE" = "debian" ] - then LUA_SUFFIX="5.1"; - LUA_SUFFIX_SET=yes - RUNWITH="lua5.1" - LUA_INCDIR=/usr/include/lua5.1; - LUA_INCDIR_SET=yes - CFLAGS="$CFLAGS -D_GNU_SOURCE" - fi - if [ "$OSTYPE" = "macosx" ] - then LUA_INCDIR=/usr/local/include; - LUA_INCDIR_SET=yes - LUA_LIBDIR=/usr/local/lib - LUA_LIBDIR_SET=yes - LDFLAGS="-bundle -undefined dynamic_lookup" - fi - if [ "$OSTYPE" = "linux" ] - then LUA_INCDIR=/usr/local/include; + if [ "$OSTYPE" = "debian" ]; then + LUA_SUFFIX="5.1"; + LUA_SUFFIX_SET=yes + RUNWITH="lua5.1" + LUA_INCDIR=/usr/include/lua5.1; + LUA_INCDIR_SET=yes + CFLAGS="$CFLAGS -D_GNU_SOURCE" + fi + if [ "$OSTYPE" = "macosx" ]; then + LUA_INCDIR=/usr/local/include; + LUA_INCDIR_SET=yes + LUA_LIBDIR=/usr/local/lib + LUA_LIBDIR_SET=yes + LDFLAGS="-bundle -undefined dynamic_lookup" + fi + if [ "$OSTYPE" = "linux" ]; then + LUA_INCDIR=/usr/local/include; LUA_INCDIR_SET=yes LUA_LIBDIR=/usr/local/lib LUA_LIBDIR_SET=yes - CFLAGS="-Wall -fPIC" - CFLAGS="$CFLAGS -D_GNU_SOURCE" + CFLAGS="-Wall -fPIC -D_GNU_SOURCE" LDFLAGS="-shared" - fi - if [ "$OSTYPE" = "freebsd" -o "$OSTYPE" = "openbsd" ] - then LUA_INCDIR="/usr/local/include/lua51" + fi + if [ "$OSTYPE" = "freebsd" -o "$OSTYPE" = "openbsd" ]; then + LUA_INCDIR="/usr/local/include/lua51" LUA_INCDIR_SET=yes CFLAGS="-Wall -fPIC -I/usr/local/include" LDFLAGS="-I/usr/local/include -L/usr/local/lib -shared" @@ -127,10 +126,10 @@ do LUA_SUFFIX_SET=yes LUA_DIR=/usr/local LUA_DIR_SET=yes - fi - if [ "$OSTYPE" = "openbsd" ] - then LUA_INCDIR="/usr/local/include"; - fi + fi + if [ "$OSTYPE" = "openbsd" ]; then + LUA_INCDIR="/usr/local/include"; + fi ;; --datadir=*) DATADIR="$value" @@ -286,7 +285,7 @@ then IDNA_LIBS="$ICU_FLAGS" CFLAGS="$CFLAGS -DUSE_STRINGPREP_ICU" fi -if [ "$IDN_LIBRARY" = "idn" ] +if [ "$IDN_LIBRARY" = "idn" ] then IDNA_LIBS="-l$IDN_LIB" fi -- cgit v1.2.3 From 2bf1a784c771c3134c46dab34ff9990acdb9174b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Jun 2013 17:44:42 +0200 Subject: certmanager: Overhaul of how ssl configs are built. --- core/certmanager.lua | 83 ++++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index 5618589b..92b63ec3 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -12,6 +12,7 @@ local ssl = ssl; local ssl_newcontext = ssl and ssl.newcontext; local tostring = tostring; +local pairs = pairs; local prosody = prosody; local resolve_path = configmanager.resolve_relative_path; @@ -28,54 +29,60 @@ end module "certmanager" -- Global SSL options if not overridden per-host -local default_ssl_config = configmanager.get("*", "ssl"); -local default_capath = "/etc/ssl/certs"; -local default_verify = (ssl and ssl.x509 and { "peer", "client_once", }) or "none"; -local default_options = { "no_sslv2", luasec_has_noticket and "no_ticket" or nil }; -local default_verifyext = { "lsec_continue", "lsec_ignore_purpose" }; +local global_ssl_config = configmanager.get("*", "ssl"); + +local core_defaults = { + capath = "/etc/ssl/certs"; + protocol = "sslv23"; + verify = (ssl and ssl.x509 and { "peer", "client_once", }) or "none"; + options = { "no_sslv2", luasec_has_noticket and "no_ticket" or nil }; + verifyext = { "lsec_continue", "lsec_ignore_purpose" }; + curve = "secp384r1"; +} +local path_options = { -- These we pass through resolve_path() + key = true, certificate = true, cafile = true, capath = true +} if ssl and not luasec_has_verifyext and ssl.x509 then -- COMPAT mw/luasec-hg - for i=1,#default_verifyext do -- Remove lsec_ prefix - default_verify[#default_verify+1] = default_verifyext[i]:sub(6); + for i=1,#core_defaults.verifyext do -- Remove lsec_ prefix + core_defaults.verify[#core_defaults.verify+1] = core_defaults.verifyext[i]:sub(6); end end -if luasec_has_no_compression and configmanager.get("*", "ssl_compression") ~= true then - default_options[#default_options+1] = "no_compression"; -end -if luasec_has_no_compression then -- Has no_compression? Then it has these too... - default_options[#default_options+1] = "single_dh_use"; - default_options[#default_options+1] = "single_ecdh_use"; +if luasec_has_no_compression and configmanager.get("*", "ssl_compression") ~= true then + core_defaults.options[#core_defaults.options+1] = "no_compression"; end function create_context(host, mode, user_ssl_config) - user_ssl_config = user_ssl_config or default_ssl_config; + user_ssl_config = user_ssl_config or {} + user_ssl_config.mode = mode; if not ssl then return nil, "LuaSec (required for encryption) was not found"; end - if not user_ssl_config then return nil, "No SSL/TLS configuration present for "..host; end + + if global_ssl_config then + for option,default_value in pairs(global_ssl_config) do + if not user_ssl_config[option] then + user_ssl_config[option] = default_value; + end + end + end + for option,default_value in pairs(core_defaults) do + if not user_ssl_config[option] then + user_ssl_config[option] = default_value; + end + end + user_ssl_config.password = user_ssl_config.password or function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; + for option in pairs(path_options) do + user_ssl_config[option] = user_ssl_config[option] and resolve_path(config_path, user_ssl_config[option]); + end + if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end - - local ssl_config = { - mode = mode; - protocol = user_ssl_config.protocol or "sslv23"; - key = resolve_path(config_path, user_ssl_config.key); - password = user_ssl_config.password or function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; - certificate = resolve_path(config_path, user_ssl_config.certificate); - capath = resolve_path(config_path, user_ssl_config.capath or default_capath); - cafile = resolve_path(config_path, user_ssl_config.cafile); - verify = user_ssl_config.verify or default_verify; - verifyext = user_ssl_config.verifyext or default_verifyext; - options = user_ssl_config.options or default_options; - depth = user_ssl_config.depth; - curve = user_ssl_config.curve or "secp384r1"; - dhparam = user_ssl_config.dhparam; - }; - - local ctx, err = ssl_newcontext(ssl_config); - - -- LuaSec ignores the cipher list from the config, so we have to take care + + local ctx, err = ssl_newcontext(user_ssl_config); + + -- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care -- of it ourselves (W/A for #x) if ctx and user_ssl_config.ciphers then local success; @@ -88,9 +95,9 @@ function create_context(host, mode, user_ssl_config) local file = err:match("^error loading (.-) %("); if file then if file == "private key" then - file = ssl_config.key or "your private key"; + file = user_ssl_config.key or "your private key"; elseif file == "certificate" then - file = ssl_config.certificate or "your certificate file"; + file = user_ssl_config.certificate or "your certificate file"; end local reason = err:match("%((.+)%)$") or "some reason"; if reason == "Permission denied" then @@ -113,7 +120,7 @@ function create_context(host, mode, user_ssl_config) end function reload_ssl_config() - default_ssl_config = configmanager.get("*", "ssl"); + global_ssl_config = configmanager.get("*", "ssl"); end prosody.events.add_handler("config-reloaded", reload_ssl_config); -- cgit v1.2.3 From 3786afa97f950322a78cf9e68ab87812c429bc92 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Jun 2013 17:47:45 +0200 Subject: mod_tls: Refactor to allow separate SSL configuration for c2s and s2s connections --- plugins/mod_tls.lua | 62 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index 80b56abb..e167cf95 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -23,20 +23,48 @@ local s2s_feature = st.stanza("starttls", starttls_attr); if secure_auth_only then c2s_feature:tag("required"):up(); end if secure_s2s_only then s2s_feature:tag("required"):up(); end -local global_ssl_ctx = prosody.global_ssl_ctx; - local hosts = prosody.hosts; local host = hosts[module.host]; +local ssl_ctx_c2s, ssl_ctx_s2sout, ssl_ctx_s2sin; +do + local function get_ssl_cfg(typ) + local cfg_key = (typ and typ.."_" or "").."ssl"; + local ssl_config = config.rawget(module.host, cfg_key); + if not ssl_config then + local base_host = module.host:match("%.(.*)"); + ssl_config = config.get(base_host, cfg_key); + end + return ssl_config or typ and get_ssl_cfg(); + end + + local ssl_config, err = get_ssl_cfg("c2s"); + ssl_ctx_c2s, err = create_context(host.host, "server", ssl_config); -- for incoming client connections + if err then module:log("error", "Error creating context for c2s: %s", err); end + + ssl_config = get_ssl_cfg("s2s"); + ssl_ctx_s2sin, err = create_context(host.host, "server", ssl_config); -- for incoming server connections + ssl_ctx_s2sout = create_context(host.host, "client", ssl_config); -- for outgoing server connections + if err then module:log("error", "Error creating context for s2s: %s", err); end -- Both would have the same issue +end + local function can_do_tls(session) + if not session.conn.starttls then + return false; + elseif session.ssl_ctx then + return true; + end if session.type == "c2s_unauthed" then - return session.conn.starttls and host.ssl_ctx_in; + module:log("debug", "session.ssl_ctx = ssl_ctx_c2s;") + session.ssl_ctx = ssl_ctx_c2s; elseif session.type == "s2sin_unauthed" and allow_s2s_tls then - return session.conn.starttls and host.ssl_ctx_in; + session.ssl_ctx = ssl_ctx_s2sin; elseif session.direction == "outgoing" and allow_s2s_tls then - return session.conn.starttls and host.ssl_ctx; + session.ssl_ctx = ssl_ctx_s2sout; + else + return false; end - return false; + return session.ssl_ctx; end -- Hook @@ -45,9 +73,7 @@ module:hook("stanza/urn:ietf:params:xml:ns:xmpp-tls:starttls", function(event) if can_do_tls(origin) then (origin.sends2s or origin.send)(starttls_proceed); origin:reset_stream(); - local host = origin.to_host or origin.host; - local ssl_ctx = host and hosts[host].ssl_ctx_in or global_ssl_ctx; - origin.conn:starttls(ssl_ctx); + origin.conn:starttls(origin.ssl_ctx); origin.log("debug", "TLS negotiation started for %s...", origin.type); origin.secure = false; else @@ -85,23 +111,7 @@ end, 500); module:hook_stanza(xmlns_starttls, "proceed", function (session, stanza) module:log("debug", "Proceeding with TLS on s2sout..."); session:reset_stream(); - local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx; - session.conn:starttls(ssl_ctx); + session.conn:starttls(session.ssl_ctx); session.secure = false; return true; end); - -function module.load() - local ssl_config = config.rawget(module.host, "ssl"); - if not ssl_config then - local base_host = module.host:match("%.(.*)"); - ssl_config = config.get(base_host, "ssl"); - end - host.ssl_ctx = create_context(host.host, "client", ssl_config); -- for outgoing connections - host.ssl_ctx_in = create_context(host.host, "server", ssl_config); -- for incoming connections -end - -function module.unload() - host.ssl_ctx = nil; - host.ssl_ctx_in = nil; -end -- cgit v1.2.3 From fdc11d1acca15a045ace62244dbb9595ec6b46f7 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Jun 2013 17:48:09 +0200 Subject: prosody: Remove global ssl context, no longer used --- prosody | 6 ------ 1 file changed, 6 deletions(-) diff --git a/prosody b/prosody index 9a88eac0..1a0f6ff2 100755 --- a/prosody +++ b/prosody @@ -264,12 +264,6 @@ function init_global_state() prosody.events.fire_event("server-stopping", {reason = reason}); server.setquitting(true); end - - -- Load SSL settings from config, and create a ctx table - local certmanager = require "core.certmanager"; - local global_ssl_ctx = certmanager.create_context("*", "server"); - prosody.global_ssl_ctx = global_ssl_ctx; - end function read_version() -- cgit v1.2.3 From e5a50872bb62aec41b74052c2f5b22fc777daca6 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Jun 2013 18:20:49 +0200 Subject: util.sasl.external: Add SASL EXTERNAL mechanism --- util/sasl.lua | 1 + util/sasl/external.lua | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 util/sasl/external.lua diff --git a/util/sasl.lua b/util/sasl.lua index afb3861b..d0da9435 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -92,5 +92,6 @@ require "util.sasl.plain" .init(registerMechanism); require "util.sasl.digest-md5".init(registerMechanism); require "util.sasl.anonymous" .init(registerMechanism); require "util.sasl.scram" .init(registerMechanism); +require "util.sasl.external" .init(registerMechanism); return _M; diff --git a/util/sasl/external.lua b/util/sasl/external.lua new file mode 100644 index 00000000..4c5c4343 --- /dev/null +++ b/util/sasl/external.lua @@ -0,0 +1,25 @@ +local saslprep = require "util.encodings".stringprep.saslprep; + +module "sasl.external" + +local function external(self, message) + message = saslprep(message); + local state + self.username, state = self.profile.external(message); + + if state == false then + return "failure", "account-disabled"; + elseif state == nil then + return "failure", "not-authorized"; + elseif state == "expired" then + return "false", "credentials-expired"; + end + + return "success"; +end + +function init(registerMechanism) + registerMechanism("EXTERNAL", {"external"}, external); +end + +return _M; -- cgit v1.2.3 From 6436abbab7906566e9bfe95015aabfe21c3f97e5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 13 Jun 2013 23:31:11 +0200 Subject: mod_http_files: Put the MIME type map in a global shared table --- plugins/mod_http_files.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_http_files.lua b/plugins/mod_http_files.lua index 915bec58..59fd50aa 100644 --- a/plugins/mod_http_files.lua +++ b/plugins/mod_http_files.lua @@ -19,7 +19,7 @@ local base_path = module:get_option_string("http_files_dir", module:get_option_s local dir_indices = module:get_option("http_index_files", { "index.html", "index.htm" }); local directory_index = module:get_option_boolean("http_dir_listing"); -local mime_map = module:shared("mime").types; +local mime_map = module:shared("/*/http_files/mime").types; if not mime_map then mime_map = { html = "text/html", htm = "text/html", -- cgit v1.2.3 From 8d3f90ac4568e7ddc0790748e4752066ecb6a9e3 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Tue, 4 Jun 2013 23:59:59 +0200 Subject: mod_disco: Allow ansering disco requests including nodes, and adding custom items to disco#items requests --- plugins/mod_disco.lua | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index b8df0bd6..06a4bb1e 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -32,7 +32,9 @@ do -- validate disco_items end end -module:add_identity("server", "im", module:get_option_string("name", "Prosody")); -- FIXME should be in the non-existing mod_router +if module:get_host_type() == "normal" then + module:add_identity("server", "im", module:get_option_string("name", "Prosody")); -- FIXME should be in the non-existing mod_router +end module:add_feature("http://jabber.org/protocol/disco#info"); module:add_feature("http://jabber.org/protocol/disco#items"); @@ -97,7 +99,18 @@ module:hook("iq/host/http://jabber.org/protocol/disco#info:query", function(even local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "get" then return; end local node = stanza.tags[1].attr.node; - if node and node ~= "" and node ~= "http://prosody.im#"..get_server_caps_hash() then return; end -- TODO fire event? + if node and node ~= "" and node ~= "http://prosody.im#"..get_server_caps_hash() then + local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#info', node=node}); + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false}; + local ret = module:fire_event("host-disco-info-node", event); + if ret ~= nil then return ret; end + if event.exists then + origin.send(reply); + else + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Node does not exist")); + end + return true; + end local reply_query = get_server_disco_info(); reply_query.node = node; local reply = st.reply(stanza):add_child(reply_query); @@ -108,9 +121,21 @@ module:hook("iq/host/http://jabber.org/protocol/disco#items:query", function(eve local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "get" then return; end local node = stanza.tags[1].attr.node; - if node and node ~= "" then return; end -- TODO fire event? - + if node and node ~= "" then + local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#items', node=node}); + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false}; + local ret = module:fire_event("host-disco-items-node", event); + if ret ~= nil then return ret; end + if event.exists then + origin.send(reply); + else + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Node does not exist")); + end + return true; + end local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#items"); + local ret = module:fire_event("host-disco-items", { origin = origin, stanza = stanza, reply = reply }); + if ret ~= nil then return ret; end for jid, name in pairs(get_children(module.host)) do reply:tag("item", {jid = jid, name = name~=true and name or nil}):up(); end @@ -138,8 +163,9 @@ module:hook("iq/bare/http://jabber.org/protocol/disco#info:query", function(even if node and node ~= "" then local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#info', node=node}); if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account - local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false} - module:fire_event("account-disco-info-node", event); + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false}; + local ret = module:fire_event("account-disco-info-node", event); + if ret ~= nil then return ret; end if event.exists then origin.send(reply); else @@ -163,8 +189,9 @@ module:hook("iq/bare/http://jabber.org/protocol/disco#items:query", function(eve if node and node ~= "" then local reply = st.reply(stanza):tag('query', {xmlns='http://jabber.org/protocol/disco#items', node=node}); if not reply.attr.from then reply.attr.from = origin.username.."@"..origin.host; end -- COMPAT To satisfy Psi when querying own account - local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false} - module:fire_event("account-disco-items-node", event); + local event = { origin = origin, stanza = stanza, reply = reply, node = node, exists = false}; + local ret = module:fire_event("account-disco-items-node", event); + if ret ~= nil then return ret; end if event.exists then origin.send(reply); else -- cgit v1.2.3 From 8cc755c0fab0260974794360044dc03208583098 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 5 Jun 2013 00:01:17 +0200 Subject: mod_pubsub: Utilize mod_disco, instead of reimplementing disco handling --- plugins/mod_pubsub/mod_pubsub.lua | 238 +++++++++++++++++--------------------- 1 file changed, 108 insertions(+), 130 deletions(-) diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua index ad20c6a7..81a66f8b 100644 --- a/plugins/mod_pubsub/mod_pubsub.lua +++ b/plugins/mod_pubsub/mod_pubsub.lua @@ -18,6 +18,10 @@ local lib_pubsub = module:require "pubsub"; local handlers = lib_pubsub.handlers; local pubsub_error_reply = lib_pubsub.pubsub_error_reply; +module:depends("disco"); +module:add_identity("pubsub", "service", pubsub_disco_name); +module:add_feature("http://jabber.org/protocol/pubsub"); + function handle_pubsub_iq(event) local origin, stanza = event.origin, event.stanza; local pubsub = stanza.tags[1]; @@ -51,8 +55,6 @@ end module:hook("iq/host/"..xmlns_pubsub..":pubsub", handle_pubsub_iq); module:hook("iq/host/"..xmlns_pubsub_owner..":pubsub", handle_pubsub_iq); -local disco_info; - local feature_map = { create = { "create-nodes", "instant-nodes", "item-ids" }; retract = { "delete-items", "retract-items" }; @@ -64,87 +66,59 @@ local feature_map = { get_subscriptions = { "retrieve-subscriptions" }; }; -local function add_disco_features_from_service(disco, service) +local function add_disco_features_from_service(service) for method, features in pairs(feature_map) do if service[method] then for _, feature in ipairs(features) do if feature then - disco:tag("feature", { var = xmlns_pubsub.."#"..feature }):up(); + module:add_feature(xmlns_pubsub.."#"..feature); end end end end for affiliation in pairs(service.config.capabilities) do if affiliation ~= "none" and affiliation ~= "owner" then - disco:tag("feature", { var = xmlns_pubsub.."#"..affiliation.."-affiliation" }):up(); + module:add_feature(xmlns_pubsub.."#"..affiliation.."-affiliation"); end end end -local function build_disco_info(service) - local disco_info = st.stanza("query", { xmlns = "http://jabber.org/protocol/disco#info" }) - :tag("identity", { category = "pubsub", type = "service", name = pubsub_disco_name }):up() - :tag("feature", { var = "http://jabber.org/protocol/pubsub" }):up(); - add_disco_features_from_service(disco_info, service); - return disco_info; -end - -module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function (event) - local origin, stanza = event.origin, event.stanza; - local node = stanza.tags[1].attr.node; - if not node then - return origin.send(st.reply(stanza):add_child(disco_info)); - else - local ok, ret = service:get_nodes(stanza.attr.from); - if ok and not ret[node] then - ok, ret = false, "item-not-found"; - end - if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); - end - local reply = st.reply(stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#info", node = node }) - :tag("identity", { category = "pubsub", type = "leaf" }); - return origin.send(reply); +module:hook("host-disco-info-node", function (event) + local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; + local ok, ret = service:get_nodes(stanza.attr.from); + if ok and not ret[node] then + return; end + if not ok then + return origin.send(pubsub_error_reply(stanza, ret)); + end + event.exists = true; + reply:tag("identity", { category = "pubsub", type = "leaf" }); end); -local function handle_disco_items_on_node(event) - local stanza, origin = event.stanza, event.origin; - local query = stanza.tags[1]; - local node = query.attr.node; +module:hook("host-disco-items-node", function (event) + local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; local ok, ret = service:get_items(node, stanza.attr.from); if not ok then return origin.send(pubsub_error_reply(stanza, ret)); end - local reply = st.reply(stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#items", node = node }); - for id, item in pairs(ret) do reply:tag("item", { jid = module.host, name = id }):up(); end - - return origin.send(reply); -end + event.exists = true; +end); -module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function (event) - if event.stanza.tags[1].attr.node then - return handle_disco_items_on_node(event); - end +module:hook("host-disco-items", function (event) + local stanza, origin, reply = event.stanza, event.origin, event.reply; local ok, ret = service:get_nodes(event.stanza.attr.from); if not ok then - event.origin.send(pubsub_error_reply(event.stanza, ret)); - else - local reply = st.reply(event.stanza) - :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }); - for node, node_obj in pairs(ret) do - reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); - end - event.origin.send(reply); + return origin.send(pubsub_error_reply(event.stanza, ret)); + end + for node, node_obj in pairs(ret) do + reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); end - return true; end); local admin_aff = module:get_option_string("default_admin_affiliation", "owner"); @@ -158,7 +132,7 @@ end function set_service(new_service) service = new_service; module.environment.service = service; - disco_info = build_disco_info(service); + add_disco_features_from_service(service); end function module.save() @@ -169,83 +143,87 @@ function module.restore(data) set_service(data.service); end -set_service(pubsub.new({ - capabilities = { - none = { - create = false; - publish = false; - retract = false; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - subscribe_other = false; - unsubscribe_other = false; - get_subscription_other = false; - get_subscriptions_other = false; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = false; - }; - publisher = { - create = false; - publish = true; - retract = true; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - subscribe_other = false; - unsubscribe_other = false; - get_subscription_other = false; - get_subscriptions_other = false; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = false; - }; - owner = { - create = true; - publish = true; - retract = true; - delete = true; - get_nodes = true; - - subscribe = true; - unsubscribe = true; - get_subscription = true; - get_subscriptions = true; - get_items = true; - - - subscribe_other = true; - unsubscribe_other = true; - get_subscription_other = true; - get_subscriptions_other = true; - - be_subscribed = true; - be_unsubscribed = true; - - set_affiliation = true; +function module.load() + if module.reloading then return; end + + set_service(pubsub.new({ + capabilities = { + none = { + create = false; + publish = false; + retract = false; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = false; + unsubscribe_other = false; + get_subscription_other = false; + get_subscriptions_other = false; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = false; + }; + publisher = { + create = false; + publish = true; + retract = true; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + subscribe_other = false; + unsubscribe_other = false; + get_subscription_other = false; + get_subscriptions_other = false; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = false; + }; + owner = { + create = true; + publish = true; + retract = true; + delete = true; + get_nodes = true; + + subscribe = true; + unsubscribe = true; + get_subscription = true; + get_subscriptions = true; + get_items = true; + + + subscribe_other = true; + unsubscribe_other = true; + get_subscription_other = true; + get_subscriptions_other = true; + + be_subscribed = true; + be_unsubscribed = true; + + set_affiliation = true; + }; }; - }; - autocreate_on_publish = autocreate_on_publish; - autocreate_on_subscribe = autocreate_on_subscribe; + autocreate_on_publish = autocreate_on_publish; + autocreate_on_subscribe = autocreate_on_subscribe; - broadcaster = simple_broadcast; - get_affiliation = get_affiliation; + broadcaster = simple_broadcast; + get_affiliation = get_affiliation; - normalize_jid = jid_bare; -})); + normalize_jid = jid_bare; + })); +end -- cgit v1.2.3 From d5159cde97a7ded0f66cac5843f78ab587c2a291 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 5 Jun 2013 00:04:44 +0200 Subject: mod_muc: Utilize mod_disco, instead of reimplementing disco handling --- plugins/muc/mod_muc.lua | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index bc865ec9..981c0bcd 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -40,6 +40,10 @@ local room_configs = module:open_store("config"); -- Configurable options muclib.set_max_history_length(module:get_option_number("max_history_messages")); +module:depends("disco"); +module:add_identity("conference", "text", muc_name); +module:add_feature("http://jabber.org/protocol/muc"); + local function is_admin(jid) return um_is_admin(jid, module.host); end @@ -107,20 +111,15 @@ local host_room = muc_new_room(muc_host); host_room.route_stanza = room_route_stanza; host_room.save = room_save; -local function get_disco_info(stanza) - return st.iq({type='result', id=stanza.attr.id, from=muc_host, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#info") - :tag("identity", {category='conference', type='text', name=muc_name}):up() - :tag("feature", {var="http://jabber.org/protocol/muc"}); -- TODO cache disco reply -end -local function get_disco_items(stanza) - local reply = st.iq({type='result', id=stanza.attr.id, from=muc_host, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#items"); +module:hook("host-disco-items", function(event) + local reply = event.reply; + module:log("debug", "host-disco-items called"); for jid, room in pairs(rooms) do if not room:get_hidden() then reply:tag("item", {jid=jid, name=room:get_name()}):up(); end end - return reply; -- TODO cache disco reply -end +end); local function handle_to_domain(event) local origin, stanza = event.origin, event.stanza; @@ -129,11 +128,7 @@ local function handle_to_domain(event) if stanza.name == "iq" and type == "get" then local xmlns = stanza.tags[1].attr.xmlns; local node = stanza.tags[1].attr.node; - if xmlns == "http://jabber.org/protocol/disco#info" and not node then - origin.send(get_disco_info(stanza)); - elseif xmlns == "http://jabber.org/protocol/disco#items" and not node then - origin.send(get_disco_items(stanza)); - elseif xmlns == "http://jabber.org/protocol/muc#unique" then + if xmlns == "http://jabber.org/protocol/muc#unique" then origin.send(st.reply(stanza):tag("unique", {xmlns = xmlns}):text(uuid_gen())); -- FIXME Random UUIDs can theoretically have collisions else origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- TODO disco/etc -- cgit v1.2.3 From ee47583ffba1c0c823afbc0943951617356800e6 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 5 Jun 2013 00:05:03 +0200 Subject: mod_muc: Add Ad-Hoc command to destroy MUC rooms --- plugins/muc/mod_muc.lua | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 981c0bcd..a9480465 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -224,3 +224,39 @@ function shutdown_component() end module.unload = shutdown_component; module:hook_global("server-stopping", shutdown_component); + +-- Ad-hoc commands +module:depends("adhoc") +local t_concat = table.concat; +local keys = require "util.iterators".keys; +local adhoc_new = module:require "adhoc".new; +local adhoc_initial = require "util.adhoc".new_initial_data_form; +local dataforms_new = require "util.dataforms".new; + +local destroy_rooms_layout = dataforms_new { + title = "Destroy rooms"; + instructions = "Select the rooms to destroy"; + + { name = "FORM_TYPE", type = "hidden", value = "http://prosody.im/protocol/muc#destroy" }; + { name = "rooms", type = "list-multi", required = true, label = "Rooms to destroy:"}; +}; + +local destroy_rooms_handler = adhoc_initial(destroy_rooms_layout, function() + return { rooms = array.collect(keys(rooms)):sort() }; +end, function(fields, errors) + if errors then + local errmsg = {}; + for name, err in pairs(errors) do + errmsg[#errmsg + 1] = name .. ": " .. err; + end + return { status = "completed", error = { message = t_concat(errmsg, "\n") } }; + end + for _, room in ipairs(fields.rooms) do + rooms[room]:destroy(); + rooms[room] = nil; + end + return { status = "completed", info = "The following rooms were destroyed:\n"..t_concat(fields.rooms, "\n") }; +end); +local destroy_rooms_desc = adhoc_new("Destroy Rooms", "http://prosody.im/protocol/muc#destroy", destroy_rooms_handler, "admin"); + +module:provides("adhoc", destroy_rooms_desc); -- cgit v1.2.3 From 885b4a7e2a8565d7d9fa9a1fd97723dc4af0d129 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 5 Jun 2013 21:37:33 +0100 Subject: mod_bosh: Remove some very verbose logging --- plugins/mod_bosh.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 03355564..3c5e18f0 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -139,9 +139,6 @@ function handle_POST(event) local r = session.requests; log("debug", "Session %s has %d out of %d requests open", context.sid, #r, session.bosh_hold); log("debug", "and there are %d things in the send_buffer:", #session.send_buffer); - for i, thing in ipairs(session.send_buffer) do - log("debug", " %s", tostring(thing)); - end if #r > session.bosh_hold then -- We are holding too many requests, send what's in the buffer, log("debug", "We are holding too many requests, so..."); -- cgit v1.2.3 From b174c0dba2d13e37a17ccb71a124063e2873215d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 5 Jun 2013 21:39:56 +0100 Subject: mod_bosh: Return errors when appropriate (invalid XML, missing sid) --- plugins/mod_bosh.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 3c5e18f0..90522031 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -123,7 +123,10 @@ function handle_POST(event) -- In particular, the streamopened() stream callback is where -- much of the session logic happens, because it's where we first -- get to see the 'sid' of this request. - stream:feed(body); + if not stream:feed(body) then + module:log("warn", "Error parsing BOSH payload") + return 400; + end -- Stanzas (if any) in the request have now been processed, and -- we take care of the high-level BOSH logic here, including @@ -174,6 +177,8 @@ function handle_POST(event) return true; -- Inform http server we shall reply later end end + module:log("warn", "Unable to associate request with a session (incomplete request?)"); + return 400; end -- cgit v1.2.3 From 70b2041049db1b148951d77993bba41646dc2f33 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 5 Jun 2013 21:41:27 +0100 Subject: mod_bosh: Clean up handling of response headers, set them only in one place --- plugins/mod_bosh.lua | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 90522031..ec8c59f5 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -35,24 +35,9 @@ local BOSH_DEFAULT_REQUESTS = module:get_option_number("bosh_max_requests", 2); local bosh_max_wait = module:get_option_number("bosh_max_wait", 120); local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure"); - -local default_headers = { ["Content-Type"] = "text/xml; charset=utf-8", ["Connection"] = "keep-alive" }; - local cross_domain = module:get_option("cross_domain_bosh", false); -if cross_domain then - default_headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"; - default_headers["Access-Control-Allow-Headers"] = "Content-Type"; - default_headers["Access-Control-Max-Age"] = "7200"; - if cross_domain == true then - default_headers["Access-Control-Allow-Origin"] = "*"; - elseif type(cross_domain) == "table" then - cross_domain = table.concat(cross_domain, ", "); - end - if type(cross_domain) == "string" then - default_headers["Access-Control-Allow-Origin"] = cross_domain; - end -end +if type(cross_domain) == "table" then cross_domain = table.concat(cross_domain, ", "); end local trusted_proxies = module:get_option_set("trusted_proxies", {"127.0.0.1"})._items; @@ -100,11 +85,22 @@ function on_destroy_request(request) end end +local function set_cross_domain_headers(response) + local headers = response.headers; + headers.access_control_allow_methods = "GET, POST, OPTIONS"; + headers.access_control_allow_headers = "Content-Type"; + headers.access_control_max_age = "7200"; + + if cross_domain == true then + headers.access_control_allow_origin = "*"; + else + headers.access_control_allow_origin = cross_domain; + end + return response; +end + function handle_OPTIONS(request) - local headers = {}; - for k,v in pairs(default_headers) do headers[k] = v; end - headers["Content-Type"] = nil; - return { headers = headers, body = "" }; + return set_cross_domain_headers(request.response); end function handle_POST(event) @@ -117,6 +113,13 @@ function handle_POST(event) local context = { request = request, response = response, notopen = true }; local stream = new_xmpp_stream(context, stream_callbacks); response.context = context; + + local headers = response.headers; + headers.content_type = "text/xml; charset=utf-8"; + + if cross_domain then + set_cross_domain_headers(response); + end -- stream:feed() calls the stream_callbacks, so all stanzas in -- the body are processed in this next line before it returns. @@ -217,7 +220,6 @@ local function bosh_close_stream(session, reason) local response_body = tostring(close_reply); for _, held_request in ipairs(session.requests) do - held_request.headers = default_headers; held_request:send(response_body); end sessions[session.sid] = nil; @@ -311,7 +313,6 @@ function stream_callbacks.streamopened(context, attr) if not session then -- Unknown sid log("info", "Client tried to use sid '%s' which we don't know about", sid); - response.headers = default_headers; response:send(tostring(st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", condition = "item-not-found" }))); context.notopen = nil; return; @@ -381,7 +382,6 @@ function stream_callbacks.error(context, error) log("debug", "Error parsing BOSH request payload; %s", error); if not context.sid then local response = context.response; - response.headers = default_headers; response.status_code = 400; response:send(); return; -- cgit v1.2.3 From 2d2b6df7cb2a17d00bc2074186a8c06c2702fd2a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 6 Jun 2013 14:48:41 +0100 Subject: mod_bosh: Remove another place we set headers, fixes #348 --- plugins/mod_bosh.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index ec8c59f5..d0202b7d 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -281,7 +281,6 @@ function stream_callbacks.streamopened(context, attr) local oldest_request = r[1]; if oldest_request and not session.bosh_processing then log("debug", "We have an open request, so sending on that"); - oldest_request.headers = default_headers; local body_attr = { xmlns = "http://jabber.org/protocol/httpbind", ["xmlns:stream"] = "http://etherx.jabber.org/streams"; type = session.bosh_terminate and "terminate" or nil; -- cgit v1.2.3 From e3784f09b95ea6afff43005cce671d4092589442 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 7 Jun 2013 13:21:38 -0400 Subject: mod_bosh: Rename event handler argument to event, not request. --- plugins/mod_bosh.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 00da914c..095ba4a3 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -99,8 +99,8 @@ local function set_cross_domain_headers(response) return response; end -function handle_OPTIONS(request) - return set_cross_domain_headers(request.response); +function handle_OPTIONS(event) + return set_cross_domain_headers(event.response); end function handle_POST(event) -- cgit v1.2.3 From a22bd3606b9c4e5017d00f9d80512d70e2bf4f6f Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 7 Jun 2013 13:24:56 -0400 Subject: mod_bosh: Return empty string from the OPTIONS event handler, don't return the response object itself. --- plugins/mod_bosh.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 095ba4a3..48d16df1 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -100,7 +100,8 @@ local function set_cross_domain_headers(response) end function handle_OPTIONS(event) - return set_cross_domain_headers(event.response); + set_cross_domain_headers(event.response); + return ""; end function handle_POST(event) -- cgit v1.2.3 From 8e44ad94a9cb442bd7a03830a2a8548c3833fe68 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 7 Jun 2013 14:20:13 -0400 Subject: mod_bosh: Only return CORS headers if the Origin header is received, and CORS is enabled. --- plugins/mod_bosh.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 48d16df1..04d85e60 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -100,7 +100,9 @@ local function set_cross_domain_headers(response) end function handle_OPTIONS(event) - set_cross_domain_headers(event.response); + if cross_domain and event.request.headers.origin then + set_cross_domain_headers(event.response); + end return ""; end @@ -118,7 +120,7 @@ function handle_POST(event) local headers = response.headers; headers.content_type = "text/xml; charset=utf-8"; - if cross_domain then + if cross_domain and event.request.headers.origin then set_cross_domain_headers(response); end -- cgit v1.2.3 From e626df2fc20257eb9e96fb9cfcfc22df10e044c9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jun 2013 20:05:23 +0200 Subject: prosodyctl: Add 'prosodyctl check --help' --- prosodyctl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prosodyctl b/prosodyctl index 4d7f678f..47273014 100755 --- a/prosodyctl +++ b/prosodyctl @@ -780,6 +780,10 @@ function commands.cert(arg) end function commands.check(arg) + if arg[1] == "--help" then + show_usage([[check]], [[Perform basic checks on your Prosody installation]]); + return 1; + end local what = table.remove(arg, 1); local array, set = require "util.array", require "util.set"; local it = require "util.iterators"; -- cgit v1.2.3 From 0a3f580122c971b7eaddd5d9b97c6c4137023054 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jun 2013 20:55:02 +0200 Subject: certmanager: Complain if key or certificate is missing from SSL config. --- core/certmanager.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/certmanager.lua b/core/certmanager.lua index 49f445f6..5be328f6 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -49,6 +49,8 @@ function create_context(host, mode, user_ssl_config) if not ssl then return nil, "LuaSec (required for encryption) was not found"; end if not user_ssl_config then return nil, "No SSL/TLS configuration present for "..host; end + if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end + if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end local ssl_config = { mode = mode; -- cgit v1.2.3 From 192d4df580039eedb58e804604874c596b2eca77 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 7 Jun 2013 20:59:43 +0200 Subject: prosodyctl: Add 'prosodyctl check certs' for validating TLS/SSL certificates --- prosodyctl | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/prosodyctl b/prosodyctl index 47273014..aa6f2073 100755 --- a/prosodyctl +++ b/prosodyctl @@ -1022,6 +1022,81 @@ function commands.check(arg) ok = false; end end + if not what or what == "certs" then + local cert_ok; + print"Checking certificates..." + local x509_verify_identity = require"util.x509".verify_identity; + local ssl = dependencies.softreq"ssl"; + -- local datetime_parse = require"util.datetime".parse_x509; + local load_cert = ssl and ssl.x509 and ssl.x509.load; + -- or ssl.cert_from_pem + if not ssl then + print("LuaSec not available, can't perform certificate checks") + if what == "certs" then cert_ok = false end + elseif not load_cert then + print("This version of LuaSec (" .. ssl._VERSION .. ") does not support certificate checking"); + cert_ok = false + else + for host in pairs(hosts) do + if host ~= "*" then -- Should check global certs too. + print("Checking certificate for "..host); + -- First, let's find out what certificate this host uses. + local ssl_config = config.rawget(host, "ssl"); + if not ssl_config then + local base_host = host:match("%.(.*)"); + ssl_config = config.get(base_host, "ssl"); + end + if not ssl_config then + print(" No 'ssl' option defined for "..host) + cert_ok = false + elseif not ssl_config.certificate then + print(" No 'certificate' set in ssl option for "..host) + cert_ok = false + elseif not ssl_config.key then + print(" No 'key' set in ssl option for "..host) + cert_ok = false + else + local key, err = io.open(ssl_config.key); -- Permissions check only + if not key then + print(" Could not open "..ssl_config.key..": "..err); + cert_ok = false + else + key:close(); + end + local cert_fh, err = io.open(ssl_config.certificate); -- Load the file. + if not cert_fh then + print(" Could not open "..ssl_config.certificate..": "..err); + cert_ok = false + else + print(" Certificate: "..ssl_config.certificate) + local cert = load_cert(cert_fh:read"*a"); cert_fh = cert_fh:close(); + if not cert:validat(os.time()) then + print(" Certificate has expired.") + cert_ok = false + end + if config.get(host, "component_module") == nil + and not x509_verify_identity(host, "_xmpp-client", cert) then + print(" Not vaild for client connections to "..host..".") + cert_ok = false + end + if (not (config.get(name, "anonymous_login") + or config.get(name, "authentication") == "anonymous")) + and not x509_verify_identity(host, "_xmpp-client", cert) then + print(" Not vaild for server-to-server connections to "..host..".") + cert_ok = false + end + end + end + end + end + if cert_ok == false then + print("") + print("For more information about certificates please see http://prosody.im/doc/certificates"); + ok = false + end + end + print("") + end if not ok then print("Problems found, see above."); else -- cgit v1.2.3 From 67161986600abebddbb9654ed2a4e8756172da8f Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Fri, 7 Jun 2013 16:26:08 -0400 Subject: mod_bosh: Don't tostring() stream:features when passing to session.send(). --- plugins/mod_bosh.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 04d85e60..d8109602 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -352,7 +352,7 @@ function stream_callbacks.streamopened(context, attr) 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(tostring(features)); + session.send(features); session.notopen = nil; end end -- cgit v1.2.3 From 8bb4a30bd1f1189da9e222a95d86cd4231c46d8c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 8 Jun 2013 18:07:36 +0100 Subject: mod_muc: Include status code 332 on service shutdown (thanks mathieui) --- plugins/muc/mod_muc.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 47809964..bc865ec9 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -219,7 +219,8 @@ function shutdown_component() if not saved then local stanza = st.presence({type = "unavailable"}) :tag("x", {xmlns = "http://jabber.org/protocol/muc#user"}) - :tag("item", { affiliation='none', role='none' }):up(); + :tag("item", { affiliation='none', role='none' }):up() + :tag("status", { code = "332"}):up(); for roomjid, room in pairs(rooms) do shutdown_room(room, stanza); end -- cgit v1.2.3 From 38e6533cbd5ba91acc581b3f0821a5c878d3d1d2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 8 Jun 2013 18:08:18 +0100 Subject: mod_bosh: Make waiting_requests and dead_sessions shared to preserve across reloads --- plugins/mod_bosh.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index d8109602..e3a1050b 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -62,7 +62,7 @@ local os_time = os.time; local sessions, inactive_sessions = module:shared("sessions", "inactive_sessions"); -- Used to respond to idle sessions (those with waiting requests) -local waiting_requests = {}; +local waiting_requests = module:shared("waiting_requests"); function on_destroy_request(request) log("debug", "Request destroyed: %s", tostring(request)); waiting_requests[request] = nil; @@ -397,7 +397,7 @@ function stream_callbacks.error(context, error) end end -local dead_sessions = {}; +local dead_sessions = module:shared("dead_sessions"); function on_timer() -- log("debug", "Checking for requests soon to timeout..."); -- Identify requests timing out within the next few seconds -- cgit v1.2.3 From a6d4b7ca4d2b039273c693d8c08844ef02b744c5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 9 Jun 2013 12:54:10 +0200 Subject: mod_s2s: Set s2s_session.ip --- plugins/mod_s2s/mod_s2s.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 309940cf..bce617ca 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -590,6 +590,7 @@ function listener.onconnect(conn) else -- Outgoing session connected session:open_stream(session.from_host, session.to_host); end + session.ip = conn:ip(); end function listener.onincoming(conn, data) -- cgit v1.2.3 From a07cafce699eefa1c588171d29ce9ad8944d30a1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 9 Jun 2013 12:59:23 +0200 Subject: mod_admin_telnet: Simplify IPv6 detection, fixes rare traceback --- plugins/mod_admin_telnet.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index ae8ca530..0fcb96b3 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -497,7 +497,7 @@ local function session_flags(session, line) if session.smacks then line[#line+1] = "(sm)"; end - if (session.ip or session.conn and session.conn:ip()):match(":") then + if session.ip and session.ip:match(":") then line[#line+1] = "(IPv6)"; end return table.concat(line, " "); -- cgit v1.2.3 From 87170a4fde14e43ed61bddd045642d96a77f47c4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Tue, 11 Jun 2013 12:55:47 -0400 Subject: mod_bosh: Reduce a little code. --- plugins/mod_bosh.lua | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index e3a1050b..9a612ae0 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -37,6 +37,7 @@ local bosh_max_wait = module:get_option_number("bosh_max_wait", 120); local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure"); local cross_domain = module:get_option("cross_domain_bosh", false); +if cross_domain == true then cross_domain = "*"; end if type(cross_domain) == "table" then cross_domain = table.concat(cross_domain, ", "); end local trusted_proxies = module:get_option_set("trusted_proxies", {"127.0.0.1"})._items; @@ -90,12 +91,7 @@ local function set_cross_domain_headers(response) headers.access_control_allow_methods = "GET, POST, OPTIONS"; headers.access_control_allow_headers = "Content-Type"; headers.access_control_max_age = "7200"; - - if cross_domain == true then - headers.access_control_allow_origin = "*"; - else - headers.access_control_allow_origin = cross_domain; - end + headers.access_control_allow_origin = cross_domain; return response; end -- cgit v1.2.3 From b6ecf01333bcb773beb784e2be93af305dd1cf01 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 11 Jun 2013 21:18:51 +0200 Subject: mod_c2s: Become a shared module and allow being disabled on some virtualhosts --- plugins/mod_c2s.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index f9a270c7..d87b3415 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -50,7 +50,7 @@ function stream_callbacks.streamopened(session, attr) session.streamid = uuid_generate(); (session.log or session)("debug", "Client sent opening to %s", session.host); - if not hosts[session.host] then + if not hosts[session.host] or not hosts[session.host].modules.c2s then -- We don't serve this host... session:close{ condition = "host-unknown", text = "This server does not serve "..tostring(session.host)}; return; @@ -273,6 +273,8 @@ function listener.associate_session(conn, session) sessions[conn] = session; end +function module.add_host() end + module:hook("server-stopping", function(event) local reason = event.reason; for _, session in pairs(sessions) do -- cgit v1.2.3 From 4c9866805e69426b720586141c73d94fc4a54cd5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 11 Jun 2013 21:36:15 +0200 Subject: mod_c2s, mod_s2s: Fire an event on read timeouts --- plugins/mod_c2s.lua | 12 ++++++++++-- plugins/mod_s2s/mod_s2s.lua | 7 ++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index d87b3415..91bde574 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -265,15 +265,23 @@ end function listener.onreadtimeout(conn) local session = sessions[conn]; if session then - return session.send(' '); + return (hosts[session.host] or prosody).events.fire_event("c2s-read-timeout", { session = session }); end end +local function keepalive(event) + return event.session.send(' '); +end + function listener.associate_session(conn, session) sessions[conn] = session; end -function module.add_host() end +function module.add_host(module) + module:hook("c2s-read-timeout", keepalive, -1); +end + +module:hook("c2s-read-timeout", keepalive, -1); module:hook("server-stopping", function(event) local reason = event.reason; diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index bce617ca..5e50e88b 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -135,6 +135,10 @@ function route_to_new_session(event) return true; end +local function keepalive(event) + return event.session.sends2s(' '); +end + function module.add_host(module) if module:get_option_boolean("disallow_s2s", false) then module:log("warn", "The 'disallow_s2s' config option is deprecated, please see http://prosody.im/doc/s2s#disabling"); @@ -143,6 +147,7 @@ function module.add_host(module) module:hook("route/remote", route_to_existing_session, -1); module:hook("route/remote", route_to_new_session, -10); module:hook("s2s-authenticated", make_authenticated, -1); + module:hook("s2s-read-timeout", keepalive, -1); end -- Stream is authorised, and ready for normal stanzas @@ -628,7 +633,7 @@ end function listener.onreadtimeout(conn) local session = sessions[conn]; if session then - return session.sends2s(' '); + return (hosts[session.host] or prosody).events.fire_event("s2s-read-timeout", { session = session }); end end -- cgit v1.2.3 From 5554e154375101f958abf6747537cb4110eac82d Mon Sep 17 00:00:00 2001 From: Vadim Misbakh-Soloviov Date: Fri, 14 Jun 2013 15:15:05 +0700 Subject: package{,c}path fixes for migration tools --- tools/ejabberd2prosody.lua | 10 ++++++---- tools/ejabberdsql2prosody.lua | 8 ++++++++ tools/jabberd14sql2prosody.lua | 9 ++++++++- tools/openfire2prosody.lua | 6 ++++++ tools/xep227toprosody.lua | 6 ++++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/tools/ejabberd2prosody.lua b/tools/ejabberd2prosody.lua index c11e41d9..941bd4d5 100755 --- a/tools/ejabberd2prosody.lua +++ b/tools/ejabberd2prosody.lua @@ -11,8 +11,10 @@ package.path = package.path ..";../?.lua"; -if arg[0]:match("[/\\]") then - package.path = package.path .. ";"..arg[0]:gsub("[^/\\]*$", "?.lua"); +local my_name = arg[0]; +if my_name:match("[/\\]") then + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); end local erlparse = require "erlparse"; @@ -229,10 +231,10 @@ local help = "/? -? ? /h -h /help -help --help"; if not arg or help:find(arg, 1, true) then print([[ejabberd db dump importer for Prosody - Usage: ejabberd2prosody.lua filename.txt + Usage: ]]..my_name..[[ filename.txt The file can be generated from ejabberd using: - sudo ./bin/ejabberdctl dump filename.txt + sudo ejabberdctl dump filename.txt Note: The path of ejabberdctl depends on your ejabberd installation, and ejabberd needs to be running for ejabberdctl to work.]]); os.exit(1); diff --git a/tools/ejabberdsql2prosody.lua b/tools/ejabberdsql2prosody.lua index 43720643..d80b9e46 100644 --- a/tools/ejabberdsql2prosody.lua +++ b/tools/ejabberdsql2prosody.lua @@ -10,6 +10,14 @@ prosody = {}; package.path = package.path ..";../?.lua"; + +local my_name = arg[0]; +if my_name:match("[/\\]") then + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); +end + + local serialize = require "util.serialization".serialize; local st = require "util.stanza"; local parse_xml = require "util.xml".parse; diff --git a/tools/jabberd14sql2prosody.lua b/tools/jabberd14sql2prosody.lua index b85d2c20..d6a6753f 100644 --- a/tools/jabberd14sql2prosody.lua +++ b/tools/jabberd14sql2prosody.lua @@ -428,7 +428,14 @@ end end -- import modules -package.path = [[C:\Documents and Settings\Waqas\Desktop\mercurial\prosody-hg\?.lua;]]..package.path; +package.path = package.path.."..\?.lua;"; + +local my_name = arg[0]; +if my_name:match("[/\\]") then + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); +end + -- ugly workaround for getting datamanager to work outside of prosody :( prosody = { }; diff --git a/tools/openfire2prosody.lua b/tools/openfire2prosody.lua index bdea9a63..5ef47602 100644 --- a/tools/openfire2prosody.lua +++ b/tools/openfire2prosody.lua @@ -9,6 +9,12 @@ package.path = package.path..";../?.lua"; package.cpath = package.cpath..";../?.so"; -- needed for util.pposix used in datamanager +local my_name = arg[0]; +if my_name:match("[/\\]") then + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); +end + -- ugly workaround for getting datamanager to work outside of prosody :( prosody = { }; prosody.platform = "unknown"; diff --git a/tools/xep227toprosody.lua b/tools/xep227toprosody.lua index b5156f45..0862b0c1 100755 --- a/tools/xep227toprosody.lua +++ b/tools/xep227toprosody.lua @@ -25,6 +25,12 @@ package.path = package.path..";../?.lua"; package.cpath = package.cpath..";../?.so"; -- needed for util.pposix used in datamanager +local my_name = arg[0]; +if my_name:match("[/\\]") then + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); +end + -- ugly workaround for getting datamanager to work outside of prosody :( prosody = { }; prosody.platform = "unknown"; -- cgit v1.2.3 From a97742e4772ca8fadb6a046eb55fc12f0b1218ca Mon Sep 17 00:00:00 2001 From: Vadim Misbakh-Soloviov Date: Fri, 14 Jun 2013 15:43:35 +0700 Subject: additional fix for erlparse loading in ejabberd2prosody.lua --- tools/ejabberd2prosody.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ejabberd2prosody.lua b/tools/ejabberd2prosody.lua index 941bd4d5..ff3004c2 100755 --- a/tools/ejabberd2prosody.lua +++ b/tools/ejabberd2prosody.lua @@ -14,6 +14,7 @@ package.path = package.path ..";../?.lua"; local my_name = arg[0]; if my_name:match("[/\\]") then package.path = package.path..";"..my_name:gsub("[^/\\]+$", "../?.lua"); + package.path = package.path..";"..my_name:gsub("[^/\\]+$", "?.lua"); package.cpath = package.cpath..";"..my_name:gsub("[^/\\]+$", "../?.so"); end -- cgit v1.2.3 From 7c51e9ec71239580290b99267bb959d2c5c3bdd8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 16 Jun 2013 15:01:31 +0200 Subject: mod_tls: Remove debug statement --- plugins/mod_tls.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index e167cf95..1af8dbe9 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -55,7 +55,6 @@ local function can_do_tls(session) return true; end if session.type == "c2s_unauthed" then - module:log("debug", "session.ssl_ctx = ssl_ctx_c2s;") session.ssl_ctx = ssl_ctx_c2s; elseif session.type == "s2sin_unauthed" and allow_s2s_tls then session.ssl_ctx = ssl_ctx_s2sin; -- cgit v1.2.3 From 15c9e030d7a54bb5a3c1acc77eb4dca3b1a9f28b Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Tue, 18 Jun 2013 23:02:20 +0200 Subject: net.dns: Support IPv6 addresses in resolv.conf --- net/dns.lua | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/net/dns.lua b/net/dns.lua index 89b50255..bd42db73 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -14,6 +14,7 @@ local socket = require "socket"; local timer = require "util.timer"; +local new_ip = require "util.ip".new_ip; local _, windows = pcall(require, "util.windows"); local is_windows = (_ and windows) or os.getenv("WINDIR"); @@ -597,11 +598,12 @@ function resolver:adddefaultnameservers() -- - - - - adddefaultnameservers if resolv_conf then for line in resolv_conf:lines() do line = line:gsub("#.*$", "") - :match('^%s*nameserver%s+(.*)%s*$'); + :match('^%s*nameserver%s+([%x:%.]*)%s*$'); if line then - line:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]", function (address) - self:addnameserver(address) - end); + local ip = new_ip(line); + if ip then + self:addnameserver(ip.addr); + end end end end @@ -621,7 +623,12 @@ function resolver:getsocket(servernum) -- - - - - - - - - - - - - getsocket if sock then return sock; end local err; - sock, err = socket.udp(); + local peer = self.server[servernum]; + if peer:find(":") then + sock, err = socket.udp6(); + else + sock, err = socket.udp(); + end if not sock then return nil, err; end @@ -629,7 +636,7 @@ function resolver:getsocket(servernum) -- - - - - - - - - - - - - getsocket sock:settimeout(0); -- todo: attempt to use a random port, fallback to 0 sock:setsockname('*', 0); - sock:setpeername(self.server[servernum], 53); + sock:setpeername(peer, 53); self.socket[servernum] = sock; self.socketset[sock] = servernum; return sock; -- cgit v1.2.3 From 3122b6ee6e4e7e530967eeefe9f60300fdfaf7a9 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Jun 2013 16:20:33 +0200 Subject: mod_admin_telnet: Refactor s2s:showcert() --- plugins/mod_admin_telnet.lua | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 73c4a578..85a9bd5c 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -683,14 +683,9 @@ end function def_env.s2s:showcert(domain) local ser = require "util.serialization".serialize; local print = self.session.print; - local domain_sessions = set.new(array.collect(keys(incoming_s2s))) - /function(session) return session.from_host == domain and session or nil; end; - for local_host in values(prosody.hosts) do - local s2sout = local_host.s2sout; - if s2sout and s2sout[domain] then - domain_sessions:add(s2sout[domain]); - end - end + local s2s_sessions = module:shared"/*/s2s/sessions"; + local domain_sessions = set.new(array.collect(values(s2s_sessions))) + /function(session) return (session.to_host == domain or session.from_host == domain) and session or nil; end; local cert_set = {}; for session in domain_sessions do local conn = session.conn; -- cgit v1.2.3 From e9956722e55a4e9d21def21abb1c1081be9a92be Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Jun 2013 16:35:19 +0200 Subject: mod_register: Fix indentation --- plugins/mod_register.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 3d7a068c..3cdb48b3 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -72,7 +72,7 @@ module:add_feature("jabber:iq:register"); local register_stream_feature = st.stanza("register", {xmlns="http://jabber.org/features/iq-register"}):up(); module:hook("stream-features", function(event) - local session, features = event.origin, event.features; + local session, features = event.origin, event.features; -- Advertise registration to unauthorized clients only. if not(allow_registration) or session.type ~= "c2s_unauthed" then -- cgit v1.2.3 From 5b49a373604cbf974266f1fe28ca32be25f105c0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 20 Jun 2013 20:53:29 +0200 Subject: mod_admin_telnet: Refactor s2s:close and s2s:closeall --- plugins/mod_admin_telnet.lua | 68 ++++++++++---------------------------------- 1 file changed, 15 insertions(+), 53 deletions(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 85a9bd5c..b2b97fa5 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -776,76 +776,38 @@ end function def_env.s2s:close(from, to) local print, count = self.session.print, 0; + local s2s_sessions = module:shared"/*/s2s/sessions"; - if not (from and to) then + local match_id; + if from and not to then + match_id, from = from; + elseif not to then return false, "Syntax: s2s:close('from', 'to') - Closes all s2s sessions from 'from' to 'to'"; elseif from == to then return false, "Both from and to are the same... you can't do that :)"; end - if hosts[from] and not hosts[to] then - -- Is an outgoing connection - local session = hosts[from].s2sout[to]; - if not session then - print("No outgoing connection from "..from.." to "..to) - else + for _, session in pairs(s2s_sessions) do + local id = session.type..tostring(session):sub(10); + if (match_id and match_id == id) + or (session.from_host == from and session.to_host == to) then + print(("Closing connection from %s to %s [%s]"):format(session.from_host, session.to_host, id)); (session.close or s2smanager.destroy_session)(session); - count = count + 1; - print("Closed outgoing session from "..from.." to "..to); + count = count + 1 ; end - elseif hosts[to] and not hosts[from] then - -- Is an incoming connection - for session in pairs(incoming_s2s) do - if session.to_host == to and session.from_host == from then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; end - end - - if count == 0 then - print("No incoming connections from "..from.." to "..to); - else - print("Closed "..count.." incoming session"..((count == 1 and "") or "s").." from "..from.." to "..to); - end - elseif hosts[to] and hosts[from] then - return false, "Both of the hostnames you specified are local, there are no s2s sessions to close"; - else - return false, "Neither of the hostnames you specified are being used on this server"; - end - return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end function def_env.s2s:closeall(host) local count = 0; - - if not host or type(host) ~= "string" then return false, "wrong syntax: please use s2s:closeall('hostname.tld')"; end - if hosts[host] then - for session in pairs(incoming_s2s) do - if session.to_host == host then - (session.close or s2smanager.destroy_session)(session); + local s2s_sessions = module:shared"/*/s2s/sessions"; + for _,session in pairs(s2s_sessions) do + if not host or session.from_host == host or session.to_host == host then + session:close(); count = count + 1; end end - for _, session in pairs(hosts[host].s2sout) do - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - else - for session in pairs(incoming_s2s) do - if session.from_host == host then - (session.close or s2smanager.destroy_session)(session); - count = count + 1; - end - end - for _, h in pairs(hosts) do - if h.s2sout[host] then - (h.s2sout[host].close or s2smanager.destroy_session)(h.s2sout[host]); - count = count + 1; - end - end - end - if count == 0 then return false, "No sessions to close."; else return true, "Closed "..count.." s2s session"..((count == 1 and "") or "s"); end end -- cgit v1.2.3 From 908b47d9071153c2b7e38a0b106a07d2c3023baa Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 20 Jun 2013 21:47:28 +0200 Subject: mod_admin_telnet: Generate session names the same way as in s2smanager --- plugins/mod_admin_telnet.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index b2b97fa5..823c71ce 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -788,7 +788,7 @@ function def_env.s2s:close(from, to) end for _, session in pairs(s2s_sessions) do - local id = session.type..tostring(session):sub(10); + local id = session.type..tostring(session):match("[a-f0-9]+$"); if (match_id and match_id == id) or (session.from_host == from and session.to_host == to) then print(("Closing connection from %s to %s [%s]"):format(session.from_host, session.to_host, id)); -- cgit v1.2.3 From d2d4d4d35f830e93719aee3b035349bd90c2955c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 20 Jun 2013 21:47:38 +0200 Subject: mod_admin_telnet: Refactor s2s:show() --- plugins/mod_admin_telnet.lua | 110 +++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 823c71ce..6fc378bb 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -17,7 +17,6 @@ local _G = _G; local prosody = _G.prosody; local hosts = prosody.hosts; -local incoming_s2s = prosody.incoming_s2s; local console_listener = { default_port = 5582; default_mode = "*a"; interface = "127.0.0.1" }; @@ -582,76 +581,77 @@ end def_env.s2s = {}; function def_env.s2s:show(match_jid) - local _print = self.session.print; local print = self.session.print; local count_in, count_out = 0,0; + local s2s_list = { }; - for host, host_session in pairs(hosts) do - print = function (...) _print(host); _print(...); print = _print; end - for remotehost, session in pairs(host_session.s2sout) do - if (not match_jid) or remotehost:match(match_jid) or host:match(match_jid) then - count_out = count_out + 1; - print(session_flags(session, {" ", host, "->", remotehost})); - if session.sendq then - print(" There are "..#session.sendq.." queued outgoing stanzas for this connection"); - end - if session.type == "s2sout_unauthed" then - if session.connecting then - print(" Connection not yet established"); - if not session.srv_hosts then - if not session.conn then - print(" We do not yet have a DNS answer for this host's SRV records"); - else - print(" This host has no SRV records, using A record instead"); - end - elseif session.srv_choice then - print(" We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts); - local srv_choice = session.srv_hosts[session.srv_choice]; - print(" Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269)); + local s2s_sessions = module:shared"/*/s2s/sessions"; + for _, session in pairs(s2s_sessions) do + local remotehost, localhost, direction; + if session.direction == "outgoing" then + direction = "->"; + count_out = count_out + 1; + remotehost, localhost = session.to_host or "?", session.from_host or "?"; + else + direction = "<-"; + count_in = count_in + 1; + remotehost, localhost = session.from_host or "?", session.to_host or "?"; + end + local sess_lines = { l = localhost, r = remotehost, + session_flags(session, { "", direction, remotehost or "?", + "["..session.type..tostring(session):match("[a-f0-9]*$").."]" })}; + + if (not match_jid) or remotehost:match(match_jid) or localhost:match(match_jid) then + table.insert(s2s_list, sess_lines); + local print = function (s) table.insert(sess_lines, " "..s); end + if session.sendq then + print("There are "..#session.sendq.." queued outgoing stanzas for this connection"); + end + if session.type == "s2sout_unauthed" then + if session.connecting then + print("Connection not yet established"); + if not session.srv_hosts then + if not session.conn then + print("We do not yet have a DNS answer for this host's SRV records"); + else + print("This host has no SRV records, using A record instead"); end - elseif session.notopen then - print(" The has not yet been opened"); - elseif not session.dialback_key then - print(" Dialback has not been initiated yet"); - elseif session.dialback_key then - print(" Dialback has been requested, but no result received"); + elseif session.srv_choice then + print("We are on SRV record "..session.srv_choice.." of "..#session.srv_hosts); + local srv_choice = session.srv_hosts[session.srv_choice]; + print("Using "..(srv_choice.target or ".")..":"..(srv_choice.port or 5269)); end + elseif session.notopen then + print("The has not yet been opened"); + elseif not session.dialback_key then + print("Dialback has not been initiated yet"); + elseif session.dialback_key then + print("Dialback has been requested, but no result received"); end end - end - local subhost_filter = function (h) - return (match_jid and h:match(match_jid)); - end - for session in pairs(incoming_s2s) do - if session.to_host == host and ((not match_jid) or host:match(match_jid) - or (session.from_host and session.from_host:match(match_jid)) - -- Pft! is what I say to list comprehensions - or (session.hosts and #array.collect(keys(session.hosts)):filter(subhost_filter)>0)) then - count_in = count_in + 1; - print(session_flags(session, {" ", host, "<-", session.from_host or "(unknown)"})); - if session.type == "s2sin_unauthed" then - print(" Connection not yet authenticated"); - end + if session.type == "s2sin_unauthed" then + print("Connection not yet authenticated"); + elseif session.type == "s2sin" then for name in pairs(session.hosts) do if name ~= session.from_host then - print(" also hosts "..tostring(name)); + print("also hosts "..tostring(name)); end end end end - - print = _print; end - - for session in pairs(incoming_s2s) do - if not session.to_host and ((not match_jid) or session.from_host and session.from_host:match(match_jid)) then - count_in = count_in + 1; - print("Other incoming s2s connections"); - print(" (unknown) <- "..(session.from_host or "(unknown)")); - end + + -- Sort by local host, then remote host + table.sort(s2s_list, function(a,b) + if a.l == b.l then return a.r < b.r; end + return a.l < b.l; + end); + local lasthost; + for _, sess_lines in ipairs(s2s_list) do + if sess_lines.l ~= lasthost then print(sess_lines.l); lasthost=sess_lines.l end + for _, line in ipairs(sess_lines) do print(line); end end - return true, "Total: "..count_out.." outgoing, "..count_in.." incoming connections"; end -- cgit v1.2.3 From 74d66c5aef7a842ddc13a87745c86b8250173655 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 26 Jun 2013 13:35:38 +0200 Subject: mod_s2s: Add missing global hook for read-timeout --- plugins/mod_s2s/mod_s2s.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 5e50e88b..01fac4d2 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -139,6 +139,8 @@ local function keepalive(event) return event.session.sends2s(' '); end +module:hook("s2s-read-timeout", keepalive, -1); + function module.add_host(module) if module:get_option_boolean("disallow_s2s", false) then module:log("warn", "The 'disallow_s2s' config option is deprecated, please see http://prosody.im/doc/s2s#disabling"); -- cgit v1.2.3 From 5adcad1a43d110e0458b38c42b0a21a70eb5336e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 29 Jun 2013 14:45:38 +0100 Subject: util.pposix: Correctly handle 'unlimited' limits (RLIM_INFINITY), by returning and accepting the string 'unlimited' in get/setrlimit() --- util-src/pposix.c | 75 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/util-src/pposix.c b/util-src/pposix.c index f5cc8270..c0d1f5a2 100644 --- a/util-src/pposix.c +++ b/util-src/pposix.c @@ -491,48 +491,51 @@ int string2resource(const char *s) { return -1; } +int arg_to_rlimit(lua_State* L, int idx, rlim_t current) { + switch(lua_type(L, idx)) { + case LUA_TSTRING: + if(strcmp(lua_tostring(L, idx), "unlimited") == 0) + return RLIM_INFINITY; + case LUA_TNUMBER: + return lua_tointeger(L, idx); + case LUA_TNONE: + case LUA_TNIL: + return current; + default: + return luaL_argerror(L, idx, "unexpected type"); + } +} + int lc_setrlimit(lua_State *L) { + struct rlimit lim; int arguments = lua_gettop(L); - int softlimit = -1; - int hardlimit = -1; - const char *resource = NULL; int rid = -1; if(arguments < 1 || arguments > 3) { lua_pushboolean(L, 0); lua_pushstring(L, "incorrect-arguments"); + return 2; } - resource = luaL_checkstring(L, 1); - softlimit = luaL_checkinteger(L, 2); - hardlimit = luaL_checkinteger(L, 3); + rid = string2resource(luaL_checkstring(L, 1)); + if (rid == -1) { + lua_pushboolean(L, 0); + lua_pushstring(L, "invalid-resource"); + return 2; + } - rid = string2resource(resource); - if (rid != -1) { - struct rlimit lim; - struct rlimit lim_current; - - if (softlimit < 0 || hardlimit < 0) { - if (getrlimit(rid, &lim_current)) { - lua_pushboolean(L, 0); - lua_pushstring(L, "getrlimit-failed"); - return 2; - } - } + /* Fetch current values to use as defaults */ + if (getrlimit(rid, &lim)) { + lua_pushboolean(L, 0); + lua_pushstring(L, "getrlimit-failed"); + return 2; + } - if (softlimit < 0) lim.rlim_cur = lim_current.rlim_cur; - else lim.rlim_cur = softlimit; - if (hardlimit < 0) lim.rlim_max = lim_current.rlim_max; - else lim.rlim_max = hardlimit; + lim.rlim_cur = arg_to_rlimit(L, 2, lim.rlim_cur); + lim.rlim_max = arg_to_rlimit(L, 3, lim.rlim_max); - if (setrlimit(rid, &lim)) { - lua_pushboolean(L, 0); - lua_pushstring(L, "setrlimit-failed"); - return 2; - } - } else { - /* Unsupported resoucrce. Sorry I'm pretty limited by POSIX standard. */ + if (setrlimit(rid, &lim)) { lua_pushboolean(L, 0); - lua_pushstring(L, "invalid-resource"); + lua_pushstring(L, "setrlimit-failed"); return 2; } lua_pushboolean(L, 1); @@ -551,6 +554,8 @@ int lc_getrlimit(lua_State *L) { return 2; } + + resource = luaL_checkstring(L, 1); rid = string2resource(resource); if (rid != -1) { @@ -566,8 +571,14 @@ int lc_getrlimit(lua_State *L) { return 2; } lua_pushboolean(L, 1); - lua_pushnumber(L, lim.rlim_cur); - lua_pushnumber(L, lim.rlim_max); + if(lim.rlim_cur == RLIM_INFINITY) + lua_pushstring(L, "unlimited"); + else + lua_pushnumber(L, lim.rlim_cur); + if(lim.rlim_max == RLIM_INFINITY) + lua_pushstring(L, "unlimited"); + else + lua_pushnumber(L, lim.rlim_max); return 3; } -- cgit v1.2.3 From 14cde80a1f8570920e598509710f2dc61b7a2510 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 1 Jul 2013 22:17:31 +0200 Subject: prosodyctl: Import local_addresses from the new util.net intead of luasocket --- prosodyctl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosodyctl b/prosodyctl index aa6f2073..b98736a7 100755 --- a/prosodyctl +++ b/prosodyctl @@ -870,7 +870,7 @@ function commands.check(arg) end end - local local_addresses = socket.local_addresses and socket.local_addresses() or {}; + local local_addresses = require"util.net".local_addresses() or {}; for addr in it.values(local_addresses) do if not ip.new_ip(addr).private then -- cgit v1.2.3 From 01de781b7ba384214f74082cd61cc1cfd0db877c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 10 Jul 2013 12:01:23 +0200 Subject: mod_storage_sql2: Make sure the user field is not NULL --- plugins/mod_storage_sql2.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 382c0e23..24c08cf5 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -148,7 +148,7 @@ local user, store; local function keyval_store_get() local haveany; local result = {}; - for row in engine:select("SELECT `key`,`type`,`value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?", host, user, store) do + for row in engine:select("SELECT `key`,`type`,`value` FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?", host, user or "", store) do haveany = true; local k = row[1]; local v = deserialize(row[2], row[3]); @@ -165,7 +165,7 @@ local function keyval_store_get() end end local function keyval_store_set(data) - engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?", host, user, store); + engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?", host, user or "", store); if data and next(data) ~= nil then local extradata = {}; @@ -173,7 +173,7 @@ local function keyval_store_set(data) if type(key) == "string" and key ~= "" then local t, value = serialize(value); assert(t, value); - engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user, store, key, t, value); + engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user or "", store, key, t, value); else extradata[key] = value; end @@ -181,7 +181,7 @@ local function keyval_store_set(data) if next(extradata) ~= nil then local t, extradata = serialize(extradata); assert(t, extradata); - engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user, store, "", t, extradata); + engine:insert("INSERT INTO `prosody` (`host`,`user`,`store`,`key`,`type`,`value`) VALUES (?,?,?,?,?,?)", host, user or "", store, "", t, extradata); end end return true; -- cgit v1.2.3 From 06561ae51323ea7e8e2939aa3fc7ac854f3b51ff Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 10 Jul 2013 12:08:44 +0200 Subject: mod_storage_sql2: Fix iteration over users and stores --- plugins/mod_storage_sql2.lua | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 24c08cf5..0b57d48b 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -2,6 +2,16 @@ local json = require "util.json"; local resolve_relative_path = require "core.configmanager".resolve_relative_path; +local unpack = unpack +local function iterator(result) + return function(result) + local row = result(); + if row ~= nil then + return unpack(row); + end + end, result, nil; +end + local mod_sql = module:require("sql"); local params = module:get_option("sql"); @@ -200,9 +210,11 @@ function keyval_store:set(username, data) end); end function keyval_store:users() - return engine:transaction(function() + local ok, result = engine:transaction(function() return engine:select("SELECT DISTINCT `user` FROM `prosody` WHERE `host`=? AND `store`=?", host, self.store); end); + if not ok then return ok, result end + return iterator(result); end local driver = {}; @@ -220,9 +232,11 @@ function driver:stores(username) if username == true or not username then username = ""; end - return engine:transaction(function() + local ok, result = engine:transaction(function() return engine:select(sql, host, username); end); + if not ok then return ok, result end + return iterator(result); end function driver:purge(username) -- cgit v1.2.3 From 1e1834a4ec05554473438f43f44c34e2809a330f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 10 Jul 2013 13:18:10 +0200 Subject: mod_storage_sql2: Keep available store types in a table --- plugins/mod_storage_sql2.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 0b57d48b..48da2d46 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -217,11 +217,16 @@ function keyval_store:users() return iterator(result); end +local stores = { + keyval = keyval_store; +}; + local driver = {}; function driver:open(store, typ) - if not typ then -- default key-value store - return setmetatable({ store = store }, keyval_store); + local store_mt = stores[typ or "keyval"]; + if store_mt then + return setmetatable({ store = store }, store_mt); end return nil, "unsupported-store"; end -- cgit v1.2.3 From 298aef6be73d7b454f14d784d21cdcba55c7a804 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 10 Jul 2013 13:19:33 +0200 Subject: mod_storage_sql2: Support XML serialization for stanzas. --- plugins/mod_storage_sql2.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 48da2d46..8081c0f9 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -1,7 +1,12 @@ local json = require "util.json"; +local xml_parse = require "util.xml".parse; local resolve_relative_path = require "core.configmanager".resolve_relative_path; +local stanza_mt = require"util.stanza".stanza_mt; +local getmetatable = getmetatable; +local function is_stanza(x) return getmetatable(x) == stanza_mt; end + local unpack = unpack local function iterator(result) return function(result) @@ -134,6 +139,8 @@ local function serialize(value) local t = type(value); if t == "string" or t == "boolean" or t == "number" then return t, tostring(value); + elseif is_stanza(value) then + return "xml", tostring(value); elseif t == "table" then local value,err = json.encode(value); if value then return "json", value; end @@ -149,6 +156,8 @@ local function deserialize(t, value) elseif t == "number" then return tonumber(value); elseif t == "json" then return json.decode(value); + elseif t == "xml" then + return xml_parse(value); end end -- cgit v1.2.3 From 7fa95071ed75a7a988efa3108a2cafd63bf919e9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 11 Jul 2013 15:13:45 +0100 Subject: Remove plugins/storage/sqlbasic.lib.lua, which seems obsolete --- plugins/storage/sqlbasic.lib.lua | 97 ---------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 plugins/storage/sqlbasic.lib.lua diff --git a/plugins/storage/sqlbasic.lib.lua b/plugins/storage/sqlbasic.lib.lua deleted file mode 100644 index ab3648f9..00000000 --- a/plugins/storage/sqlbasic.lib.lua +++ /dev/null @@ -1,97 +0,0 @@ - --- Basic SQL driver --- This driver stores data as simple key-values - -local ser = require "util.serialization".serialize; -local envload = require "util.envload".envload; -local deser = function(data) - module:log("debug", "deser: %s", tostring(data)); - if not data then return nil; end - local f = envload("return "..data, nil, {}); - if not f then return nil; end - local s, d = pcall(f); - if not s then return nil; end - return d; -end; - -local driver = {}; -driver.__index = driver; - -driver.item_table = "item"; -driver.list_table = "list"; - -function driver:prepare(sql) - module:log("debug", "query: %s", sql); - local err; - if not self.sqlcache then self.sqlcache = {}; end - local r = self.sqlcache[sql]; - if r then return r; end - r, err = self.connection:prepare(sql); - if not r then error("Unable to prepare SQL statement: "..err); end - self.sqlcache[sql] = r; - return r; -end - -function driver:load(username, host, datastore) - local select = self:prepare("select data from "..self.item_table.." where username=? and host=? and datastore=?"); - select:execute(username, host, datastore); - local row = select:fetch(); - return row and deser(row[1]) or nil; -end - -function driver:store(username, host, datastore, data) - if not data or next(data) == nil then - local delete = self:prepare("delete from "..self.item_table.." where username=? and host=? and datastore=?"); - delete:execute(username, host, datastore); - return true; - else - local d = self:load(username, host, datastore); - if d then -- update - local update = self:prepare("update "..self.item_table.." set data=? where username=? and host=? and datastore=?"); - return update:execute(ser(data), username, host, datastore); - else -- insert - local insert = self:prepare("insert into "..self.item_table.." values (?, ?, ?, ?)"); - return insert:execute(username, host, datastore, ser(data)); - end - end -end - -function driver:list_append(username, host, datastore, data) - if not data then return; end - local insert = self:prepare("insert into "..self.list_table.." values (?, ?, ?, ?)"); - return insert:execute(username, host, datastore, ser(data)); -end - -function driver:list_store(username, host, datastore, data) - -- remove existing data - local delete = self:prepare("delete from "..self.list_table.." where username=? and host=? and datastore=?"); - delete:execute(username, host, datastore); - if data and next(data) ~= nil then - -- add data - for _, d in ipairs(data) do - self:list_append(username, host, datastore, ser(d)); - end - end - return true; -end - -function driver:list_load(username, host, datastore) - local select = self:prepare("select data from "..self.list_table.." where username=? and host=? and datastore=?"); - select:execute(username, host, datastore); - local r = {}; - for row in select:rows() do - table.insert(r, deser(row[1])); - end - return r; -end - -local _M = {}; -function _M.new(dbtype, dbname, ...) - local d = {}; - setmetatable(d, driver); - local dbh = get_database(dbtype, dbname, ...); - --d:set_connection(dbh); - d.connection = dbh; - return d; -end -return _M; -- cgit v1.2.3 From 06e7d7b489229a80e144ad883a2addde6d92c730 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 11 Jul 2013 22:07:55 +0200 Subject: util.sql: Set charset and collation for MySQL when creating tables --- util/sql.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/sql.lua b/util/sql.lua index f360d6d0..771df7aa 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -264,6 +264,8 @@ function engine:_create_table(table) sql = sql.. ");" if self.params.driver == "PostgreSQL" then sql = sql:gsub("`", "\""); + elseif self.params.driver == "MySQL" then + sql = sql:gsub(";$", " CHARACTER SET 'utf8' COLLATE 'utf8_bin';"); end local success,err = self:execute(sql); if not success then return success,err; end -- cgit v1.2.3 From 8a80110435df4e5f99956486ea3fb85df337f462 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 12 Jul 2013 01:34:38 +0200 Subject: mod_storage_sql2: Create an additional table `prosodyarchive` for chronological collections --- plugins/mod_storage_sql2.lua | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 8081c0f9..4f6f7f04 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -23,7 +23,8 @@ local params = module:get_option("sql"); local engine; -- TODO create engine local function create_table() - --[[local Table,Column,Index = mod_sql.Table,mod_sql.Column,mod_sql.Index; + local Table,Column,Index = mod_sql.Table,mod_sql.Column,mod_sql.Index; + --[[ local ProsodyTable = Table { name="prosody"; Column { name="host", type="TEXT", nullable=false }; @@ -78,6 +79,22 @@ local function create_table() end end end + local ProsodyArchiveTable = Table { + name="prosodyarchive"; + Column { name="sort_id", type="INTEGER PRIMARY KEY AUTOINCREMENT", nullable=false }; + Column { name="host", type="TEXT", nullable=false }; + Column { name="user", type="TEXT", nullable=false }; + Column { name="store", type="TEXT", nullable=false }; + Column { name="key", type="TEXT", nullable=false }; -- item id + Column { name="when", type="INTEGER", nullable=false }; -- timestamp + Column { name="with", type="TEXT", nullable=false }; -- related id + Column { name="type", type="TEXT", nullable=false }; + Column { name="value", type=params.driver == "MySQL" and "MEDIUMTEXT" or "TEXT", nullable=false }; + Index { name="prosodyarchive_index", "host", "user", "store", "key" }; + }; + engine:transaction(function() + ProsodyArchiveTable:create(engine); + end); end local function set_encoding() if params.driver ~= "SQLite3" then -- cgit v1.2.3 From 3d9b1be698c50b65fe8924d64bcd3da7123dbf9b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 12 Jul 2013 02:53:24 +0200 Subject: mod_storage_sql2: Add archive store with append and find methods --- plugins/mod_storage_sql2.lua | 89 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 4f6f7f04..7560d1f1 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -1,12 +1,15 @@ local json = require "util.json"; local xml_parse = require "util.xml".parse; +local uuid = require "util.uuid"; local resolve_relative_path = require "core.configmanager".resolve_relative_path; local stanza_mt = require"util.stanza".stanza_mt; local getmetatable = getmetatable; +local t_concat = table.concat; local function is_stanza(x) return getmetatable(x) == stanza_mt; end +local noop = function() end local unpack = unpack local function iterator(result) return function(result) @@ -243,8 +246,94 @@ function keyval_store:users() return iterator(result); end +local archive_store = {} +archive_store.__index = archive_store +function archive_store:append(username, when, with, value) + local user,store = username,self.store; + return engine:transaction(function() + local key = uuid.generate(); + local t, value = serialize(value); + engine:insert("INSERT INTO `prosodyarchive` (`host`, `user`, `store`, `when`, `with`, `key`, `type`, `value`) VALUES (?,?,?,?,?,?,?,?)", host, user or "", store, when, with, key, t, value); + return key; + end); +end +function archive_store:find(username, query) + query = query or {}; + local user,store = username,self.store; + local total; + local ok, result = engine:transaction(function() + local sql_query = "SELECT `key`, `type`, `value`, `when` FROM `prosodyarchive` WHERE %s ORDER BY `sort_id` %s%s;"; + local args = { host, user or "", store, }; + local where = { "`host` = ?", "`user` = ?", "`store` = ?", }; + + -- Time range, inclusive + if query.start then + args[#args+1] = query.start + where[#where+1] = "`when` >= ?" + end + if query["end"] then + args[#args+1] = query["end"]; + if query.start then + where[#where] = "`when` BETWEEN ? AND ?" -- is this inclusive? + else + where[#where+1] = "`when` >= ?" + end + end + + -- Related name + if query.with then + where[#where+1] = "`with` = ?"; + args[#args+1] = query.with + end + + -- Unique id + if query.key then + where[#where+1] = "`key` = ?"; + args[#args+1] = query.key + end + + -- Total matching + if query.total then + local stats = engine:select(sql_query:gsub("^(SELECT).-(FROM)", "%1 COUNT(*) %2"):format(t_concat(where, " AND "), "DESC", ""), unpack(args)); + if stats then + local _total = stats() + total = _total and _total[1]; + end + if query.limit == 0 then -- Skip the real query + return noop, total; + end + end + + -- Before or after specific item, exclusive + if query.after then + where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" + args[#args+1] = query.after + end + if query.before then + where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" + args[#args+1] = query.before + end + + if query.limit then + args[#args+1] = query.limit; + end + + sql_query = sql_query:format(t_concat(where, " AND "), query.reverse and "DESC" or "ASC", query.limit and " LIMIT ?" or ""); + module:log("debug", sql_query); + return engine:select(sql_query, unpack(args)); + end); + if not ok then return ok, result end + return function() + local row = result(); + if row ~= nil then + return row[1], deserialize(row[2], row[3]), row[4]; + end + end, total; +end + local stores = { keyval = keyval_store; + archive = archive_store; }; local driver = {}; -- cgit v1.2.3 From c41f00e53fd2adcda02df292b98d01cebabfa773 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 12 Jul 2013 17:03:09 +0200 Subject: util.sql: Don't fetch row count of result sets for queries that don't have result sets --- util/sql.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/util/sql.lua b/util/sql.lua index 771df7aa..475215bb 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -178,7 +178,6 @@ end local result_mt = { __index = { affected = function(self) return self.__affected; end; - rowcount = function(self) return self.__rowcount; end; } }; function engine:execute_query(sql, ...) @@ -200,7 +199,7 @@ function engine:execute_update(sql, ...) prepared[sql] = stmt; end assert(stmt:execute(...)); - return setmetatable({ __affected = stmt:affected(), __rowcount = stmt:rowcount() }, result_mt); + return setmetatable({ __affected = stmt:affected() }, result_mt); end engine.insert = engine.execute_update; engine.select = engine.execute_query; -- cgit v1.2.3 From 051779d694221adc06600418becbdeda0f48d63e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 12 Jul 2013 17:41:54 +0200 Subject: Backed out changeset 3c57c2281087 --- util/sql.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 475215bb..771df7aa 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -178,6 +178,7 @@ end local result_mt = { __index = { affected = function(self) return self.__affected; end; + rowcount = function(self) return self.__rowcount; end; } }; function engine:execute_query(sql, ...) @@ -199,7 +200,7 @@ function engine:execute_update(sql, ...) prepared[sql] = stmt; end assert(stmt:execute(...)); - return setmetatable({ __affected = stmt:affected() }, result_mt); + return setmetatable({ __affected = stmt:affected(), __rowcount = stmt:rowcount() }, result_mt); end engine.insert = engine.execute_update; engine.select = engine.execute_query; -- cgit v1.2.3 From f7acbbc7831ab1cd8f2bcdf66d284fb47d3ff04e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 12 Jul 2013 17:44:30 +0200 Subject: util.sql: Do lazy fetching of affected/rowcount --- util/sql.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/sql.lua b/util/sql.lua index 771df7aa..63c399ff 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -177,8 +177,8 @@ function engine:execute(sql, ...) end local result_mt = { __index = { - affected = function(self) return self.__affected; end; - rowcount = function(self) return self.__rowcount; end; + affected = function(self) return self.__stmt:affected(); end; + rowcount = function(self) return self.__stmt:rowcount(); end; } }; function engine:execute_query(sql, ...) @@ -200,7 +200,7 @@ function engine:execute_update(sql, ...) prepared[sql] = stmt; end assert(stmt:execute(...)); - return setmetatable({ __affected = stmt:affected(), __rowcount = stmt:rowcount() }, result_mt); + return setmetatable({ __stmt = stmt }, result_mt); end engine.insert = engine.execute_update; engine.select = engine.execute_query; -- cgit v1.2.3 From 71ab938d534d425b388ab0d76204b3a232bcadce Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 15 Jul 2013 11:43:23 +0100 Subject: rostermanager, mod_groups: Change roster-load event to pass an event table for consistency --- core/rostermanager.lua | 2 +- plugins/mod_groups.lua | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/rostermanager.lua b/core/rostermanager.lua index 5e06e3f7..4c669eac 100644 --- a/core/rostermanager.lua +++ b/core/rostermanager.lua @@ -100,7 +100,7 @@ function load_roster(username, host) log("warn", "roster for %s has a self-contact", jid); end if not err then - hosts[host].events.fire_event("roster-load", username, host, roster); + hosts[host].events.fire_event("roster-load", { username = username, host = host, roster = roster }); end return roster, err; end diff --git a/plugins/mod_groups.lua b/plugins/mod_groups.lua index f7f632c2..dc6976d4 100644 --- a/plugins/mod_groups.lua +++ b/plugins/mod_groups.lua @@ -17,11 +17,13 @@ local jid_prep = jid.prep; local module_host = module:get_host(); -function inject_roster_contacts(username, host, roster) +function inject_roster_contacts(event) + local username, host= event.username, event.host; --module:log("debug", "Injecting group members to roster"); local bare_jid = username.."@"..host; if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups + local roster = event.roster; local function import_jids_to_roster(group_name) for jid in pairs(groups[group_name]) do -- Add them to roster -- cgit v1.2.3 From cab180216b49e1c6f1f0e847357df58436551643 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 15 Jul 2013 11:44:49 +0100 Subject: mod_bosh, mod_c2s: No longer fire stream-features globally (nobody uses it, and shared modules make it easy for global modules to hook per-host now) --- plugins/mod_bosh.lua | 1 - plugins/mod_c2s.lua | 2 -- 2 files changed, 3 deletions(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index d8717d18..d109547e 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -349,7 +349,6 @@ function stream_callbacks.streamopened(context, attr) 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; end diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 91bde574..d667e781 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -79,8 +79,6 @@ function stream_callbacks.streamopened(session, attr) local features = st.stanza("stream:features"); hosts[session.host].events.fire_event("stream-features", { origin = session, features = features }); - module:fire_event("stream-features", session, features); - send(features); end -- cgit v1.2.3 From 3df683edb76cf206e137caea94b0ea2091d98c70 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 15 Jul 2013 12:15:51 +0100 Subject: util.events: Remove varargs, event handlers can now only accept a single parameter --- util/events.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/events.lua b/util/events.lua index 412acccd..4ace026f 100644 --- a/util/events.lua +++ b/util/events.lua @@ -60,11 +60,11 @@ function new() remove_handler(event, handler); end end; - local function fire_event(event, ...) - local h = handlers[event]; + local function fire_event(event_name, event_data) + local h = handlers[event_name]; if h then for i=1,#h do - local ret = h[i](...); + local ret = h[i](event_data); if ret ~= nil then return ret; end end end -- cgit v1.2.3 From 81410b7371d8acf80d759b827f60229b147f2432 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 24 Jul 2013 22:08:07 +0200 Subject: mod_adhoc: Sort commands by node. This guarantees the order remains the same across restarts etc. --- plugins/adhoc/mod_adhoc.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/adhoc/mod_adhoc.lua b/plugins/adhoc/mod_adhoc.lua index 69b2c8da..73744969 100644 --- a/plugins/adhoc/mod_adhoc.lua +++ b/plugins/adhoc/mod_adhoc.lua @@ -6,6 +6,8 @@ -- local st = require "util.stanza"; +local keys = require "util.iterators".keys; +local array_collect = require "util.array".collect; local is_admin = require "core.usermanager".is_admin; local adhoc_handle_cmd = module:require "adhoc".handle_cmd; local xmlns_cmd = "http://jabber.org/protocol/commands"; @@ -56,7 +58,9 @@ module:hook("iq/host/"..xmlns_disco.."#items:query", function (event) reply = st.reply(stanza); reply:tag("query", { xmlns = xmlns_disco.."#items", node = xmlns_cmd }); - for node, command in pairs(commands) do + local nodes = array_collect(keys(commands)):sort(); + for _, node in ipairs(nodes) do + local command = commands[node]; if (command.permission == "admin" and admin) or (command.permission == "global_admin" and global_admin) or (command.permission == "user") then -- cgit v1.2.3 From c24241a389e3d359288a694ffa6c14779b387d98 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 24 Jul 2013 22:58:44 +0200 Subject: mod_adhoc: Use mod_disco for disco handling --- plugins/adhoc/mod_adhoc.lua | 91 +++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/plugins/adhoc/mod_adhoc.lua b/plugins/adhoc/mod_adhoc.lua index 73744969..683d5870 100644 --- a/plugins/adhoc/mod_adhoc.lua +++ b/plugins/adhoc/mod_adhoc.lua @@ -11,68 +11,55 @@ local array_collect = require "util.array".collect; local is_admin = require "core.usermanager".is_admin; local adhoc_handle_cmd = module:require "adhoc".handle_cmd; local xmlns_cmd = "http://jabber.org/protocol/commands"; -local xmlns_disco = "http://jabber.org/protocol/disco"; local commands = {}; module:add_feature(xmlns_cmd); -module:hook("iq/host/"..xmlns_disco.."#info:query", function (event) - local origin, stanza = event.origin, event.stanza; - local node = stanza.tags[1].attr.node; - if stanza.attr.type == "get" and node then - if commands[node] then - local privileged = is_admin(stanza.attr.from, stanza.attr.to); - if (commands[node].permission == "admin" and privileged) - or (commands[node].permission == "user") then - reply = st.reply(stanza); - reply:tag("query", { xmlns = xmlns_disco.."#info", - node = node }); - reply:tag("identity", { name = commands[node].name, - category = "automation", type = "command-node" }):up(); - reply:tag("feature", { var = xmlns_cmd }):up(); - reply:tag("feature", { var = "jabber:x:data" }):up(); - else - reply = st.error_reply(stanza, "auth", "forbidden", "This item is not available to you"); - end - origin.send(reply); - return true; - elseif node == xmlns_cmd then - reply = st.reply(stanza); - reply:tag("query", { xmlns = xmlns_disco.."#info", - node = node }); - reply:tag("identity", { name = "Ad-Hoc Commands", - category = "automation", type = "command-list" }):up(); - origin.send(reply); - return true; - +module:hook("host-disco-info-node", function (event) + local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; + if commands[node] then + local privileged = is_admin(stanza.attr.from, stanza.attr.to); + local global_admin = is_admin(stanza.attr.from); + local command = commands[node]; + if (command.permission == "admin" and privileged) + or (command.permission == "global_admin" and global_admin) + or (command.permission == "user") then + reply:tag("identity", { name = command.name, + category = "automation", type = "command-node" }):up(); + reply:tag("feature", { var = xmlns_cmd }):up(); + reply:tag("feature", { var = "jabber:x:data" }):up(); + event.exists = true; + else + return origin.send(st.error_reply(stanza, "auth", "forbidden", "This item is not available to you")); end + elseif node == xmlns_cmd then + reply:tag("identity", { name = "Ad-Hoc Commands", + category = "automation", type = "command-list" }):up(); + event.exists = true; end end); -module:hook("iq/host/"..xmlns_disco.."#items:query", function (event) - local origin, stanza = event.origin, event.stanza; - if stanza.attr.type == "get" and stanza.tags[1].attr.node - and stanza.tags[1].attr.node == xmlns_cmd then - local admin = is_admin(stanza.attr.from, stanza.attr.to); - local global_admin = is_admin(stanza.attr.from); - reply = st.reply(stanza); - reply:tag("query", { xmlns = xmlns_disco.."#items", - node = xmlns_cmd }); - local nodes = array_collect(keys(commands)):sort(); - for _, node in ipairs(nodes) do - local command = commands[node]; - if (command.permission == "admin" and admin) - or (command.permission == "global_admin" and global_admin) - or (command.permission == "user") then - reply:tag("item", { name = command.name, - node = node, jid = module:get_host() }); - reply:up(); - end +module:hook("host-disco-items-node", function (event) + local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; + if node ~= xmlns_cmd then + return; + end + + local admin = is_admin(stanza.attr.from, stanza.attr.to); + local global_admin = is_admin(stanza.attr.from); + local nodes = array_collect(keys(commands)):sort(); + for _, node in ipairs(nodes) do + local command = commands[node]; + if (command.permission == "admin" and admin) + or (command.permission == "global_admin" and global_admin) + or (command.permission == "user") then + reply:tag("item", { name = command.name, + node = node, jid = module:get_host() }); + reply:up(); end - origin.send(reply); - return true; end -end, 500); + event.exists = true; +end); module:hook("iq/host/"..xmlns_cmd..":command", function (event) local origin, stanza = event.origin, event.stanza; -- cgit v1.2.3 From df20900907530138ceed92cc195c350b464c0de4 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 24 Jul 2013 23:30:32 +0200 Subject: mod_adhoc: Add local_user permission --- plugins/adhoc/mod_adhoc.lua | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/plugins/adhoc/mod_adhoc.lua b/plugins/adhoc/mod_adhoc.lua index 683d5870..f3e7f520 100644 --- a/plugins/adhoc/mod_adhoc.lua +++ b/plugins/adhoc/mod_adhoc.lua @@ -9,6 +9,7 @@ local st = require "util.stanza"; local keys = require "util.iterators".keys; local array_collect = require "util.array".collect; local is_admin = require "core.usermanager".is_admin; +local jid_split = require "util.jid".split; local adhoc_handle_cmd = module:require "adhoc".handle_cmd; local xmlns_cmd = "http://jabber.org/protocol/commands"; local commands = {}; @@ -18,11 +19,14 @@ module:add_feature(xmlns_cmd); module:hook("host-disco-info-node", function (event) local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; if commands[node] then - local privileged = is_admin(stanza.attr.from, stanza.attr.to); - local global_admin = is_admin(stanza.attr.from); + local from = stanza.attr.from; + local privileged = is_admin(from, stanza.attr.to); + local global_admin = is_admin(from); + local username, hostname = jid_split(from); local command = commands[node]; if (command.permission == "admin" and privileged) or (command.permission == "global_admin" and global_admin) + or (command.permission == "local_user" and hostname == module.host) or (command.permission == "user") then reply:tag("identity", { name = command.name, category = "automation", type = "command-node" }):up(); @@ -45,13 +49,16 @@ module:hook("host-disco-items-node", function (event) return; end - local admin = is_admin(stanza.attr.from, stanza.attr.to); - local global_admin = is_admin(stanza.attr.from); + local from = stanza.attr.from; + local admin = is_admin(from, stanza.attr.to); + local global_admin = is_admin(from); + local username, hostname = jid_split(from); local nodes = array_collect(keys(commands)):sort(); for _, node in ipairs(nodes) do local command = commands[node]; if (command.permission == "admin" and admin) or (command.permission == "global_admin" and global_admin) + or (command.permission == "local_user" and hostname == module.host) or (command.permission == "user") then reply:tag("item", { name = command.name, node = node, jid = module:get_host() }); @@ -65,11 +72,15 @@ module:hook("iq/host/"..xmlns_cmd..":command", function (event) local origin, stanza = event.origin, event.stanza; if stanza.attr.type == "set" then local node = stanza.tags[1].attr.node - if commands[node] then - local admin = is_admin(stanza.attr.from, stanza.attr.to); - local global_admin = is_admin(stanza.attr.from); - if (commands[node].permission == "admin" and not admin) - or (commands[node].permission == "global_admin" and not global_admin) then + local command = commands[node]; + if command then + local from = stanza.attr.from; + local admin = is_admin(from, stanza.attr.to); + local global_admin = is_admin(from); + local username, hostname = jid_split(from); + if (command.permission == "admin" and not admin) + or (command.permission == "global_admin" and not global_admin) + or (command.permission == "local_user" and hostname ~= module.host) then origin.send(st.error_reply(stanza, "auth", "forbidden", "You don't have permission to execute this command"):up() :add_child(commands[node]:cmdtag("canceled") :tag("note", {type="error"}):text("You don't have permission to execute this command"))); -- cgit v1.2.3 From 7204bd3a23ef485c07271f5ba0ec4f95033e02f1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 2 Aug 2013 14:44:56 +0200 Subject: mod_register: Use more specific get_option variants --- plugins/mod_register.lua | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 3cdb48b3..5b03c480 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -170,13 +170,10 @@ local function parse_response(query) end local recent_ips = {}; -local min_seconds_between_registrations = module:get_option("min_seconds_between_registrations"); -local whitelist_only = module:get_option("whitelist_registration_only"); -local whitelisted_ips = module:get_option("registration_whitelist") or { "127.0.0.1" }; -local blacklisted_ips = module:get_option("registration_blacklist") or {}; - -for _, ip in ipairs(whitelisted_ips) do whitelisted_ips[ip] = true; end -for _, ip in ipairs(blacklisted_ips) do blacklisted_ips[ip] = true; end +local min_seconds_between_registrations = module:get_option_number("min_seconds_between_registrations"); +local whitelist_only = module:get_option_boolean("whitelist_registration_only"); +local whitelisted_ips = module:get_option_set("registration_whitelist", { "127.0.0.1" })._items; +local blacklisted_ips = module:get_option_set("registration_blacklist", {})._items; module:hook("stanza/iq/jabber:iq:register:query", function(event) local session, stanza = event.origin, event.stanza; -- cgit v1.2.3 From 0c6c0e9c294d9b3b757cf853facaf845087f17ae Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 2 Aug 2013 15:12:24 +0200 Subject: mod_c2s, mod_s2s: Log a message that stream encryption has been enabled with some details --- plugins/mod_c2s.lua | 11 +++++++---- plugins/mod_s2s/mod_s2s.lua | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 3eb9e975..c26c5510 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -68,12 +68,15 @@ function stream_callbacks.streamopened(session, attr) if session.secure == false then session.secure = true; - -- Check if TLS compression is used local sock = session.conn:socket(); if sock.info then - session.compressed = sock:info"compression"; - elseif sock.compression then - session.compressed = sock:compression(); --COMPAT mw/luasec-hg + local info = sock:info(); + (session.log or log)("info", "Stream encrypted (%s) with %s, authenticated with %s and exchanged keys with %s", + info.protocol, info.encryption, info.authentication, info.key); + session.compressed = info.compression; + else + (session.log or log)("info", "Stream encrypted"); + session.compressed = sock.compression and sock:compression(); --COMPAT mw/luasec-hg end end diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 01fac4d2..b6614d2f 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -283,12 +283,15 @@ function stream_callbacks.streamopened(session, attr) if session.secure == false then session.secure = true; - -- Check if TLS compression is used local sock = session.conn:socket(); if sock.info then - session.compressed = sock:info"compression"; - elseif sock.compression then - session.compressed = sock:compression(); --COMPAT mw/luasec-hg + local info = sock:info(); + (session.log or log)("info", "Stream encrypted (%s) with %s, authenticated with %s and exchanged keys with %s", + info.protocol, info.encryption, info.authentication, info.key); + session.compressed = info.compression; + else + (session.log or log)("info", "Stream encrypted"); + session.compressed = sock.compression and sock:compression(); --COMPAT mw/luasec-hg end end -- cgit v1.2.3 From 6b7b6e0e7b6afa7964e22a4af1bf117f17dbff9c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 2 Aug 2013 15:40:21 +0200 Subject: mod_storage_sql2: Do an early return and drop an indentation level --- plugins/mod_storage_sql2.lua | 59 ++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 7560d1f1..8ce5a722 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -100,38 +100,37 @@ local function create_table() end); end local function set_encoding() - if params.driver ~= "SQLite3" then - local set_names_query = "SET NAMES 'utf8';"; - if params.driver == "MySQL" then - set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); - end - local success,err = engine:transaction(function() return engine:execute(set_names_query); end); - if not success then - module:log("error", "Failed to set database connection encoding to UTF8: %s", err); - return; - end - if params.driver == "MySQL" then - -- COMPAT w/pre-0.9: Upgrade tables to UTF-8 if not already - local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE` FROM `information_schema`.`columns` WHERE `TABLE_NAME`='prosody' AND ( `CHARACTER_SET_NAME`!='utf8' OR `COLLATION_NAME`!='utf8_bin' );"; - local success,err = engine:transaction(function() - local result = engine:execute(check_encoding_query); - local n_bad_columns = result:rowcount(); - if n_bad_columns > 0 then - module:log("warn", "Found %d columns in prosody table requiring encoding change, updating now...", n_bad_columns); - local fix_column_query1 = "ALTER TABLE `prosody` CHANGE `%s` `%s` BLOB;"; - local fix_column_query2 = "ALTER TABLE `prosody` CHANGE `%s` `%s` %s CHARACTER SET 'utf8' COLLATE 'utf8_bin';"; - for row in result:rows() do - local column_name, column_type = unpack(row); - engine:execute(fix_column_query1:format(column_name, column_name)); - engine:execute(fix_column_query2:format(column_name, column_name, column_type)); - end - module:log("info", "Database encoding upgrade complete!"); + if params.driver == "SQLite3" then return end + local set_names_query = "SET NAMES 'utf8';"; + if params.driver == "MySQL" then + set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); + end + local success,err = engine:transaction(function() return engine:execute(set_names_query); end); + if not success then + module:log("error", "Failed to set database connection encoding to UTF8: %s", err); + return; + end + if params.driver == "MySQL" then + -- COMPAT w/pre-0.9: Upgrade tables to UTF-8 if not already + local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE` FROM `information_schema`.`columns` WHERE `TABLE_NAME`='prosody' AND ( `CHARACTER_SET_NAME`!='utf8' OR `COLLATION_NAME`!='utf8_bin' );"; + local success,err = engine:transaction(function() + local result = engine:execute(check_encoding_query); + local n_bad_columns = result:rowcount(); + if n_bad_columns > 0 then + module:log("warn", "Found %d columns in prosody table requiring encoding change, updating now...", n_bad_columns); + local fix_column_query1 = "ALTER TABLE `prosody` CHANGE `%s` `%s` BLOB;"; + local fix_column_query2 = "ALTER TABLE `prosody` CHANGE `%s` `%s` %s CHARACTER SET 'utf8' COLLATE 'utf8_bin';"; + for row in result:rows() do + local column_name, column_type = unpack(row); + engine:execute(fix_column_query1:format(column_name, column_name)); + engine:execute(fix_column_query2:format(column_name, column_name, column_type)); end - end); - local success,err = engine:transaction(function() return engine:execute(check_encoding_query); end); - if not success then - module:log("error", "Failed to check/upgrade database encoding: %s", err or "unknown error"); + module:log("info", "Database encoding upgrade complete!"); end + end); + local success,err = engine:transaction(function() return engine:execute(check_encoding_query); end); + if not success then + module:log("error", "Failed to check/upgrade database encoding: %s", err or "unknown error"); end end end -- cgit v1.2.3 From c8e0c8a63bd2e0a7604c4bb5a637287e7ddffc25 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 6 Aug 2013 17:17:23 +0100 Subject: moduleapi: module:get_host_type() now returns 'global' for * and 'local' for non-components --- core/moduleapi.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/moduleapi.lua b/core/moduleapi.lua index ed75669b..a4ba9bc8 100644 --- a/core/moduleapi.lua +++ b/core/moduleapi.lua @@ -44,7 +44,7 @@ function api:get_host() end function api:get_host_type() - return self.host ~= "*" and hosts[self.host].type or nil; + return (self.host == "*" and "global") or hosts[self.host].type or "local"; end function api:set_global() -- cgit v1.2.3 From 96466999c175612fd341819695f473f4b019ea0c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 6 Aug 2013 17:18:39 +0100 Subject: mod_disco: Check for host type == 'local' ('normal' never existed) --- plugins/mod_disco.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index 06a4bb1e..85a544f9 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -32,7 +32,7 @@ do -- validate disco_items end end -if module:get_host_type() == "normal" then +if module:get_host_type() == "local" then module:add_identity("server", "im", module:get_option_string("name", "Prosody")); -- FIXME should be in the non-existing mod_router end module:add_feature("http://jabber.org/protocol/disco#info"); -- cgit v1.2.3 From 53836024291aa7c72bee8e2437648d3eb114f5cc Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 9 Aug 2013 11:10:22 +0100 Subject: mod_c2s: Add session:sleep() and session:wake() to pause a session (e.g. while waiting for an external event). Needs a gallon or two of testing. --- plugins/mod_c2s.lua | 83 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index c26c5510..79a16e29 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -18,6 +18,8 @@ local uuid_generate = require "util.uuid".generate; local xpcall, tostring, type = xpcall, tostring, type; local traceback = debug.traceback; +local t_insert, t_remove = table.insert, table.remove; +local co_running, co_resume = coroutine.running, coroutine.resume; local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; @@ -31,7 +33,7 @@ local sessions = module:shared("sessions"); local core_process_stanza = prosody.core_process_stanza; local hosts = prosody.hosts; -local stream_callbacks = { default_ns = "jabber:client", handlestanza = core_process_stanza }; +local stream_callbacks = { default_ns = "jabber:client" }; local listener = {}; --- Stream events handlers @@ -120,9 +122,7 @@ end local function handleerr(err) log("error", "Traceback[c2s]: %s", traceback(tostring(err), 2)); end function stream_callbacks.handlestanza(session, stanza) stanza = session.filter("stanzas/in", stanza); - if stanza then - return xpcall(function () return core_process_stanza(session, stanza) end, handleerr); - end + t_insert(session.pending_stanzas, stanza); end --- Session methods @@ -224,18 +224,65 @@ function listener.onconnect(conn) session.stream:reset(); end + session.thread = coroutine.create(function (stanza) + while true do + core_process_stanza(session, stanza); + stanza = coroutine.yield("ready"); + end + end); + + session.pending_stanzas = {}; + local filter = session.filter; function session.data(data) - data = filter("bytes/in", data); + -- Parse the data, which will store stanzas in session.pending_stanzas if data then - local ok, err = stream:feed(data); - if ok then return; end - log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); - session:close("not-well-formed"); + data = filter("bytes/in", data); + if data then + local ok, err = stream:feed(data); + if not ok then + log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); + session:close("not-well-formed"); + end + end + end + + if co_running() ~= session.thread and not session.paused then + if session.state == "wait" then + session.state = "ready"; + local ok, state = co_resume(session.thread); + if not ok then + log("error", "Traceback[c2s]: %s", state); + elseif state == "wait" then + return; + end + end + -- We're not currently running, so start the thread to process pending stanzas + local s, thread = session.pending_stanzas, session.thread; + local n = #s; + while n > 0 and session.state ~= "wait" do + session.log("debug", "processing %d stanzas", n); + local consumed; + for i = 1,n do + local stanza = s[i]; + local ok, state = co_resume(thread, stanza); + if not ok then + log("error", "Traceback[c2s]: %s", state); + elseif state == "wait" then + consumed = i; + session.state = "wait"; + break; + end + end + if not consumed then consumed = n; end + for i = 1, #s do + s[i] = s[consumed+i]; + end + n = #s; + end end end - if c2s_timeout then add_task(c2s_timeout, function () if session.type == "c2s_unauthed" then @@ -245,6 +292,22 @@ function listener.onconnect(conn) end session.dispatch_stanza = stream_callbacks.handlestanza; + + function session:sleep(by) + session.log("debug", "Sleeping for %s", by); + session.paused = by or "?"; + session.conn:pause(); + if co_running() == session.thread then + coroutine.yield("wait"); + end + end + function session:wake(by) + assert(session.paused == (by or "?")); + session.log("debug", "Waking for %s", by); + session.paused = nil; + session.conn:resume(); + session.data(); --FIXME: next tick? + end end function listener.onincoming(conn, data) -- cgit v1.2.3 From 1d833bb80779ed9c9e1d7ec6c7fab231ebf48182 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Fri, 9 Aug 2013 17:48:21 +0200 Subject: Remove all trailing whitespace --- core/certmanager.lua | 2 +- core/configmanager.lua | 28 +- core/hostmanager.lua | 14 +- core/loggingmanager.lua | 30 +- core/moduleapi.lua | 12 +- core/modulemanager.lua | 26 +- core/portmanager.lua | 8 +- core/rostermanager.lua | 2 +- core/s2smanager.lua | 8 +- core/sessionmanager.lua | 24 +- core/stanza_router.lua | 4 +- core/storagemanager.lua | 4 +- core/usermanager.lua | 10 +- fallbacks/bit.lua | 2 +- fallbacks/lxp.lua | 4 +- net/adns.lua | 6 +- net/dns.lua | 6 +- net/http.lua | 30 +- net/http/server.lua | 4 +- net/server.lua | 2 +- net/server_event.lua | 56 ++-- net/server_select.lua | 10 +- plugins/mod_admin_telnet.lua | 62 ++--- plugins/mod_announce.lua | 14 +- plugins/mod_auth_internal_hashed.lua | 12 +- plugins/mod_auth_internal_plain.lua | 2 +- plugins/mod_bosh.lua | 32 +-- plugins/mod_c2s.lua | 20 +- plugins/mod_component.lua | 32 +-- plugins/mod_compression.lua | 26 +- plugins/mod_dialback.lua | 20 +- plugins/mod_disco.lua | 2 +- plugins/mod_groups.lua | 12 +- plugins/mod_http.lua | 6 +- plugins/mod_http_errors.lua | 2 +- plugins/mod_http_files.lua | 2 +- plugins/mod_iq.lua | 2 +- plugins/mod_lastactivity.lua | 2 +- plugins/mod_legacyauth.lua | 4 +- plugins/mod_message.lua | 6 +- plugins/mod_motd.lua | 2 +- plugins/mod_offline.lua | 6 +- plugins/mod_pep.lua | 2 +- plugins/mod_ping.lua | 2 +- plugins/mod_posix.lua | 4 +- plugins/mod_presence.lua | 8 +- plugins/mod_privacy.lua | 30 +- plugins/mod_private.lua | 2 +- plugins/mod_proxy65.lua | 22 +- plugins/mod_register.lua | 10 +- plugins/mod_roster.lua | 6 +- plugins/mod_s2s/mod_s2s.lua | 48 ++-- plugins/mod_s2s/s2sout.lib.lua | 26 +- plugins/mod_saslauth.lua | 2 +- plugins/mod_storage_sql.lua | 26 +- plugins/mod_storage_sql2.lua | 8 +- plugins/mod_time.lua | 2 +- plugins/mod_tls.lua | 2 +- plugins/mod_uptime.lua | 2 +- plugins/mod_vcard.lua | 2 +- plugins/mod_version.lua | 2 +- plugins/mod_watchregistrations.lua | 2 +- plugins/mod_welcome.lua | 2 +- plugins/muc/mod_muc.lua | 4 +- plugins/muc/muc.lib.lua | 10 +- tests/modulemanager_option_conversion.lua | 4 +- tests/test.lua | 18 +- tests/test_core_configmanager.lua | 6 +- tests/test_core_s2smanager.lua | 4 +- tests/test_core_stanza_router.lua | 44 +-- tests/test_sasl.lua | 4 +- tests/test_util_http.lua | 2 +- tests/test_util_ip.lua | 4 +- tests/test_util_jid.lua | 2 +- tests/test_util_multitable.lua | 8 +- tests/test_util_stanza.lua | 4 +- tests/util/logger.lua | 2 +- tools/ejabberd2prosody.lua | 2 +- tools/ejabberdsql2prosody.lua | 2 +- tools/erlparse.lua | 2 +- tools/jabberd14sql2prosody.lua | 438 +++++++++++++++--------------- tools/migration/migrator/prosody_sql.lua | 2 +- tools/migration/prosody-migrator.lua | 2 +- tools/openfire2prosody.lua | 2 +- tools/xep227toprosody.lua | 2 +- util/array.lua | 6 +- util/caps.lua | 2 +- util/dataforms.lua | 8 +- util/datetime.lua | 2 +- util/debug.lua | 10 +- util/dependencies.lua | 20 +- util/events.lua | 2 +- util/filters.lua | 16 +- util/helpers.lua | 2 +- util/hmac.lua | 2 +- util/import.lua | 2 +- util/ip.lua | 2 +- util/iterators.lua | 10 +- util/jid.lua | 2 +- util/json.lua | 4 +- util/logger.lua | 2 +- util/multitable.lua | 2 +- util/pluginloader.lua | 2 +- util/prosodyctl.lua | 30 +- util/pubsub.lua | 10 +- util/sasl/scram.lua | 28 +- util/sasl_cyrus.lua | 4 +- util/serialization.lua | 2 +- util/set.lua | 36 +-- util/sql.lua | 2 +- util/stanza.lua | 16 +- util/termcolours.lua | 2 +- util/timer.lua | 4 +- util/uuid.lua | 2 +- util/xml.lua | 4 +- util/xmppstream.lua | 24 +- 116 files changed, 798 insertions(+), 798 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index dc08cb78..b39f4ed4 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/core/configmanager.lua b/core/configmanager.lua index 9720f48a..71f60c81 100644 --- a/core/configmanager.lua +++ b/core/configmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -73,7 +73,7 @@ do -- Some normalization parent_path = parent_path:gsub("%"..path_sep.."+$", ""); path = path:gsub("^%.%"..path_sep.."+", ""); - + local is_relative; if path_sep == "/" and path:sub(1,1) ~= "/" then is_relative = true; @@ -85,7 +85,7 @@ do end end return path; - end + end end -- Helper function to convert a glob to a Lua pattern @@ -167,7 +167,7 @@ do set(config, env.__currenthost or "*", k, v); end }); - + rawset(env, "__currenthost", "*") -- Default is global function env.VirtualHost(name) if rawget(config, name) and rawget(config[name], "component_module") then @@ -185,7 +185,7 @@ do end; end env.Host, env.host = env.VirtualHost, env.VirtualHost; - + function env.Component(name) if rawget(config, name) and rawget(config[name], "defined") and not rawget(config[name], "component_module") then error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s", @@ -201,7 +201,7 @@ do set(config, name or "*", option_name, option_value); end end - + return function (module) if type(module) == "string" then set(config, name, "component_module", module); @@ -211,7 +211,7 @@ do end end env.component = env.Component; - + function env.Include(file) if file:match("[*?]") then local path_pos, glob = file:match("()([^"..path_sep.."]+)$"); @@ -240,26 +240,26 @@ do end end env.include = env.Include; - + function env.RunScript(file) return dofile(resolve_relative_path(config_file:gsub("[^"..path_sep.."]+$", ""), file)); end - + local chunk, err = envload(data, "@"..config_file, env); - + if not chunk then return nil, err; end - + local ok, err = pcall(chunk); - + if not ok then return nil, err; end - + return true; end - + end return _M; diff --git a/core/hostmanager.lua b/core/hostmanager.lua index 06ba72a1..91b052d1 100644 --- a/core/hostmanager.lua +++ b/core/hostmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -35,7 +35,7 @@ local hosts_loaded_once; local function load_enabled_hosts(config) local defined_hosts = config or configmanager.getconfig(); local activated_any_host; - + for host, host_config in pairs(defined_hosts) do if host ~= "*" and host_config.enabled ~= false then if not host_config.component_module then @@ -44,11 +44,11 @@ local function load_enabled_hosts(config) activate(host, host_config); end end - + if not activated_any_host then log("error", "No active VirtualHost entries in the config file. This may cause unexpected behaviour as no modules will be loaded."); end - + prosody_events.fire_event("hosts-activated", defined_hosts); hosts_loaded_once = true; end @@ -93,7 +93,7 @@ function activate(host, host_config) log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host, option_name); end end - + log((hosts_loaded_once and "info") or "debug", "Activated host: %s", host); prosody_events.fire_event("host-activated", host); return true; @@ -104,11 +104,11 @@ function deactivate(host, reason) if not host_session then return nil, "The host "..tostring(host).." is not activated"; end log("info", "Deactivating host: %s", host); prosody_events.fire_event("host-deactivating", { host = host, host_session = host_session, reason = reason }); - + if type(reason) ~= "table" then reason = { condition = "host-gone", text = tostring(reason or "This server has stopped serving "..host) }; end - + -- Disconnect local users, s2s connections -- TODO: These should move to mod_c2s and mod_s2s (how do they know they're being unloaded and not reloaded?) if host_session.sessions then diff --git a/core/loggingmanager.lua b/core/loggingmanager.lua index c69dede8..c6361146 100644 --- a/core/loggingmanager.lua +++ b/core/loggingmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -48,7 +48,7 @@ local function add_rule(sink_config) if sink_maker then -- Create sink local sink = sink_maker(sink_config); - + -- Set sink for all chosen levels for level in pairs(get_levels(sink_config.levels or logging_levels)) do logger.add_level_sink(level, sink); @@ -63,7 +63,7 @@ end -- the log_sink_types table. function apply_sink_rules(sink_type) if type(logging_config) == "table" then - + for _, level in ipairs(logging_levels) do if type(logging_config[level]) == "string" then local value = logging_config[level]; @@ -82,7 +82,7 @@ function apply_sink_rules(sink_type) end end end - + for _, sink_config in ipairs(logging_config) do if (type(sink_config) == "table" and sink_config.to == sink_type) then add_rule(sink_config); @@ -128,7 +128,7 @@ function get_levels(criteria, set) end end end - + for _, level in ipairs(criteria) do set[level] = true; end @@ -138,12 +138,12 @@ end -- Initialize config, etc. -- function reload_logging() local old_sink_types = {}; - + for name, sink_maker in pairs(log_sink_types) do old_sink_types[name] = sink_maker; log_sink_types[name] = nil; end - + logger.reset(); local debug_mode = config.get("*", "debug"); @@ -155,12 +155,12 @@ function reload_logging() default_timestamp = "%b %d %H:%M:%S"; logging_config = config.get("*", "log") or default_logging; - - + + for name, sink_maker in pairs(old_sink_types) do log_sink_types[name] = sink_maker; end - + prosody.events.fire_event("logging-reloaded"); end @@ -179,11 +179,11 @@ local sourcewidth = 20; function log_sink_types.stdout(config) local timestamps = config.timestamps; - + if timestamps == true then timestamps = default_timestamp; -- Default format end - + return function (name, level, message, ...) sourcewidth = math_max(#name+2, sourcewidth); local namelen = #name; @@ -200,7 +200,7 @@ end do local do_pretty_printing = true; - + local logstyles = {}; if do_pretty_printing then logstyles["info"] = getstyle("bold"); @@ -212,7 +212,7 @@ do if not do_pretty_printing then return log_sink_types.stdout(config); end - + local timestamps = config.timestamps; if timestamps == true then @@ -222,7 +222,7 @@ do return function (name, level, message, ...) sourcewidth = math_max(#name+2, sourcewidth); local namelen = #name; - + if timestamps then io_write(os_date(timestamps), " "); end diff --git a/core/moduleapi.lua b/core/moduleapi.lua index a4ba9bc8..6e857531 100644 --- a/core/moduleapi.lua +++ b/core/moduleapi.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2012 Matthew Wild -- Copyright (C) 2008-2012 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -74,7 +74,7 @@ end function api:has_identity(category, type, name) for _, id in ipairs(self:get_host_items("identity")) do if id.category == category and id.type == type and id.name == name then - return true; + return true; end end return false; @@ -252,21 +252,21 @@ function api:get_option_array(name, ...) if value == nil then return nil; end - + if type(value) ~= "table" then return array{ value }; -- Assume any non-list is a single-item list end - + return array():append(value); -- Clone end function api:get_option_set(name, ...) local value = self:get_option_array(name, ...); - + if value == nil then return nil; end - + return set.new(value); end diff --git a/core/modulemanager.lua b/core/modulemanager.lua index 535c227b..2ad2fc17 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -45,28 +45,28 @@ local modulemap = { ["*"] = {} }; -- Load modules when a host is activated function load_modules_for_host(host) local component = config.get(host, "component_module"); - + local global_modules_enabled = config.get("*", "modules_enabled"); local global_modules_disabled = config.get("*", "modules_disabled"); local host_modules_enabled = config.get(host, "modules_enabled"); local host_modules_disabled = config.get(host, "modules_disabled"); - + if host_modules_enabled == global_modules_enabled then host_modules_enabled = nil; end if host_modules_disabled == global_modules_disabled then host_modules_disabled = nil; end - + local global_modules = set.new(autoload_modules) + set.new(global_modules_enabled) - set.new(global_modules_disabled); if component then global_modules = set.intersection(set.new(component_inheritable_modules), global_modules); end local modules = (global_modules + set.new(host_modules_enabled)) - set.new(host_modules_disabled); - + -- COMPAT w/ pre 0.8 if modules:contains("console") then log("error", "The mod_console plugin has been renamed to mod_admin_telnet. Please update your config."); modules:remove("console"); modules:add("admin_telnet"); end - + if component then load(host, component); end @@ -84,18 +84,18 @@ end); local function do_unload_module(host, name) local mod = get_module(host, name); if not mod then return nil, "module-not-loaded"; end - + if module_has_method(mod, "unload") then local ok, err = call_module_method(mod, "unload"); if (not ok) and err then log("warn", "Non-fatal error unloading module '%s' on '%s': %s", name, host, err); end end - + for object, event, handler in mod.module.event_handlers:iter(nil, nil, nil) do object.remove_handler(event, handler); end - + if mod.module.items then -- remove items local events = (host == "*" and prosody.events) or hosts[host].events; for key,t in pairs(mod.module.items) do @@ -117,11 +117,11 @@ local function do_load_module(host, module_name, state) elseif not hosts[host] and host ~= "*"then return nil, "unknown-host"; end - + if not modulemap[host] then modulemap[host] = hosts[host].modules; end - + if modulemap[host][module_name] then log("warn", "%s is already loaded for %s, so not loading again", module_name, host); return nil, "module-already-loaded"; @@ -147,7 +147,7 @@ local function do_load_module(host, module_name, state) end return nil, "global-module-already-loaded"; end - + local _log = logger.init(host..":"..module_name); @@ -158,7 +158,7 @@ local function do_load_module(host, module_name, state) local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); api_instance.environment = pluginenv; - + local mod, err = pluginloader.load_code(module_name, nil, pluginenv); if not mod then log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); diff --git a/core/portmanager.lua b/core/portmanager.lua index 7a247452..95900c08 100644 --- a/core/portmanager.lua +++ b/core/portmanager.lua @@ -87,7 +87,7 @@ function activate(service_name) if not service_info then return nil, "Unknown service: "..service_name; end - + local listener = service_info.listener; local config_prefix = (service_info.config_prefix or service_name).."_"; @@ -103,7 +103,7 @@ function activate(service_name) or listener.default_interface -- COMPAT w/pre0.9 or default_interfaces bind_interfaces = set.new(type(bind_interfaces)~="table" and {bind_interfaces} or bind_interfaces); - + local bind_ports = config.get("*", config_prefix.."ports") or service_info.default_ports or {service_info.default_port @@ -113,7 +113,7 @@ function activate(service_name) local mode, ssl = listener.default_mode or "*a"; local hooked_ports = {}; - + for interface in bind_interfaces do for port in bind_ports do local port_number = tonumber(port); @@ -188,7 +188,7 @@ function register_service(service_name, service_info) log("error", "Failed to activate service '%s': %s", service_name, err or "unknown error"); end end - + fire_event("service-added", { name = service_name, service = service_info }); return true; end diff --git a/core/rostermanager.lua b/core/rostermanager.lua index 4c669eac..5266afb5 100644 --- a/core/rostermanager.lua +++ b/core/rostermanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/core/s2smanager.lua b/core/s2smanager.lua index 06d3f2c9..59c1831b 100644 --- a/core/s2smanager.lua +++ b/core/s2smanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -70,14 +70,14 @@ end function destroy_session(session, reason) if session.destroyed then return; end (session.log or log)("debug", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host)..(reason and (": "..reason) or "")); - + if session.direction == "outgoing" then hosts[session.from_host].s2sout[session.to_host] = nil; session:bounce_sendq(reason); elseif session.direction == "incoming" then incoming_s2s[session] = nil; end - + local event_data = { session = session, reason = reason }; if session.type == "s2sout" then fire_event("s2sout-destroyed", event_data); @@ -90,7 +90,7 @@ function destroy_session(session, reason) hosts[session.to_host].events.fire_event("s2sin-destroyed", event_data); end end - + retire_session(session, reason); -- Clean session until it is GC'd return true; end diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index 98ead07f..5f7f688e 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -44,7 +44,7 @@ function new_session(conn) session.ip = conn:ip(); local conn_name = "c2s"..tostring(session):match("[a-f0-9]+$"); session.log = logger.init(conn_name); - + return session; end @@ -73,19 +73,19 @@ end function destroy_session(session, err) (session.log or log)("debug", "Destroying session for %s (%s@%s)%s", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)", err and (": "..err) or ""); if session.destroyed then return; end - + -- Remove session/resource from user's session list if session.full_jid then local host_session = hosts[session.host]; - + -- Allow plugins to prevent session destruction if host_session.events.fire_event("pre-resource-unbind", {session=session, error=err}) then return; end - + host_session.sessions[session.username].sessions[session.resource] = nil; full_sessions[session.full_jid] = nil; - + if not next(host_session.sessions[session.username].sessions) then log("debug", "All resources of %s are now offline", session.username); host_session.sessions[session.username] = nil; @@ -94,7 +94,7 @@ function destroy_session(session, err) host_session.events.fire_event("resource-unbind", {session=session, error=err}); end - + retire_session(session); end @@ -119,7 +119,7 @@ function bind_resource(session, resource) resource = resourceprep(resource); resource = resource ~= "" and resource or uuid_generate(); --FIXME: Randomly-generated resources must be unique per-user, and never conflict with existing - + if not hosts[session.host].sessions[session.username] then local sessions = { sessions = {} }; hosts[session.host].sessions[session.username] = sessions; @@ -156,12 +156,12 @@ function bind_resource(session, resource) end end end - + session.resource = resource; session.full_jid = session.username .. '@' .. session.host .. '/' .. resource; hosts[session.host].sessions[session.username].sessions[resource] = session; full_sessions[session.full_jid] = session; - + local err; session.roster, err = rm_load_roster(session.username, session.host); if err then @@ -176,9 +176,9 @@ function bind_resource(session, resource) session.log("error", "Roster loading failed: %s", err); return nil, "cancel", "internal-server-error", "Error loading roster"; end - + hosts[session.host].events.fire_event("resource-bind", {session=session}); - + return true; end diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 94753678..c78a657a 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -196,7 +196,7 @@ function core_route_stanza(origin, stanza) -- Auto-detect origin if not specified origin = origin or hosts[from_host]; if not origin then return false; end - + if hosts[host] then -- old stanza routing code removed core_post_stanza(origin, stanza); diff --git a/core/storagemanager.lua b/core/storagemanager.lua index 1c82af6d..5674ff32 100644 --- a/core/storagemanager.lua +++ b/core/storagemanager.lua @@ -37,7 +37,7 @@ function initialize_host(host) local item = event.item; stores_available:set(host, item.name, item); end); - + host_session.events.add_handler("item-removed/storage-provider", function (event) local item = event.item; stores_available:set(host, item.name, nil); @@ -70,7 +70,7 @@ function get_driver(host, store) if not driver_name then driver_name = config.get(host, "default_storage") or "internal"; end - + local driver = load_driver(host, driver_name); if not driver then log("warn", "Falling back to null driver for %s storage on %s", store, host); diff --git a/core/usermanager.lua b/core/usermanager.lua index 08343bee..886bd5cb 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -39,7 +39,7 @@ local provider_mt = { __index = new_null_provider() }; function initialize_host(host) local host_session = hosts[host]; if host_session.type ~= "local" then return; end - + host_session.events.add_handler("item-added/auth-provider", function (event) local provider = event.item; local auth_provider = config.get(host, "authentication") or default_provider; @@ -115,10 +115,10 @@ function is_admin(jid, host) local is_admin; jid = jid_bare(jid); host = host or "*"; - + local host_admins = config.get(host, "admins"); local global_admins = config.get("*", "admins"); - + if host_admins and host_admins ~= global_admins then if type(host_admins) == "table" then for _,admin in ipairs(host_admins) do @@ -131,7 +131,7 @@ function is_admin(jid, host) log("error", "Option 'admins' for host '%s' is not a list", host); end end - + if not is_admin and global_admins then if type(global_admins) == "table" then for _,admin in ipairs(global_admins) do @@ -144,7 +144,7 @@ function is_admin(jid, host) log("error", "Global option 'admins' is not a list"); end end - + -- Still not an admin, check with auth provider if not is_admin and host ~= "*" and hosts[host].users and hosts[host].users.is_admin then is_admin = hosts[host].users.is_admin(jid); diff --git a/fallbacks/bit.lua b/fallbacks/bit.lua index 2482c473..28dca4e6 100644 --- a/fallbacks/bit.lua +++ b/fallbacks/bit.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/fallbacks/lxp.lua b/fallbacks/lxp.lua index 6d3297d1..ac1c9a03 100644 --- a/fallbacks/lxp.lua +++ b/fallbacks/lxp.lua @@ -61,7 +61,7 @@ local function parser(data, handlers, ns_separator) while #data == 0 do data = coroutine.yield(); end return data:sub(1,1); end - + local ns = { xml = "http://www.w3.org/XML/1998/namespace" }; ns.__index = ns; local function apply_ns(name, dodefault) @@ -100,7 +100,7 @@ local function parser(data, handlers, ns_separator) ns = getmetatable(ns); return tag; end - + while true do if peek() == "<" then local elem = read_until(">"):sub(2,-2); diff --git a/net/adns.lua b/net/adns.lua index 158747c6..08421f77 100644 --- a/net/adns.lua +++ b/net/adns.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -64,7 +64,7 @@ function new_async_socket(sock, resolver) if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]); end - + resolver:servfail(conn); -- Let the magic commence end end @@ -72,7 +72,7 @@ function new_async_socket(sock, resolver) if not handler then return nil, err; end - + handler.settimeout = function () end handler.setsockname = function (_, ...) return sock:setsockname(...); end handler.setpeername = function (_, ...) peername = (...); local ret = sock:setpeername(...); _:set_send(dummy_send); return ret; end diff --git a/net/dns.lua b/net/dns.lua index 95f09cc9..bd5c260e 100644 --- a/net/dns.lua +++ b/net/dns.lua @@ -753,7 +753,7 @@ function resolver:query(qname, qtype, qclass) -- - - - - - - - - - -- query return nil, err; end conn:send (o.packet) - + if timer and self.timeout then local num_servers = #self.server; local i = 1; @@ -849,7 +849,7 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive -- retire the query local queries = self.active[response.header.id]; queries[response.question.raw] = nil; - + if not next(queries) then self.active[response.header.id] = nil; end if not next(self.active) then self:closeall(); end @@ -864,7 +864,7 @@ function resolver:receive(rset) -- - - - - - - - - - - - - - - - - receive set(self.wanted, q.class, q.type, q.name, nil); end end - + end end end diff --git a/net/http.lua b/net/http.lua index b7d2beb9..5ec3163c 100644 --- a/net/http.lua +++ b/net/http.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -36,7 +36,7 @@ function listener.onconnect(conn) if req.query then t_insert(request_line, 4, "?"..req.query); end - + conn:write(t_concat(request_line)); local t = { [2] = ": ", [4] = "\r\n" }; for k, v in pairs(req.headers) do @@ -44,7 +44,7 @@ function listener.onconnect(conn) conn:write(t_concat(t)); end conn:write("\r\n"); - + if req.body then conn:write(req.body); end @@ -80,12 +80,12 @@ local function request_reader(request, data, err) end destroy_request(request); end - + if not data then error_cb(err); return; end - + local function success_cb(r) if request.callback then request.callback(r.body, r.code, r, request); @@ -104,18 +104,18 @@ end local function handleerr(err) log("error", "Traceback[http]: %s", traceback(tostring(err), 2)); end function request(u, ex, callback) local req = url.parse(u); - + if not (req and req.host) then callback(nil, 0, req); return nil, "invalid-url"; end - + if not req.path then req.path = "/"; end - + local method, headers, body; - + local host, port = req.host, req.port; local host_header = host; if (port == "80" and req.scheme == "http") @@ -129,7 +129,7 @@ function request(u, ex, callback) ["Host"] = host_header; ["User-Agent"] = "Prosody XMPP Server"; }; - + if req.userinfo then headers["Authorization"] = "Basic "..b64(req.userinfo); end @@ -149,16 +149,16 @@ function request(u, ex, callback) end end end - + -- Attach to request object req.method, req.headers, req.body = method, headers, body; - + local using_https = req.scheme == "https"; if using_https and not ssl_available then error("SSL not available, unable to contact https URL"); end local port_number = port and tonumber(port) or (using_https and 443 or 80); - + -- Connect the socket, and wrap it with net.server local conn = socket.tcp(); conn:settimeout(10); @@ -167,7 +167,7 @@ function request(u, ex, callback) callback(nil, 0, req); return nil, err; end - + local sslctx = false; if using_https then sslctx = ex and ex.sslctx or { mode = "client", protocol = "sslv23", options = { "no_sslv2" } }; @@ -175,7 +175,7 @@ function request(u, ex, callback) req.handler, req.conn = server.wrapclient(conn, host, port_number, listener, "*a", sslctx); req.write = function (...) return req.handler:write(...); end - + req.callback = function (content, code, request, response) log("debug", "Calling callback, status %s", code or "---"); return select(2, xpcall(function () return callback(content, code, request, response) end, handleerr)); end req.reader = request_reader; req.state = "status"; diff --git a/net/http/server.lua b/net/http/server.lua index 0f379e96..5961169f 100644 --- a/net/http/server.lua +++ b/net/http/server.lua @@ -204,7 +204,7 @@ function handle_request(conn, request, finish_cb) err_code, err = 400, "Missing or invalid 'Host' header"; end end - + if err then response.status_code = err_code; response:send(events.fire_event("http-error", { code = err_code, message = err })); @@ -250,7 +250,7 @@ function _M.send_response(response, body) if response.finished then return; end response.finished = true; response.conn._http_open_response = nil; - + local status_line = "HTTP/"..response.request.httpversion.." "..(response.status or codes[response.status_code]); local headers = response.headers; body = body or response.body or ""; diff --git a/net/server.lua b/net/server.lua index 375e7081..2a0b89ae 100644 --- a/net/server.lua +++ b/net/server.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/net/server_event.lua b/net/server_event.lua index 9f479d5b..59217a0c 100644 --- a/net/server_event.lua +++ b/net/server_event.lua @@ -115,10 +115,10 @@ end )( ) local interface_mt do interface_mt = {}; interface_mt.__index = interface_mt; - + local addevent = base.addevent local coroutine_wrap, coroutine_yield = coroutine.wrap,coroutine.yield - + -- Private methods function interface_mt:_position(new_position) self.position = new_position or self.position @@ -127,7 +127,7 @@ do function interface_mt:_close() return self:_destroy(); end - + function interface_mt:_start_connection(plainssl) -- should be called from addclient local callback = function( event ) if EV_TIMEOUT == event then -- timeout during connection @@ -268,12 +268,12 @@ do interfacelist( "delete", self ) return true end - + function interface_mt:_lock(nointerface, noreading, nowriting) -- lock or unlock this interface or events self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting return nointerface, noreading, nowriting end - + --TODO: Deprecate function interface_mt:lock_read(switch) if switch then @@ -300,7 +300,7 @@ do end return self._connections end - + -- Public methods function interface_mt:write(data) if self.nowriting then return nil, "locked" end @@ -343,27 +343,27 @@ do return true end end - + function interface_mt:socket() return self.conn end - + function interface_mt:server() return self._server or self; end - + function interface_mt:port() return self._port end - + function interface_mt:serverport() return self._serverport end - + function interface_mt:ip() return self._ip end - + function interface_mt:ssl() return self._usingssl end @@ -371,15 +371,15 @@ do function interface_mt:type() return self._type or "client" end - + function interface_mt:connections() return self._connections end - + function interface_mt:address() return self.addr end - + function interface_mt:set_sslctx(sslctx) self._sslctx = sslctx; if sslctx then @@ -395,11 +395,11 @@ do end return self._pattern; end - + function interface_mt:set_send(new_send) -- No-op, we always use the underlying connection's send end - + function interface_mt:starttls(sslctx, call_onconnect) debug( "try to start ssl at client id:", self.id ) local err @@ -428,14 +428,14 @@ do self.starttls = false; return true end - + function interface_mt:setoption(option, value) if self.conn.setoption then return self.conn:setoption(option, value); end return false, "setoption not implemented"; end - + function interface_mt:setlistener(listener) self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout, self.onreadtimeout, self.onstatus = listener.onconnect, listener.ondisconnect, listener.onincoming, @@ -499,7 +499,7 @@ do noreading = false, nowriting = false; -- locks of the read/writecallback startsslcallback = false; -- starting handshake callback position = false; -- position of client in interfacelist - + -- Properties _ip = ip, _port = port, _server = server, _pattern = pattern, _serverport = (server and server:port() or nil), @@ -575,7 +575,7 @@ do end end end - + interface.readcallback = function( event ) -- called on read events --vdebug( "new client read event, id/ip/port:", tostring(interface.id), tostring(ip), tostring(port) ) if interface.noreading or interface.fatalerror then -- leave this event @@ -648,7 +648,7 @@ do debug "creating server interface..." local interface = { _connections = 0; - + conn = server; onconnect = listener.onconnect; -- will be called when new client connected eventread = false; -- read event handler @@ -656,7 +656,7 @@ do readcallback = false; -- read event callback fatalerror = false; -- error message nointerface = true; -- lock/unlock parameter - + _ip = addr, _port = port, _pattern = pattern, _sslctx = sslctx; } @@ -695,12 +695,12 @@ do clientinterface:_start_session( true ) end debug( "accepted incoming client connection from:", client_ip or "", client_port or "", "to", port or ""); - + client, err = server:accept() -- try to accept again end return EV_READ end - + server:settimeout( 0 ) setmetatable(interface, interface_mt) interfacelist( "add", interface ) @@ -743,7 +743,7 @@ do return interface, client --function handleclient( client, ip, port, server, pattern, listener, _, sslctx ) -- creates an client interface end - + function addclient( addr, serverport, listener, pattern, localaddr, localport, sslcfg, startssl ) local client, err = socket.tcp() -- creating new socket if not client then @@ -834,14 +834,14 @@ end local function link(sender, receiver, buffersize) local sender_locked; - + function receiver:ondrain() if sender_locked then sender:resume(); sender_locked = nil; end end - + function sender:onincoming(data) receiver:write(data); if receiver.writebufferlen >= buffersize then diff --git a/net/server_select.lua b/net/server_select.lua index 98e9f847..7b550bf9 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -1,7 +1,7 @@ --- +-- -- server.lua by blastbeat of the luadch project -- Re-used here under the MIT/X Consortium License --- +-- -- Modifications (C) 2008-2010 Matthew Wild, Waqas Hussain -- @@ -607,7 +607,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport shutdown = id _socketlist[ socket ] = handler _readlistlen = addsocket(_readlist, socket, _readlistlen) - + -- remove traces of the old socket _readlistlen = removesocket( _readlist, oldsocket, _readlistlen ) _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen ) @@ -695,7 +695,7 @@ local function link(sender, receiver, buffersize) sender_locked = nil; end end - + local _readbuffer = sender.readbuffer; function sender.readbuffer() _readbuffer(); @@ -969,7 +969,7 @@ return { addclient = addclient, wrapclient = wrapclient, - + loop = loop, link = link, step = step, diff --git a/plugins/mod_admin_telnet.lua b/plugins/mod_admin_telnet.lua index 18ae4fe0..e13d27c2 100644 --- a/plugins/mod_admin_telnet.lua +++ b/plugins/mod_admin_telnet.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -60,20 +60,20 @@ function console:new_session(conn) disconnect = function () conn:close(); end; }; session.env = setmetatable({}, default_env_mt); - + -- Load up environment with helper objects for name, t in pairs(def_env) do if type(t) == "table" then session.env[name] = setmetatable({ session = session }, { __index = t }); end end - + return session; end function console:process_line(session, line) local useglobalenv; - + if line:match("^>") then line = line:gsub("^>", ""); useglobalenv = true; @@ -87,9 +87,9 @@ function console:process_line(session, line) return; end end - + session.env._ = line; - + local chunkname = "=console"; local env = (useglobalenv and redirect_output(_G, session)) or session.env or nil local chunk, err = envload("return "..line, chunkname, env); @@ -103,20 +103,20 @@ function console:process_line(session, line) return; end end - + local ranok, taskok, message = pcall(chunk); - + if not (ranok or message or useglobalenv) and commands[line:lower()] then commands[line:lower()](session, line); return; end - + if not ranok then session.print("Fatal error while running command, it did not complete"); session.print("Error: "..taskok); return; end - + if not message then session.print("Result: "..tostring(taskok)); return; @@ -125,7 +125,7 @@ function console:process_line(session, line) session.print("Message: "..tostring(message)); return; end - + session.print("OK: "..tostring(message)); end @@ -344,9 +344,9 @@ end function def_env.module:load(name, hosts, config) local mm = require "modulemanager"; - + hosts = get_hosts_set(hosts); - + -- Load the module for each host local ok, err, count, mod = true, nil, 0, nil; for host in hosts do @@ -367,15 +367,15 @@ function def_env.module:load(name, hosts, config) end end end - - return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); + + return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err)); end function def_env.module:unload(name, hosts) local mm = require "modulemanager"; hosts = get_hosts_set(hosts, name); - + -- Unload the module for each host local ok, err, count = true, nil, 0; for host in hosts do @@ -433,7 +433,7 @@ function def_env.module:list(hosts) if type(hosts) ~= "table" then return false, "Please supply a host or a list of hosts you would like to see"; end - + local print = self.session.print; for _, host in ipairs(hosts) do print((host == "*" and "Global" or host)..":"); @@ -520,7 +520,7 @@ function def_env.c2s:count(match_jid) show_c2s(function (jid, session) if (not match_jid) or jid:match(match_jid) then count = count + 1; - end + end end); return true, "Total: "..count.." clients"; end @@ -540,7 +540,7 @@ function def_env.c2s:show(match_jid) status = session.presence:get_child_text("show") or "available"; end print(session_flags(session, { " "..jid.." - "..status.."("..priority..")" })); - end + end end); return true, "Total: "..count.." clients"; end @@ -551,7 +551,7 @@ function def_env.c2s:show_insecure(match_jid) if ((not match_jid) or jid:match(match_jid)) and not session.secure then count = count + 1; print(jid); - end + end end); return true, "Total: "..count.." insecure client connections"; end @@ -562,7 +562,7 @@ function def_env.c2s:show_secure(match_jid) if ((not match_jid) or jid:match(match_jid)) and session.secure then count = count + 1; print(jid); - end + end end); return true, "Total: "..count.." secure client connections"; end @@ -582,10 +582,10 @@ end def_env.s2s = {}; function def_env.s2s:show(match_jid) local print = self.session.print; - + local count_in, count_out = 0,0; local s2s_list = { }; - + local s2s_sessions = module:shared"/*/s2s/sessions"; for _, session in pairs(s2s_sessions) do local remotehost, localhost, direction; @@ -724,18 +724,18 @@ function def_env.s2s:showcert(domain) local domain_certs = array.collect(values(cert_set)); -- Phew. We now have a array of unique certificates presented by domain. local n_certs = #domain_certs; - + if n_certs == 0 then return "No certificates found for "..domain; end - + local function _capitalize_and_colon(byte) return string.upper(byte)..":"; end local function pretty_fingerprint(hash) return hash:gsub("..", _capitalize_and_colon):sub(1, -2); end - + for cert_info in values(domain_certs) do local certs = cert_info.certs; local cert = certs[1]; @@ -777,7 +777,7 @@ end function def_env.s2s:close(from, to) local print, count = self.session.print, 0; local s2s_sessions = module:shared"/*/s2s/sessions"; - + local match_id; if from and not to then match_id, from = from; @@ -786,7 +786,7 @@ function def_env.s2s:close(from, to) elseif from == to then return false, "Both from and to are the same... you can't do that :)"; end - + for _, session in pairs(s2s_sessions) do local id = session.type..tostring(session):match("[a-f0-9]+$"); if (match_id and match_id == id) @@ -1031,12 +1031,12 @@ function printbanner(session) local option = module:get_option("console_banner"); if option == nil or option == "full" or option == "graphic" then session.print [[ - ____ \ / _ - | _ \ _ __ ___ ___ _-_ __| |_ _ + ____ \ / _ + | _ \ _ __ ___ ___ _-_ __| |_ _ | |_) | '__/ _ \/ __|/ _ \ / _` | | | | | __/| | | (_) \__ \ |_| | (_| | |_| | |_| |_| \___/|___/\___/ \__,_|\__, | - A study in simplicity |___/ + A study in simplicity |___/ ]] end diff --git a/plugins/mod_announce.lua b/plugins/mod_announce.lua index 96976d6f..9327556c 100644 --- a/plugins/mod_announce.lua +++ b/plugins/mod_announce.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -39,22 +39,22 @@ end function handle_announcement(event) local origin, stanza = event.origin, event.stanza; local node, host, resource = jid.split(stanza.attr.to); - + if resource ~= "announce/online" then return; -- Not an announcement end - + if not is_admin(stanza.attr.from) then -- Not an admin? Not allowed! module:log("warn", "Non-admin '%s' tried to send server announcement", stanza.attr.from); return; end - + module:log("info", "Sending server announcement to all online users"); local message = st.clone(stanza); message.attr.type = "headline"; message.attr.from = host; - + local c = send_to_online(message, host); module:log("info", "Announcement sent to %d online users", c); return true; @@ -83,9 +83,9 @@ function announce_handler(self, data, state) module:log("info", "Sending server announcement to all online users"); local message = st.message({type = "headline"}, fields.announcement):up() :tag("subject"):text(fields.subject or "Announcement"); - + local count = send_to_online(message, data.to); - + module:log("info", "Announcement sent to %d online users", count); return { status = "completed", info = ("Announcement sent to %d online users"):format(count) }; else diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 2b041e43..57396731 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -62,12 +62,12 @@ function provider.test_password(username, password) if credentials.iteration_count == nil or credentials.salt == nil or string.len(credentials.salt) == 0 then return nil, "Auth failed. Stored salt and iteration count information is not complete."; end - + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, credentials.salt, credentials.iteration_count); - + local stored_key_hex = to_hex(stored_key); local server_key_hex = to_hex(server_key); - + if valid and stored_key_hex == credentials.stored_key and server_key_hex == credentials.server_key then return true; else @@ -83,7 +83,7 @@ function provider.set_password(username, password) local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, account.salt, account.iteration_count); local stored_key_hex = to_hex(stored_key); local server_key_hex = to_hex(server_key); - + account.stored_key = stored_key_hex account.server_key = server_key_hex @@ -134,7 +134,7 @@ function provider.get_sasl_handler() credentials = accounts:get(username); if not credentials then return; end end - + local stored_key, server_key, iteration_count, salt = credentials.stored_key, credentials.server_key, credentials.iteration_count, credentials.salt; stored_key = stored_key and from_hex(stored_key); server_key = server_key and from_hex(server_key); @@ -143,6 +143,6 @@ function provider.get_sasl_handler() }; return new_sasl(host, testpass_authentication_profile); end - + module:provides("auth", provider); diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua index d226fdbe..4d698fa0 100644 --- a/plugins/mod_auth_internal_plain.lua +++ b/plugins/mod_auth_internal_plain.lua @@ -76,6 +76,6 @@ function provider.get_sasl_handler() }; return new_sasl(host, getpass_authentication_profile); end - + module:provides("auth", provider); diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index d109547e..ca67db73 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -78,7 +78,7 @@ function on_destroy_request(request) break; end end - + -- If this session now has no requests open, mark it as inactive local max_inactive = session.bosh_max_inactive; if max_inactive and #requests == 0 then @@ -121,7 +121,7 @@ function handle_POST(event) if cross_domain and event.request.headers.origin then set_cross_domain_headers(response); end - + -- stream:feed() calls the stream_callbacks, so all stanzas in -- the body are processed in this next line before it returns. -- In particular, the streamopened() stream callback is where @@ -131,7 +131,7 @@ function handle_POST(event) module:log("warn", "Error parsing BOSH payload") return 400; end - + -- Stanzas (if any) in the request have now been processed, and -- we take care of the high-level BOSH logic here, including -- giving a response or putting the request "on hold". @@ -164,7 +164,7 @@ function handle_POST(event) session.send_buffer = {}; session.send(resp); end - + if not response.finished then -- We're keeping this request open, to respond later log("debug", "Have nothing to say, so leaving request unanswered for now"); @@ -172,7 +172,7 @@ function handle_POST(event) waiting_requests[response] = os_time() + session.bosh_wait; end end - + if session.bosh_terminate then session.log("debug", "Closing session with %d requests open", #session.requests); session:close(); @@ -192,10 +192,10 @@ local stream_xmlns_attr = { xmlns = "urn:ietf:params:xml:ns:xmpp-streams" }; local function bosh_close_stream(session, reason) (session.log or log)("info", "BOSH client disconnected"); - + local close_reply = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate", ["xmlns:stream"] = xmlns_streams }); - + if reason then close_reply.attr.condition = "remote-stream-error"; @@ -236,7 +236,7 @@ function stream_callbacks.streamopened(context, attr) if not sid then -- New session request context.notopen = nil; -- Signals that we accept this opening tag - + -- TODO: Sanity checks here (rid, to, known host, etc.) if not hosts[attr.to] then -- Unknown host @@ -246,7 +246,7 @@ function stream_callbacks.streamopened(context, attr) response:send(tostring(close_reply)); return; end - + -- New session sid = new_uuid(); local session = { @@ -259,9 +259,9 @@ function stream_callbacks.streamopened(context, attr) ip = get_ip_from_request(request); }; sessions[sid] = session; - + local filter = initialize_filters(session); - + session.log("debug", "BOSH session created for request from %s", session.ip); log("info", "New BOSH session, assigned it sid '%s'", sid); @@ -308,7 +308,7 @@ function stream_callbacks.streamopened(context, attr) end request.sid = sid; end - + local session = sessions[sid]; if not session then -- Unknown sid @@ -317,7 +317,7 @@ function stream_callbacks.streamopened(context, attr) context.notopen = nil; return; end - + if session.rid then local rid = tonumber(attr.rid); local diff = rid - session.rid; @@ -334,7 +334,7 @@ function stream_callbacks.streamopened(context, attr) end session.rid = rid; end - + if attr.type == "terminate" then -- Client wants to end this session, which we'll do -- after processing any stanzas in this request @@ -388,7 +388,7 @@ function stream_callbacks.error(context, error) response:send(); return; end - + local session = sessions[context.sid]; if error == "stream-error" then -- Remote stream error, we close normally session:close(); @@ -412,7 +412,7 @@ function on_timer() end end end - + now = now - 3; local n_dead_sessions = 0; for session, close_after in pairs(inactive_sessions) do diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 79a16e29..fbac12cd 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -154,10 +154,10 @@ local function session_close(session, reason) log("debug", "Disconnecting client, is: %s", stream_error); session.send(stream_error); end - + session.send(""); function session.send() return false; end - + local reason = (reason and (reason.name or reason.text or reason.condition)) or reason; session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed"); @@ -193,9 +193,9 @@ end, 200); function listener.onconnect(conn) local session = sm_new_session(conn); sessions[conn] = session; - + session.log("info", "Client connected"); - + -- Client is using legacy SSL (otherwise mod_tls sets this flag) if conn:ssl() then session.secure = true; @@ -208,22 +208,22 @@ function listener.onconnect(conn) session.compressed = sock:compression(); --COMPAT mw/luasec-hg end end - + if opt_keepalives then conn:setoption("keepalive", opt_keepalives); end - + session.close = session_close; - + local stream = new_xmpp_stream(session, stream_callbacks); session.stream = stream; session.notopen = true; - + function session.reset_stream() session.notopen = true; session.stream:reset(); end - + session.thread = coroutine.create(function (stanza) while true do core_process_stanza(session, stanza); diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua index a5767c9a..3eaacb8e 100644 --- a/plugins/mod_component.lua +++ b/plugins/mod_component.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -31,7 +31,7 @@ function module.add_host(module) if module:get_host_type() ~= "component" then error("Don't load mod_component manually, it should be for a component, please see http://prosody.im/doc/components", 0); end - + local env = module.environment; env.connected = false; @@ -42,26 +42,26 @@ function module.add_host(module) send = nil; session.on_destroy = nil; end - + -- Handle authentication attempts by component local function handle_component_auth(event) local session, stanza = event.origin, event.stanza; - + if session.type ~= "component_unauthed" then return; end - + if (not session.host) or #stanza.tags > 0 then (session.log or log)("warn", "Invalid component handshake for host: %s", session.host); session:close("not-authorized"); return true; end - + local secret = module:get_option("component_secret"); if not secret then (session.log or log)("warn", "Component attempted to identify as %s, but component_secret is not set", session.host); session:close("not-authorized"); return true; end - + local supplied_token = t_concat(stanza); local calculated_token = sha1(session.streamid..secret, true); if supplied_token:lower() ~= calculated_token:lower() then @@ -69,13 +69,13 @@ function module.add_host(module) session:close{ condition = "not-authorized", text = "Given token does not match calculated token" }; return true; end - + if env.connected then module:log("error", "Second component attempted to connect, denying connection"); session:close{ condition = "conflict", text = "Component already connected" }; return true; end - + env.connected = true; send = session.send; session.on_destroy = on_destroy; @@ -83,7 +83,7 @@ function module.add_host(module) session.type = "component"; module:log("info", "External component successfully authenticated"); session.send(st.stanza("handshake")); - + return true; end module:hook("stanza/jabber:component:accept:handshake", handle_component_auth); @@ -114,7 +114,7 @@ function module.add_host(module) end return true; end - + module:hook("iq/bare", handle_stanza, -1); module:hook("message/bare", handle_stanza, -1); module:hook("presence/bare", handle_stanza, -1); @@ -269,14 +269,14 @@ function listener.onconnect(conn) local conn_name = "jcp"..tostring(session):match("[a-f0-9]+$"); session.log = logger.init(conn_name); session.close = session_close; - + session.log("info", "Incoming Jabber component connection"); - + local stream = new_xmpp_stream(session, stream_callbacks); session.stream = stream; - + session.notopen = true; - + function session.reset_stream() session.notopen = true; session.stream:reset(); @@ -288,7 +288,7 @@ function listener.onconnect(conn) module:log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_")); session:close("not-well-formed"); end - + session.dispatch_stanza = stream_callbacks.handlestanza; sessions[conn] = session; diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua index 92856099..f44e8a6d 100644 --- a/plugins/mod_compression.lua +++ b/plugins/mod_compression.lua @@ -1,6 +1,6 @@ -- Prosody IM -- Copyright (C) 2009-2012 Tobias Markmann --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -103,7 +103,7 @@ local function setup_compression(session, deflate_stream) return; end return compressed; - end); + end); end -- setup decompression for a stream @@ -125,19 +125,19 @@ end module:hook("stanza/http://jabber.org/protocol/compress:compressed", function(event) local session = event.origin; - + if session.type == "s2sout_unauthed" or session.type == "s2sout" then session.log("debug", "Activating compression...") -- create deflate and inflate streams local deflate_stream = get_deflate_stream(session); if not deflate_stream then return true; end - + local inflate_stream = get_inflate_stream(session); if not inflate_stream then return true; end - + -- setup compression for session.w setup_compression(session, deflate_stream); - + -- setup decompression for session.data setup_decompression(session, inflate_stream); session:reset_stream(); @@ -158,29 +158,29 @@ module:hook("stanza/http://jabber.org/protocol/compress:compress", function(even session.log("debug", "Client tried to establish another compression layer."); return true; end - + -- checking if the compression method is supported local method = stanza:child_with_name("method"); method = method and (method[1] or ""); if method == "zlib" then session.log("debug", "zlib compression enabled."); - + -- create deflate and inflate streams local deflate_stream = get_deflate_stream(session); if not deflate_stream then return true; end - + local inflate_stream = get_inflate_stream(session); if not inflate_stream then return true; end - + (session.sends2s or session.send)(st.stanza("compressed", {xmlns=xmlns_compression_protocol})); session:reset_stream(); - + -- setup compression for session.w setup_compression(session, deflate_stream); - + -- setup decompression for session.data setup_decompression(session, inflate_stream); - + session.compressed = true; elseif method then session.log("debug", "%s compression selected, but we don't support it.", tostring(method)); diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index 9dcb0ed5..afee9d58 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -35,7 +35,7 @@ end module:hook("stanza/jabber:server:dialback:verify", function(event) local origin, stanza = event.origin, event.stanza; - + if origin.type == "s2sin_unauthed" or origin.type == "s2sin" then -- We are being asked to verify the key, to ensure it was generated by us origin.log("debug", "verifying that dialback key is ours..."); @@ -62,13 +62,13 @@ end); module:hook("stanza/jabber:server:dialback:result", function(event) local origin, stanza = event.origin, event.stanza; - + if origin.type == "s2sin_unauthed" or origin.type == "s2sin" then -- he wants to be identified through dialback -- We need to check the key with the Authoritative server local attr = stanza.attr; local to, from = nameprep(attr.to), nameprep(attr.from); - + if not hosts[to] then -- Not a host that we serve origin.log("info", "%s tried to connect to %s, which we don't serve", from, to); @@ -77,11 +77,11 @@ module:hook("stanza/jabber:server:dialback:result", function(event) elseif not from then origin:close("improper-addressing"); end - + origin.hosts[from] = { dialback_key = stanza[1] }; - + dialback_requests[from.."/"..origin.streamid] = origin; - + -- COMPAT: ejabberd, gmail and perhaps others do not always set 'to' and 'from' -- on streams. We fill in the session's to/from here instead. if not origin.from_host then @@ -102,7 +102,7 @@ end); module:hook("stanza/jabber:server:dialback:verify", function(event) local origin, stanza = event.origin, event.stanza; - + if origin.type == "s2sout_unauthed" or origin.type == "s2sout" then local attr = stanza.attr; local dialback_verifying = dialback_requests[attr.from.."/"..(attr.id or "")]; @@ -131,10 +131,10 @@ end); module:hook("stanza/jabber:server:dialback:result", function(event) local origin, stanza = event.origin, event.stanza; - + if origin.type == "s2sout_unauthed" or origin.type == "s2sout" then -- Remote server is telling us whether we passed dialback - + local attr = stanza.attr; if not hosts[attr.to] then origin:close("host-unknown"); diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index 85a544f9..61749580 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_groups.lua b/plugins/mod_groups.lua index dc6976d4..be1a5508 100644 --- a/plugins/mod_groups.lua +++ b/plugins/mod_groups.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -22,7 +22,7 @@ function inject_roster_contacts(event) --module:log("debug", "Injecting group members to roster"); local bare_jid = username.."@"..host; if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups - + local roster = event.roster; local function import_jids_to_roster(group_name) for jid in pairs(groups[group_name]) do @@ -50,7 +50,7 @@ function inject_roster_contacts(event) import_jids_to_roster(group_name); end end - + -- Import public groups if members[false] then for _, group_name in ipairs(members[false]) do @@ -58,7 +58,7 @@ function inject_roster_contacts(event) import_jids_to_roster(group_name); end end - + if roster[false] then roster[false].version = true; end @@ -84,10 +84,10 @@ end function module.load() groups_file = module:get_option_string("groups_file"); if not groups_file then return; end - + module:hook("roster-load", inject_roster_contacts); datamanager.add_callback(remove_virtual_contacts); - + groups = { default = {} }; members = { }; local curr_group = "default"; diff --git a/plugins/mod_http.lua b/plugins/mod_http.lua index 0689634e..95933da5 100644 --- a/plugins/mod_http.lua +++ b/plugins/mod_http.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2012 Matthew Wild -- Copyright (C) 2008-2012 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -108,7 +108,7 @@ function module.add_host(module) end end end - + local function http_app_removed(event) local app_handlers = apps[event.item.name]; apps[event.item.name] = nil; @@ -116,7 +116,7 @@ function module.add_host(module) module:unhook_object_event(server, event, handler); end end - + module:handle_items("http-provider", http_app_added, http_app_removed); server.add_host(host); diff --git a/plugins/mod_http_errors.lua b/plugins/mod_http_errors.lua index 2568ea80..0c37e104 100644 --- a/plugins/mod_http_errors.lua +++ b/plugins/mod_http_errors.lua @@ -53,7 +53,7 @@ local entities = { local function tohtml(plain) return (plain:gsub("[<>&'\"\n]", entities)); - + end local function get_page(code, extra) diff --git a/plugins/mod_http_files.lua b/plugins/mod_http_files.lua index 6ab295ac..dd04853b 100644 --- a/plugins/mod_http_files.lua +++ b/plugins/mod_http_files.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_iq.lua b/plugins/mod_iq.lua index e7901ab4..c6d62e85 100644 --- a/plugins/mod_iq.lua +++ b/plugins/mod_iq.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_lastactivity.lua b/plugins/mod_lastactivity.lua index 11053709..fabf07b4 100644 --- a/plugins/mod_lastactivity.lua +++ b/plugins/mod_lastactivity.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_legacyauth.lua b/plugins/mod_legacyauth.lua index 5fb66441..cb5ce0d3 100644 --- a/plugins/mod_legacyauth.lua +++ b/plugins/mod_legacyauth.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -43,7 +43,7 @@ module:hook("stanza/iq/jabber:iq:auth:query", function(event) session.send(st.error_reply(stanza, "modify", "not-acceptable", "Encryption (SSL or TLS) is required to connect to this server")); return true; end - + local username = stanza.tags[1]:child_with_name("username"); local password = stanza.tags[1]:child_with_name("password"); local resource = stanza.tags[1]:child_with_name("resource"); diff --git a/plugins/mod_message.lua b/plugins/mod_message.lua index e85da613..fc337db0 100644 --- a/plugins/mod_message.lua +++ b/plugins/mod_message.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -17,7 +17,7 @@ local user_exists = require "core.usermanager".user_exists; local function process_to_bare(bare, origin, stanza) local user = bare_sessions[bare]; - + local t = stanza.attr.type; if t == "error" then -- discard @@ -66,7 +66,7 @@ end module:hook("message/full", function(data) -- message to full JID recieved local origin, stanza = data.origin, data.stanza; - + local session = full_sessions[stanza.attr.to]; if session and session.send(stanza) then return true; diff --git a/plugins/mod_motd.lua b/plugins/mod_motd.lua index ed78294b..1e2ee395 100644 --- a/plugins/mod_motd.lua +++ b/plugins/mod_motd.lua @@ -2,7 +2,7 @@ -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain -- Copyright (C) 2010 Jeff Mitchell --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_offline.lua b/plugins/mod_offline.lua index 1ac62f94..c168711b 100644 --- a/plugins/mod_offline.lua +++ b/plugins/mod_offline.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2009 Matthew Wild -- Copyright (C) 2008-2009 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -24,11 +24,11 @@ module:hook("message/offline/handle", function(event) else node, host = origin.username, origin.host; end - + stanza.attr.stamp, stanza.attr.stamp_legacy = datetime.datetime(), datetime.legacy(); local result = datamanager.list_append(node, host, "offline", st.preserialize(stanza)); stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil; - + return result; end); diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua index 778f83ed..04f70221 100644 --- a/plugins/mod_pep.lua +++ b/plugins/mod_pep.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_ping.lua b/plugins/mod_ping.lua index 0bfcac66..eddb92d2 100644 --- a/plugins/mod_ping.lua +++ b/plugins/mod_ping.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua index 28fd7f38..7a6ccd94 100644 --- a/plugins/mod_posix.lua +++ b/plugins/mod_posix.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -183,7 +183,7 @@ if signal.signal then prosody.reload_config(); prosody.reopen_logfiles(); end); - + signal.signal("SIGINT", function () module:log("info", "Received SIGINT"); prosody.unlock_globals(); diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua index 8dac2d35..2899bd7e 100644 --- a/plugins/mod_presence.lua +++ b/plugins/mod_presence.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -227,7 +227,7 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b local st_from, st_to = stanza.attr.from, stanza.attr.to; stanza.attr.from, stanza.attr.to = from_bare, to_bare; log("debug", "inbound presence %s from %s for %s", stanza.attr.type, from_bare, to_bare); - + if stanza.attr.type == "probe" then local result, err = rostermanager.is_contact_subscribed(node, host, from_bare); if result then @@ -312,7 +312,7 @@ module:hook("presence/bare", function(data) if t ~= nil and t ~= "unavailable" and t ~= "error" then -- check for subscriptions and probes sent to bare JID return handle_inbound_presence_subscriptions_and_probes(origin, stanza, jid_bare(stanza.attr.from), jid_bare(stanza.attr.to)); end - + local user = bare_sessions[to]; if user then for _, session in pairs(user.sessions) do @@ -347,7 +347,7 @@ end); module:hook("presence/host", function(data) -- inbound presence to the host local stanza = data.stanza; - + local from_bare = jid_bare(stanza.attr.from); local t = stanza.attr.type; if t == "probe" then diff --git a/plugins/mod_privacy.lua b/plugins/mod_privacy.lua index 31ace9f9..aaa8e383 100644 --- a/plugins/mod_privacy.lua +++ b/plugins/mod_privacy.lua @@ -2,7 +2,7 @@ -- Copyright (C) 2009-2010 Matthew Wild -- Copyright (C) 2009-2010 Waqas Hussain -- Copyright (C) 2009 Thilo Cestonaro --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -103,7 +103,7 @@ end function createOrReplaceList (privacy_lists, origin, stanza, name, entries) local bare_jid = origin.username.."@"..origin.host; - + if privacy_lists.lists == nil then privacy_lists.lists = {}; end @@ -119,14 +119,14 @@ function createOrReplaceList (privacy_lists, origin, stanza, name, entries) if to_number(item.attr.order) == nil or to_number(item.attr.order) < 0 or orderCheck[item.attr.order] ~= nil then return {"modify", "bad-request", "Order attribute not valid."}; end - + if item.attr.type ~= nil and item.attr.type ~= "jid" and item.attr.type ~= "subscription" and item.attr.type ~= "group" then return {"modify", "bad-request", "Type attribute not valid."}; end - + local tmp = {}; orderCheck[item.attr.order] = true; - + tmp["type"] = item.attr.type; tmp["value"] = item.attr.value; tmp["action"] = item.attr.action; @@ -135,13 +135,13 @@ function createOrReplaceList (privacy_lists, origin, stanza, name, entries) tmp["presence-out"] = false; tmp["message"] = false; tmp["iq"] = false; - + if #item.tags > 0 then for _,tag in ipairs(item.tags) do tmp[tag.name] = true; end end - + if tmp.type == "subscription" then if tmp.value ~= "both" and tmp.value ~= "to" and @@ -150,13 +150,13 @@ function createOrReplaceList (privacy_lists, origin, stanza, name, entries) return {"cancel", "bad-request", "Subscription value must be both, to, from or none."}; end end - + if tmp.action ~= "deny" and tmp.action ~= "allow" then return {"cancel", "bad-request", "Action must be either deny or allow."}; end list.items[#list.items + 1] = tmp; end - + table.sort(list, function(a, b) return a.order < b.order; end); origin.send(st.reply(stanza)); @@ -207,14 +207,14 @@ function getList(privacy_lists, origin, stanza, name) return {"cancel", "item-not-found", "Unknown list specified."}; end end - + origin.send(reply); return true; end module:hook("iq/bare/jabber:iq:privacy:query", function(data) local origin, stanza = data.origin, data.stanza; - + if stanza.attr.to == nil then -- only service requests to own bare JID local query = stanza.tags[1]; -- the query element local valid = false; @@ -285,12 +285,12 @@ function checkIfNeedToBeBlocked(e, session) local bare_jid = session.username.."@"..session.host; local to = stanza.attr.to or bare_jid; local from = stanza.attr.from; - + local is_to_user = bare_jid == jid_bare(to); local is_from_user = bare_jid == jid_bare(from); - + --module:log("debug", "stanza: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from)); - + if privacy_lists.lists == nil or not (session.activePrivacyList or privacy_lists.default) then @@ -300,7 +300,7 @@ function checkIfNeedToBeBlocked(e, session) --module:log("debug", "Not blocking communications between user's resources"); return; -- from one of a user's resource to another => HANDS OFF! end - + local listname = session.activePrivacyList; if listname == nil then listname = privacy_lists.default; -- no active list selected, use default list diff --git a/plugins/mod_private.lua b/plugins/mod_private.lua index 365a997c..446a80b2 100644 --- a/plugins/mod_private.lua +++ b/plugins/mod_private.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 1fa42bd8..2ed9faac 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -2,7 +2,7 @@ -- Copyright (C) 2008-2011 Matthew Wild -- Copyright (C) 2008-2011 Waqas Hussain -- Copyright (C) 2009 Thilo Cestonaro --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -30,7 +30,7 @@ function listener.onincoming(conn, data) (conn == initiator and target or initiator):write(data); return; end -- FIXME server.link should be doing this? - + if not session.greeting_done then local nmethods = data:byte(2) or 0; if data:byte(1) == 0x05 and nmethods > 0 and #data == 2 + nmethods then -- check if we have all the data @@ -90,7 +90,7 @@ end function module.add_host(module) local host, name = module:get_host(), module:get_option_string("name", "SOCKS5 Bytestreams Service"); - + local proxy_address = module:get_option("proxy65_address", host); local proxy_port = next(portmanager.get_active_services():search("proxy65", nil)[1] or {}); local proxy_acl = module:get_option("proxy65_acl"); @@ -103,7 +103,7 @@ function module.add_host(module) module:add_identity("proxy", "bytestreams", name); module:add_feature("http://jabber.org/protocol/bytestreams"); - + module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) local origin, stanza = event.origin, event.stanza; if not stanza.tags[1].attr.node then @@ -113,7 +113,7 @@ function module.add_host(module) return true; end end, -1); - + module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function(event) local origin, stanza = event.origin, event.stanza; if not stanza.tags[1].attr.node then @@ -121,10 +121,10 @@ function module.add_host(module) return true; end end, -1); - + module:hook("iq-get/host/http://jabber.org/protocol/bytestreams:query", function(event) local origin, stanza = event.origin, event.stanza; - + -- check ACL while proxy_acl and #proxy_acl > 0 do -- using 'while' instead of 'if' so we can break out of it local jid = stanza.attr.from; @@ -137,22 +137,22 @@ function module.add_host(module) origin.send(st.error_reply(stanza, "auth", "forbidden")); return true; end - + local sid = stanza.tags[1].attr.sid; origin.send(st.reply(stanza):tag("query", {xmlns="http://jabber.org/protocol/bytestreams", sid=sid}) :tag("streamhost", {jid=host, host=proxy_address, port=proxy_port})); return true; end); - + module:hook("iq-set/host/http://jabber.org/protocol/bytestreams:query", function(event) local origin, stanza = event.origin, event.stanza; - + local query = stanza.tags[1]; local sid = query.attr.sid; local from = stanza.attr.from; local to = query:get_child_text("activate"); local prepped_to = jid_prep(to); - + local info = "sid: "..tostring(sid)..", initiator: "..tostring(from)..", target: "..tostring(prepped_to or to); if prepped_to and sid then local sha = sha1(sid .. from .. prepped_to, true); diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index 5b03c480..e537e903 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -102,16 +102,16 @@ local function handle_registration_stanza(event) session.send(st.reply(stanza)); return old_session_close(session, ...); end - + local ok, err = usermanager_delete_user(username, host); - + if not ok then module:log("debug", "Removing user account %s@%s failed: %s", username, host, err); session.close = old_session_close; session.send(st.error_reply(stanza, "cancel", "service-unavailable", err)); return true; end - + module:log("info", "User removed their account: %s@%s", username, host); module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session }); else @@ -206,7 +206,7 @@ module:hook("stanza/iq/jabber:iq:register:query", function(event) else local ip = recent_ips[session.ip]; ip.count = ip.count + 1; - + if os_time() - ip.time < min_seconds_between_registrations then ip.time = os_time(); session.send(st.error_reply(stanza, "wait", "not-acceptable")); diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua index d530bb45..56af5368 100644 --- a/plugins/mod_roster.lua +++ b/plugins/mod_roster.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -36,10 +36,10 @@ module:hook("iq/self/jabber:iq:roster:query", function(event) if stanza.attr.type == "get" then local roster = st.reply(stanza); - + local client_ver = tonumber(stanza.tags[1].attr.ver); local server_ver = tonumber(session.roster[false].version or 1); - + if not (client_ver and server_ver) or client_ver ~= server_ver then roster:query("jabber:iq:roster"); -- Client does not support versioning, or has stale roster diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index c628dc47..d64a02ac 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -155,9 +155,9 @@ end -- Stream is authorised, and ready for normal stanzas function mark_connected(session) local sendq, send = session.sendq, session.sends2s; - + local from, to = session.from_host, session.to_host; - + session.log("info", "%s s2s connection %s->%s complete", session.direction, from, to); local event_data = { session = session }; @@ -173,7 +173,7 @@ function mark_connected(session) fire_global_event("s2sin-established", event_data); hosts[to].events.fire_event("s2sin-established", event_data); end - + if session.direction == "outgoing" then if sendq then session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", #sendq, session.to_host); @@ -183,7 +183,7 @@ function mark_connected(session) end session.sendq = nil; end - + session.ip_hosts = nil; session.srv_hosts = nil; end @@ -218,9 +218,9 @@ function make_authenticated(event) return false; end session.log("debug", "connection %s->%s is now authenticated for %s", session.from_host, session.to_host, host); - + mark_connected(session); - + return true; end @@ -277,9 +277,9 @@ local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; function stream_callbacks.streamopened(session, attr) local send = session.sends2s; - + session.version = tonumber(attr.version) or 0; - + -- TODO: Rename session.secure to session.encrypted if session.secure == false then session.secure = true; @@ -298,7 +298,7 @@ function stream_callbacks.streamopened(session, attr) if session.direction == "incoming" then -- Send a reply stream header - + -- Validate to/from local to, from = nameprep(attr.to), nameprep(attr.from); if not to and attr.to then -- COMPAT: Some servers do not reliably set 'to' (especially on stream restarts) @@ -309,7 +309,7 @@ function stream_callbacks.streamopened(session, attr) session:close({ condition = "improper-addressing", text = "Invalid 'from' address" }); return; end - + -- Set session.[from/to]_host if they have not been set already and if -- this session isn't already authenticated if session.type == "s2sin_unauthed" and from and not session.from_host then @@ -324,10 +324,10 @@ function stream_callbacks.streamopened(session, attr) session:close({ condition = "improper-addressing", text = "New stream 'to' attribute does not match original" }); return; end - + -- For convenience we'll put the sanitised values into these variables to, from = session.to_host, session.from_host; - + session.streamid = uuid_gen(); (session.log or log)("debug", "Incoming s2s received %s", st.stanza("stream:stream", attr):top_tag()); if to then @@ -362,13 +362,13 @@ function stream_callbacks.streamopened(session, attr) session:open_stream(session.to_host, session.from_host) if session.version >= 1.0 then local features = st.stanza("stream:features"); - + if to then hosts[to].events.fire_event("s2s-stream-features", { origin = session, features = features }); else (session.log or log)("warn", "No 'to' on stream header from %s means we can't offer any features", from or "unknown host"); end - + log("debug", "Sending stream features: %s", tostring(features)); send(features); end @@ -396,7 +396,7 @@ function stream_callbacks.streamopened(session, attr) end end session.send_buffer = nil; - + -- If server is pre-1.0, don't wait for features, just do dialback if session.version < 1.0 then if not session.dialback_verifying then @@ -489,10 +489,10 @@ local function session_close(session, reason, remote_reason) session.sends2s(""); function session.sends2s() return false; end - + local reason = remote_reason or (reason and (reason.text or reason.condition)) or reason; session.log("info", "%s s2s stream %s->%s closed: %s", session.direction, session.from_host or "(unknown host)", session.to_host or "(unknown host)", reason or "stream closed"); - + -- Authenticated incoming stream may still be sending us stanzas, so wait for from remote local conn = session.conn; if reason == nil and not session.notopen and session.type == "s2sin" then @@ -532,16 +532,16 @@ end local function initialize_session(session) local stream = new_xmpp_stream(session, stream_callbacks); session.stream = stream; - + session.notopen = true; - + function session.reset_stream() session.notopen = true; session.stream:reset(); end session.open_stream = session_open_stream; - + local filter = session.filter; function session.data(data) data = filter("bytes/in", data); @@ -596,7 +596,7 @@ function listener.onconnect(conn) end end end - + initialize_session(session); else -- Outgoing session connected session:open_stream(session.from_host, session.to_host); @@ -610,7 +610,7 @@ function listener.onincoming(conn, data) session.data(data); end end - + function listener.onstatus(conn, status) if status == "ssl-handshake-complete" then local session = sessions[conn]; @@ -658,7 +658,7 @@ function check_auth_policy(event) elseif must_secure and insecure_domains[host] then must_secure = false; end - + if must_secure and (session.cert_chain_status ~= "valid" or session.cert_identity_status ~= "valid") then module:log("warn", "Forbidding insecure connection to/from %s", host); if session.direction == "incoming" then diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index 575d37ac..10ee4f0e 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -47,14 +47,14 @@ end function s2sout.initiate_connection(host_session) initialize_filters(host_session); host_session.version = 1; - + -- Kick the connection attempting machine into life if not s2sout.attempt_connection(host_session) then -- Intentionally not returning here, the -- session is needed, connected or not s2s_destroy_session(host_session); end - + if not host_session.sends2s then -- A sends2s which buffers data (until the stream is opened) -- note that data in this buffer will be sent before the stream is authed @@ -75,11 +75,11 @@ end function s2sout.attempt_connection(host_session, err) local to_host = host_session.to_host; local connect_host, connect_port = to_host and idna_to_ascii(to_host), 5269; - + if not connect_host then return false; end - + if not err then -- This is our first attempt log("debug", "First attempt to connect to %s, starting with SRV lookup...", to_host); host_session.connecting = true; @@ -100,7 +100,7 @@ function s2sout.attempt_connection(host_session, err) return; end t_sort(srv_hosts, compare_srv_priorities); - + local srv_choice = srv_hosts[1]; host_session.srv_choice = 1; if srv_choice then @@ -119,7 +119,7 @@ function s2sout.attempt_connection(host_session, err) end end end, "_xmpp-server._tcp."..connect_host..".", "SRV"); - + return true; -- Attempt in progress elseif host_session.ip_hosts then return s2sout.try_connect(host_session, connect_host, connect_port, err); @@ -133,7 +133,7 @@ function s2sout.attempt_connection(host_session, err) -- We're out of options return false; end - + if not (connect_host and connect_port) then -- Likely we couldn't resolve DNS log("warn", "Hmm, we're without a host (%s) and port (%s) to connect to for %s, giving up :(", tostring(connect_host), tostring(connect_port), tostring(to_host)); @@ -280,7 +280,7 @@ function s2sout.make_connect(host_session, connect_host, connect_port) else handler = "Unsupported protocol: "..tostring(proto); end - + if not conn then log("warn", "Failed to create outgoing connection, system error: %s", handler); return false, handler; @@ -292,10 +292,10 @@ function s2sout.make_connect(host_session, connect_host, connect_port) log("warn", "s2s connect() to %s (%s:%d) failed: %s", host_session.to_host, connect_host.addr, connect_port, err); return false, err; end - + conn = wrapclient(conn, connect_host.addr, connect_port, s2s_listener, "*a"); host_session.conn = conn; - + local filter = initialize_filters(host_session); local w, log = conn.write, host_session.log; host_session.sends2s = function (t) @@ -310,11 +310,11 @@ function s2sout.make_connect(host_session, connect_host, connect_port) end end end - + -- Register this outgoing connection so that xmppserver_listener knows about it -- otherwise it will assume it is a new incoming connection s2s_listener.register_outgoing(conn, host_session); - + log("debug", "Connection attempt in progress..."); return true; end diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 201cc477..1bf6fb96 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_storage_sql.lua b/plugins/mod_storage_sql.lua index eed3fec9..1f453d42 100644 --- a/plugins/mod_storage_sql.lua +++ b/plugins/mod_storage_sql.lua @@ -93,7 +93,7 @@ local function create_table() elseif params.driver == "MySQL" then create_sql = create_sql:gsub("`value` TEXT", "`value` MEDIUMTEXT"); end - + local stmt, err = connection:prepare(create_sql); if stmt then local ok = stmt:execute(); @@ -159,18 +159,18 @@ do -- process options to get a db connection end params = params or { driver = "SQLite3" }; - + if params.driver == "SQLite3" then params.database = resolve_relative_path(prosody.paths.data or ".", params.database or "prosody.sqlite"); end - + assert(params.driver and params.database, "Both the SQL driver and the database need to be specified"); dburi = db2uri(params); connection = connections[dburi]; - + assert(connect()); - + -- Automatically create table, ignore failure (table probably already exists) create_table(); end @@ -209,7 +209,7 @@ local function dosql(sql, ...) local ok, err = stmt:execute(...); if not ok and not test_connection() then error("connection failed"); end if not ok then return nil, err; end - + return stmt; end local function getsql(sql, ...) @@ -236,7 +236,7 @@ end local function keyval_store_get() local stmt, err = getsql("SELECT * FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?"); if not stmt then return rollback(nil, err); end - + local haveany; local result = {}; for row in stmt:rows(true) do @@ -256,7 +256,7 @@ end local function keyval_store_set(data) local affected, err = setsql("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?"); if not affected then return rollback(affected, err); end - + if data and next(data) ~= nil then local extradata = {}; for key, value in pairs(data) do @@ -314,7 +314,7 @@ end local function map_store_get(key) local stmt, err = getsql("SELECT * FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", key or ""); if not stmt then return rollback(nil, err); end - + local haveany; local result = {}; for row in stmt:rows(true) do @@ -334,7 +334,7 @@ end local function map_store_set(key, data) local affected, err = setsql("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", key or ""); if not affected then return rollback(affected, err); end - + if data and next(data) ~= nil then if type(key) == "string" and key ~= "" then local t, value = serialize(data); @@ -365,15 +365,15 @@ local list_store = {}; list_store.__index = list_store; function list_store:scan(username, from, to, jid, typ) user,store = username,self.store; - + local cols = {"from", "to", "jid", "typ"}; local vals = { from , to , jid , typ }; local stmt, err; local query = "SELECT * FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=?"; - + query = query.." ORDER BY time"; --local stmt, err = getsql("SELECT * FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", key or ""); - + return nil, "not-implemented" end diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 8ce5a722..3c5f9d20 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -137,16 +137,16 @@ end do -- process options to get a db connection params = params or { driver = "SQLite3" }; - + if params.driver == "SQLite3" then params.database = resolve_relative_path(prosody.paths.data or ".", params.database or "prosody.sqlite"); end - + assert(params.driver and params.database, "Both the SQL driver and the database need to be specified"); --local dburi = db2uri(params); engine = mod_sql:create_engine(params); - + -- Encoding mess set_encoding(); @@ -204,7 +204,7 @@ local function keyval_store_get() end local function keyval_store_set(data) engine:delete("DELETE FROM `prosody` WHERE `host`=? AND `user`=? AND `store`=?", host, user or "", store); - + if data and next(data) ~= nil then local extradata = {}; for key, value in pairs(data) do diff --git a/plugins/mod_time.lua b/plugins/mod_time.lua index cb69ebe7..ae7da916 100644 --- a/plugins/mod_time.lua +++ b/plugins/mod_time.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua index 1af8dbe9..bab2202e 100644 --- a/plugins/mod_tls.lua +++ b/plugins/mod_tls.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_uptime.lua b/plugins/mod_uptime.lua index 3f275b2f..2e369b16 100644 --- a/plugins/mod_uptime.lua +++ b/plugins/mod_uptime.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_vcard.lua b/plugins/mod_vcard.lua index 26b30e3a..72f92ef7 100644 --- a/plugins/mod_vcard.lua +++ b/plugins/mod_vcard.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_version.lua b/plugins/mod_version.lua index d35103b6..be244beb 100644 --- a/plugins/mod_version.lua +++ b/plugins/mod_version.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_watchregistrations.lua b/plugins/mod_watchregistrations.lua index abca90bd..b7be5daf 100644 --- a/plugins/mod_watchregistrations.lua +++ b/plugins/mod_watchregistrations.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/mod_welcome.lua b/plugins/mod_welcome.lua index e498f0b3..9c0c821b 100644 --- a/plugins/mod_welcome.lua +++ b/plugins/mod_welcome.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index a9480465..6b4c7006 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -16,7 +16,7 @@ local muc_name = module:get_option("name"); if type(muc_name) ~= "string" then muc_name = "Prosody Chatrooms"; end local restrict_room_creation = module:get_option("restrict_room_creation"); if restrict_room_creation then - if restrict_room_creation == true then + if restrict_room_creation == true then restrict_room_creation = "admin"; elseif restrict_room_creation ~= "admin" and restrict_room_creation ~= "local" then restrict_room_creation = nil; diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 483b0812..8800640f 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -147,10 +147,10 @@ function room_mt:send_history(to, stanza) 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 @@ -163,7 +163,7 @@ function room_mt:send_history(to, stanza) local n = 0; local charcount = 0; - + for i=#history,1,-1 do local entry = history[i]; if maxchars then @@ -351,7 +351,7 @@ local function construct_stanza_id(room, stanza) local from_nick = room._jid_nick[from_jid]; local occupant = room._occupants[to_nick]; local to_jid = occupant.jid; - + return from_nick, to_jid, base64.encode(to_jid.."\0"..stanza.attr.id.."\0"..md5(from_jid)); end local function deconstruct_stanza_id(room, stanza) diff --git a/tests/modulemanager_option_conversion.lua b/tests/modulemanager_option_conversion.lua index 7dceeaed..100dbe83 100644 --- a/tests/modulemanager_option_conversion.lua +++ b/tests/modulemanager_option_conversion.lua @@ -18,7 +18,7 @@ function test_value(value, returns) assert(module:get_option_number("opt") == returns.number, "number doesn't match"); assert(module:get_option_string("opt") == returns.string, "string doesn't match"); assert(module:get_option_boolean("opt") == returns.boolean, "boolean doesn't match"); - + if type(returns.array) == "table" then local target_array, returned_array = returns.array, module:get_option_array("opt"); assert(#target_array == #returned_array, "array length doesn't match"); @@ -28,7 +28,7 @@ function test_value(value, returns) else assert(module:get_option_array("opt") == returns.array, "array is returned (not nil)"); end - + if type(returns.set) == "table" then local target_items, returned_items = set.new(returns.set), module:get_option_set("opt"); assert(target_items == returned_items, "set doesn't match"); diff --git a/tests/test.lua b/tests/test.lua index b6728061..f7475a80 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -20,7 +20,7 @@ function run_all_tests() dotest "util.ip" dotest "util.stanza" dotest "util.sasl.scram" - + dosingletest("test_sasl.lua", "latin1toutf8"); end @@ -87,12 +87,12 @@ function dosingletest(testname, fname) print("WARNING: ", "Failed to initialise tests for "..testname, err); return; end - + if type(tests[fname]) ~= "function" then error(testname.." has no test '"..fname.."'", 0); end - - + + local line_hook, line_info = new_line_coverage_monitor(testname); debug.sethook(line_hook, "l") local success, ret = pcall(tests[fname]); @@ -134,7 +134,7 @@ function dotest(unitname) print("WARNING: ", "Failed to load module: "..unitname, err); return; end - + local oldmodule, old_M = _fakeG.module, _fakeG._M; _fakeG.module = function () _M = unit end setfenv(chunk, unit); @@ -144,7 +144,7 @@ function dotest(unitname) print("WARNING: ", "Failed to initialise module: "..unitname, err); return; end - + if type(ret) == "table" then for k,v in pairs(ret) do unit[k] = v; @@ -197,11 +197,11 @@ end function new_line_coverage_monitor(file) local lines_hit, funcs_hit = {}, {}; local total_lines, covered_lines = 0, 0; - + for line in io.lines(file) do total_lines = total_lines + 1; end - + return function (event, line) -- Line hook if not lines_hit[line] then local info = debug.getinfo(2, "fSL") diff --git a/tests/test_core_configmanager.lua b/tests/test_core_configmanager.lua index d7919965..5bd469c6 100644 --- a/tests/test_core_configmanager.lua +++ b/tests/test_core_configmanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -15,10 +15,10 @@ function get(get, config) config.set("*", "testkey1", 321); assert_equal(get("*", "testkey1"), 321, "Retrieving a set global key"); assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key of undefined host, of which only a globally set one exists"); - + config.set("example.com", ""); -- Creates example.com host in config assert_equal(get("example.com", "testkey1"), 321, "Retrieving a set key, of which only a globally set one exists"); - + assert_equal(get(), nil, "No parameters to get()"); assert_equal(get("undefined host"), nil, "Getting for undefined host"); assert_equal(get("undefined host", "undefined key"), nil, "Getting for undefined host & key"); diff --git a/tests/test_core_s2smanager.lua b/tests/test_core_s2smanager.lua index 7194d201..d2dbf830 100644 --- a/tests/test_core_s2smanager.lua +++ b/tests/test_core_s2smanager.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -16,7 +16,7 @@ function compare_srv_priorities(csp) local r3 = { priority = 1000, weight = 2 } local r4 = { priority = 1000, weight = 2 } local r5 = { priority = 1000, weight = 5 } - + assert_equal(csp(r1, r1), false); assert_equal(csp(r1, r2), true); assert_equal(csp(r1, r3), true); diff --git a/tests/test_core_stanza_router.lua b/tests/test_core_stanza_router.lua index 0a93694f..ca6b78fc 100644 --- a/tests/test_core_stanza_router.lua +++ b/tests/test_core_stanza_router.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -14,7 +14,7 @@ function core_process_stanza(core_process_stanza, u) local s2sin_session = { from_host = "remotehost", to_host = "localhost", type = "s2sin", hosts = { ["remotehost"] = { authed = true } } } local local_host_session = { host = "localhost", type = "local", s2sout = { ["remotehost"] = s2sout_session } } local local_user_session = { username = "user", host = "localhost", resource = "resource", full_jid = "user@localhost/resource", type = "c2s" } - + _G.prosody.hosts["localhost"] = local_host_session; _G.prosody.full_sessions["user@localhost/resource"] = local_user_session; _G.prosody.bare_sessions["user@localhost"] = { sessions = { resource = local_user_session } }; @@ -23,15 +23,15 @@ function core_process_stanza(core_process_stanza, u) local function test_message_full_jid() local env = testlib_new_env(); local msg = stanza.stanza("message", { to = "user@localhost/resource", type = "chat" }):tag("body"):text("Hello world"); - + local target_routed; - + function env.core_post_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of routed stanza is not correct"); assert_equal(p_stanza, msg, "routed stanza is not correct one: "..p_stanza:pretty_print()); target_routed = true; end - + env.hosts = hosts; env.prosody = { hosts = hosts }; setfenv(core_process_stanza, env); @@ -42,9 +42,9 @@ function core_process_stanza(core_process_stanza, u) local function test_message_bare_jid() local env = testlib_new_env(); local msg = stanza.stanza("message", { to = "user@localhost", type = "chat" }):tag("body"):text("Hello world"); - + local target_routed; - + function env.core_post_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of routed stanza is not correct"); assert_equal(p_stanza, msg, "routed stanza is not correct one: "..p_stanza:pretty_print()); @@ -60,9 +60,9 @@ function core_process_stanza(core_process_stanza, u) local function test_message_no_to() local env = testlib_new_env(); local msg = stanza.stanza("message", { type = "chat" }):tag("body"):text("Hello world"); - + local target_handled; - + function env.core_post_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -78,9 +78,9 @@ function core_process_stanza(core_process_stanza, u) local function test_message_to_remote_bare() local env = testlib_new_env(); local msg = stanza.stanza("message", { to = "user@remotehost", type = "chat" }):tag("body"):text("Hello world"); - + local target_routed; - + function env.core_route_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -88,7 +88,7 @@ function core_process_stanza(core_process_stanza, u) end function env.core_post_stanza(...) env.core_route_stanza(...); end - + env.hosts = hosts; setfenv(core_process_stanza, env); assert_equal(core_process_stanza(local_user_session, msg), nil, "core_process_stanza returned incorrect value"); @@ -98,9 +98,9 @@ function core_process_stanza(core_process_stanza, u) local function test_message_to_remote_server() local env = testlib_new_env(); local msg = stanza.stanza("message", { to = "remotehost", type = "chat" }):tag("body"):text("Hello world"); - + local target_routed; - + function env.core_route_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -123,9 +123,9 @@ function core_process_stanza(core_process_stanza, u) local function test_iq_to_remote_server() local env = testlib_new_env(); local msg = stanza.stanza("iq", { to = "remotehost", type = "get", id = "id" }):tag("body"):text("Hello world"); - + local target_routed; - + function env.core_route_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -145,9 +145,9 @@ function core_process_stanza(core_process_stanza, u) local function test_iq_error_to_local_user() local env = testlib_new_env(); local msg = stanza.stanza("iq", { to = "user@localhost/resource", from = "user@remotehost", type = "error", id = "id" }):tag("error", { type = 'cancel' }):tag("item-not-found", { xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' }); - + local target_routed; - + function env.core_route_stanza(p_origin, p_stanza) assert_equal(p_origin, s2sin_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -167,9 +167,9 @@ function core_process_stanza(core_process_stanza, u) local function test_iq_to_local_bare() local env = testlib_new_env(); local msg = stanza.stanza("iq", { to = "user@localhost", from = "user@localhost", type = "get", id = "id" }):tag("ping", { xmlns = "urn:xmpp:ping:0" }); - + local target_handled; - + function env.core_post_stanza(p_origin, p_stanza) assert_equal(p_origin, local_user_session, "origin of handled stanza is not correct"); assert_equal(p_stanza, msg, "handled stanza is not correct one: "..p_stanza:pretty_print()); @@ -209,11 +209,11 @@ function core_route_stanza(core_route_stanza) local msg2 = stanza.stanza("iq", { to = "user@localhost/foo", from = "user@localhost", type = "error" }):tag("ping", { xmlns = "urn:xmpp:ping:0" }); --package.loaded["core.usermanager"] = { user_exists = function (user, host) print("RAR!") return true or user == "user" and host == "localhost" and true; end }; local target_handled, target_replied; - + function env.core_post_stanza(p_origin, p_stanza) target_handled = true; end - + function local_user_session.send(data) --print("Replying with: ", tostring(data)); --print(debug.traceback()) diff --git a/tests/test_sasl.lua b/tests/test_sasl.lua index 271fa69a..dd63c5a0 100644 --- a/tests/test_sasl.lua +++ b/tests/test_sasl.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -30,7 +30,7 @@ function latin1toutf8() local function assert_utf8(latin, utf8) assert_equal(_latin1toutf8(latin), utf8, "Incorrect UTF8 from Latin1: "..tostring(latin)); end - + assert_utf8("", "") assert_utf8("test", "test") assert_utf8(nil, nil) diff --git a/tests/test_util_http.lua b/tests/test_util_http.lua index e68f96e9..a195df6b 100644 --- a/tests/test_util_http.lua +++ b/tests/test_util_http.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tests/test_util_ip.lua b/tests/test_util_ip.lua index 410f1da2..0ded1123 100644 --- a/tests/test_util_ip.lua +++ b/tests/test_util_ip.lua @@ -31,9 +31,9 @@ end function parse_cidr(parse_cidr, _M) local new_ip = _M.new_ip; - + assert_equal(new_ip"0.0.0.0", new_ip"0.0.0.0") - + local function assert_cidr(cidr, ip, bits) local parsed_ip, parsed_bits = parse_cidr(cidr); assert_equal(new_ip(ip), parsed_ip, cidr.." parsed ip is "..ip); diff --git a/tests/test_util_jid.lua b/tests/test_util_jid.lua index a817e644..02a90c3b 100644 --- a/tests/test_util_jid.lua +++ b/tests/test_util_jid.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tests/test_util_multitable.lua b/tests/test_util_multitable.lua index ed10b128..71a83450 100644 --- a/tests/test_util_multitable.lua +++ b/tests/test_util_multitable.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -41,7 +41,7 @@ function get(get, multitable) end mt = multitable.new(); - + local trigger1, trigger2, trigger3 = {}, {}, {}; local item1, item2, item3 = {}, {}, {}; @@ -51,12 +51,12 @@ function get(get, multitable) mt:add(1, 2, 3, item1); assert_has_all("Has item1 for 1, 2, 3", mt:get(1, 2, 3), item1); - + -- Doesn't support nil --[[ mt:add(nil, item1); mt:add(nil, item2); mt:add(nil, item3); - + assert_has_all("Has all items with (nil)", mt:get(nil), item1, item2, item3); ]] end diff --git a/tests/test_util_stanza.lua b/tests/test_util_stanza.lua index fce26f3a..20cc8274 100644 --- a/tests/test_util_stanza.lua +++ b/tests/test_util_stanza.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -18,7 +18,7 @@ end function deserialize(deserialize, st) local stanza = st.stanza("message", { a = "a" }); - + local stanza2 = deserialize(st.preserialize(stanza)); assert_is(stanza2 and stanza.name, "deserialize returns a stanza"); assert_table(stanza2.attr, "Deserialized stanza has attributes"); diff --git a/tests/util/logger.lua b/tests/util/logger.lua index 35facd4e..c133e332 100644 --- a/tests/util/logger.lua +++ b/tests/util/logger.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tools/ejabberd2prosody.lua b/tools/ejabberd2prosody.lua index ff3004c2..0a6736d7 100755 --- a/tools/ejabberd2prosody.lua +++ b/tools/ejabberd2prosody.lua @@ -2,7 +2,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tools/ejabberdsql2prosody.lua b/tools/ejabberdsql2prosody.lua index d80b9e46..930d5a6b 100644 --- a/tools/ejabberdsql2prosody.lua +++ b/tools/ejabberdsql2prosody.lua @@ -2,7 +2,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tools/erlparse.lua b/tools/erlparse.lua index 174585d3..25c38bcf 100644 --- a/tools/erlparse.lua +++ b/tools/erlparse.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tools/jabberd14sql2prosody.lua b/tools/jabberd14sql2prosody.lua index d6a6753f..03376b30 100644 --- a/tools/jabberd14sql2prosody.lua +++ b/tools/jabberd14sql2prosody.lua @@ -5,242 +5,242 @@ do local _parse_sql_actions = { [0] = - 0, 1, 0, 1, 1, 2, 0, 2, 2, 0, 9, 2, 0, 10, 2, 0, 11, 2, 0, 13, - 2, 1, 2, 2, 1, 6, 3, 0, 3, 4, 3, 0, 3, 5, 3, 0, 3, 7, 3, 0, + 0, 1, 0, 1, 1, 2, 0, 2, 2, 0, 9, 2, 0, 10, 2, 0, 11, 2, 0, 13, + 2, 1, 2, 2, 1, 6, 3, 0, 3, 4, 3, 0, 3, 5, 3, 0, 3, 7, 3, 0, 3, 8, 3, 0, 3, 12, 4, 0, 2, 3, 7, 4, 0, 3, 8, 11 }; local _parse_sql_trans_keys = { [0] = - 0, 0, 45, 45, 10, 10, 42, 42, 10, 42, 10, 47, 82, 82, - 69, 69, 65, 65, 84, 84, 69, 69, 32, 32, 68, 84, 65, - 65, 84, 84, 65, 65, 66, 66, 65, 65, 83, 83, 69, 69, - 9, 47, 9, 96, 45, 45, 10, 10, 42, 42, 10, 42, 10, 47, - 10, 96, 10, 96, 9, 47, 9, 59, 45, 45, 10, 10, 42, - 42, 10, 42, 10, 47, 65, 65, 66, 66, 76, 76, 69, 69, - 32, 32, 73, 96, 70, 70, 32, 32, 78, 78, 79, 79, 84, 84, - 32, 32, 69, 69, 88, 88, 73, 73, 83, 83, 84, 84, 83, - 83, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 40, 40, - 10, 10, 32, 41, 32, 32, 75, 96, 69, 69, 89, 89, 32, 32, - 96, 96, 10, 96, 10, 96, 10, 10, 82, 82, 73, 73, 77, - 77, 65, 65, 82, 82, 89, 89, 32, 32, 75, 75, 69, 69, - 89, 89, 32, 32, 78, 78, 73, 73, 81, 81, 85, 85, 69, 69, - 32, 32, 75, 75, 10, 96, 10, 96, 10, 10, 10, 59, 10, - 59, 82, 82, 79, 79, 80, 80, 32, 32, 84, 84, 65, 65, - 66, 66, 76, 76, 69, 69, 32, 32, 73, 73, 70, 70, 32, 32, - 69, 69, 88, 88, 73, 73, 83, 83, 84, 84, 83, 83, 32, - 32, 96, 96, 10, 96, 10, 96, 59, 59, 78, 78, 83, 83, - 69, 69, 82, 82, 84, 84, 32, 32, 73, 73, 78, 78, 84, 84, - 79, 79, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 40, - 86, 10, 41, 32, 32, 86, 86, 65, 65, 76, 76, 85, 85, - 69, 69, 83, 83, 32, 32, 40, 40, 39, 78, 10, 92, 10, 92, - 41, 44, 44, 59, 32, 78, 48, 57, 41, 57, 48, 57, 41, - 57, 85, 85, 76, 76, 76, 76, 34, 116, 79, 79, 67, 67, - 75, 75, 32, 32, 84, 84, 65, 65, 66, 66, 76, 76, 69, 69, - 83, 83, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 87, - 87, 82, 82, 73, 73, 84, 84, 69, 69, 69, 69, 84, 84, - 32, 32, 10, 59, 10, 59, 78, 83, 76, 76, 79, 79, 67, 67, - 75, 75, 32, 32, 84, 84, 65, 65, 66, 66, 76, 76, 69, + 0, 0, 45, 45, 10, 10, 42, 42, 10, 42, 10, 47, 82, 82, + 69, 69, 65, 65, 84, 84, 69, 69, 32, 32, 68, 84, 65, + 65, 84, 84, 65, 65, 66, 66, 65, 65, 83, 83, 69, 69, + 9, 47, 9, 96, 45, 45, 10, 10, 42, 42, 10, 42, 10, 47, + 10, 96, 10, 96, 9, 47, 9, 59, 45, 45, 10, 10, 42, + 42, 10, 42, 10, 47, 65, 65, 66, 66, 76, 76, 69, 69, + 32, 32, 73, 96, 70, 70, 32, 32, 78, 78, 79, 79, 84, 84, + 32, 32, 69, 69, 88, 88, 73, 73, 83, 83, 84, 84, 83, + 83, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 40, 40, + 10, 10, 32, 41, 32, 32, 75, 96, 69, 69, 89, 89, 32, 32, + 96, 96, 10, 96, 10, 96, 10, 10, 82, 82, 73, 73, 77, + 77, 65, 65, 82, 82, 89, 89, 32, 32, 75, 75, 69, 69, + 89, 89, 32, 32, 78, 78, 73, 73, 81, 81, 85, 85, 69, 69, + 32, 32, 75, 75, 10, 96, 10, 96, 10, 10, 10, 59, 10, + 59, 82, 82, 79, 79, 80, 80, 32, 32, 84, 84, 65, 65, + 66, 66, 76, 76, 69, 69, 32, 32, 73, 73, 70, 70, 32, 32, + 69, 69, 88, 88, 73, 73, 83, 83, 84, 84, 83, 83, 32, + 32, 96, 96, 10, 96, 10, 96, 59, 59, 78, 78, 83, 83, + 69, 69, 82, 82, 84, 84, 32, 32, 73, 73, 78, 78, 84, 84, + 79, 79, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 40, + 86, 10, 41, 32, 32, 86, 86, 65, 65, 76, 76, 85, 85, + 69, 69, 83, 83, 32, 32, 40, 40, 39, 78, 10, 92, 10, 92, + 41, 44, 44, 59, 32, 78, 48, 57, 41, 57, 48, 57, 41, + 57, 85, 85, 76, 76, 76, 76, 34, 116, 79, 79, 67, 67, + 75, 75, 32, 32, 84, 84, 65, 65, 66, 66, 76, 76, 69, 69, + 83, 83, 32, 32, 96, 96, 10, 96, 10, 96, 32, 32, 87, + 87, 82, 82, 73, 73, 84, 84, 69, 69, 69, 69, 84, 84, + 32, 32, 10, 59, 10, 59, 78, 83, 76, 76, 79, 79, 67, 67, + 75, 75, 32, 32, 84, 84, 65, 65, 66, 66, 76, 76, 69, 69, 83, 83, 69, 69, 9, 85, 0 }; local _parse_sql_key_spans = { [0] = - 0, 1, 1, 1, 33, 38, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 1, - 39, 88, 1, 1, 1, 33, 38, 87, 87, 39, 51, 1, 1, 1, 33, 38, 1, 1, 1, 1, - 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, - 1, 10, 1, 22, 1, 1, 1, 1, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 50, 50, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 47, 32, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 40, 83, 83, 4, 16, 47, 10, 17, 10, 17, 1, 1, 1, 83, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 33, 38, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 1, + 39, 88, 1, 1, 1, 33, 38, 87, 87, 39, 51, 1, 1, 1, 33, 38, 1, 1, 1, 1, + 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, + 1, 10, 1, 22, 1, 1, 1, 1, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 47, 32, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 40, 83, 83, 4, 16, 47, 10, 17, 10, 17, 1, 1, 1, 83, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 87, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50, 50, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 77 }; local _parse_sql_index_offsets = { [0] = - 0, 0, 2, 4, 6, 40, 79, 81, 83, 85, 87, 89, 91, 109, 111, 113, 115, 117, 119, 121, - 123, 163, 252, 254, 256, 258, 292, 331, 419, 507, 547, 599, 601, 603, 605, 639, 678, 680, 682, 684, - 686, 688, 713, 715, 717, 719, 721, 723, 725, 727, 729, 731, 733, 735, 737, 739, 741, 829, 917, 919, - 921, 923, 934, 936, 959, 961, 963, 965, 967, 1055, 1143, 1145, 1147, 1149, 1151, 1153, 1155, 1157, 1159, 1161, - 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1269, 1357, 1359, 1410, 1461, 1463, 1465, 1467, 1469, 1471, - 1473, 1475, 1477, 1479, 1481, 1483, 1485, 1487, 1489, 1491, 1493, 1495, 1497, 1499, 1501, 1503, 1591, 1679, 1681, 1683, - 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1793, 1881, 1883, 1931, 1964, 1966, 1968, 1970, 1972, - 1974, 1976, 1978, 1980, 1982, 2023, 2107, 2191, 2196, 2213, 2261, 2272, 2290, 2301, 2319, 2321, 2323, 2325, 2409, 2411, - 2413, 2415, 2417, 2419, 2421, 2423, 2425, 2427, 2429, 2431, 2433, 2521, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, + 0, 0, 2, 4, 6, 40, 79, 81, 83, 85, 87, 89, 91, 109, 111, 113, 115, 117, 119, 121, + 123, 163, 252, 254, 256, 258, 292, 331, 419, 507, 547, 599, 601, 603, 605, 639, 678, 680, 682, 684, + 686, 688, 713, 715, 717, 719, 721, 723, 725, 727, 729, 731, 733, 735, 737, 739, 741, 829, 917, 919, + 921, 923, 934, 936, 959, 961, 963, 965, 967, 1055, 1143, 1145, 1147, 1149, 1151, 1153, 1155, 1157, 1159, 1161, + 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1269, 1357, 1359, 1410, 1461, 1463, 1465, 1467, 1469, 1471, + 1473, 1475, 1477, 1479, 1481, 1483, 1485, 1487, 1489, 1491, 1493, 1495, 1497, 1499, 1501, 1503, 1591, 1679, 1681, 1683, + 1685, 1687, 1689, 1691, 1693, 1695, 1697, 1699, 1701, 1703, 1705, 1793, 1881, 1883, 1931, 1964, 1966, 1968, 1970, 1972, + 1974, 1976, 1978, 1980, 1982, 2023, 2107, 2191, 2196, 2213, 2261, 2272, 2290, 2301, 2319, 2321, 2323, 2325, 2409, 2411, + 2413, 2415, 2417, 2419, 2421, 2423, 2425, 2427, 2429, 2431, 2433, 2521, 2609, 2611, 2613, 2615, 2617, 2619, 2621, 2623, 2625, 2627, 2678, 2729, 2736, 2738, 2740, 2742, 2744, 2746, 2748, 2750, 2752, 2754, 2756, 2758, 2760 }; local _parse_sql_indicies = { [0] = - 0, 1, 2, 0, 3, 1, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, - 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 6, 3, 7, - 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, - 1, 21, 1, 22, 23, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, - 1, 25, 1, 22, 23, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, - 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 1, 27, 1, 23, 27, 28, 1, 29, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 30, 28, 29, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 30, 28, 28, 28, 28, 22, 28, 32, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 31, 32, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 33, 31, 34, 35, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 36, 1, 37, 1, 34, 35, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 36, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 38, - 1, 35, 38, 39, 1, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 41, 39, 40, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 41, 39, 39, 39, 39, 34, 39, 42, 1, - 43, 1, 44, 1, 45, 1, 46, 1, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 48, 1, 49, 1, 50, 1, 51, 1, 52, - 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 1, 59, 1, 60, 1, 61, 1, 48, - 1, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 1, 62, 65, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 66, 64, 67, 1, 68, - 1, 69, 1, 70, 1, 1, 1, 1, 1, 1, 1, 1, 71, 1, 72, 1, 73, 1, 1, 1, - 1, 74, 1, 1, 1, 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 76, 1, 77, - 1, 78, 1, 79, 1, 80, 1, 82, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 1, 81, 82, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 83, 81, 69, 83, 84, 1, 85, 1, 86, 1, 87, 1, 88, 1, 89, 1, 90, 1, 91, - 1, 92, 1, 93, 1, 83, 1, 94, 1, 95, 1, 96, 1, 97, 1, 98, 1, 99, 1, 73, - 1, 101, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100, 1, 100, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 104, 102, 105, 83, 106, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 107, 71, 108, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 107, - 71, 109, 1, 110, 1, 111, 1, 112, 1, 113, 1, 114, 1, 115, 1, 116, 1, 117, 1, 118, - 1, 119, 1, 120, 1, 121, 1, 122, 1, 123, 1, 124, 1, 125, 1, 126, 1, 127, 1, 128, - 1, 129, 1, 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 1, 130, 131, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, - 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 132, 130, 6, - 1, 133, 1, 134, 1, 135, 1, 136, 1, 137, 1, 138, 1, 139, 1, 140, 1, 141, 1, 142, - 1, 143, 1, 144, 1, 146, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, - 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, - 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, - 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, - 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 1, 145, 148, 147, 147, 147, 147, 147, 147, - 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, - 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, - 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, - 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 149, - 147, 150, 1, 151, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 152, 1, 153, 151, 151, 151, 151, 151, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, - 151, 151, 154, 151, 155, 1, 152, 1, 156, 1, 157, 1, 158, 1, 159, 1, 160, 1, 161, 1, - 162, 1, 163, 1, 1, 1, 1, 1, 164, 1, 1, 165, 165, 165, 165, 165, 165, 165, 165, 165, - 165, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 166, 1, 168, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 170, 167, 172, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 173, 171, 171, 171, - 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 171, 171, 171, 171, 171, 171, 171, 171, 171, 174, 171, 175, 1, 1, 176, 1, 161, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 177, 1, 178, 1, 1, 1, 1, 1, 1, - 163, 1, 1, 1, 1, 1, 164, 1, 1, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 166, - 1, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 1, 180, 1, 1, 181, 1, 182, 1, 179, - 179, 179, 179, 179, 179, 179, 179, 179, 179, 1, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, - 1, 180, 1, 1, 181, 1, 1, 1, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 1, 184, - 1, 185, 1, 186, 1, 171, 1, 1, 171, 1, 171, 1, 1, 1, 1, 1, 1, 1, 1, 171, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 171, 1, 171, 1, 1, 171, 1, 1, 171, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 171, 1, 1, 1, 171, 1, 171, 1, 187, 1, 188, 1, 189, 1, 190, 1, 191, 1, 192, - 1, 193, 1, 194, 1, 195, 1, 196, 1, 197, 1, 198, 1, 200, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 1, - 199, 200, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, - 199, 199, 199, 199, 199, 199, 199, 201, 199, 202, 1, 203, 1, 204, 1, 205, 1, 206, 1, 132, - 1, 207, 1, 208, 1, 209, 1, 210, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 211, 209, 2, 209, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, - 209, 209, 209, 209, 209, 209, 209, 211, 209, 212, 1, 1, 1, 1, 213, 1, 214, 1, 215, 1, - 216, 1, 217, 1, 218, 1, 219, 1, 220, 1, 221, 1, 222, 1, 223, 1, 132, 1, 127, 1, - 6, 2, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 224, 1, 225, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 226, 227, + 0, 1, 2, 0, 3, 1, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, + 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 6, 3, 7, + 1, 8, 1, 9, 1, 10, 1, 11, 1, 12, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20, + 1, 21, 1, 22, 23, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, + 1, 25, 1, 22, 23, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24, + 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 1, 27, 1, 23, 27, 28, 1, 29, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 30, 28, 29, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 30, 28, 28, 28, 28, 22, 28, 32, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 1, 31, 32, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 33, 31, 34, 35, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 36, 1, 37, 1, 34, 35, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 36, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 38, + 1, 35, 38, 39, 1, 40, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 41, 39, 40, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 41, 39, 39, 39, 39, 34, 39, 42, 1, + 43, 1, 44, 1, 45, 1, 46, 1, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 48, 1, 49, 1, 50, 1, 51, 1, 52, + 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 1, 59, 1, 60, 1, 61, 1, 48, + 1, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 1, 62, 65, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 66, 64, 67, 1, 68, + 1, 69, 1, 70, 1, 1, 1, 1, 1, 1, 1, 1, 71, 1, 72, 1, 73, 1, 1, 1, + 1, 74, 1, 1, 1, 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 76, 1, 77, + 1, 78, 1, 79, 1, 80, 1, 82, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 1, 81, 82, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 83, 81, 69, 83, 84, 1, 85, 1, 86, 1, 87, 1, 88, 1, 89, 1, 90, 1, 91, + 1, 92, 1, 93, 1, 83, 1, 94, 1, 95, 1, 96, 1, 97, 1, 98, 1, 99, 1, 73, + 1, 101, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 1, 100, 103, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 104, 102, 105, 83, 106, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 107, 71, 108, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 107, + 71, 109, 1, 110, 1, 111, 1, 112, 1, 113, 1, 114, 1, 115, 1, 116, 1, 117, 1, 118, + 1, 119, 1, 120, 1, 121, 1, 122, 1, 123, 1, 124, 1, 125, 1, 126, 1, 127, 1, 128, + 1, 129, 1, 131, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 1, 130, 131, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 132, 130, 6, + 1, 133, 1, 134, 1, 135, 1, 136, 1, 137, 1, 138, 1, 139, 1, 140, 1, 141, 1, 142, + 1, 143, 1, 144, 1, 146, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, + 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 1, 145, 148, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 149, + 147, 150, 1, 151, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 152, 1, 153, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 154, 151, 155, 1, 152, 1, 156, 1, 157, 1, 158, 1, 159, 1, 160, 1, 161, 1, + 162, 1, 163, 1, 1, 1, 1, 1, 164, 1, 1, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 166, 1, 168, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 170, 167, 172, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 173, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, + 171, 171, 171, 171, 171, 171, 171, 171, 171, 174, 171, 175, 1, 1, 176, 1, 161, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 177, 1, 178, 1, 1, 1, 1, 1, 1, + 163, 1, 1, 1, 1, 1, 164, 1, 1, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 166, + 1, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 1, 180, 1, 1, 181, 1, 182, 1, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 1, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, + 1, 180, 1, 1, 181, 1, 1, 1, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 1, 184, + 1, 185, 1, 186, 1, 171, 1, 1, 171, 1, 171, 1, 1, 1, 1, 1, 1, 1, 1, 171, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 171, 1, 171, 1, 1, 171, 1, 1, 171, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 171, 1, 1, 1, 171, 1, 171, 1, 187, 1, 188, 1, 189, 1, 190, 1, 191, 1, 192, + 1, 193, 1, 194, 1, 195, 1, 196, 1, 197, 1, 198, 1, 200, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 1, + 199, 200, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 201, 199, 202, 1, 203, 1, 204, 1, 205, 1, 206, 1, 132, + 1, 207, 1, 208, 1, 209, 1, 210, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 211, 209, 2, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 211, 209, 212, 1, 1, 1, 1, 213, 1, 214, 1, 215, 1, + 216, 1, 217, 1, 218, 1, 219, 1, 220, 1, 221, 1, 222, 1, 223, 1, 132, 1, 127, 1, + 6, 2, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 224, 1, 225, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 226, 227, 1, 1, 1, 1, 228, 1, 1, 229, 1, 1, 1, 1, 1, 1, 230, 1, 231, 1, 0 }; local _parse_sql_trans_targs = { [0] = - 2, 0, 196, 4, 4, 5, 196, 7, 8, 9, 10, 11, 12, 13, 36, 14, 15, 16, 17, 18, - 19, 20, 21, 21, 22, 24, 27, 23, 25, 25, 26, 28, 28, 29, 30, 30, 31, 33, 32, 34, - 34, 35, 37, 38, 39, 40, 41, 42, 56, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 57, 57, 57, 57, 58, 59, 60, 61, 62, 92, 63, 64, 71, 82, 89, 65, 66, 67, - 68, 69, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, - 90, 90, 90, 90, 91, 70, 92, 93, 196, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 116, 117, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 131, 131, 131, 132, 133, 134, 137, 134, 135, 136, 138, 139, 140, 141, - 142, 143, 144, 145, 150, 151, 154, 146, 146, 147, 157, 146, 146, 147, 157, 148, 149, 196, 144, 151, - 148, 149, 152, 153, 155, 156, 147, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 171, 172, 173, 174, 175, 176, 177, 179, 180, 181, 181, 182, 184, 195, 185, 186, 187, 188, 189, 190, + 2, 0, 196, 4, 4, 5, 196, 7, 8, 9, 10, 11, 12, 13, 36, 14, 15, 16, 17, 18, + 19, 20, 21, 21, 22, 24, 27, 23, 25, 25, 26, 28, 28, 29, 30, 30, 31, 33, 32, 34, + 34, 35, 37, 38, 39, 40, 41, 42, 56, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 57, 57, 57, 57, 58, 59, 60, 61, 62, 92, 63, 64, 71, 82, 89, 65, 66, 67, + 68, 69, 69, 70, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, + 90, 90, 90, 90, 91, 70, 92, 93, 196, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 116, 117, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 131, 131, 131, 132, 133, 134, 137, 134, 135, 136, 138, 139, 140, 141, + 142, 143, 144, 145, 150, 151, 154, 146, 146, 147, 157, 146, 146, 147, 157, 148, 149, 196, 144, 151, + 148, 149, 152, 153, 155, 156, 147, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 171, 172, 173, 174, 175, 176, 177, 179, 180, 181, 181, 182, 184, 195, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 1, 3, 6, 94, 118, 158, 178, 183 }; local _parse_sql_trans_actions = { [0] = - 1, 0, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 5, 20, 1, 3, 30, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 5, 20, 1, 3, 26, 3, 3, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 5, 20, 1, 3, 42, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 11, 1, 5, 5, 1, 5, 20, 46, 5, 1, 3, 34, 1, 14, 1, 17, 1, 1, - 51, 38, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 1, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 5, 20, 1, 3, 30, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 5, 20, 1, 3, 26, 3, 3, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5, 20, 1, 3, 42, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 11, 1, 5, 5, 1, 5, 20, 46, 5, 1, 3, 34, 1, 14, 1, 17, 1, 1, + 51, 38, 1, 1, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -277,7 +277,7 @@ function parse_sql(data, h) local mark, token; local table_name, columns, value_lists, value_list, value_count; - + cs = parse_sql_start; -- ragel flat exec @@ -322,10 +322,10 @@ function parse_sql(data, h) _inds = _parse_sql_index_offsets[cs]; _slen = _parse_sql_key_spans[cs]; - if _slen > 0 and - _parse_sql_trans_keys[_keys] <= data:byte(p) and - data:byte(p) <= _parse_sql_trans_keys[_keys + 1] then - _trans = _parse_sql_indicies[ _inds + data:byte(p) - _parse_sql_trans_keys[_keys] ]; + if _slen > 0 and + _parse_sql_trans_keys[_keys] <= data:byte(p) and + data:byte(p) <= _parse_sql_trans_keys[_keys + 1] then + _trans = _parse_sql_indicies[ _inds + data:byte(p) - _parse_sql_trans_keys[_keys] ]; else _trans =_parse_sql_indicies[ _inds + _slen ]; end cs = _parse_sql_trans_targs[_trans]; @@ -364,7 +364,7 @@ function parse_sql(data, h) h.create(table_name, columns); -- ACTION elseif _tempval == 7 then --4 FROM_STATE_ACTION_SWITCH -- line 65 "sql.rl" -- end of line directive - + value_count = value_count + 1; value_list[value_count] = token:gsub("\\.", _sql_unescapes); -- ACTION elseif _tempval == 8 then --4 FROM_STATE_ACTION_SWITCH @@ -392,7 +392,7 @@ function parse_sql(data, h) end if _trigger_goto then _continue = true; break; end - end -- endif + end -- endif if _goto_level <= _again then if cs == 0 then diff --git a/tools/migration/migrator/prosody_sql.lua b/tools/migration/migrator/prosody_sql.lua index 27b5835e..180ae910 100644 --- a/tools/migration/migrator/prosody_sql.lua +++ b/tools/migration/migrator/prosody_sql.lua @@ -24,7 +24,7 @@ local function create_table(connection, params) elseif params.driver == "MySQL" then create_sql = create_sql:gsub("`value` TEXT", "`value` MEDIUMTEXT"); end - + local stmt = connection:prepare(create_sql); if stmt then local ok = stmt:execute(); diff --git a/tools/migration/prosody-migrator.lua b/tools/migration/prosody-migrator.lua index 7c933b88..b86e9892 100644 --- a/tools/migration/prosody-migrator.lua +++ b/tools/migration/prosody-migrator.lua @@ -115,7 +115,7 @@ if have_err then print(""); os.exit(1); end - + local itype = config[from_store].type; local otype = config[to_store].type; local reader = require("migrator."..itype).reader(config[from_store]); diff --git a/tools/openfire2prosody.lua b/tools/openfire2prosody.lua index 5ef47602..cd3e62e5 100644 --- a/tools/openfire2prosody.lua +++ b/tools/openfire2prosody.lua @@ -1,7 +1,7 @@ #!/usr/bin/env lua -- Prosody IM -- Copyright (C) 2008-2009 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/tools/xep227toprosody.lua b/tools/xep227toprosody.lua index 0862b0c1..e95a9d59 100755 --- a/tools/xep227toprosody.lua +++ b/tools/xep227toprosody.lua @@ -3,7 +3,7 @@ -- Copyright (C) 2008-2009 Matthew Wild -- Copyright (C) 2008-2009 Waqas Hussain -- Copyright (C) 2010 Stefan Gehn --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/array.lua b/util/array.lua index 2d58e7fb..9bf215af 100644 --- a/util/array.lua +++ b/util/array.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -59,13 +59,13 @@ function array_base.filter(outa, ina, func) write = write + 1; end end - + if inplace and write <= start_length then for i=write,start_length do outa[i] = nil; end end - + return outa; end diff --git a/util/caps.lua b/util/caps.lua index a61e7403..4723b912 100644 --- a/util/caps.lua +++ b/util/caps.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/dataforms.lua b/util/dataforms.lua index 52924841..b38d0e27 100644 --- a/util/dataforms.lua +++ b/util/dataforms.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -38,7 +38,7 @@ function form_t.form(layout, data, formtype) form:tag("field", { type = field_type, var = field.name, label = field.label }); local value = (data and data[field.name]) or field.value; - + if value then -- Add value, depending on type if field_type == "hidden" then @@ -93,11 +93,11 @@ function form_t.form(layout, data, formtype) end end end - + if field.required then form:tag("required"):up(); end - + -- Jump back up to list of fields form:up(); end diff --git a/util/datetime.lua b/util/datetime.lua index a1f62a48..dd596527 100644 --- a/util/datetime.lua +++ b/util/datetime.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/debug.lua b/util/debug.lua index bff0e347..1f1ec9df 100644 --- a/util/debug.lua +++ b/util/debug.lua @@ -93,14 +93,14 @@ function get_traceback_table(thread, start_level) info = debug.getinfo(level+1); end if not info then break; end - + levels[(level-start_level)+1] = { level = level; info = info; locals = get_locals_table(level+1); upvalues = get_upvalues_table(info.func); }; - end + end return levels; end @@ -137,12 +137,12 @@ function _traceback(thread, message, level) level = level or 1; message = message and (message.."\n") or ""; - + -- +3 counts for this function, and the pcall() and wrapper above us local levels = get_traceback_table(thread, level+3); - + local last_source_desc; - + local lines = {}; for nlevel, level in ipairs(levels) do local info = level.info; diff --git a/util/dependencies.lua b/util/dependencies.lua index 53d2719d..109a3332 100644 --- a/util/dependencies.lua +++ b/util/dependencies.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -35,7 +35,7 @@ function missingdep(name, sources, msg) print(""); end --- COMPAT w/pre-0.8 Debian: The Debian config file used to use +-- COMPAT w/pre-0.8 Debian: The Debian config file used to use -- util.ztact, which has been removed from Prosody in 0.8. This -- is to log an error for people who still use it, so they can -- update their configs. @@ -50,9 +50,9 @@ end; function check_dependencies() local fatal; - + local lxp = softreq "lxp" - + if not lxp then missingdep("luaexpat", { ["Debian/Ubuntu"] = "sudo apt-get install liblua5.1-expat0"; @@ -61,9 +61,9 @@ function check_dependencies() }); fatal = true; end - + local socket = softreq "socket" - + if not socket then missingdep("luasocket", { ["Debian/Ubuntu"] = "sudo apt-get install liblua5.1-socket2"; @@ -72,7 +72,7 @@ function check_dependencies() }); fatal = true; end - + local lfs, err = softreq "lfs" if not lfs then missingdep("luafilesystem", { @@ -82,9 +82,9 @@ function check_dependencies() }); fatal = true; end - + local ssl = softreq "ssl" - + if not ssl then missingdep("LuaSec", { ["Debian/Ubuntu"] = "http://prosody.im/download/start#debian_and_ubuntu"; @@ -92,7 +92,7 @@ function check_dependencies() ["Source"] = "http://www.inf.puc-rio.br/~brunoos/luasec/"; }, "SSL/TLS support will not be available"); end - + local encodings, err = softreq "util.encodings" if not encodings then if err:match("not found") then diff --git a/util/events.lua b/util/events.lua index 4ace026f..40ca3913 100644 --- a/util/events.lua +++ b/util/events.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/filters.lua b/util/filters.lua index d143666b..8a470011 100644 --- a/util/filters.lua +++ b/util/filters.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -16,7 +16,7 @@ function initialize(session) if not session.filters then local filters = {}; session.filters = filters; - + function session.filter(type, data) local filter_list = filters[type]; if filter_list then @@ -28,11 +28,11 @@ function initialize(session) return data; end end - + for i=1,#new_filter_hooks do new_filter_hooks[i](session); end - + return session.filter; end @@ -40,20 +40,20 @@ function add_filter(session, type, callback, priority) if not session.filters then initialize(session); end - + local filter_list = session.filters[type]; if not filter_list then filter_list = {}; session.filters[type] = filter_list; end - + priority = priority or 0; - + local i = 0; repeat i = i + 1; until not filter_list[i] or filter_list[filter_list[i]] >= priority; - + t_insert(filter_list, i, callback); filter_list[callback] = priority; end diff --git a/util/helpers.lua b/util/helpers.lua index 08b86a7c..437a920c 100644 --- a/util/helpers.lua +++ b/util/helpers.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/hmac.lua b/util/hmac.lua index 51211c7a..2c4cc6ef 100644 --- a/util/hmac.lua +++ b/util/hmac.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/import.lua b/util/import.lua index 81401e8b..174da0ca 100644 --- a/util/import.lua +++ b/util/import.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/ip.lua b/util/ip.lua index 62649c9b..d0ae07eb 100644 --- a/util/ip.lua +++ b/util/ip.lua @@ -92,7 +92,7 @@ local function v6scope(ip) if ip:match("^[0:]*1$") then return 0x2; -- Link-local unicast: - elseif ip:match("^[Ff][Ee][89ABab]") then + elseif ip:match("^[Ff][Ee][89ABab]") then return 0x2; -- Site-local unicast: elseif ip:match("^[Ff][Ee][CcDdEeFf]") then diff --git a/util/iterators.lua b/util/iterators.lua index 4b429163..aa9c3ec0 100644 --- a/util/iterators.lua +++ b/util/iterators.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -25,7 +25,7 @@ function it.reverse(f, s, var) if var == nil then break; end t_insert(results, 1, ret); end - + -- Then return our reverse one local i,max = 0, #results; return function (results) @@ -56,7 +56,7 @@ end -- Given an iterator, iterate only over unique items function it.unique(f, s, var) local set = {}; - + return function () while true do local ret = pack(f(s, var)); @@ -73,13 +73,13 @@ end --[[ Return the number of items an iterator returns ]]-- function it.count(f, s, var) local x = 0; - + while true do var = f(s, var); if var == nil then break; end x = x + 1; end - + return x; end diff --git a/util/jid.lua b/util/jid.lua index 4c4371d8..0d9a864f 100644 --- a/util/jid.lua +++ b/util/jid.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/json.lua b/util/json.lua index 82ebcc43..a8a58afc 100644 --- a/util/json.lua +++ b/util/json.lua @@ -348,9 +348,9 @@ local first_escape = { function json.decode(json) json = json:gsub("\\.", first_escape) -- get rid of all escapes except \uXXXX, making string parsing much simpler --:gsub("[\r\n]", "\t"); -- \r\n\t are equivalent, we care about none of them, and none of them can be in strings - + -- TODO do encoding verification - + local val, index = _readvalue(json, 1); if val == nil then return val, index; end if json:find("[^ \t\r\n]", index) then return nil, "garbage at eof"; end diff --git a/util/logger.lua b/util/logger.lua index 26206d4d..cd0769f9 100644 --- a/util/logger.lua +++ b/util/logger.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/multitable.lua b/util/multitable.lua index dbf34d28..caf25118 100644 --- a/util/multitable.lua +++ b/util/multitable.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/pluginloader.lua b/util/pluginloader.lua index c10fdf65..b894f527 100644 --- a/util/pluginloader.lua +++ b/util/pluginloader.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua index b80a69f2..fe862114 100644 --- a/util/prosodyctl.lua +++ b/util/prosodyctl.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -146,7 +146,7 @@ function adduser(params) if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end - + local ok, errmsg = usermanager.create_user(user, password, host); if not ok then return false, errmsg; @@ -162,7 +162,7 @@ function user_exists(params) if not(provider) or provider.name == "null" then usermanager.initialize_host(host); end - + return usermanager.user_exists(user, host); end @@ -170,7 +170,7 @@ function passwd(params) if not _M.user_exists(params) then return false, "no-such-user"; end - + return _M.adduser(params); end @@ -179,7 +179,7 @@ function deluser(params) return false, "no-such-user"; end local user, host = nodeprep(params.user), nameprep(params.host); - + return usermanager.delete_user(user, host); end @@ -188,30 +188,30 @@ function getpid() if not pidfile then return false, "no-pidfile"; end - + local modules_enabled = set.new(config.get("*", "modules_enabled")); if not modules_enabled:contains("posix") then return false, "no-posix"; end - + local file, err = io.open(pidfile, "r+"); if not file then return false, "pidfile-read-failed", err; end - + local locked, err = lfs.lock(file, "w"); if locked then file:close(); return false, "pidfile-not-locked"; end - + local pid = tonumber(file:read("*a")); file:close(); - + if not pid then return false, "invalid-pid"; end - + return true, pid; end @@ -252,10 +252,10 @@ function stop() if not ret then return false, "not-running"; end - + local ok, pid = _M.getpid() if not ok then return false, pid; end - + signal.kill(pid, signal.SIGTERM); return true; end @@ -268,10 +268,10 @@ function reload() if not ret then return false, "not-running"; end - + local ok, pid = _M.getpid() if not ok then return false, pid; end - + signal.kill(pid, signal.SIGHUP); return true; end diff --git a/util/pubsub.lua b/util/pubsub.lua index e1418c62..0dfd196b 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -29,13 +29,13 @@ end function service:may(node, actor, action) if actor == true then return true; end - + local node_obj = self.nodes[node]; local node_aff = node_obj and node_obj.affiliations[actor]; local service_aff = self.affiliations[actor] or self.config.get_affiliation(actor, node, action) or "none"; - + -- Check if node allows/forbids it local node_capabilities = node_obj and node_obj.capabilities; if node_capabilities then @@ -47,7 +47,7 @@ function service:may(node, actor, action) end end end - + -- Check service-wide capabilities instead local service_capabilities = self.config.capabilities; local caps = service_capabilities[node_aff or service_aff]; @@ -57,7 +57,7 @@ function service:may(node, actor, action) return can; end end - + return false; end @@ -211,7 +211,7 @@ function service:create(node, actor) if self.nodes[node] then return false, "conflict"; end - + self.nodes[node] = { name = node; subscribers = {}; diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index cf2f0ede..31c078a0 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -73,11 +73,11 @@ local function validate_username(username, _nodeprep) return false end end - + -- replace =2C with , and =3D with = username = username:gsub("=2C", ","); username = username:gsub("=3D", "="); - + -- apply SASLprep username = saslprep(username); @@ -108,12 +108,12 @@ 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 - + if type(message) ~= "string" or #message == 0 then return "failure", "malformed-request" end if not self.state.name then -- we are processing client_first_message local client_first_message = message; - + -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; self.state["gs2_cbind_flag"], self.state["authzid"], self.state["name"], self.state["clientnonce"] @@ -127,21 +127,21 @@ local function scram_gen(hash_name, H_f, HMAC_f) if not self.state.name or not self.state.clientnonce then return "failure", "malformed-request", "Channel binding isn't support at this time."; end - + self.state.name = validate_username(self.state.name, self.profile.nodeprep); 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, 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."); @@ -161,22 +161,22 @@ local function scram_gen(hash_name, H_f, HMAC_f) local stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self, self.state.name, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end - + self.state.stored_key = stored_key; self.state.server_key = server_key; self.state.iteration_count = iteration_count; self.state.salt = salt end - + 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 -- we are processing client_final_message local client_final_message = message; - + self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); - + 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 @@ -184,10 +184,10 @@ local function scram_gen(hash_name, H_f, HMAC_f) if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then return "failure", "malformed-request", "Wrong nonce in client-final-message."; end - + local ServerKey = self.state.server_key; local StoredKey = self.state.stored_key; - + 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 ClientKey = binaryXOR(ClientSignature, base64.decode(self.state.proof)) diff --git a/util/sasl_cyrus.lua b/util/sasl_cyrus.lua index 19684587..a0e8bd69 100644 --- a/util/sasl_cyrus.lua +++ b/util/sasl_cyrus.lua @@ -78,10 +78,10 @@ local function init(service_name) end -- create a new SASL object which can be used to authenticate clients --- host_fqdn may be nil in which case gethostname() gives the value. +-- host_fqdn may be nil in which case gethostname() gives the value. -- For GSSAPI, this determines the hostname in the service ticket (after -- reverse DNS canonicalization, only if [libdefaults] rdns = true which --- is the default). +-- is the default). function new(realm, service_name, app_name, host_fqdn) init(app_name or service_name); diff --git a/util/serialization.lua b/util/serialization.lua index 8a259184..06e45054 100644 --- a/util/serialization.lua +++ b/util/serialization.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/set.lua b/util/set.lua index 7f45526e..e9dfec1b 100644 --- a/util/set.lua +++ b/util/set.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -40,13 +40,13 @@ function set_mt.__eq(set1, set2) return false; end end - + for item in pairs(set2) do if not set1[item] then return false; end end - + return true; end function set_mt.__tostring(set) @@ -65,23 +65,23 @@ end function new(list) local items = setmetatable({}, items_mt); local set = { _items = items }; - + function set:add(item) items[item] = true; end - + function set:contains(item) return items[item]; end - + function set:items() return items; end - + function set:remove(item) items[item] = nil; end - + function set:add_list(list) if list then for _, item in ipairs(list) do @@ -89,7 +89,7 @@ function new(list) end end end - + function set:include(otherset) for item in pairs(otherset) do items[item] = true; @@ -101,22 +101,22 @@ function new(list) items[item] = nil; end end - + function set:empty() return not next(items); end - + if list then set:add_list(list); end - + return setmetatable(set, set_mt); end function union(set1, set2) local set = new(); local items = set._items; - + for item in pairs(set1._items) do items[item] = true; end @@ -124,14 +124,14 @@ function union(set1, set2) for item in pairs(set2._items) do items[item] = true; end - + return set; end function difference(set1, set2) local set = new(); local items = set._items; - + for item in pairs(set1._items) do items[item] = (not set2._items[item]) or nil; end @@ -142,13 +142,13 @@ end function intersection(set1, set2) local set = new(); local items = set._items; - + set1, set2 = set1._items, set2._items; - + for item in pairs(set1) do items[item] = (not not set2[item]) or nil; end - + return set; end diff --git a/util/sql.lua b/util/sql.lua index 63c399ff..b8c16e27 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -45,7 +45,7 @@ function String(n) return "String()" end }; local functions = { - + }; local cmap = { diff --git a/util/stanza.lua b/util/stanza.lua index 7c214210..82601e63 100644 --- a/util/stanza.lua +++ b/util/stanza.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -99,7 +99,7 @@ function stanza_mt:get_child(name, xmlns) if (not name or child.name == name) and ((not xmlns and self.attr.xmlns == child.attr.xmlns) or child.attr.xmlns == xmlns) then - + return child; end end @@ -152,7 +152,7 @@ end function stanza_mt:maptags(callback) local tags, curr_tag = self.tags, 1; local n_children, n_tags = #self, #tags; - + local i = 1; while curr_tag <= n_tags and n_tags > 0 do if self[i] == tags[curr_tag] then @@ -258,13 +258,13 @@ end function stanza_mt.get_error(stanza) local type, condition, text; - + local error_tag = stanza:get_child("error"); if not error_tag then return nil, nil, nil; end type = error_tag.attr.type; - + for _, child in ipairs(error_tag.tags) do if child.attr.xmlns == xmlns_stanzas then if not text and child.name == "text" then @@ -333,7 +333,7 @@ function deserialize(stanza) stanza.tags = tags; end end - + return stanza; end @@ -390,7 +390,7 @@ if do_pretty_printing then local style_attrv = getstyle("red"); local style_tagname = getstyle("red"); local style_punc = getstyle("magenta"); - + local attr_format = " "..getstring(style_attrk, "%s")..getstring(style_punc, "=")..getstring(style_attrv, "'%s'"); local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">"); --local tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">").."%s"..getstring(style_punc, ""); @@ -411,7 +411,7 @@ if do_pretty_printing then end return s_format(tag_format, t.name, attr_string, children_text, t.name); end - + function stanza_mt.pretty_top_tag(t) local attr_string = ""; if t.attr then diff --git a/util/termcolours.lua b/util/termcolours.lua index 6ef3b689..ef978364 100644 --- a/util/termcolours.lua +++ b/util/termcolours.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/timer.lua b/util/timer.lua index af1e57b6..0e10e144 100644 --- a/util/timer.lua +++ b/util/timer.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -42,7 +42,7 @@ if not server.event then end new_data = {}; end - + local next_time = math_huge; for i, d in pairs(data) do local t, callback = d[1], d[2]; diff --git a/util/uuid.lua b/util/uuid.lua index 796c8ee4..fc487c72 100644 --- a/util/uuid.lua +++ b/util/uuid.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- diff --git a/util/xml.lua b/util/xml.lua index 076490fa..6dbed65d 100644 --- a/util/xml.lua +++ b/util/xml.lua @@ -26,8 +26,8 @@ local parse_xml = (function() attr[i] = nil; local ns, nm = k:match(ns_pattern); if nm ~= "" then - ns = ns_prefixes[ns]; - if ns then + ns = ns_prefixes[ns]; + if ns then attr[ns..":"..nm] = attr[k]; attr[k] = nil; end diff --git a/util/xmppstream.lua b/util/xmppstream.lua index 4909678c..550170c9 100644 --- a/util/xmppstream.lua +++ b/util/xmppstream.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -42,21 +42,21 @@ _M.ns_pattern = ns_pattern; function new_sax_handlers(session, stream_callbacks) local xml_handlers = {}; - + local cb_streamopened = stream_callbacks.streamopened; local cb_streamclosed = stream_callbacks.streamclosed; local cb_error = stream_callbacks.error or function(session, e, stanza) error("XML stream error: "..tostring(e)..(stanza and ": "..tostring(stanza) or ""),2); end; local cb_handlestanza = stream_callbacks.handlestanza; - + local stream_ns = stream_callbacks.stream_ns or xmlns_streams; local stream_tag = stream_callbacks.stream_tag or "stream"; if stream_ns ~= "" then stream_tag = stream_ns..ns_separator..stream_tag; end local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error"); - + local stream_default_ns = stream_callbacks.default_ns; - + local stack = {}; local chardata, stanza = {}; local non_streamns_depth = 0; @@ -75,7 +75,7 @@ function new_sax_handlers(session, stream_callbacks) attr.xmlns = curr_ns; non_streamns_depth = non_streamns_depth + 1; end - + for i=1,#attr do local k = attr[i]; attr[i] = nil; @@ -85,7 +85,7 @@ function new_sax_handlers(session, stream_callbacks) attr[k] = nil; end end - + if not stanza then --if we are not currently inside a stanza if session.notopen then if tagname == stream_tag then @@ -102,7 +102,7 @@ function new_sax_handlers(session, stream_callbacks) if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then cb_error(session, "invalid-top-level-element"); end - + stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt); else -- we are inside a stanza, so add a tag t_insert(stack, stanza); @@ -151,22 +151,22 @@ function new_sax_handlers(session, stream_callbacks) error("Failed to abort parsing"); end end - + if lxp_supports_doctype then xml_handlers.StartDoctypeDecl = restricted_handler; end xml_handlers.Comment = restricted_handler; xml_handlers.ProcessingInstruction = restricted_handler; - + local function reset() stanza, chardata = nil, {}; stack = {}; end - + local function set_session(stream, new_session) session = new_session; end - + return xml_handlers, { reset = reset, set_session = set_session }; end -- cgit v1.2.3 From e350fb8478bc304f4ca1ea1e29829b6d37066cb6 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 19:02:52 +0200 Subject: util.pposix: Fix overflow in rlimit argument conversion (thanks gcc, now be quiet please) --- util-src/pposix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-src/pposix.c b/util-src/pposix.c index c0d1f5a2..2e1de971 100644 --- a/util-src/pposix.c +++ b/util-src/pposix.c @@ -491,7 +491,7 @@ int string2resource(const char *s) { return -1; } -int arg_to_rlimit(lua_State* L, int idx, rlim_t current) { +unsigned long int arg_to_rlimit(lua_State* L, int idx, rlim_t current) { switch(lua_type(L, idx)) { case LUA_TSTRING: if(strcmp(lua_tostring(L, idx), "unlimited") == 0) -- cgit v1.2.3 From 8717f83b219e6d1d7d5624c304e4808e5c43e00c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 19:53:22 +0200 Subject: mod_dialback: Change level of some log statements to be more appropriate --- plugins/mod_dialback.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index afee9d58..8d2bbd8f 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -26,7 +26,7 @@ function initiate_dialback(session) -- generate dialback key session.dialback_key = generate_dialback(session.streamid, session.to_host, session.from_host); session.sends2s(st.stanza("db:result", { from = session.from_host, to = session.to_host }):text(session.dialback_key)); - session.log("info", "sent dialback key on outgoing s2s stream"); + session.log("debug", "sent dialback key on outgoing s2s stream"); end function verify_dialback(id, to, from, key) @@ -71,7 +71,7 @@ module:hook("stanza/jabber:server:dialback:result", function(event) if not hosts[to] then -- Not a host that we serve - origin.log("info", "%s tried to connect to %s, which we don't serve", from, to); + origin.log("warn", "%s tried to connect to %s, which we don't serve", from, to); origin:close("host-unknown"); return true; elseif not from then -- cgit v1.2.3 From 5dc7169a08a3261e176b60844a6024994cb4d06a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:06:51 +0200 Subject: mod_auth_internal_plain: Remove redundant hostname from log messages --- plugins/mod_auth_internal_plain.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua index 4d698fa0..b2c8cb2b 100644 --- a/plugins/mod_auth_internal_plain.lua +++ b/plugins/mod_auth_internal_plain.lua @@ -19,7 +19,7 @@ local provider = {}; log("debug", "initializing internal_plain authentication provider for host '%s'", host); function provider.test_password(username, password) - log("debug", "test password for user %s at host %s", username, host); + log("debug", "test password for user '%s'", username); local credentials = accounts:get(username) or {}; if password == credentials.password then @@ -30,7 +30,7 @@ function provider.test_password(username, password) end function provider.get_password(username) - log("debug", "get_password for username '%s' at host '%s'", username, host); + log("debug", "get_password for username '%s'", username); return (accounts:get(username) or {}).password; end @@ -46,7 +46,7 @@ end function provider.user_exists(username) local account = accounts:get(username); if not account then - log("debug", "account not found for username '%s' at host '%s'", username, host); + log("debug", "account not found for username '%s'", username); return nil, "Auth failed. Invalid username"; end return true; -- cgit v1.2.3 From 692e6d1221927c370fae7d3885ac543d877f0e3d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:09:33 +0200 Subject: mod_auth_internal_plain: Log a debug message when changing password to be consistent with the other methods --- plugins/mod_auth_internal_plain.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua index b2c8cb2b..2e231065 100644 --- a/plugins/mod_auth_internal_plain.lua +++ b/plugins/mod_auth_internal_plain.lua @@ -35,6 +35,7 @@ function provider.get_password(username) end function provider.set_password(username, password) + log("debug", "set_password for username '%s'", username); local account = accounts:get(username); if account then account.password = password; -- cgit v1.2.3 From 69adf36132dde074c9d8115350453524118f447e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:10:30 +0200 Subject: mod_auth_internal_plain: Remove "initializing" log message, hostmanager logs this too --- plugins/mod_auth_internal_plain.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_auth_internal_plain.lua b/plugins/mod_auth_internal_plain.lua index 2e231065..db528432 100644 --- a/plugins/mod_auth_internal_plain.lua +++ b/plugins/mod_auth_internal_plain.lua @@ -16,7 +16,6 @@ local accounts = module:open_store("accounts"); -- define auth provider local provider = {}; -log("debug", "initializing internal_plain authentication provider for host '%s'", host); function provider.test_password(username, password) log("debug", "test password for user '%s'", username); -- cgit v1.2.3 From 6ee727dd250678445982e8f07400fd395e44f801 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:15:25 +0200 Subject: mod_auth_internal_hashed: Remove this 'initializing' message too --- plugins/mod_auth_internal_hashed.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 57396731..8a1c2b3e 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -42,7 +42,6 @@ local iteration_count = 4096; local host = module.host; -- define auth provider local provider = {}; -log("debug", "initializing internal_hashed authentication provider for host '%s'", host); function provider.test_password(username, password) local credentials = accounts:get(username) or {}; -- cgit v1.2.3 From 31c364ad7f4dccfba397d280e9c28d27fda4ee61 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:17:45 +0200 Subject: mod_auth_internal_hashed: Use logger setup by moduleapi instead of going for util.logger directly --- plugins/mod_auth_internal_hashed.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index 8a1c2b3e..ff0c7631 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -7,12 +7,13 @@ -- COPYING file in the source package for more information. -- -local log = require "util.logger".init("auth_internal_hashed"); local getAuthenticationDatabaseSHA1 = require "util.sasl.scram".getAuthenticationDatabaseSHA1; local usermanager = require "core.usermanager"; local generate_uuid = require "util.uuid".generate; local new_sasl = require "util.sasl".new; +local log = module._log; + local accounts = module:open_store("accounts"); local to_hex; -- cgit v1.2.3 From a10c051fb26431f23f4086b8b20b02e32482b389 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Aug 2013 20:19:40 +0200 Subject: mod_auth_internal_hashed: Log calls to provider methods and be consistent with mod_auth_internal_plain --- plugins/mod_auth_internal_hashed.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index ff0c7631..fb87bb9f 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -13,6 +13,7 @@ local generate_uuid = require "util.uuid".generate; local new_sasl = require "util.sasl".new; local log = module._log; +local host = module.host; local accounts = module:open_store("accounts"); @@ -40,11 +41,11 @@ end -- Default; can be set per-user local iteration_count = 4096; -local host = module.host; -- define auth provider local provider = {}; function provider.test_password(username, password) + log("debug", "test password for user '%s'", username); local credentials = accounts:get(username) or {}; if credentials.password ~= nil and string.len(credentials.password) ~= 0 then @@ -76,6 +77,7 @@ function provider.test_password(username, password) end function provider.set_password(username, password) + log("debug", "set_password for username '%s'", username); local account = accounts:get(username); if account then account.salt = account.salt or generate_uuid(); @@ -96,7 +98,7 @@ end function provider.user_exists(username) local account = accounts:get(username); if not account then - log("debug", "account not found for username '%s' at host '%s'", username, host); + log("debug", "account not found for username '%s'", username); return nil, "Auth failed. Invalid username"; end return true; -- cgit v1.2.3 From 51549fe050a1aec00284d1e2599c93010bc763c2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 10 Aug 2013 20:30:40 +0100 Subject: util.debug: Fixes to make coroutine tracebacks work properly --- util/debug.lua | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/util/debug.lua b/util/debug.lua index 1f1ec9df..52ba52d0 100644 --- a/util/debug.lua +++ b/util/debug.lua @@ -88,7 +88,7 @@ function get_traceback_table(thread, start_level) for level = start_level, math.huge do local info; if thread then - info = debug.getinfo(thread, level+1); + info = debug.getinfo(thread, level); else info = debug.getinfo(level+1); end @@ -97,7 +97,7 @@ function get_traceback_table(thread, start_level) levels[(level-start_level)+1] = { level = level; info = info; - locals = get_locals_table(level+1); + locals = not thread and get_locals_table(level+1); upvalues = get_upvalues_table(info.func); }; end @@ -134,12 +134,12 @@ function _traceback(thread, message, level) return nil; -- debug.traceback() does this end - level = level or 1; + level = level or 0; message = message and (message.."\n") or ""; - -- +3 counts for this function, and the pcall() and wrapper above us - local levels = get_traceback_table(thread, level+3); + -- +3 counts for this function, and the pcall() and wrapper above us, the +1... I don't know. + local levels = get_traceback_table(thread, level+(thread == nil and 4 or 0)); local last_source_desc; @@ -171,9 +171,11 @@ function _traceback(thread, message, level) nlevel = nlevel-1; table.insert(lines, "\t"..(nlevel==0 and ">" or " ")..getstring(styles.level_num, "("..nlevel..") ")..line); local npadding = (" "):rep(#tostring(nlevel)); - local locals_str = string_from_var_table(level.locals, optimal_line_length, "\t "..npadding); - if locals_str then - table.insert(lines, "\t "..npadding.."Locals: "..locals_str); + if level.locals then + local locals_str = string_from_var_table(level.locals, optimal_line_length, "\t "..npadding); + if locals_str then + table.insert(lines, "\t "..npadding.."Locals: "..locals_str); + end end local upvalues_str = string_from_var_table(level.upvalues, optimal_line_length, "\t "..npadding); if upvalues_str then -- cgit v1.2.3 From 6cd5b48d8f0643d6e0e6d27b20099f5a9c410317 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 10 Aug 2013 20:40:45 +0100 Subject: util.debug: Further fix to display locals in extended tracebacks --- util/debug.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util/debug.lua b/util/debug.lua index 52ba52d0..417359f8 100644 --- a/util/debug.lua +++ b/util/debug.lua @@ -24,11 +24,13 @@ do end module("debugx", package.seeall); -function get_locals_table(level) - level = level + 1; -- Skip this function itself +function get_locals_table(thread, level) + if not thread then + level = level + 1; -- Skip this function itself + end local locals = {}; for local_num = 1, math.huge do - local name, value = debug.getlocal(level, local_num); + local name, value = debug.getlocal(thread, level, local_num); if not name then break; end table.insert(locals, { name = name, value = value }); end @@ -97,7 +99,7 @@ function get_traceback_table(thread, start_level) levels[(level-start_level)+1] = { level = level; info = info; - locals = not thread and get_locals_table(level+1); + locals = get_locals_table(thread, level+(thread and 0 or 1)); upvalues = get_upvalues_table(info.func); }; end -- cgit v1.2.3 From 82f565b55b4bb068050330e1f0d8185c3c2a7bb2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 11 Aug 2013 10:42:58 +0100 Subject: util.debug: Fix level of locals when inspecting a coroutine --- util/debug.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/util/debug.lua b/util/debug.lua index 417359f8..91f691e1 100644 --- a/util/debug.lua +++ b/util/debug.lua @@ -25,12 +25,14 @@ end module("debugx", package.seeall); function get_locals_table(thread, level) - if not thread then - level = level + 1; -- Skip this function itself - end local locals = {}; for local_num = 1, math.huge do - local name, value = debug.getlocal(thread, level, local_num); + local name, value; + if thread then + name, value = debug.getlocal(thread, level, local_num); + else + name, value = debug.getlocal(level+1, local_num); + end if not name then break; end table.insert(locals, { name = name, value = value }); end -- cgit v1.2.3 From 95c8ddb01ceb9cdc4352ddb6af163b02e59b1303 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 11 Aug 2013 14:46:07 +0100 Subject: util.async: New library to provide support around coroutine-based non-blocking functions --- util/async.lua | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 util/async.lua diff --git a/util/async.lua b/util/async.lua new file mode 100644 index 00000000..9036a876 --- /dev/null +++ b/util/async.lua @@ -0,0 +1,115 @@ +local log = require "util.logger".init("util.async"); + +local function runner_continue(thread) + -- ASSUMPTION: runner is in 'waiting' state (but we don't have the runner to know for sure) + if coroutine.status(thread) ~= "suspended" then -- This should suffice + return false; + end + local ok, state, runner = coroutine.resume(thread); + if not ok then + local level = 0; + while debug.getinfo(thread, level, "") do level = level + 1; end + ok, runner = debug.getlocal(thread, level-1, 1); + local error_handler = runner.watchers.error; + if error_handler then error_handler(runner, debug.traceback(thread, state)); end + elseif state == "ready" then + -- If state is 'ready', it is our responsibility to update runner.state from 'waiting'. + -- We also have to :run(), because the queue might have further items that will not be + -- processed otherwise. FIXME: It's probably best to do this in a nexttick (0 timer). + runner.state = "ready"; + runner:run(); + end + return true; +end + +function waiter(num) + local thread = coroutine.running(); + if not thread then + error("Not running in an async context, see http://prosody.im/doc/developers/async"); + end + num = num or 1; + return function () + coroutine.yield("wait"); + end, function () + num = num - 1; + if num == 0 then + if not runner_continue(thread) then + error("done() called without wait()!"); + end + end + end; +end + +local runner_mt = {}; +runner_mt.__index = runner_mt; + +local function runner_create_thread(func, self) + local thread = coroutine.create(function (self) + while true do + func(coroutine.yield("ready", self)); + end + end); + assert(coroutine.resume(thread, self)); -- Start it up, it will return instantly to wait for the first input + return thread; +end + +local empty_watchers = {}; +function runner(func, watchers, data) + return setmetatable({ func = func, thread = false, state = "ready", notified_state = "ready", + queue = {}, watchers = watchers or empty_watchers, data = data } + , runner_mt); +end + +function runner_mt:run(input) + if input ~= nil then + table.insert(self.queue, input); + end + if self.state ~= "ready" then + return true, self.state, #self.queue; + end + + local q, thread = self.queue, self.thread; + if not thread or coroutine.status(thread) == "dead" then + thread = runner_create_thread(self.func, self); + self.thread = thread; + end + + local n, state, err = #q, self.state, nil; + self.state = "running"; + while n > 0 and state == "ready" do + local consumed; + for i = 1,n do + local input = q[i]; + local ok, new_state = coroutine.resume(thread, input); + if not ok then + consumed, state, err = i, "ready", debug.traceback(thread, new_state); + self.thread = nil; + break; + elseif state == "wait" then + consumed, state = i, "waiting"; + break; + end + end + if not consumed then consumed = n; end + if q[n+1] ~= nil then + n = #q; + end + for i = 1, n do + q[i] = q[consumed+i]; + end + n = #q; + end + self.state = state; + if state ~= self.notified_state then + self.notified_state = state; + local handler = self.watchers[state]; + if handler then handler(self, err); end + end + return true, state, n; +end + +function runner_mt:enqueue(input) + table.insert(self.queue, input); +end + +return { waiter = waiter, runner = runner }; -- cgit v1.2.3 From e0216573ab30d11b54056a9fe4b43293ebf0a910 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 11 Aug 2013 14:46:27 +0100 Subject: mod_c2s: Port coroutine code to util.async --- plugins/mod_c2s.lua | 81 ++++++++++++----------------------------------------- 1 file changed, 18 insertions(+), 63 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index fbac12cd..8a652a33 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -15,11 +15,10 @@ local sessionmanager = require "core.sessionmanager"; local st = require "util.stanza"; local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; local uuid_generate = require "util.uuid".generate; +local runner = require "util.async".runner; local xpcall, tostring, type = xpcall, tostring, type; -local traceback = debug.traceback; local t_insert, t_remove = table.insert, table.remove; -local co_running, co_resume = coroutine.running, coroutine.resume; local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams"; @@ -35,6 +34,7 @@ local hosts = prosody.hosts; local stream_callbacks = { default_ns = "jabber:client" }; local listener = {}; +local runner_callbacks = {}; --- Stream events handlers local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; @@ -119,10 +119,9 @@ function stream_callbacks.error(session, error, data) end end -local function handleerr(err) log("error", "Traceback[c2s]: %s", traceback(tostring(err), 2)); end function stream_callbacks.handlestanza(session, stanza) stanza = session.filter("stanzas/in", stanza); - t_insert(session.pending_stanzas, stanza); + session.thread:run(stanza); end --- Session methods @@ -189,6 +188,18 @@ module:hook_global("user-deleted", function(event) end end, 200); +function runner_callbacks:ready() + self.data.conn:resume(); +end + +function runner_callbacks:waiting() + self.data.conn:pause(); +end + +function runner_callbacks:error(err) + (self.data.log or log)("error", "Traceback[c2s]: %s", err); +end + --- Port listener function listener.onconnect(conn) local session = sm_new_session(conn); @@ -224,14 +235,9 @@ function listener.onconnect(conn) session.stream:reset(); end - session.thread = coroutine.create(function (stanza) - while true do - core_process_stanza(session, stanza); - stanza = coroutine.yield("ready"); - end - end); - - session.pending_stanzas = {}; + session.thread = runner(function (stanza) + core_process_stanza(session, stanza); + end, runner_callbacks, session); local filter = session.filter; function session.data(data) @@ -246,41 +252,6 @@ function listener.onconnect(conn) end end end - - if co_running() ~= session.thread and not session.paused then - if session.state == "wait" then - session.state = "ready"; - local ok, state = co_resume(session.thread); - if not ok then - log("error", "Traceback[c2s]: %s", state); - elseif state == "wait" then - return; - end - end - -- We're not currently running, so start the thread to process pending stanzas - local s, thread = session.pending_stanzas, session.thread; - local n = #s; - while n > 0 and session.state ~= "wait" do - session.log("debug", "processing %d stanzas", n); - local consumed; - for i = 1,n do - local stanza = s[i]; - local ok, state = co_resume(thread, stanza); - if not ok then - log("error", "Traceback[c2s]: %s", state); - elseif state == "wait" then - consumed = i; - session.state = "wait"; - break; - end - end - if not consumed then consumed = n; end - for i = 1, #s do - s[i] = s[consumed+i]; - end - n = #s; - end - end end if c2s_timeout then @@ -292,22 +263,6 @@ function listener.onconnect(conn) end session.dispatch_stanza = stream_callbacks.handlestanza; - - function session:sleep(by) - session.log("debug", "Sleeping for %s", by); - session.paused = by or "?"; - session.conn:pause(); - if co_running() == session.thread then - coroutine.yield("wait"); - end - end - function session:wake(by) - assert(session.paused == (by or "?")); - session.log("debug", "Waking for %s", by); - session.paused = nil; - session.conn:resume(); - session.data(); --FIXME: next tick? - end end function listener.onincoming(conn, data) -- cgit v1.2.3 From 056eec9953383a5a5418e1cbf8fb89c07fb0e903 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 12 Aug 2013 10:27:08 +0100 Subject: util.async: Make functions local --- util/async.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/async.lua b/util/async.lua index 9036a876..59d3c6f2 100644 --- a/util/async.lua +++ b/util/async.lua @@ -22,7 +22,7 @@ local function runner_continue(thread) return true; end -function waiter(num) +local function waiter(num) local thread = coroutine.running(); if not thread then error("Not running in an async context, see http://prosody.im/doc/developers/async"); @@ -54,7 +54,7 @@ local function runner_create_thread(func, self) end local empty_watchers = {}; -function runner(func, watchers, data) +local function runner(func, watchers, data) return setmetatable({ func = func, thread = false, state = "ready", notified_state = "ready", queue = {}, watchers = watchers or empty_watchers, data = data } , runner_mt); -- cgit v1.2.3 From d135b8fef982f97c0912444d0dc79688a2670322 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 12 Aug 2013 11:50:27 +0100 Subject: util.async: runner: Fix check for new state to recognise transition to 'waiting' --- util/async.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/async.lua b/util/async.lua index 59d3c6f2..afbaba5c 100644 --- a/util/async.lua +++ b/util/async.lua @@ -85,7 +85,7 @@ function runner_mt:run(input) consumed, state, err = i, "ready", debug.traceback(thread, new_state); self.thread = nil; break; - elseif state == "wait" then + elseif new_state == "wait" then consumed, state = i, "waiting"; break; end -- cgit v1.2.3 From 516179867e7ffbe56343375aa0d8abcf41dee83a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 12 Aug 2013 12:08:51 +0100 Subject: util.async: waiter: Remove restriction about wait() being called before done() --- util/async.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/util/async.lua b/util/async.lua index afbaba5c..c81f8639 100644 --- a/util/async.lua +++ b/util/async.lua @@ -28,14 +28,15 @@ local function waiter(num) error("Not running in an async context, see http://prosody.im/doc/developers/async"); end num = num or 1; + local waiting; return function () + if num == 0 then return; end -- already done + waiting = true; coroutine.yield("wait"); end, function () num = num - 1; - if num == 0 then - if not runner_continue(thread) then - error("done() called without wait()!"); - end + if num == 0 and waiting then + runner_continue(thread); end end; end -- cgit v1.2.3 From 0e702abb1f191bbf83bf3b24a99536fa4dc3dd73 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 12 Aug 2013 13:22:27 +0200 Subject: util.async: waiter: Throw error if done() called too many times --- util/async.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/async.lua b/util/async.lua index c81f8639..d0bc6c3d 100644 --- a/util/async.lua +++ b/util/async.lua @@ -37,6 +37,8 @@ local function waiter(num) num = num - 1; if num == 0 and waiting then runner_continue(thread); + elseif num < 0 then + error("done() called too many times"); end end; end -- cgit v1.2.3 From 7a082cb3938619202436656daf96fbeb18a50c22 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 13 Aug 2013 19:23:00 +0100 Subject: util.async: Fix logic bug that prevented error watcher being called for runners --- util/async.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/async.lua b/util/async.lua index d0bc6c3d..8af8730f 100644 --- a/util/async.lua +++ b/util/async.lua @@ -103,8 +103,12 @@ function runner_mt:run(input) n = #q; end self.state = state; - if state ~= self.notified_state then - self.notified_state = state; + if err or state ~= self.notified_state then + if err then + state = "error" + else + self.notified_state = state; + end local handler = self.watchers[state]; if handler then handler(self, err); end end -- cgit v1.2.3 From de0f19e1af3ce580229dfad3ab15bf5600369d38 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 13 Aug 2013 19:38:05 +0100 Subject: usermanager: Remove unused import of pairs() --- core/usermanager.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/core/usermanager.lua b/core/usermanager.lua index 886bd5cb..4ac288a4 100644 --- a/core/usermanager.lua +++ b/core/usermanager.lua @@ -10,7 +10,6 @@ local modulemanager = require "core.modulemanager"; local log = require "util.logger".init("usermanager"); local type = type; local ipairs = ipairs; -local pairs = pairs; local jid_bare = require "util.jid".bare; local jid_prep = require "util.jid".prep; local config = require "core.configmanager"; -- cgit v1.2.3 From 14f85f2f4e06a46fd46bd33bbfb23ad642ec01fd Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 13 Aug 2013 21:26:53 +0100 Subject: util.async: Add guarder method, to create guards to ensure only a single runner can pass through a section of code at a time --- util/async.lua | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/util/async.lua b/util/async.lua index 8af8730f..32ed0542 100644 --- a/util/async.lua +++ b/util/async.lua @@ -43,6 +43,42 @@ local function waiter(num) end; end +function guarder() + local guards = {}; + return function (id, func) + local thread = coroutine.running(); + if not thread then + error("Not running in an async context, see http://prosody.im/doc/developers/async"); + end + local guard = guards[id]; + if not guard then + guard = {}; + guards[id] = guard; + log("debug", "New guard!"); + else + table.insert(guard, thread); + log("debug", "Guarded. %d threads waiting.", #guard) + coroutine.yield("wait"); + end + local function exit() + local next_waiting = table.remove(guard, 1); + if next_waiting then + log("debug", "guard: Executing next waiting thread (%d left)", #guard) + runner_continue(next_waiting); + else + log("debug", "Guard off duty.") + guards[id] = nil; + end + end + if func then + func(); + exit(); + return; + end + return exit; + end; +end + local runner_mt = {}; runner_mt.__index = runner_mt; @@ -119,4 +155,4 @@ function runner_mt:enqueue(input) table.insert(self.queue, input); end -return { waiter = waiter, runner = runner }; +return { waiter = waiter, guarder = guarder, runner = runner }; -- cgit v1.2.3 From 7f367c1d6eee23dfef56634f59b72f77f9b3a33c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 13 Aug 2013 23:38:50 +0100 Subject: util.async: Make guarder() local --- util/async.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/async.lua b/util/async.lua index 32ed0542..968ec804 100644 --- a/util/async.lua +++ b/util/async.lua @@ -43,7 +43,7 @@ local function waiter(num) end; end -function guarder() +local function guarder() local guards = {}; return function (id, func) local thread = coroutine.running(); -- cgit v1.2.3 From 2666d8e8e7b2cdbad8d61caf1351d24782c0da74 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 14 Aug 2013 00:18:39 +0100 Subject: mod_s2s/s2sout.lib: Improve error message logged at 'info' level when failing to connect to a host. Now 'Failed in all attempts to connect to XYZ' --- plugins/mod_s2s/s2sout.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index 10ee4f0e..9500cac7 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -129,7 +129,7 @@ function s2sout.attempt_connection(host_session, err) connect_host, connect_port = srv_choice.target or to_host, srv_choice.port or connect_port; host_session.log("info", "Connection failed (%s). Attempt #%d: This time to %s:%d", tostring(err), host_session.srv_choice, connect_host, connect_port); else - host_session.log("info", "Out of connection options, can't connect to %s", tostring(host_session.to_host)); + host_session.log("info", "Failed in all attempts to connect to %s", tostring(host_session.to_host)); -- We're out of options return false; end -- cgit v1.2.3 From b21a19359832f4007ae3a713d89f4b3779bcd297 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 14 Aug 2013 14:44:56 +0200 Subject: mod_s2s: Lower "Beginning new connection attempt" message from info to debug level --- plugins/mod_s2s/s2sout.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index 9500cac7..ec8ea4d4 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -265,7 +265,7 @@ function s2sout.try_connect(host_session, connect_host, connect_port, err) end function s2sout.make_connect(host_session, connect_host, connect_port) - (host_session.log or log)("info", "Beginning new connection attempt to %s ([%s]:%d)", host_session.to_host, connect_host.addr, connect_port); + (host_session.log or log)("debug", "Beginning new connection attempt to %s ([%s]:%d)", host_session.to_host, connect_host.addr, connect_port); -- Reset secure flag in case this is another -- connection attempt after a failed STARTTLS -- cgit v1.2.3 From 1764b9fba374409db402ab96190c9b4cd5db112b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 14 Aug 2013 14:53:50 +0200 Subject: mod_s2s: Captitalize log messages that begin with a stream direction --- plugins/mod_s2s/mod_s2s.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index d64a02ac..331e99f1 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -158,7 +158,7 @@ function mark_connected(session) local from, to = session.from_host, session.to_host; - session.log("info", "%s s2s connection %s->%s complete", session.direction, from, to); + session.log("info", "%s s2s connection %s->%s complete", session.direction:gsub("^.", string.upper), from, to); local event_data = { session = session }; if session.type == "s2sout" then @@ -491,7 +491,7 @@ local function session_close(session, reason, remote_reason) function session.sends2s() return false; end local reason = remote_reason or (reason and (reason.text or reason.condition)) or reason; - session.log("info", "%s s2s stream %s->%s closed: %s", session.direction, session.from_host or "(unknown host)", session.to_host or "(unknown host)", reason or "stream closed"); + session.log("info", "%s s2s stream %s->%s closed: %s", session.direction:gsub("^.", string.upper), session.from_host or "(unknown host)", session.to_host or "(unknown host)", reason or "stream closed"); -- Authenticated incoming stream may still be sending us stanzas, so wait for from remote local conn = session.conn; -- cgit v1.2.3 From 938d568ac476bb73e83b8ee44ba61c23f29557a8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 14 Aug 2013 15:00:36 +0200 Subject: mod_c2s, mod_s2s: Log cipher and encryption info in a more compact and (hopefully) less confusing way --- plugins/mod_c2s.lua | 3 +-- plugins/mod_s2s/mod_s2s.lua | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 8a652a33..1cf4b98d 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -73,8 +73,7 @@ function stream_callbacks.streamopened(session, attr) local sock = session.conn:socket(); if sock.info then local info = sock:info(); - (session.log or log)("info", "Stream encrypted (%s) with %s, authenticated with %s and exchanged keys with %s", - info.protocol, info.encryption, info.authentication, info.key); + (session.log or log)("info", "Stream encrypted (%s with %s)", info.protocol, info.cipher); session.compressed = info.compression; else (session.log or log)("info", "Stream encrypted"); diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 331e99f1..1d03f3e4 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -287,8 +287,7 @@ function stream_callbacks.streamopened(session, attr) local sock = session.conn:socket(); if sock.info then local info = sock:info(); - (session.log or log)("info", "Stream encrypted (%s) with %s, authenticated with %s and exchanged keys with %s", - info.protocol, info.encryption, info.authentication, info.key); + (session.log or log)("info", "Stream encrypted (%s with %s)", info.protocol, info.cipher); session.compressed = info.compression; else (session.log or log)("info", "Stream encrypted"); -- cgit v1.2.3 From 0c39eb02b91bc1028f523dde1d6b5112cbff8a7f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 14 Aug 2013 15:38:56 +0200 Subject: mod_c2s: Move another log message to debug level --- plugins/mod_c2s.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 1cf4b98d..1fb8dcf5 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -157,7 +157,7 @@ local function session_close(session, reason) function session.send() return false; end local reason = (reason and (reason.name or reason.text or reason.condition)) or reason; - session.log("info", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed"); + session.log("debug", "c2s stream for %s closed: %s", session.full_jid or ("<"..session.ip..">"), reason or "session closed"); -- Authenticated incoming stream may still be sending us stanzas, so wait for from remote local conn = session.conn; -- cgit v1.2.3 From e6e0a05efa00c9fe22eca554c9dae23a361b182e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 29 Aug 2013 11:59:27 +0100 Subject: prosody.cfg.lua.dist: Set c2s_require_encryption = true --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 30221da9..1d11a658 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -94,7 +94,7 @@ ssl = { -- Force clients to use encrypted connections? This option will -- prevent clients from authenticating unless they are using encryption. -c2s_require_encryption = false +c2s_require_encryption = true -- Force certificate authentication for server-to-server connections? -- This provides ideal security, but requires servers you communicate -- cgit v1.2.3 From 0485b69ae4fccc82fcd63d13fb2b3b73a229e80b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 30 Aug 2013 14:10:51 +0100 Subject: mod_muc: Import util.array --- plugins/muc/mod_muc.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 6b4c7006..f9b6ca58 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -6,6 +6,7 @@ -- COPYING file in the source package for more information. -- +local array = require "util.array"; if module:get_host_type() ~= "component" then error("MUC should be loaded as a component, please see http://prosody.im/doc/components", 0); -- cgit v1.2.3 From 6b32cecbae817e9dad851974e468aff3d3dec392 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 30 Aug 2013 14:15:29 +0100 Subject: mod_muc: Support for locking newly-created rooms until they are configured (enabled with muc_room_locking = true) --- plugins/muc/mod_muc.lua | 13 +++++++++++++ plugins/muc/muc.lib.lua | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index f9b6ca58..cb967c90 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -23,6 +23,9 @@ if restrict_room_creation then restrict_room_creation = nil; end end +local lock_rooms = module:get_option_boolean("muc_room_locking", false); +local lock_room_timeout = module:get_option_number("muc_room_lock_timeout", 300); + local muclib = module:require "muc"; local muc_new_room = muclib.new_room; local jid_split = require "util.jid".split; @@ -88,6 +91,16 @@ function create_room(jid) room.route_stanza = room_route_stanza; room.save = room_save; rooms[jid] = room; + if lock_rooms then + room.locked = true; + if lock_room_timeout and lock_room_timeout > 0 then + module:add_timer(lock_room_timeout, function () + if room.locked then + room:destroy(); -- Not unlocked in time + end + end); + end + end module:fire_event("muc-room-created", { room = room }); return room; end diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 8800640f..0565d692 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -480,6 +480,12 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc log("debug", "%s joining as %s", from, to); if not next(self._affiliations) then -- new room, no owners self._affiliations[jid_bare(from)] = "owner"; + if self.locked and not stanza:get_child("x", "http://jabber.org/protocol/muc") then + self.locked = nil; -- Older groupchat protocol doesn't lock + end + elseif self.locked then -- Deny entry + origin.send(st.error_reply(stanza, "cancel", "item-not-found")); + return; end local affiliation = self:get_affiliation(from); local role = self:get_default_role(affiliation) @@ -501,6 +507,9 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc if self._data.whois == 'anyone' then pr:tag("status", {code='100'}):up(); end + if self.locked then + pr:tag("status", {code='201'}):up(); + end pr.attr.to = from; self:_route_stanza(pr); self:send_history(from, stanza); @@ -688,6 +697,10 @@ function room_mt:process_form(origin, stanza) handle_option("password", "muc#roomconfig_roomsecret"); if self.save then self:save(true); end + if self.locked then + module:fire_event("muc-room-unlocked", { room = self }); + self.locked = nil; + end origin.send(st.reply(stanza)); if next(changed) then -- cgit v1.2.3 From acf2cd9d36489efca06af796f2ba0d084f4dfe1b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 2 Sep 2013 15:22:41 +0100 Subject: prosodyctl: check: Support for unicode (IDN) domains (thanks once again albert) --- prosodyctl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/prosodyctl b/prosodyctl index b98736a7..cf2ab74d 100755 --- a/prosodyctl +++ b/prosodyctl @@ -838,6 +838,7 @@ function commands.check(arg) end if not what or what == "dns" then local dns = require "net.dns"; + local idna = require "util.encodings".idna; local ip = require "util.ip"; local c2s_ports = set.new(config.get("*", "c2s_ports") or {5222}); local s2s_ports = set.new(config.get("*", "s2s_ports") or {5269}); @@ -856,13 +857,13 @@ function commands.check(arg) local fqdn = socket.dns.tohostname(socket.dns.gethostname()); if fqdn then - local res = dns.lookup(fqdn, "A"); + local res = dns.lookup(idna.to_ascii(fqdn), "A"); if res then for _, record in ipairs(res) do external_addresses:add(record.a); end end - local res = dns.lookup(fqdn, "AAAA"); + local res = dns.lookup(idna.to_ascii(fqdn), "AAAA"); if res then for _, record in ipairs(res) do external_addresses:add(record.aaaa); @@ -895,7 +896,7 @@ function commands.check(arg) print("Checking DNS for "..(is_component and "component" or "host").." "..host.."..."); local target_hosts = set.new(); if not is_component then - local res = dns.lookup("_xmpp-client._tcp."..host..".", "SRV"); + local res = dns.lookup("_xmpp-client._tcp."..idna.to_ascii(host)..".", "SRV"); if res then for _, record in ipairs(res) do target_hosts:add(record.srv.target); @@ -912,7 +913,7 @@ function commands.check(arg) end end end - local res = dns.lookup("_xmpp-server._tcp."..host..".", "SRV"); + local res = dns.lookup("_xmpp-server._tcp."..idna.to_ascii(host)..".", "SRV"); if res then for _, record in ipairs(res) do target_hosts:add(record.srv.target); @@ -943,7 +944,7 @@ function commands.check(arg) if modules:contains("proxy65") then local proxy65_target = config.get(host, "proxy65_address") or host; - local A, AAAA = dns.lookup(proxy65_target, "A"), dns.lookup(proxy65_target, "AAAA"); + local A, AAAA = dns.lookup(idna.to_ascii(proxy65_target), "A"), dns.lookup(idna.to_ascii(proxy65_target), "AAAA"); local prob = {}; if not A then table.insert(prob, "A"); @@ -958,7 +959,7 @@ function commands.check(arg) for host in target_hosts do local host_ok_v4, host_ok_v6; - local res = dns.lookup(host, "A"); + local res = dns.lookup(idna.to_ascii(host), "A"); if res then for _, record in ipairs(res) do if external_addresses:contains(record.a) then @@ -974,7 +975,7 @@ function commands.check(arg) end end end - local res = dns.lookup(host, "AAAA"); + local res = dns.lookup(idna.to_ascii(host), "AAAA"); if res then for _, record in ipairs(res) do if external_addresses:contains(record.aaaa) then -- cgit v1.2.3 From bd8755411c872988afb0343e0e39492f280d8a90 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 3 Sep 2013 12:21:43 +0100 Subject: util.set: :items() now returns an iterator instead of the underlying table. This is much more efficient than 'for item in set' (which still works for now). Current access to _items is generally done directly, this may change. --- util/set.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/set.lua b/util/set.lua index a2df669c..89cd7cf3 100644 --- a/util/set.lua +++ b/util/set.lua @@ -75,7 +75,7 @@ function new(list) end function set:items() - return items; + return next, items; end function set:remove(item) -- cgit v1.2.3 From af9bff4f7ad3dfa4a3d3a9ec67d4a7ebde6ebf1f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 3 Sep 2013 12:22:22 +0100 Subject: mod_admin_adhoc: As the only user of set:items(), update... it's now an iterator, and the extra keys() iterator is now unnecessary --- plugins/mod_admin_adhoc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua index 2c6047da..d5aaa0c4 100644 --- a/plugins/mod_admin_adhoc.lua +++ b/plugins/mod_admin_adhoc.lua @@ -489,7 +489,7 @@ local globally_reload_module_handler = adhoc_initial(globally_reload_module_layo for _, host in pairs(hosts) do loaded_modules:append(array(keys(host.modules))); end - loaded_modules = array(keys(set.new(loaded_modules):items())):sort(); + loaded_modules = array(set.new(loaded_modules):items()):sort(); return { module = loaded_modules }; end, function(fields, err) local is_global = false; @@ -631,7 +631,7 @@ local globally_unload_module_handler = adhoc_initial(globally_unload_module_layo for _, host in pairs(hosts) do loaded_modules:append(array(keys(host.modules))); end - loaded_modules = array(keys(set.new(loaded_modules):items())):sort(); + loaded_modules = array(set.new(loaded_modules):items()):sort(); return { module = loaded_modules }; end, function(fields, err) local is_global = false; -- cgit v1.2.3 From 247c7be5c780c54a9f08a20dd1a12e176896bb19 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 3 Sep 2013 15:43:59 +0200 Subject: certmanager: Allow for specifying the dhparam option as a path to a file instead of a callback --- core/certmanager.lua | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index b39f4ed4..caa4afce 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -13,6 +13,8 @@ local ssl_newcontext = ssl and ssl.newcontext; local tostring = tostring; local pairs = pairs; +local type = type; +local io_open = io.open; local prosody = prosody; local resolve_path = configmanager.resolve_relative_path; @@ -41,7 +43,7 @@ local core_defaults = { ciphers = "HIGH:!DSS:!aNULL@STRENGTH"; } local path_options = { -- These we pass through resolve_path() - key = true, certificate = true, cafile = true, capath = true + key = true, certificate = true, cafile = true, capath = true, dhparam = true } if ssl and not luasec_has_verifyext and ssl.x509 then @@ -75,12 +77,25 @@ function create_context(host, mode, user_ssl_config) end user_ssl_config.password = user_ssl_config.password or function() log("error", "Encrypted certificate for %s requires 'ssl' 'password' to be set in config", host); end; for option in pairs(path_options) do - user_ssl_config[option] = user_ssl_config[option] and resolve_path(config_path, user_ssl_config[option]); + if type(user_ssl_config[option]) == "string" then + user_ssl_config[option] = resolve_path(config_path, user_ssl_config[option]); + end end if not user_ssl_config.key then return nil, "No key present in SSL/TLS configuration for "..host; end if not user_ssl_config.certificate then return nil, "No certificate present in SSL/TLS configuration for "..host; end + -- LuaSec expects dhparam to be a callback that takes two arguments. + -- We ignore those because it is mostly used for having a separate + -- set of params for EXPORT ciphers, which we don't have by default. + if type(user_ssl_config.dhparam) == "string" then + local f, err = io_open(user_ssl_config.dhparam); + if not f then return nil, "Could not open DH parameters: "..err end + local dhparam = f:read("*a"); + f:close(); + user_ssl_config.dhparam = function() return dhparam; end + end + local ctx, err = ssl_newcontext(user_ssl_config); -- COMPAT Older LuaSec ignores the cipher list from the config, so we have to take care -- cgit v1.2.3 From 5129829bbf9c146885eaca2d290e2033bb6b8833 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 6 Sep 2013 10:52:37 +0200 Subject: net.server_select: Pass on all arguments to addclient on to wrapclient --- net/server_select.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/server_select.lua b/net/server_select.lua index 7b550bf9..d5d27206 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -937,7 +937,7 @@ local addclient = function( address, port, listeners, pattern, sslctx ) client:settimeout( 0 ) _, err = client:connect( address, port ) if err then -- try again - local handler = wrapclient( client, address, port, listeners ) + local handler = wrapclient( client, address, port, listeners, pattern, sslctx ) else wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx ) end -- cgit v1.2.3 From 314c9eec90110aa104a066f22d48e9420705f769 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Fri, 6 Sep 2013 10:53:04 +0200 Subject: net.server_select: Return handler from addclient --- net/server_select.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/server_select.lua b/net/server_select.lua index d5d27206..ca55d2d5 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -937,9 +937,9 @@ local addclient = function( address, port, listeners, pattern, sslctx ) client:settimeout( 0 ) _, err = client:connect( address, port ) if err then -- try again - local handler = wrapclient( client, address, port, listeners, pattern, sslctx ) + return wrapclient( client, address, port, listeners, pattern, sslctx ) else - wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx ) + return wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx ) end end -- cgit v1.2.3 From 88613e4e188d1ea21f44d7db686a06287ffee6a6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 16 Sep 2013 18:41:09 +0100 Subject: moduleapi: Add module:unhook() --- core/moduleapi.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/moduleapi.lua b/core/moduleapi.lua index 6e857531..65e00d41 100644 --- a/core/moduleapi.lua +++ b/core/moduleapi.lua @@ -113,6 +113,10 @@ function api:hook_tag(xmlns, name, handler, priority) end api.hook_stanza = api.hook_tag; -- COMPAT w/pre-0.9 +function api:unhook(event, handler) + return self:unhook_object_event((hosts[self.host] or prosody).events, event, handler); +end + function api:require(lib) local f, n = pluginloader.load_code(self.name, lib..".lib.lua", self.environment); if not f then -- cgit v1.2.3 From f06c9f7d0da2fb9f1d0af09ce24e74b983fa49b3 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 22 Sep 2013 00:37:04 +0200 Subject: Backout ae48bf828f21 --- prosody | 3 --- util/dependencies.lua | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/prosody b/prosody index c86eea42..7c819214 100755 --- a/prosody +++ b/prosody @@ -16,9 +16,6 @@ CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR"); CFG_PLUGINDIR=os.getenv("PROSODY_PLUGINDIR"); CFG_DATADIR=os.getenv("PROSODY_DATADIR"); -package.path = "/Users/tfar/share/lua/5.1/?.lua;"..package.path; -package.cpath = "/Users/tfar/lib/lua/5.1/?.so;"..package.cpath; - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Tell Lua where to find our libraries diff --git a/util/dependencies.lua b/util/dependencies.lua index 9258be88..9371521c 100644 --- a/util/dependencies.lua +++ b/util/dependencies.lua @@ -11,9 +11,9 @@ module("dependencies", package.seeall) function softreq(...) local ok, lib = pcall(require, ...); if ok then return lib; else return nil, lib; end end -- Required to be able to find packages installed with luarocks ---if not softreq "luarocks.loader" then -- LuaRocks 2.x --- softreq "luarocks.require"; -- LuaRocks <1.x ---end +if not softreq "luarocks.loader" then -- LuaRocks 2.x + softreq "luarocks.require"; -- LuaRocks <1.x +end function missingdep(name, sources, msg) print(""); -- cgit v1.2.3 From d5dc3c96f74b500b12f12acd730afec214652c32 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 22 Sep 2013 04:29:27 +0200 Subject: util.sasl.scram: Simplify validation of client-first-message --- util/sasl/scram.lua | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index cf938dba..9dd7fdf8 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -13,7 +13,6 @@ local s_match = string.match; local type = type -local string = string local tostring = tostring; local base64 = require "util.encodings".base64; local hmac_sha1 = require "util.hashes".hmac_sha1; @@ -124,28 +123,33 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] - = client_first_message:match("^(%a)=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); + = client_first_message:match("^([ynp])=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); - -- check for invalid gs2_flag_type start - local gs2_flag_type = string.sub(self.state.gs2_cbind_flag, 0, 1) - if gs2_flag_type ~= "y" and gs2_flag_type ~= "n" and gs2_flag_type ~= "p" then - return "failure", "malformed-request", "The GS2 header has to start with 'y', 'n', or 'p'." + local gs2_cbind_flag = self.state.gs2_cbind_flag; + + if not gs2_cbind_flag then + return "failure", "malformed-request"; end - if support_channel_binding then - if string.sub(self.state.gs2_cbind_flag, 0, 1) == "y" then + if support_channel_binding and gs2_cbind_flag == "y" then + -- "y" -> client does support channel binding + -- but thinks the server does not. return "failure", "malformed-request"; end - + + if gs2_cbind_flag == "n" then + -- "n" -> client doesn't support channel binding. + support_channel_binding = false; + end + + if support_channel_binding and gs2_cbind_flag == "p" then -- check whether we support the proposed channel binding type if not self.profile.cb[self.state.gs2_cbind_name] then return "failure", "malformed-request", "Proposed channel binding type isn't supported."; end else - -- we don't support channelbinding, - if self.state.gs2_cbind_flag ~= "n" and self.state.gs2_cbind_flag ~= "y" then - return "failure", "malformed-request"; - end + -- no channel binding, + self.state.gs2_cbind_name = nil; end if not self.state.name or not self.state.clientnonce then @@ -242,7 +246,7 @@ end function init(registerMechanism) local function registerSCRAMMechanism(hash_name, hash, hmac_hash) registerMechanism("SCRAM-"..hash_name, {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash)); - + -- register channel binding equivalent registerMechanism("SCRAM-"..hash_name.."-PLUS", {"plain", "scram_"..(hashprep(hash_name))}, scram_gen(hash_name:lower(), hash, hmac_hash), {"tls-unique"}); end -- cgit v1.2.3 From be672f8a37667683bb5d14e61fbd5e759b8750c5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 26 Sep 2013 16:55:39 +0200 Subject: util.x509: Only compare identity with oid-on-xmppAddr for XMPP services --- util/x509.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/x509.lua b/util/x509.lua index 19d4ec6d..857f02a4 100644 --- a/util/x509.lua +++ b/util/x509.lua @@ -161,7 +161,9 @@ function verify_identity(host, service, cert) if sans[oid_xmppaddr] then had_supported_altnames = true - if compare_xmppaddr(host, sans[oid_xmppaddr]) then return true end + if service == "_xmpp-client" or service == "_xmpp-server" then + if compare_xmppaddr(host, sans[oid_xmppaddr]) then return true end + end end if sans[oid_dnssrv] then -- cgit v1.2.3 From 6802ee756301d50ad58f4b10d6612815ef70996e Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 28 Sep 2013 18:40:48 +0100 Subject: server_select: fix onreadtimeout support so that listeners can override the default (disconnect) behaviour --- net/server_select.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/server_select.lua b/net/server_select.lua index ca55d2d5..4721d6ad 100644 --- a/net/server_select.lua +++ b/net/server_select.lua @@ -284,6 +284,7 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport local status = listeners.onstatus local disconnect = listeners.ondisconnect local drain = listeners.ondrain + local onreadtimeout = listeners.onreadtimeout; local bufferqueue = { } -- buffer array local bufferqueuelen = 0 -- end of buffer array @@ -312,11 +313,14 @@ wrapconnection = function( server, listeners, socket, ip, serverport, clientport handler.disconnect = function( ) return disconnect end + handler.onreadtimeout = onreadtimeout; + handler.setlistener = function( self, listeners ) dispatch = listeners.onincoming disconnect = listeners.ondisconnect status = listeners.onstatus drain = listeners.ondrain + handler.onreadtimeout = listeners.onreadtimeout end handler.getstats = function( ) return readtraffic, sendtraffic -- cgit v1.2.3 From c9f9fdd69ca8fa710a9a8467f289e4ca7bb0b94e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 28 Sep 2013 21:58:01 +0200 Subject: mod_storage_sql2: Split out code for building WHERE clauses into separate functions --- plugins/mod_storage_sql2.lua | 78 +++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 3c5f9d20..1ce8c204 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -256,6 +256,48 @@ function archive_store:append(username, when, with, value) return key; end); end + +-- Helpers for building the WHERE clause +local function archive_where(query, args, where) + -- Time range, inclusive + if query.start then + args[#args+1] = query.start + where[#where+1] = "`when` >= ?" + end + + if query["end"] then + args[#args+1] = query["end"]; + if query.start then + where[#where] = "`when` BETWEEN ? AND ?" -- is this inclusive? + else + where[#where+1] = "`when` >= ?" + end + end + + -- Related name + if query.with then + where[#where+1] = "`with` = ?"; + args[#args+1] = query.with + end + + -- Unique id + if query.key then + where[#where+1] = "`key` = ?"; + args[#args+1] = query.key + end +end +local function archive_where_id_range(query, args, where) + -- Before or after specific item, exclusive + if query.after then -- keys better be unique! + where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" + args[#args+1] = query.after + end + if query.before then + where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" + args[#args+1] = query.before + end +end + function archive_store:find(username, query) query = query or {}; local user,store = username,self.store; @@ -265,31 +307,7 @@ function archive_store:find(username, query) local args = { host, user or "", store, }; local where = { "`host` = ?", "`user` = ?", "`store` = ?", }; - -- Time range, inclusive - if query.start then - args[#args+1] = query.start - where[#where+1] = "`when` >= ?" - end - if query["end"] then - args[#args+1] = query["end"]; - if query.start then - where[#where] = "`when` BETWEEN ? AND ?" -- is this inclusive? - else - where[#where+1] = "`when` >= ?" - end - end - - -- Related name - if query.with then - where[#where+1] = "`with` = ?"; - args[#args+1] = query.with - end - - -- Unique id - if query.key then - where[#where+1] = "`key` = ?"; - args[#args+1] = query.key - end + archive_where(query, args, where); -- Total matching if query.total then @@ -303,15 +321,7 @@ function archive_store:find(username, query) end end - -- Before or after specific item, exclusive - if query.after then - where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" - args[#args+1] = query.after - end - if query.before then - where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" - args[#args+1] = query.before - end + archive_where_id_range(query, args, where); if query.limit then args[#args+1] = query.limit; -- cgit v1.2.3 From e8380a3cd2a3747554ac3da1b1c106344b484f0b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 28 Sep 2013 22:04:04 +0200 Subject: mod_storage_sql2: Add method for deleting items from archives with same syntax as :find() --- plugins/mod_storage_sql2.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 1ce8c204..174bad78 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -340,6 +340,21 @@ function archive_store:find(username, query) end, total; end +function archive_store:delete(username, query) + query = query or {}; + local user,store = username,self.store; + return engine:transaction(function() + local sql_query = "DELETE FROM `prosodyarchive` WHERE %s;"; + local args = { host, user or "", store, }; + local where = { "`host` = ?", "`user` = ?", "`store` = ?", }; + archive_where(query, args, where); + archive_where_id_range(query, args, where); + sql_query = sql_query:format(t_concat(where, " AND ")); + module:log("debug", sql_query); + return engine:delete(sql_query, unpack(args)); + end); +end + local stores = { keyval = keyval_store; archive = archive_store; -- cgit v1.2.3 From 8f5b133c60ed0064a081a8222a110f4fb09a73db Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Oct 2013 23:17:05 +0200 Subject: util.sasl.scram: Remove unused function and import --- util/sasl/scram.lua | 9 --------- 1 file changed, 9 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 9dd7fdf8..d89eb872 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -13,7 +13,6 @@ local s_match = string.match; local type = type -local tostring = tostring; local base64 = require "util.encodings".base64; local hmac_sha1 = require "util.hashes".hmac_sha1; local sha1 = require "util.hashes".sha1; @@ -47,14 +46,6 @@ Supported Channel Binding Backends local default_i = 4096 -local function bp( b ) - local result = "" - for i=1, b:len() do - result = result.."\\"..b:byte(i) - end - return result -end - local xor_map = {0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;1;0;3;2;5;4;7;6;9;8;11;10;13;12;15;14;2;3;0;1;6;7;4;5;10;11;8;9;14;15;12;13;3;2;1;0;7;6;5;4;11;10;9;8;15;14;13;12;4;5;6;7;0;1;2;3;12;13;14;15;8;9;10;11;5;4;7;6;1;0;3;2;13;12;15;14;9;8;11;10;6;7;4;5;2;3;0;1;14;15;12;13;10;11;8;9;7;6;5;4;3;2;1;0;15;14;13;12;11;10;9;8;8;9;10;11;12;13;14;15;0;1;2;3;4;5;6;7;9;8;11;10;13;12;15;14;1;0;3;2;5;4;7;6;10;11;8;9;14;15;12;13;2;3;0;1;6;7;4;5;11;10;9;8;15;14;13;12;3;2;1;0;7;6;5;4;12;13;14;15;8;9;10;11;4;5;6;7;0;1;2;3;13;12;15;14;9;8;11;10;5;4;7;6;1;0;3;2;14;15;12;13;10;11;8;9;6;7;4;5;2;3;0;1;15;14;13;12;11;10;9;8;7;6;5;4;3;2;1;0;}; local result = {}; -- cgit v1.2.3 From 04699a3aa4f2f86e841941ad49a02d2f5f21f8fc Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Oct 2013 23:18:54 +0200 Subject: util.array: Improve array:reverse() and make it work as both method and non-mutating function --- util/array.lua | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/util/array.lua b/util/array.lua index 9bf215af..6f2abe04 100644 --- a/util/array.lua +++ b/util/array.lua @@ -11,6 +11,7 @@ local t_insert, t_sort, t_remove, t_concat local setmetatable = setmetatable; local math_random = math.random; +local math_floor = math.floor; local pairs, ipairs = pairs, ipairs; local tostring = tostring; @@ -84,6 +85,25 @@ function array_base.pluck(outa, ina, key) return outa; end +function array_base.reverse(outa, ina) + local len = #ina; + if ina == outa then + local middle = math_floor(len/2); + len = len + 1; + local o; -- opposite + for i = 1, middle do + o = len - i; + outa[i], outa[o] = outa[o], outa[i]; + end + else + local off = len + 1; + for i = 1, len do + outa[i] = ina[off - i]; + end + end + return outa; +end + --- These methods only mutate the array function array_methods:shuffle(outa, ina) local len = #self; @@ -94,15 +114,6 @@ function array_methods:shuffle(outa, ina) return self; end -function array_methods:reverse() - local len = #self-1; - for i=len,1,-1 do - self:push(self[i]); - self:pop(i); - end - return self; -end - function array_methods:append(array) local len,len2 = #self, #array; for i=1,len2 do -- cgit v1.2.3 From 5178a1e79fed67890c26d0f9a052c70b6a36b5a6 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 7 Oct 2013 12:43:00 +0200 Subject: mod_c2s, mod_s2s: Set session.encrypted as session.secure does not allways mean encrypted (eg consider_bosh_secure) --- plugins/mod_c2s.lua | 2 ++ plugins/mod_s2s/mod_s2s.lua | 1 + plugins/mod_s2s/s2sout.lib.lua | 1 + 3 files changed, 4 insertions(+) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 1fb8dcf5..3bdffc7d 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -69,6 +69,7 @@ function stream_callbacks.streamopened(session, attr) -- since we now have a new stream header, session is secured if session.secure == false then session.secure = true; + session.encrypted = true; local sock = session.conn:socket(); if sock.info then @@ -209,6 +210,7 @@ function listener.onconnect(conn) -- Client is using legacy SSL (otherwise mod_tls sets this flag) if conn:ssl() then session.secure = true; + session.encrypted = true; -- Check if TLS compression is used local sock = conn:socket(); diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 1d03f3e4..5afb958c 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -283,6 +283,7 @@ function stream_callbacks.streamopened(session, attr) -- TODO: Rename session.secure to session.encrypted if session.secure == false then session.secure = true; + session.encrypted = true; local sock = session.conn:socket(); if sock.info then diff --git a/plugins/mod_s2s/s2sout.lib.lua b/plugins/mod_s2s/s2sout.lib.lua index ec8ea4d4..dbbef360 100644 --- a/plugins/mod_s2s/s2sout.lib.lua +++ b/plugins/mod_s2s/s2sout.lib.lua @@ -270,6 +270,7 @@ function s2sout.make_connect(host_session, connect_host, connect_port) -- Reset secure flag in case this is another -- connection attempt after a failed STARTTLS host_session.secure = nil; + host_session.encrypted = nil; local conn, handler; local proto = connect_host.proto; -- cgit v1.2.3 From c89ca6cad504e083f310f82177d32dea0e25f462 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 7 Oct 2013 12:56:21 +0200 Subject: mod_saslauth: Collect data for channel binding only if we know for sure that the stream is encrypted --- plugins/mod_saslauth.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index f24eacf8..4513c511 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -242,7 +242,7 @@ module:hook("stream-features", function(event) return; end origin.sasl_handler = usermanager_get_sasl_handler(module.host, origin); - if origin.secure then + if origin.encrypted then -- check wether LuaSec has the nifty binding to the function needed for tls-unique -- FIXME: would be nice to have this check only once and not for every socket if origin.conn:socket().getpeerfinished then -- cgit v1.2.3 From ed452e4e844713819df4e862a8c52c9670f22df4 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 7 Oct 2013 17:57:06 -0400 Subject: util.sasl: Make registerMechanism a public function (again) --- util/sasl.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/sasl.lua b/util/sasl.lua index 0d90880d..2eb52c1d 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -48,7 +48,7 @@ local backend_mechanism = {}; local mechanism_channelbindings = {}; -- register a new SASL mechanims -local function registerMechanism(name, backends, f, cb_backends) +function registerMechanism(name, backends, f, cb_backends) assert(type(name) == "string", "Parameter name MUST be a string."); assert(type(backends) == "string" or type(backends) == "table", "Parameter backends MUST be either a string or a table."); assert(type(f) == "function", "Parameter f MUST be a function."); -- cgit v1.2.3 From 78247fb898a91995475f1dd8fa382b6704e41586 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 7 Oct 2013 18:02:58 -0400 Subject: util.sasl: Remove unused print() import. --- util/sasl.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/util/sasl.lua b/util/sasl.lua index 2eb52c1d..c8490842 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -18,7 +18,6 @@ local type = type local setmetatable = setmetatable; local assert = assert; local require = require; -local print = print module "sasl" -- cgit v1.2.3 From 9f9050e590c54c817546799f8a678386dc697081 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 12 Oct 2013 21:15:36 +0200 Subject: util.sasl.scram: Compare gs2-header to cbind-input (Thanks Tobias) --- util/sasl/scram.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index d89eb872..65090719 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -113,8 +113,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- TODO: fail if authzid is provided, since we don't support them yet self.state["client_first_message"] = client_first_message; - self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] - = client_first_message:match("^([ynp])=?([%a%-]*),(.*),n=(.*),r=([^,]*).*"); + self.state["gs2_header"], self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] + = client_first_message:match("^(([ynp])=?([%a%-]*),(.*),)n=(.*),r=([^,]*).*"); local gs2_cbind_flag = self.state.gs2_cbind_flag; @@ -200,14 +200,14 @@ local function scram_gen(hash_name, H_f, HMAC_f) return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; end + local client_gs2_header = base64.decode(self.state.channelbinding) + local our_client_gs2_header = self.state["gs2_header"] if self.state.gs2_cbind_name then -- we support channelbinding, so check if the value is valid - local client_gs2_header = base64.decode(self.state.channelbinding) - local our_client_gs2_header = "p="..self.state.gs2_cbind_name..","..self.state["authzid"]..","..self.profile.cb[self.state.gs2_cbind_name](self); - - if client_gs2_header ~= our_client_gs2_header then - return "failure", "malformed-request", "Invalid channel binding value."; - end + our_client_gs2_header = our_client_gs2_header .. self.profile.cb[self.state.gs2_cbind_name](self); + end + if client_gs2_header ~= our_client_gs2_header then + return "failure", "malformed-request", "Invalid channel binding value."; end if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then -- cgit v1.2.3 From f08c618d0563f0e0f57c375609c1564491733396 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 13 Oct 2013 00:29:47 +0200 Subject: util.sasl.scram: Create the state table as late as possible, keep state in locals for faster access --- util/sasl/scram.lua | 81 ++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 65090719..a18f025e 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -102,22 +102,19 @@ 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 support_channel_binding = false; if self.profile.cb then support_channel_binding = true; end if type(message) ~= "string" or #message == 0 then return "failure", "malformed-request" end - if not self.state.name then + local state = self.state; + if not state then -- we are processing client_first_message local client_first_message = message; -- TODO: fail if authzid is provided, since we don't support them yet - self.state["client_first_message"] = client_first_message; - self.state["gs2_header"], self.state["gs2_cbind_flag"], self.state["gs2_cbind_name"], self.state["authzid"], self.state["name"], self.state["clientnonce"] + local gs2_header, gs2_cbind_flag, gs2_cbind_name, authzid, name, clientnonce = client_first_message:match("^(([ynp])=?([%a%-]*),(.*),)n=(.*),r=([^,]*).*"); - local gs2_cbind_flag = self.state.gs2_cbind_flag; - if not gs2_cbind_flag then return "failure", "malformed-request"; end @@ -135,29 +132,24 @@ local function scram_gen(hash_name, H_f, HMAC_f) if support_channel_binding and gs2_cbind_flag == "p" then -- check whether we support the proposed channel binding type - if not self.profile.cb[self.state.gs2_cbind_name] then + if not self.profile.cb[gs2_cbind_name] then return "failure", "malformed-request", "Proposed channel binding type isn't supported."; end else -- no channel binding, - self.state.gs2_cbind_name = nil; - end - - if not self.state.name or not self.state.clientnonce then - return "failure", "malformed-request", "Channel binding isn't support at this time."; + gs2_cbind_name = nil; end - self.state.name = validate_username(self.state.name, self.profile.nodeprep); - if not self.state.name then + name = validate_username(name, self.profile.nodeprep); + if not 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 + local stored_key, server_key, salt, iteration_count; if self.profile.plain then - local password, state = self.profile.plain(self, self.state.name, self.realm) + local password, state = self.profile.plain(self, name, self.realm) if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end @@ -167,64 +159,71 @@ local function scram_gen(hash_name, H_f, HMAC_f) return "failure", "not-authorized", "Invalid password." end - self.state.salt = generate_uuid(); - self.state.iteration_count = default_i; + salt = generate_uuid(); + iteration_count = default_i; local succ = false; - succ, self.state.stored_key, self.state.server_key = getAuthenticationDatabaseSHA1(password, self.state.salt, default_i, self.state.iteration_count); + succ, stored_key, server_key = getAuthenticationDatabaseSHA1(password, salt, iteration_count); if not succ then - log("error", "Generating authentication database failed. Reason: %s", self.state.stored_key); + log("error", "Generating authentication database failed. Reason: %s", stored_key); return "failure", "temporary-auth-failure"; end elseif self.profile["scram_"..hashprep(hash_name)] then - local stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self, self.state.name, self.realm); + local state; + stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self, name, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end - - self.state.stored_key = stored_key; - self.state.server_key = server_key; - self.state.iteration_count = iteration_count; - self.state.salt = salt end - 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; + local nonce = clientnonce .. generate_uuid(); + local server_first_message = "r="..nonce..",s="..base64.encode(salt)..",i="..iteration_count; + self.state = { + gs2_header = gs2_header; + gs2_cbind_name = gs2_cbind_name; + name = name; + nonce = nonce; + + server_key = server_key; + stored_key = stored_key; + client_first_message = client_first_message; + server_first_message = server_first_message; + } return "challenge", server_first_message else -- we are processing client_final_message local client_final_message = message; - self.state["channelbinding"], self.state["nonce"], self.state["proof"] = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); + local channelbinding, nonce, proof = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); - if not self.state.proof or not self.state.nonce or not self.state.channelbinding then + if not proof or not nonce or not channelbinding then return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; end - local client_gs2_header = base64.decode(self.state.channelbinding) - local our_client_gs2_header = self.state["gs2_header"] - if self.state.gs2_cbind_name then + local client_gs2_header = base64.decode(channelbinding) + local our_client_gs2_header = state["gs2_header"] + if state.gs2_cbind_name then -- we support channelbinding, so check if the value is valid - our_client_gs2_header = our_client_gs2_header .. self.profile.cb[self.state.gs2_cbind_name](self); + our_client_gs2_header = our_client_gs2_header .. self.profile.cb[state.gs2_cbind_name](self); end if client_gs2_header ~= our_client_gs2_header then return "failure", "malformed-request", "Invalid channel binding value."; end - if self.state.nonce ~= self.state.clientnonce..self.state.servernonce then + if nonce ~= state.nonce then return "failure", "malformed-request", "Wrong nonce in client-final-message."; end - local ServerKey = self.state.server_key; - local StoredKey = self.state.stored_key; + local ServerKey = state.server_key; + local StoredKey = state.stored_key; - local AuthMessage = "n=" .. s_match(self.state.client_first_message,"n=(.+)") .. "," .. self.state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") + local AuthMessage = "n=" .. s_match(state.client_first_message,"n=(.+)") .. "," .. state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") local ClientSignature = HMAC_f(StoredKey, AuthMessage) - local ClientKey = binaryXOR(ClientSignature, base64.decode(self.state.proof)) + local ClientKey = binaryXOR(ClientSignature, base64.decode(proof)) local ServerSignature = HMAC_f(ServerKey, AuthMessage) if StoredKey == H_f(ClientKey) then local server_final_message = "v="..base64.encode(ServerSignature); - self["username"] = self.state.name; + self["username"] = 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."; -- cgit v1.2.3 From d2c0175023d1ba650a904ddf80bac12ace72384a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 13 Oct 2013 01:14:21 +0200 Subject: util.sasl.scram: Rewrite patterns and capture client-first-message-bare, client-final-message-without-proof --- util/sasl/scram.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index a18f025e..11fa4e7c 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -112,8 +112,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) local client_first_message = message; -- TODO: fail if authzid is provided, since we don't support them yet - local gs2_header, gs2_cbind_flag, gs2_cbind_name, authzid, name, clientnonce - = client_first_message:match("^(([ynp])=?([%a%-]*),(.*),)n=(.*),r=([^,]*).*"); + local gs2_header, gs2_cbind_flag, gs2_cbind_name, authzid, client_first_message_bare, name, clientnonce + = s_match(client_first_message, "^(([pny])=?([^,]*),([^,]*),)(m?=?[^,]*,?n=([^,]*),r=([^,]*),?.*)$"); if not gs2_cbind_flag then return "failure", "malformed-request"; @@ -185,7 +185,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) server_key = server_key; stored_key = stored_key; - client_first_message = client_first_message; + client_first_message_bare = client_first_message_bare; server_first_message = server_first_message; } return "challenge", server_first_message @@ -193,7 +193,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- we are processing client_final_message local client_final_message = message; - local channelbinding, nonce, proof = client_final_message:match("^c=(.*),r=(.*),.*p=(.*)"); + local client_final_message_without_proof, channelbinding, nonce, proof + = s_match(client_final_message, "(c=([^,]*),r=([^,]*),?.-),p=(.*)$"); if not proof or not nonce or not channelbinding then return "failure", "malformed-request", "Missing an attribute(p, r or c) in SASL message."; @@ -216,7 +217,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) local ServerKey = state.server_key; local StoredKey = state.stored_key; - local AuthMessage = "n=" .. s_match(state.client_first_message,"n=(.+)") .. "," .. state.server_first_message .. "," .. s_match(client_final_message, "(.+),p=.+") + local AuthMessage = state.client_first_message_bare .. "," .. state.server_first_message .. "," .. client_final_message_without_proof local ClientSignature = HMAC_f(StoredKey, AuthMessage) local ClientKey = binaryXOR(ClientSignature, base64.decode(proof)) local ServerSignature = HMAC_f(ServerKey, AuthMessage) -- cgit v1.2.3 From 5ee9fb684a3e444a38be6d4cbcf92c351f1243e6 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 13 Oct 2013 01:36:28 +0200 Subject: util.sasl.scram: Cache profile name instead of concatenating when used --- util/sasl/scram.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index 11fa4e7c..e1404b3b 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -101,6 +101,7 @@ function getAuthenticationDatabaseSHA1(password, salt, iteration_count) end local function scram_gen(hash_name, H_f, HMAC_f) + local profile_name = "scram_" .. hashprep(hash_name); local function scram_hash(self, message) local support_channel_binding = false; if self.profile.cb then support_channel_binding = true; end @@ -168,9 +169,9 @@ local function scram_gen(hash_name, H_f, HMAC_f) log("error", "Generating authentication database failed. Reason: %s", stored_key); return "failure", "temporary-auth-failure"; end - elseif self.profile["scram_"..hashprep(hash_name)] then + elseif self.profile[profile_name] then local state; - stored_key, server_key, iteration_count, salt, state = self.profile["scram_"..hashprep(hash_name)](self, name, self.realm); + stored_key, server_key, iteration_count, salt, state = self.profile[profile_name](self, name, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end end -- cgit v1.2.3 From e82a638911a8d1bb9e85fbbaefcc74adbef4562f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 13 Oct 2013 01:43:04 +0200 Subject: util.sasl.scram: Rename variable for clarity --- util/sasl/scram.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/util/sasl/scram.lua b/util/sasl/scram.lua index e1404b3b..0d2852bf 100644 --- a/util/sasl/scram.lua +++ b/util/sasl/scram.lua @@ -113,7 +113,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) local client_first_message = message; -- TODO: fail if authzid is provided, since we don't support them yet - local gs2_header, gs2_cbind_flag, gs2_cbind_name, authzid, client_first_message_bare, name, clientnonce + local gs2_header, gs2_cbind_flag, gs2_cbind_name, authzid, client_first_message_bare, username, clientnonce = s_match(client_first_message, "^(([pny])=?([^,]*),([^,]*),)(m?=?[^,]*,?n=([^,]*),r=([^,]*),?.*)$"); if not gs2_cbind_flag then @@ -141,8 +141,8 @@ local function scram_gen(hash_name, H_f, HMAC_f) gs2_cbind_name = nil; end - name = validate_username(name, self.profile.nodeprep); - if not name then + username = validate_username(username, self.profile.nodeprep); + if not username then log("debug", "Username violates either SASLprep or contains forbidden character sequences.") return "failure", "malformed-request", "Invalid username."; end @@ -150,7 +150,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) -- retreive credentials local stored_key, server_key, salt, iteration_count; if self.profile.plain then - local password, state = self.profile.plain(self, name, self.realm) + local password, state = self.profile.plain(self, username, self.realm) if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end @@ -171,7 +171,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) end elseif self.profile[profile_name] then local state; - stored_key, server_key, iteration_count, salt, state = self.profile[profile_name](self, name, self.realm); + stored_key, server_key, iteration_count, salt, state = self.profile[profile_name](self, username, self.realm); if state == nil then return "failure", "not-authorized" elseif state == false then return "failure", "account-disabled" end end @@ -181,7 +181,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) self.state = { gs2_header = gs2_header; gs2_cbind_name = gs2_cbind_name; - name = name; + username = username; nonce = nonce; server_key = server_key; @@ -225,7 +225,7 @@ local function scram_gen(hash_name, H_f, HMAC_f) if StoredKey == H_f(ClientKey) then local server_final_message = "v="..base64.encode(ServerSignature); - self["username"] = state.name; + self["username"] = state.username; return "success", server_final_message; else return "failure", "not-authorized", "The response provided by the client doesn't match the one we calculated."; -- cgit v1.2.3 From 65931067bf8d24dc78885fabeed2297864ccebde Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 15 Oct 2013 01:37:16 +0200 Subject: certmanager: Add back single_dh_use and single_ecdh_use to default options (Zash breaks, Zash unbreaks) --- core/certmanager.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index caa4afce..0709c650 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -53,8 +53,12 @@ if ssl and not luasec_has_verifyext and ssl.x509 then end end -if luasec_has_no_compression and configmanager.get("*", "ssl_compression") ~= true then - core_defaults.options[#core_defaults.options+1] = "no_compression"; +if luasec_has_no_compression then -- Has no_compression? Then it has these too... + default_options[#default_options+1] = "single_dh_use"; + default_options[#default_options+1] = "single_ecdh_use"; + if configmanager.get("*", "ssl_compression") ~= true then + core_defaults.options[#core_defaults.options+1] = "no_compression"; + end end function create_context(host, mode, user_ssl_config) -- cgit v1.2.3 From 4c2ea20af4ca9ea1136a83863bd9b7d2a8469f3f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 15 Oct 2013 10:47:34 +0200 Subject: certmanager: Fix. Again. --- core/certmanager.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/certmanager.lua b/core/certmanager.lua index 0709c650..e8030581 100644 --- a/core/certmanager.lua +++ b/core/certmanager.lua @@ -54,8 +54,8 @@ if ssl and not luasec_has_verifyext and ssl.x509 then end if luasec_has_no_compression then -- Has no_compression? Then it has these too... - default_options[#default_options+1] = "single_dh_use"; - default_options[#default_options+1] = "single_ecdh_use"; + core_defaults.options[#core_defaults.options+1] = "single_dh_use"; + core_defaults.options[#core_defaults.options+1] = "single_ecdh_use"; if configmanager.get("*", "ssl_compression") ~= true then core_defaults.options[#core_defaults.options+1] = "no_compression"; end -- cgit v1.2.3 From af3f07ec571349201837f6824d992ab877b1b14d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 21:34:55 +0100 Subject: mod_storage_sql2: Split up setting of encoding and table upgrade code --- plugins/mod_storage_sql2.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 174bad78..7e4de79b 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -108,8 +108,9 @@ local function set_encoding() local success,err = engine:transaction(function() return engine:execute(set_names_query); end); if not success then module:log("error", "Failed to set database connection encoding to UTF8: %s", err); - return; end +end +local function upgrade_table() if params.driver == "MySQL" then -- COMPAT w/pre-0.9: Upgrade tables to UTF-8 if not already local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE` FROM `information_schema`.`columns` WHERE `TABLE_NAME`='prosody' AND ( `CHARACTER_SET_NAME`!='utf8' OR `COLLATION_NAME`!='utf8_bin' );"; @@ -149,6 +150,7 @@ do -- process options to get a db connection -- Encoding mess set_encoding(); + upgrade_table(); -- Automatically create table, ignore failure (table probably already exists) create_table(); -- cgit v1.2.3 From d011ca8a325fc9bda520898a58a0c255d8c52968 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 21:37:30 +0100 Subject: mod_storage_sql2: Move all schema upgrade code to the same place --- plugins/mod_storage_sql2.lua | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 7e4de79b..90e9a2f6 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -64,24 +64,7 @@ local function create_table() engine:execute(create_sql); engine:execute(index_sql); end); - if not success then -- so we failed to create - if params.driver == "MySQL" then - success,err = engine:transaction(function() - local result = engine:execute("SHOW COLUMNS FROM prosody WHERE Field='value' and Type='text'"); - if result:rowcount() > 0 then - module:log("info", "Upgrading database schema..."); - engine:execute("ALTER TABLE prosody MODIFY COLUMN `value` MEDIUMTEXT"); - module:log("info", "Database table automatically upgraded"); - end - return true; - end); - if not success then - module:log("error", "Failed to check/upgrade database schema (%s), please see " - .."http://prosody.im/doc/mysql for help", - err or "unknown error"); - end - end - end + local ProsodyArchiveTable = Table { name="prosodyarchive"; Column { name="sort_id", type="INTEGER PRIMARY KEY AUTOINCREMENT", nullable=false }; @@ -112,9 +95,24 @@ local function set_encoding() end local function upgrade_table() if params.driver == "MySQL" then + local success,err = engine:transaction(function() + local result = engine:execute("SHOW COLUMNS FROM prosody WHERE Field='value' and Type='text'"); + if result:rowcount() > 0 then + module:log("info", "Upgrading database schema..."); + engine:execute("ALTER TABLE prosody MODIFY COLUMN `value` MEDIUMTEXT"); + module:log("info", "Database table automatically upgraded"); + end + return true; + end); + if not success then + module:log("error", "Failed to check/upgrade database schema (%s), please see " + .."http://prosody.im/doc/mysql for help", + err or "unknown error"); + return false; + end -- COMPAT w/pre-0.9: Upgrade tables to UTF-8 if not already local check_encoding_query = "SELECT `COLUMN_NAME`,`COLUMN_TYPE` FROM `information_schema`.`columns` WHERE `TABLE_NAME`='prosody' AND ( `CHARACTER_SET_NAME`!='utf8' OR `COLLATION_NAME`!='utf8_bin' );"; - local success,err = engine:transaction(function() + success,err = engine:transaction(function() local result = engine:execute(check_encoding_query); local n_bad_columns = result:rowcount(); if n_bad_columns > 0 then @@ -129,7 +127,7 @@ local function upgrade_table() module:log("info", "Database encoding upgrade complete!"); end end); - local success,err = engine:transaction(function() return engine:execute(check_encoding_query); end); + success,err = engine:transaction(function() return engine:execute(check_encoding_query); end); if not success then module:log("error", "Failed to check/upgrade database encoding: %s", err or "unknown error"); end @@ -148,12 +146,12 @@ do -- process options to get a db connection --local dburi = db2uri(params); engine = mod_sql:create_engine(params); - -- Encoding mess set_encoding(); - upgrade_table(); -- Automatically create table, ignore failure (table probably already exists) create_table(); + -- Encoding mess + upgrade_table(); end local function serialize(value) -- cgit v1.2.3 From e9935707592087e51ec0e6e63e3fd389407ebe9a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 22:07:16 +0100 Subject: mod_storage_sql2, util.sql: Move code for setting encoding to util.sql --- plugins/mod_storage_sql2.lua | 14 ++------------ util/sql.lua | 11 +++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 90e9a2f6..0e6aca3a 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -82,17 +82,7 @@ local function create_table() ProsodyArchiveTable:create(engine); end); end -local function set_encoding() - if params.driver == "SQLite3" then return end - local set_names_query = "SET NAMES 'utf8';"; - if params.driver == "MySQL" then - set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); - end - local success,err = engine:transaction(function() return engine:execute(set_names_query); end); - if not success then - module:log("error", "Failed to set database connection encoding to UTF8: %s", err); - end -end + local function upgrade_table() if params.driver == "MySQL" then local success,err = engine:transaction(function() @@ -146,7 +136,7 @@ do -- process options to get a db connection --local dburi = db2uri(params); engine = mod_sql:create_engine(params); - set_encoding(); + engine:set_encoding(); -- Automatically create table, ignore failure (table probably already exists) create_table(); diff --git a/util/sql.lua b/util/sql.lua index b8c16e27..972940f7 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -276,6 +276,17 @@ function engine:_create_table(table) end return success; end +function engine:set_encoding() -- to UTF-8 + if self.params.driver == "SQLite3" then return end + local set_names_query = "SET NAMES 'utf8';"; + if self.params.driver == "MySQL" then + set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); + end + local success,err = engine:transaction(function() return engine:execute(set_names_query); end); + if not success then + log("error", "Failed to set database connection encoding to UTF8: %s", err); + end +end local engine_mt = { __index = engine }; local function db2uri(params) -- cgit v1.2.3 From f925ba7723bf4336b6ad7089e5cfb8841d5ffa4a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 22:08:46 +0100 Subject: mod_storage_sql2: Move checking of the sql_manage_tables option so it also includes table upgrades (again) --- plugins/mod_storage_sql2.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 0e6aca3a..4148024e 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -41,9 +41,6 @@ local function create_table() engine:transaction(function() ProsodyTable:create(engine); end);]] - if not module:get_option("sql_manage_tables", true) then - return; - end local create_sql = "CREATE TABLE `prosody` (`host` TEXT, `user` TEXT, `store` TEXT, `key` TEXT, `type` TEXT, `value` TEXT);"; if params.driver == "PostgreSQL" then @@ -138,10 +135,12 @@ do -- process options to get a db connection engine:set_encoding(); - -- Automatically create table, ignore failure (table probably already exists) - create_table(); - -- Encoding mess - upgrade_table(); + if module:get_option("sql_manage_tables", true) then + -- Automatically create table, ignore failure (table probably already exists) + create_table(); + -- Encoding mess + upgrade_table(); + end end local function serialize(value) -- cgit v1.2.3 From 6c769838e9a81a145796cb447c03967f5c6fdb7a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 23:18:54 +0100 Subject: util.sql: Allow creating unique indices --- util/sql.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util/sql.lua b/util/sql.lua index 972940f7..736417bb 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -251,6 +251,9 @@ function engine:_create_index(index) elseif self.params.driver == "MySQL" then sql = sql:gsub("`([,)])", "`(20)%1"); end + if index.unique then + sql = sql:gsub("^CREATE", "CREATE UNIQUE"); + end --print(sql); return self:execute(sql); end -- cgit v1.2.3 From 136139f068145195233ed7aeb444d1a9bb45f7d4 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 23:19:47 +0100 Subject: util.sql: Allow columns to be marked the primary key --- util/sql.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/util/sql.lua b/util/sql.lua index 736417bb..7c9743e1 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -262,6 +262,7 @@ function engine:_create_table(table) for i,col in ipairs(table.c) do sql = sql.."`"..col.name.."` "..col.type; if col.nullable == false then sql = sql.." NOT NULL"; end + if col.primary_key == true then sql = sql.." PRIMARY KEY"; end if i ~= #table.c then sql = sql..", "; end end sql = sql.. ");" -- cgit v1.2.3 From 22be28318711e0846c9a00ef3a308119f1f3f1b1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 Oct 2013 23:20:25 +0100 Subject: util.sql: Support incrementing columns --- util/sql.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/sql.lua b/util/sql.lua index 7c9743e1..cab1bcec 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -263,6 +263,15 @@ function engine:_create_table(table) sql = sql.."`"..col.name.."` "..col.type; if col.nullable == false then sql = sql.." NOT NULL"; end if col.primary_key == true then sql = sql.." PRIMARY KEY"; end + if col.auto_increment == true then + if self.params.driver == "PostgreSQL" then + sql = sql.." SERIAL"; + elseif self.params.driver == "MySQL" then + sql = sql.." AUTO_INCREMENT"; + elseif self.params.driver == "SQLite3" then + sql = sql.." AUTOINCREMENT"; + end + end if i ~= #table.c then sql = sql..", "; end end sql = sql.. ");" -- cgit v1.2.3 From a0d18144edee980a55660b4c9dfe34462f1e1d17 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 29 Oct 2013 11:42:55 +0100 Subject: util.sql: Find out if MySQL supports utf8mb4 and use that --- util/sql.lua | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/util/sql.lua b/util/sql.lua index cab1bcec..4e63bed7 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -291,14 +291,19 @@ function engine:_create_table(table) end function engine:set_encoding() -- to UTF-8 if self.params.driver == "SQLite3" then return end - local set_names_query = "SET NAMES 'utf8';"; - if self.params.driver == "MySQL" then + local driver = self.params.driver; + local set_names_query = "SET NAMES '%s';" + local charset = "utf8"; + if driver == "MySQL" then set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); + local ok, charsets = self:transaction(function() + return self:select"SELECT `CHARACTER_SET_NAME` FROM `CHARACTER_SETS` WHERE `CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;"; + end); + local row = ok and charsets(); + charset = row and row[1] or charset; end - local success,err = engine:transaction(function() return engine:execute(set_names_query); end); - if not success then - log("error", "Failed to set database connection encoding to UTF8: %s", err); - end + self.charset = charset; + return self:transaction(function() return engine:execute(set_names_query:format(charset)); end); end local engine_mt = { __index = engine }; -- cgit v1.2.3 From 29988cfa70e9f0c0e8be63d3f6334a36fbe55ec3 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 29 Oct 2013 11:43:49 +0100 Subject: util.sql: Check what encoding SQLite3 uses --- util/sql.lua | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 4e63bed7..8c870b64 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -290,8 +290,14 @@ function engine:_create_table(table) return success; end function engine:set_encoding() -- to UTF-8 - if self.params.driver == "SQLite3" then return end local driver = self.params.driver; + if driver == "SQLite3" then + return self:transaction(function() + if self:select"PRAGMA encoding;"()[1] == "UTF-8" then + self.charset = "utf8"; + end + end); + end local set_names_query = "SET NAMES '%s';" local charset = "utf8"; if driver == "MySQL" then -- cgit v1.2.3 From 1bcfdab54f7785d3db05c65ad5672406885d0b91 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 30 Oct 2013 10:24:35 +0100 Subject: util.sql: Rewrite MEDIUMTEXT to TEXT for drivers other than MySQL --- util/sql.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 8c870b64..735fbce8 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -260,7 +260,11 @@ end function engine:_create_table(table) local sql = "CREATE TABLE `"..table.name.."` ("; for i,col in ipairs(table.c) do - sql = sql.."`"..col.name.."` "..col.type; + local col_type = col.type; + if col_type == "MEDIUMTEXT" and self.params.driver ~= "MySQL" then + col_type = "TEXT"; -- MEDIUMTEXT is MySQL-specific + end + sql = sql.."`"..col.name.."` "..col_type; if col.nullable == false then sql = sql.." NOT NULL"; end if col.primary_key == true then sql = sql.." PRIMARY KEY"; end if col.auto_increment == true then -- cgit v1.2.3 From 029256f34a7f430d379007f783d9f6c1a86da1f8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 30 Oct 2013 14:33:15 +0100 Subject: mod_storage_sql2: Use MEDIUMTEXT fields for value columns (ie TEXT on non-MySQL) --- plugins/mod_storage_sql2.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 4148024e..dcd7a45a 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -35,7 +35,7 @@ local function create_table() Column { name="store", type="TEXT", nullable=false }; Column { name="key", type="TEXT", nullable=false }; Column { name="type", type="TEXT", nullable=false }; - Column { name="value", type="TEXT", nullable=false }; + Column { name="value", type="MEDIUMTEXT", nullable=false }; Index { name="prosody_index", "host", "user", "store", "key" }; }; engine:transaction(function() @@ -72,7 +72,7 @@ local function create_table() Column { name="when", type="INTEGER", nullable=false }; -- timestamp Column { name="with", type="TEXT", nullable=false }; -- related id Column { name="type", type="TEXT", nullable=false }; - Column { name="value", type=params.driver == "MySQL" and "MEDIUMTEXT" or "TEXT", nullable=false }; + Column { name="value", type="MEDIUMTEXT", nullable=false }; Index { name="prosodyarchive_index", "host", "user", "store", "key" }; }; engine:transaction(function() -- cgit v1.2.3 From abb45cc639f5974aaf5c4fd61618886aa492425b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 30 Oct 2013 22:27:22 +0100 Subject: mod_storage_sql2: Use primary_key and auto_increment flags instead of baking that into the type --- plugins/mod_storage_sql2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index dcd7a45a..a4f47a87 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -64,7 +64,7 @@ local function create_table() local ProsodyArchiveTable = Table { name="prosodyarchive"; - Column { name="sort_id", type="INTEGER PRIMARY KEY AUTOINCREMENT", nullable=false }; + Column { name="sort_id", type="INTEGER", primary_key=true, auto_increment=true, nullable=false }; Column { name="host", type="TEXT", nullable=false }; Column { name="user", type="TEXT", nullable=false }; Column { name="store", type="TEXT", nullable=false }; -- cgit v1.2.3 From b3f9455c97ef20a674c774daa2490028ee168801 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 30 Oct 2013 22:37:07 +0100 Subject: mod_storage_sql2: The prosodyarchive_index should be unique --- plugins/mod_storage_sql2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index a4f47a87..9be10d24 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -73,7 +73,7 @@ local function create_table() Column { name="with", type="TEXT", nullable=false }; -- related id Column { name="type", type="TEXT", nullable=false }; Column { name="value", type="MEDIUMTEXT", nullable=false }; - Index { name="prosodyarchive_index", "host", "user", "store", "key" }; + Index { name="prosodyarchive_index", unique = true, "host", "user", "store", "key" }; }; engine:transaction(function() ProsodyArchiveTable:create(engine); -- cgit v1.2.3 From 7769c9bc36dce87f4d4f51dc8578b1aa6c220b08 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 31 Oct 2013 00:53:59 +0100 Subject: mod_storage_sql2: Switch to the util.sql table definition for the main table --- plugins/mod_storage_sql2.lua | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 9be10d24..9b365a1e 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -27,7 +27,7 @@ local engine; -- TODO create engine local function create_table() local Table,Column,Index = mod_sql.Table,mod_sql.Column,mod_sql.Index; - --[[ + local ProsodyTable = Table { name="prosody"; Column { name="host", type="TEXT", nullable=false }; @@ -40,26 +40,6 @@ local function create_table() }; engine:transaction(function() ProsodyTable:create(engine); - end);]] - - local create_sql = "CREATE TABLE `prosody` (`host` TEXT, `user` TEXT, `store` TEXT, `key` TEXT, `type` TEXT, `value` TEXT);"; - if params.driver == "PostgreSQL" then - create_sql = create_sql:gsub("`", "\""); - elseif params.driver == "MySQL" then - create_sql = create_sql:gsub("`value` TEXT", "`value` MEDIUMTEXT") - :gsub(";$", " CHARACTER SET 'utf8' COLLATE 'utf8_bin';"); - end - - local index_sql = "CREATE INDEX `prosody_index` ON `prosody` (`host`, `user`, `store`, `key`)"; - if params.driver == "PostgreSQL" then - index_sql = index_sql:gsub("`", "\""); - elseif params.driver == "MySQL" then - index_sql = index_sql:gsub("`([,)])", "`(20)%1"); - end - - local success,err = engine:transaction(function() - engine:execute(create_sql); - engine:execute(index_sql); end); local ProsodyArchiveTable = Table { -- cgit v1.2.3 From 999ec7ca77c56260f21908372e4dd1a29815c471 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 7 Nov 2013 17:18:20 +0100 Subject: mod_storage_sql2: Fix backwards comparison of timestamp --- plugins/mod_storage_sql2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 9b365a1e..824ab859 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -239,7 +239,7 @@ local function archive_where(query, args, where) if query.start then where[#where] = "`when` BETWEEN ? AND ?" -- is this inclusive? else - where[#where+1] = "`when` >= ?" + where[#where+1] = "`when` <= ?" end end -- cgit v1.2.3 From a80e00e16f382874e7caffd60b37160fc2d81f5b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sun, 10 Nov 2013 23:10:27 +0000 Subject: util.sql: Fix to call execute on 'self' rather than 'engine' (thanks eisensheng) --- util/sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 735fbce8..07b1a4e0 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -313,7 +313,7 @@ function engine:set_encoding() -- to UTF-8 charset = row and row[1] or charset; end self.charset = charset; - return self:transaction(function() return engine:execute(set_names_query:format(charset)); end); + return self:transaction(function() return self:execute(set_names_query:format(charset)); end); end local engine_mt = { __index = engine }; -- cgit v1.2.3 From 95457cb25bd866e3e06cc4cf1116e8408f62b744 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Nov 2013 23:09:18 +0100 Subject: util.sql: Rewrite auto increment columns to SERIAL for PostgreSQL --- util/sql.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/util/sql.lua b/util/sql.lua index 07b1a4e0..a7f46421 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -264,13 +264,14 @@ function engine:_create_table(table) if col_type == "MEDIUMTEXT" and self.params.driver ~= "MySQL" then col_type = "TEXT"; -- MEDIUMTEXT is MySQL-specific end + if col.auto_increment == true and self.params.driver == "PostgreSQL" then + col_type = "BIGSERIAL"; + end sql = sql.."`"..col.name.."` "..col_type; if col.nullable == false then sql = sql.." NOT NULL"; end if col.primary_key == true then sql = sql.." PRIMARY KEY"; end if col.auto_increment == true then - if self.params.driver == "PostgreSQL" then - sql = sql.." SERIAL"; - elseif self.params.driver == "MySQL" then + if self.params.driver == "MySQL" then sql = sql.." AUTO_INCREMENT"; elseif self.params.driver == "SQLite3" then sql = sql.." AUTOINCREMENT"; -- cgit v1.2.3 From b8218da015567c95dbc958d4d3885cf3ccb36050 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 11 Nov 2013 23:15:26 +0100 Subject: mod_storage_sql2: Auto increment columns won't be NULL, so drop nullable=false --- plugins/mod_storage_sql2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 824ab859..e03b1fd6 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -44,7 +44,7 @@ local function create_table() local ProsodyArchiveTable = Table { name="prosodyarchive"; - Column { name="sort_id", type="INTEGER", primary_key=true, auto_increment=true, nullable=false }; + Column { name="sort_id", type="INTEGER", primary_key=true, auto_increment=true }; Column { name="host", type="TEXT", nullable=false }; Column { name="user", type="TEXT", nullable=false }; Column { name="store", type="TEXT", nullable=false }; -- cgit v1.2.3 From a9e2cb510a760ac13bb8aeab47afdb64d19ea710 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 12 Nov 2013 11:13:45 +0100 Subject: util.sql: Get character set info from the correct database. --- util/sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index a7f46421..5e441c10 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -308,7 +308,7 @@ function engine:set_encoding() -- to UTF-8 if driver == "MySQL" then set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); local ok, charsets = self:transaction(function() - return self:select"SELECT `CHARACTER_SET_NAME` FROM `CHARACTER_SETS` WHERE `CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;"; + return self:select"SELECT `CHARACTER_SET_NAME` FROM `CHARACTER_SETS` WHERE `information_schema`.`CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;"; end); local row = ok and charsets(); charset = row and row[1] or charset; -- cgit v1.2.3 From 0dce82a095192a7a581511eb1455732e5a3da16c Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 12 Nov 2013 11:38:52 +0100 Subject: util.sql: Fix previous commit --- util/sql.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/sql.lua b/util/sql.lua index 5e441c10..5a1dda5d 100644 --- a/util/sql.lua +++ b/util/sql.lua @@ -308,7 +308,7 @@ function engine:set_encoding() -- to UTF-8 if driver == "MySQL" then set_names_query = set_names_query:gsub(";$", " COLLATE 'utf8_bin';"); local ok, charsets = self:transaction(function() - return self:select"SELECT `CHARACTER_SET_NAME` FROM `CHARACTER_SETS` WHERE `information_schema`.`CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;"; + return self:select"SELECT `CHARACTER_SET_NAME` FROM `information_schema`.`CHARACTER_SETS` WHERE `CHARACTER_SET_NAME` LIKE 'utf8%' ORDER BY MAXLEN DESC LIMIT 1;"; end); local row = ok and charsets(); charset = row and row[1] or charset; -- cgit v1.2.3 From 39d6068003836790e511e9f4df76ec2feb24d0ed Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 14 Dec 2013 17:25:17 +0100 Subject: mod_muc: Remove extra parenthesis (thanks janhouse) --- plugins/muc/mod_muc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 38c97d61..042d3891 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -164,7 +164,7 @@ function stanza_handler(event) return true; end if not(restrict_room_creation) or - is_admin(stanza.attr.from)) or + is_admin(stanza.attr.from) or (restrict_room_creation == "local" and select(2, jid_split(stanza.attr.from)) == module.host:gsub("^[^%.]+%.", "")) then room = create_room(bare); end -- cgit v1.2.3 From da4f11269dfc8f0157c94aa9c5f8e3eb2c5bc134 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 25 Dec 2013 15:28:55 +0100 Subject: mod_storage_sql2: Include user, host and store in id lookup --- plugins/mod_storage_sql2.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index e03b1fd6..bec35292 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -256,14 +256,16 @@ local function archive_where(query, args, where) end end local function archive_where_id_range(query, args, where) + local args_len = #args -- Before or after specific item, exclusive if query.after then -- keys better be unique! - where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" - args[#args+1] = query.after + where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?`AND user` = ?`AND store` = ? LIMIT 1)" + args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.after, args[1], args[2], args[3]; + args_len = args_len + 4 end if query.before then - where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? LIMIT 1)" - args[#args+1] = query.before + where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?`AND user` = ?`AND store` = ? LIMIT 1)" + args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.before, args[1], args[2], args[3]; end end -- cgit v1.2.3 From 2a25194b55d76eca92bafb30a3bb57cbf0b3bc1e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 25 Dec 2013 22:37:52 +0100 Subject: mod_storage_sql2: Expose the unique key argument, allowing arbitrary ids. Conflicting items are removed. --- plugins/mod_storage_sql2.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index bec35292..a97bee58 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -216,11 +216,15 @@ end local archive_store = {} archive_store.__index = archive_store -function archive_store:append(username, when, with, value) +function archive_store:append(username, key, when, with, value) + if value == nil then -- COMPAT early versions + when, with, value, key = key, when, with, value + end local user,store = username,self.store; return engine:transaction(function() - local key = uuid.generate(); + local key = key or uuid.generate(); local t, value = serialize(value); + engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND KEY=?", host, user or "", store, key); engine:insert("INSERT INTO `prosodyarchive` (`host`, `user`, `store`, `when`, `with`, `key`, `type`, `value`) VALUES (?,?,?,?,?,?,?,?)", host, user or "", store, when, with, key, t, value); return key; end); -- cgit v1.2.3 From bd8154130f88a89bd4f548264f935afb5e773951 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 30 Dec 2013 21:49:17 +0100 Subject: mod_pubsub: Don't sent error replies from service disco events, let mod_disco handle that --- plugins/mod_pubsub/mod_pubsub.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua index 81a66f8b..c6dbe831 100644 --- a/plugins/mod_pubsub/mod_pubsub.lua +++ b/plugins/mod_pubsub/mod_pubsub.lua @@ -86,12 +86,9 @@ end module:hook("host-disco-info-node", function (event) local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; local ok, ret = service:get_nodes(stanza.attr.from); - if ok and not ret[node] then + if not ok or not ret[node] then return; end - if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); - end event.exists = true; reply:tag("identity", { category = "pubsub", type = "leaf" }); end); @@ -100,7 +97,7 @@ module:hook("host-disco-items-node", function (event) local stanza, origin, reply, node = event.stanza, event.origin, event.reply, event.node; local ok, ret = service:get_items(node, stanza.attr.from); if not ok then - return origin.send(pubsub_error_reply(stanza, ret)); + return; end for id, item in pairs(ret) do @@ -114,7 +111,7 @@ module:hook("host-disco-items", function (event) local stanza, origin, reply = event.stanza, event.origin, event.reply; local ok, ret = service:get_nodes(event.stanza.attr.from); if not ok then - return origin.send(pubsub_error_reply(event.stanza, ret)); + return; end for node, node_obj in pairs(ret) do reply:tag("item", { jid = module.host, node = node, name = node_obj.config.name }):up(); -- cgit v1.2.3 From dbe25f8d3325674034a5dabb8b98e888d88767ee Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 26 Dec 2013 18:14:34 +0100 Subject: util.pubsub: Fire events on more actions --- util/pubsub.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/util/pubsub.lua b/util/pubsub.lua index 0dfd196b..a68b256c 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -219,6 +219,7 @@ function service:create(node, actor) data = {}; affiliations = {}; }; + self.events.fire_event("node-created", { node = node, actor = actor }); local ok, err = self:set_affiliation(node, true, actor, "owner"); if not ok then self.nodes[node] = nil; @@ -237,6 +238,7 @@ function service:delete(node, actor) return false, "item-not-found"; end self.nodes[node] = nil; + self.events.fire_event("node-deleted", { node = node, actor = actor }); self.config.broadcaster("delete", node, node_obj.subscribers); return true; end @@ -274,6 +276,7 @@ function service:retract(node, actor, id, retract) if (not node_obj) or (not node_obj.data[id]) then return false, "item-not-found"; end + self.events.fire_event("item-retracted", { node = node, actor = actor, id = id }); node_obj.data[id] = nil; if retract then self.config.broadcaster("items", node, node_obj.subscribers, retract); @@ -292,6 +295,7 @@ function service:purge(node, actor, notify) return false, "item-not-found"; end node_obj.data = {}; -- Purge + self.events.fire_event("node-purged", { node = node, actor = actor }); if notify then self.config.broadcaster("purge", node, node_obj.subscribers); end -- cgit v1.2.3 From c9a6cd1b3365ffb0676f542cc81ddecd4b46dbd0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 30 Dec 2013 23:49:23 +0100 Subject: util.pubsub: Separate data from node configuration --- util/pubsub.lua | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/util/pubsub.lua b/util/pubsub.lua index a68b256c..fc67cb1f 100644 --- a/util/pubsub.lua +++ b/util/pubsub.lua @@ -1,4 +1,5 @@ local events = require "util.events"; +local t_remove = table.remove; module("pubsub", package.seeall); @@ -18,6 +19,7 @@ function new(config) affiliations = {}; subscriptions = {}; nodes = {}; + data = {}; events = events.new(); }, service_mt); end @@ -212,17 +214,19 @@ function service:create(node, actor) return false, "conflict"; end + self.data[node] = {}; self.nodes[node] = { name = node; subscribers = {}; config = {}; - data = {}; affiliations = {}; }; + setmetatable(self.nodes[node], { __index = { data = self.data[node] } }); -- COMPAT self.events.fire_event("node-created", { node = node, actor = actor }); local ok, err = self:set_affiliation(node, true, actor, "owner"); if not ok then self.nodes[node] = nil; + self.data[node] = nil; end return ok, err; end @@ -238,11 +242,23 @@ function service:delete(node, actor) return false, "item-not-found"; end self.nodes[node] = nil; + self.data[node] = nil; self.events.fire_event("node-deleted", { node = node, actor = actor }); self.config.broadcaster("delete", node, node_obj.subscribers); return true; end +local function remove_item_by_id(data, id) + if not data[id] then return end + data[id] = nil; + for i, _id in ipairs(data) do + if id == _id then + t_remove(data, i); + return i; + end + end +end + function service:publish(node, actor, id, item) -- Access checking if not self:may(node, actor, "publish") then @@ -260,7 +276,10 @@ function service:publish(node, actor, id, item) end node_obj = self.nodes[node]; end - node_obj.data[id] = item; + local node_data = self.data[node]; + remove_item_by_id(node_data, id); + node_data[#self.data[node] + 1] = id; + node_data[id] = item; self.events.fire_event("item-published", { node = node, actor = actor, id = id, item = item }); self.config.broadcaster("items", node, node_obj.subscribers, item); return true; @@ -273,11 +292,11 @@ function service:retract(node, actor, id, retract) end -- local node_obj = self.nodes[node]; - if (not node_obj) or (not node_obj.data[id]) then + if (not node_obj) or (not self.data[node][id]) then return false, "item-not-found"; end self.events.fire_event("item-retracted", { node = node, actor = actor, id = id }); - node_obj.data[id] = nil; + remove_item_by_id(self.data[node], id); if retract then self.config.broadcaster("items", node, node_obj.subscribers, retract); end @@ -294,7 +313,7 @@ function service:purge(node, actor, notify) if not node_obj then return false, "item-not-found"; end - node_obj.data = {}; -- Purge + self.data[node] = {}; -- Purge self.events.fire_event("node-purged", { node = node, actor = actor }); if notify then self.config.broadcaster("purge", node, node_obj.subscribers); @@ -313,9 +332,9 @@ function service:get_items(node, actor, id) return false, "item-not-found"; end if id then -- Restrict results to a single specific item - return true, { [id] = node_obj.data[id] }; + return true, { id, [id] = self.data[node][id] }; else - return true, node_obj.data; + return true, self.data[node]; end end -- cgit v1.2.3 From c1ce22bc823d01a478cc2babbcf303d89e4ee4da Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 5 Jan 2014 23:38:34 +0100 Subject: mod_storage_sql2: Fix syntax error in subquery (Thanks Lance) --- plugins/mod_storage_sql2.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index a97bee58..8c8728da 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -263,12 +263,12 @@ local function archive_where_id_range(query, args, where) local args_len = #args -- Before or after specific item, exclusive if query.after then -- keys better be unique! - where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?`AND user` = ?`AND store` = ? LIMIT 1)" + where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?` AND user` = ?` AND store` = ? LIMIT 1)" args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.after, args[1], args[2], args[3]; args_len = args_len + 4 end if query.before then - where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?`AND user` = ?`AND store` = ? LIMIT 1)" + where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?` AND user` = ?` AND store` = ? LIMIT 1)" args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.before, args[1], args[2], args[3]; end end -- cgit v1.2.3 From 514a6edb7ecf5329816b743cc2b0c22fdf58ab88 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 18 Jan 2014 18:05:42 +0100 Subject: MUC: Split saving to history into a separate method --- plugins/muc/muc.lib.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 1b76ec94..ac04eb54 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -107,18 +107,21 @@ function room_mt:broadcast_message(stanza, historic) end stanza.attr.to = to; if historic then -- add to history - 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(); - stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):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); - while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end + return self:save_to_history(stanza) end end +function room_mt:save_to_history(stanza) + 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(); + stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):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); + while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end +end function room_mt:broadcast_except_nick(stanza, nick) for rnick, occupant in pairs(self._occupants) do if rnick ~= nick then -- cgit v1.2.3 From 5de535c834c2b641697751743b358064ffe1e99f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 18 Jan 2014 18:11:13 +0100 Subject: MUC: Split out sending of the topic into method separate from sending history --- plugins/muc/muc.lib.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index ac04eb54..462d6893 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -187,6 +187,8 @@ function room_mt:send_history(to, stanza) self:_route_stanza(msg); end end +end +function room_mt:send_subject(to) if self._data['subject'] then self:_route_stanza(st.message({type='groupchat', from=self._data['subject_from'] or self.jid, to=to}):tag("subject"):text(self._data['subject'])); end @@ -516,6 +518,7 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc pr.attr.to = from; self:_route_stanza(pr); self:send_history(from, stanza); + self:send_subject(from); elseif not affiliation then -- registration required for entering members-only room local reply = st.error_reply(stanza, "auth", "registration-required"):up(); reply.tags[1].attr.code = "407"; -- cgit v1.2.3 From 4d6d0891f6c4286aa4e9847d2869f725a70773ee Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 18 Jan 2014 18:28:50 +0100 Subject: MUC: Expose room metatable on module --- plugins/muc/mod_muc.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 042d3891..7bb1d8b2 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -52,8 +52,9 @@ local function is_admin(jid) return um_is_admin(jid, module.host); end -local _set_affiliation = muc_new_room.room_mt.set_affiliation; -local _get_affiliation = muc_new_room.room_mt.get_affiliation; +room_mt = muclib.room_mt; -- Yes, global. +local _set_affiliation = room_mt.set_affiliation; +local _get_affiliation = room_mt.get_affiliation; function muclib.room_mt:get_affiliation(jid) if is_admin(jid) then return "owner"; end return _get_affiliation(self, jid); -- cgit v1.2.3 From 1262f0373f70ecdc0f7e39c5ffbe065bc8042ce5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 18 Jan 2014 19:33:33 +0100 Subject: mod_storage_sql2: Fix SQL syntax --- plugins/mod_storage_sql2.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 8c8728da..b9e9d3ca 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -263,12 +263,12 @@ local function archive_where_id_range(query, args, where) local args_len = #args -- Before or after specific item, exclusive if query.after then -- keys better be unique! - where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?` AND user` = ?` AND store` = ? LIMIT 1)" + where[#where+1] = "`sort_id` > (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)" args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.after, args[1], args[2], args[3]; args_len = args_len + 4 end if query.before then - where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ?` AND user` = ?` AND store` = ? LIMIT 1)" + where[#where+1] = "`sort_id` < (SELECT `sort_id` FROM `prosodyarchive` WHERE `key` = ? AND `host` = ? AND `user` = ? AND `store` = ? LIMIT 1)" args[args_len+1], args[args_len+2], args[args_len+3], args[args_len+4] = query.before, args[1], args[2], args[3]; end end -- cgit v1.2.3 From 372c2b460a00506bd779c8081dc3774b6e81d93b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 21 Jan 2014 00:51:31 +0100 Subject: mod_storage_sql2: Fix another SQL syntax error that slipped trough --- plugins/mod_storage_sql2.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index b9e9d3ca..e02ad681 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -224,7 +224,7 @@ function archive_store:append(username, key, when, with, value) return engine:transaction(function() local key = key or uuid.generate(); local t, value = serialize(value); - engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND KEY=?", host, user or "", store, key); + engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", host, user or "", store, key); engine:insert("INSERT INTO `prosodyarchive` (`host`, `user`, `store`, `when`, `with`, `key`, `type`, `value`) VALUES (?,?,?,?,?,?,?,?)", host, user or "", store, when, with, key, t, value); return key; end); -- cgit v1.2.3 From 9550295c9d54f962435836dffc708bba67feaad5 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 21 Jan 2014 01:51:13 +0100 Subject: mod_storage_sql2: Only attempt to delete conflicting items if an ID/key is given --- plugins/mod_storage_sql2.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index e02ad681..90e9ead0 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -222,9 +222,12 @@ function archive_store:append(username, key, when, with, value) end local user,store = username,self.store; return engine:transaction(function() - local key = key or uuid.generate(); + if key then + engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", host, user or "", store, key); + else + key = uuid.generate(); + end local t, value = serialize(value); - engine:delete("DELETE FROM `prosodyarchive` WHERE `host`=? AND `user`=? AND `store`=? AND `key`=?", host, user or "", store, key); engine:insert("INSERT INTO `prosodyarchive` (`host`, `user`, `store`, `when`, `with`, `key`, `type`, `value`) VALUES (?,?,?,?,?,?,?,?)", host, user or "", store, when, with, key, t, value); return key; end); -- cgit v1.2.3 From 4896e7ca7e604309d65e8d0baefc24ad362b6772 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 26 Jan 2014 18:35:03 +0100 Subject: mod_posix: Daemonize by default only when installed --- plugins/mod_posix.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_posix.lua b/plugins/mod_posix.lua index 7a6ccd94..69542c96 100644 --- a/plugins/mod_posix.lua +++ b/plugins/mod_posix.lua @@ -128,7 +128,7 @@ function syslog_sink_maker(config) end require "core.loggingmanager".register_sink_type("syslog", syslog_sink_maker); -local daemonize = module:get_option("daemonize"); +local daemonize = module:get_option("daemonize", prosody.installed); if daemonize == nil then local no_daemonize = module:get_option("no_daemonize"); --COMPAT w/ 0.5 daemonize = not no_daemonize; -- cgit v1.2.3 From f73e31b9c2bcade1f146ff957117ae02e15f537e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 26 Jan 2014 21:16:24 +0100 Subject: modulemanager: Always load a platform-specific module, add stub modules for Windows and unknown platforms --- core/modulemanager.lua | 2 +- plugins/mod_unknown.lua | 4 ++++ plugins/mod_windows.lua | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 plugins/mod_unknown.lua create mode 100644 plugins/mod_windows.lua diff --git a/core/modulemanager.lua b/core/modulemanager.lua index 2ad2fc17..2e488fd5 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -29,7 +29,7 @@ pcall = function(f, ...) return xpcall(function() return f(unpack(params, 1, n)) end, function(e) return tostring(e).."\n"..debug_traceback(); end); end -local autoload_modules = {"presence", "message", "iq", "offline", "c2s", "s2s"}; +local autoload_modules = {prosody.platform, "presence", "message", "iq", "offline", "c2s", "s2s"}; local component_inheritable_modules = {"tls", "dialback", "iq", "s2s"}; -- We need this to let modules access the real global namespace diff --git a/plugins/mod_unknown.lua b/plugins/mod_unknown.lua new file mode 100644 index 00000000..4d20b8ad --- /dev/null +++ b/plugins/mod_unknown.lua @@ -0,0 +1,4 @@ +-- Unknown platform stub +module:set_global(); + +-- TODO Do things that make sense if we don't know about the platform diff --git a/plugins/mod_windows.lua b/plugins/mod_windows.lua new file mode 100644 index 00000000..8085fd88 --- /dev/null +++ b/plugins/mod_windows.lua @@ -0,0 +1,4 @@ +-- Windows platform stub +module:set_global(); + +-- TODO Add Windows-specific things here -- cgit v1.2.3 From e5faa1bfa21a99addfa92f637af6d8cf32144b34 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 28 Jan 2014 19:21:21 +0100 Subject: MUC: Tag PMs with , like presence stanzas --- plugins/muc/muc.lib.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 462d6893..d09c768e 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -570,6 +570,7 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc end stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id; else -- message + stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up(); stanza.attr.from = current_nick; for jid in pairs(o_data.sessions) do stanza.attr.to = jid; -- cgit v1.2.3 From c5c7ef5b0f47d1e51117f756420176f1f0a2466d Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Fri, 31 Jan 2014 12:01:12 +0100 Subject: mod_c2s: Break out stream opening into a separate function --- plugins/mod_c2s.lua | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua index 3bdffc7d..7a8af406 100644 --- a/plugins/mod_c2s.lua +++ b/plugins/mod_c2s.lua @@ -38,7 +38,6 @@ local runner_callbacks = {}; --- Stream events handlers local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'}; -local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" }; function stream_callbacks.streamopened(session, attr) local send = session.send; @@ -58,9 +57,7 @@ function stream_callbacks.streamopened(session, attr) return; end - send(""..st.stanza("stream:stream", { - xmlns = 'jabber:client', ["xmlns:stream"] = 'http://etherx.jabber.org/streams'; - id = session.streamid, from = session.host, version = '1.0', ["xml:lang"] = 'en' }):top_tag()); + session:open_stream(); (session.log or log)("debug", "Sent reply to client"); session.notopen = nil; @@ -129,8 +126,7 @@ local function session_close(session, reason) local log = session.log or log; if session.conn then if session.notopen then - session.send(""); - session.send(st.stanza("stream:stream", default_stream_attr):top_tag()); + session:open_stream(); end if reason then -- nil == no err, initiated by us, false == initiated by client local stream_error = st.stanza("stream:error"); @@ -178,6 +174,19 @@ local function session_close(session, reason) end end +local function session_open_stream(session) + local attr = { + ["xmlns:stream"] = 'http://etherx.jabber.org/streams', + xmlns = stream_callbacks.default_ns, + version = "1.0", + ["xml:lang"] = 'en', + id = session.streamid or "", + from = session.host + }; + session.send(""); + session.send(st.stanza("stream:stream", attr):top_tag()); +end + module:hook_global("user-deleted", function(event) local username, host = event.username, event.host; local user = hosts[host].sessions[username]; @@ -225,6 +234,7 @@ function listener.onconnect(conn) conn:setoption("keepalive", opt_keepalives); end + session.open_stream = session_open_stream; session.close = session_close; local stream = new_xmpp_stream(session, stream_callbacks); -- cgit v1.2.3 From a4f64d4c8b9d8df6774a9e319423c06109d8bfbf Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 9 Feb 2014 15:09:12 +0100 Subject: mod_ping: Use type-specific event --- plugins/mod_ping.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/mod_ping.lua b/plugins/mod_ping.lua index eddb92d2..1a503409 100644 --- a/plugins/mod_ping.lua +++ b/plugins/mod_ping.lua @@ -11,14 +11,11 @@ local st = require "util.stanza"; module:add_feature("urn:xmpp:ping"); local function ping_handler(event) - if event.stanza.attr.type == "get" then - event.origin.send(st.reply(event.stanza)); - return true; - end + return event.origin.send(st.reply(event.stanza)); end -module:hook("iq/bare/urn:xmpp:ping:ping", ping_handler); -module:hook("iq/host/urn:xmpp:ping:ping", ping_handler); +module:hook("iq-get/bare/urn:xmpp:ping:ping", ping_handler); +module:hook("iq-get/host/urn:xmpp:ping:ping", ping_handler); -- Ad-hoc command -- cgit v1.2.3 From 481aefcb7192dfb83379df2fa92a317f95e81c72 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 9 Feb 2014 15:12:13 +0100 Subject: mod_storage_sql2: archive:delete() with username = true deletes for all users --- plugins/mod_storage_sql2.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/mod_storage_sql2.lua b/plugins/mod_storage_sql2.lua index 90e9ead0..7a2ec4a7 100644 --- a/plugins/mod_storage_sql2.lua +++ b/plugins/mod_storage_sql2.lua @@ -325,6 +325,10 @@ function archive_store:delete(username, query) local sql_query = "DELETE FROM `prosodyarchive` WHERE %s;"; local args = { host, user or "", store, }; local where = { "`host` = ?", "`user` = ?", "`store` = ?", }; + if user == true then + table.remove(args, 2); + table.remove(where, 2); + end archive_where(query, args, where); archive_where_id_range(query, args, where); sql_query = sql_query:format(t_concat(where, " AND ")); -- cgit v1.2.3 From 4078dc07a2a867aa7e7f010c63a9a85b52c433ee Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 12 Feb 2014 19:25:15 +0100 Subject: mod_saslauth: Make sure sasl handler has add_cb_handler (fixes #392) --- plugins/mod_saslauth.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index 4513c511..94c060b3 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -245,7 +245,7 @@ module:hook("stream-features", function(event) if origin.encrypted then -- check wether LuaSec has the nifty binding to the function needed for tls-unique -- FIXME: would be nice to have this check only once and not for every socket - if origin.conn:socket().getpeerfinished then + if origin.conn:socket().getpeerfinished and origin.sasl_handler.add_cb_handler then origin.sasl_handler:add_cb_handler("tls-unique", function(self) return self.userdata:getpeerfinished(); end); -- cgit v1.2.3 From e4186638c7e61215b1df2020a98ae5e7dce313f4 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 12 Feb 2014 13:45:16 +0100 Subject: mod_auth_interal_hashed: Update salt and iteration count when setting a new password --- plugins/mod_auth_internal_hashed.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/mod_auth_internal_hashed.lua b/plugins/mod_auth_internal_hashed.lua index fb87bb9f..954392c9 100644 --- a/plugins/mod_auth_internal_hashed.lua +++ b/plugins/mod_auth_internal_hashed.lua @@ -7,6 +7,8 @@ -- COPYING file in the source package for more information. -- +local max = math.max; + local getAuthenticationDatabaseSHA1 = require "util.sasl.scram".getAuthenticationDatabaseSHA1; local usermanager = require "core.usermanager"; local generate_uuid = require "util.uuid".generate; @@ -39,7 +41,7 @@ end -- Default; can be set per-user -local iteration_count = 4096; +local default_iteration_count = 4096; -- define auth provider local provider = {}; @@ -80,8 +82,8 @@ function provider.set_password(username, password) log("debug", "set_password for username '%s'", username); local account = accounts:get(username); if account then - account.salt = account.salt or generate_uuid(); - account.iteration_count = account.iteration_count or iteration_count; + account.salt = generate_uuid(); + account.iteration_count = max(account.iteration_count or 0, default_iteration_count); local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, account.salt, account.iteration_count); local stored_key_hex = to_hex(stored_key); local server_key_hex = to_hex(server_key); @@ -113,10 +115,10 @@ function provider.create_user(username, password) return accounts:set(username, {}); end local salt = generate_uuid(); - local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, salt, iteration_count); + local valid, stored_key, server_key = getAuthenticationDatabaseSHA1(password, salt, default_iteration_count); local stored_key_hex = to_hex(stored_key); local server_key_hex = to_hex(server_key); - return accounts:set(username, {stored_key = stored_key_hex, server_key = server_key_hex, salt = salt, iteration_count = iteration_count}); + return accounts:set(username, {stored_key = stored_key_hex, server_key = server_key_hex, salt = salt, iteration_count = default_iteration_count}); end function provider.delete_user(username) -- cgit v1.2.3 From 0213c9ded3d5be56806a5e9e528f61bc37331997 Mon Sep 17 00:00:00 2001 From: Florian Zeitz Date: Wed, 19 Feb 2014 20:13:35 +0100 Subject: mod_proxy65: Use mod_disco --- plugins/mod_proxy65.lua | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/plugins/mod_proxy65.lua b/plugins/mod_proxy65.lua index 2ed9faac..73527cbc 100644 --- a/plugins/mod_proxy65.lua +++ b/plugins/mod_proxy65.lua @@ -101,27 +101,10 @@ function module.add_host(module) module:log("warn", "proxy65_port is deprecated, please put proxy65_ports = { %d } into the global section instead", legacy_config); end + module:depends("disco"); module:add_identity("proxy", "bytestreams", name); module:add_feature("http://jabber.org/protocol/bytestreams"); - module:hook("iq-get/host/http://jabber.org/protocol/disco#info:query", function(event) - local origin, stanza = event.origin, event.stanza; - if not stanza.tags[1].attr.node then - origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#info") - :tag("identity", {category='proxy', type='bytestreams', name=name}):up() - :tag("feature", {var="http://jabber.org/protocol/bytestreams"}) ); - return true; - end - end, -1); - - module:hook("iq-get/host/http://jabber.org/protocol/disco#items:query", function(event) - local origin, stanza = event.origin, event.stanza; - if not stanza.tags[1].attr.node then - origin.send(st.reply(stanza):query("http://jabber.org/protocol/disco#items")); - return true; - end - end, -1); - module:hook("iq-get/host/http://jabber.org/protocol/bytestreams:query", function(event) local origin, stanza = event.origin, event.stanza; -- cgit v1.2.3 From add9033b9b25362ebce1f91a32b4911e66ff8452 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 22 Mar 2014 14:45:04 +0100 Subject: util.sasl: Fix logic for when mechanisms with channel binding support are offered --- util/sasl.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/util/sasl.lua b/util/sasl.lua index c8490842..b91e29a6 100644 --- a/util/sasl.lua +++ b/util/sasl.lua @@ -100,14 +100,16 @@ end function method:mechanisms() local current_mechs = {}; for mech, _ in pairs(self.mechs) do - if mechanism_channelbindings[mech] and self.profile.cb then - local ok = false; - for cb_name, _ in pairs(self.profile.cb) do - if mechanism_channelbindings[mech][cb_name] then - ok = true; + if mechanism_channelbindings[mech] then + if self.profile.cb then + local ok = false; + for cb_name, _ in pairs(self.profile.cb) do + if mechanism_channelbindings[mech][cb_name] then + ok = true; + end end + if ok == true then current_mechs[mech] = true; end end - if ok == true then current_mechs[mech] = true; end else current_mechs[mech] = true; end -- cgit v1.2.3 From 18f7ffec151b965af2745600f272db50a1c92ad2 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 22 Mar 2014 14:53:17 +0100 Subject: prosody.cfg.lua.dist: mod_posix is enabled by default on posix platforms now --- prosody.cfg.lua.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist index 1d11a658..ade219a8 100644 --- a/prosody.cfg.lua.dist +++ b/prosody.cfg.lua.dist @@ -63,7 +63,6 @@ modules_enabled = { --"http_files"; -- Serve static files from a directory over HTTP -- Other specific functionality - --"posix"; -- POSIX functionality, sends server to background, enables syslog, etc. --"groups"; -- Shared roster support --"announce"; -- Send announcement to all online users --"welcome"; -- Welcome users who register accounts @@ -78,6 +77,7 @@ modules_disabled = { -- "offline"; -- Store offline messages -- "c2s"; -- Handle client connections -- "s2s"; -- Handle server-to-server connections + -- "posix"; -- POSIX functionality, sends server to background, enables syslog, etc. } -- Disable account creation by default, for security -- cgit v1.2.3