aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mod_bosh.lua4
-rw-r--r--plugins/mod_component.lua2
-rw-r--r--plugins/mod_compression.lua8
-rw-r--r--plugins/mod_console.lua2
-rw-r--r--plugins/mod_debug.lua191
-rw-r--r--plugins/mod_offline.lua56
-rw-r--r--plugins/mod_pep.lua93
-rw-r--r--plugins/mod_presence.lua41
-rw-r--r--plugins/mod_register.lua2
-rw-r--r--plugins/mod_saslauth.lua6
-rw-r--r--plugins/mod_selftests.lua61
-rw-r--r--plugins/mod_tls.lua14
-rw-r--r--plugins/muc/muc.lib.lua43
13 files changed, 156 insertions, 367 deletions
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index 3e41ef7b..5de79eff 100644
--- a/plugins/mod_bosh.lua
+++ b/plugins/mod_bosh.lua
@@ -152,7 +152,7 @@ function stream_callbacks.streamopened(request, attr)
local r, send_buffer = session.requests, session.send_buffer;
local response = { headers = default_headers }
function session.send(s)
- log("debug", "Sending BOSH data: %s", tostring(s));
+ --log("debug", "Sending BOSH data: %s", tostring(s));
local oldest_request = r[1];
while oldest_request and oldest_request.destroyed do
t_remove(r, 1);
@@ -160,7 +160,7 @@ function stream_callbacks.streamopened(request, attr)
oldest_request = r[1];
end
if oldest_request then
- log("debug", "We have an open request, so using that to send with");
+ log("debug", "We have an open request, so sending on that");
response.body = t_concat{"<body xmlns='http://jabber.org/protocol/httpbind' sid='", sid, "' xmlns:stream = 'http://etherx.jabber.org/streams'>", tostring(s), "</body>" };
oldest_request:send(response);
--log("debug", "Sent");
diff --git a/plugins/mod_component.lua b/plugins/mod_component.lua
index 69a42eaf..4201bb19 100644
--- a/plugins/mod_component.lua
+++ b/plugins/mod_component.lua
@@ -44,7 +44,7 @@ function handle_component_auth(session, stanza)
local secret = config.get(session.user, "core", "component_secret");
if not secret then
- (session.log or log)("warn", "Component attempted to identify as %s, but component_password is not set", session.user);
+ (session.log or log)("warn", "Component attempted to identify as %s, but component_secret is not set", session.user);
session:close("not-authorized");
return;
end
diff --git a/plugins/mod_compression.lua b/plugins/mod_compression.lua
index f1cae737..ec9e24ec 100644
--- a/plugins/mod_compression.lua
+++ b/plugins/mod_compression.lua
@@ -14,10 +14,10 @@ local xmlns_compression_protocol = "http://jabber.org/protocol/compress"
local compression_stream_feature = st.stanza("compression", {xmlns=xmlns_compression_feature}):tag("method"):text("zlib"):up();
local compression_level = module:get_option("compression_level");
-
-- if not defined assume admin wants best compression
if compression_level == nil then compression_level = 9 end;
+
compression_level = tonumber(compression_level);
if not compression_level or compression_level < 1 or compression_level > 9 then
module:log("warn", "Invalid compression level in config: %s", tostring(compression_level));
@@ -41,7 +41,7 @@ module:add_handler({"c2s_unauthed", "c2s"}, "compress", xmlns_compression_protoc
if session.compressed then
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
session.send(error_st);
- session:log("warn", "Tried to establish another compression layer.");
+ session.log("warn", "Tried to establish another compression layer.");
end
-- checking if the compression method is supported
@@ -56,7 +56,7 @@ module:add_handler({"c2s_unauthed", "c2s"}, "compress", xmlns_compression_protoc
if status == false then
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
session.send(error_st);
- session:log("error", "Failed to create zlib.deflate filter.");
+ session.log("error", "Failed to create zlib.deflate filter.");
module:log("error", deflate_stream);
return
end
@@ -65,7 +65,7 @@ module:add_handler({"c2s_unauthed", "c2s"}, "compress", xmlns_compression_protoc
if status == false then
local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
session.send(error_st);
- session:log("error", "Failed to create zlib.deflate filter.");
+ session.log("error", "Failed to create zlib.deflate filter.");
module:log("error", inflate_stream);
return
end
diff --git a/plugins/mod_console.lua b/plugins/mod_console.lua
index 82045232..d8362a07 100644
--- a/plugins/mod_console.lua
+++ b/plugins/mod_console.lua
@@ -192,7 +192,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:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]]
+ print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]]
elseif section == "config" then
print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]]
elseif section == "console" then
diff --git a/plugins/mod_debug.lua b/plugins/mod_debug.lua
deleted file mode 100644
index 9f80202f..00000000
--- a/plugins/mod_debug.lua
+++ /dev/null
@@ -1,191 +0,0 @@
--- 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.
---
-
-module.host = "*";
-
-local connlisteners_register = require "net.connlisteners".register;
-
-local console_listener = { default_port = 5583; default_mode = "*l"; default_interface = "127.0.0.1" };
-
-local sha256, missingglobal = require "util.hashes".sha256;
-
-local commands = {};
-local debug_env = {};
-local debug_env_mt = { __index = function (t, k) return rawget(_G, k) or missingglobal(k); end, __newindex = function (t, k, v) rawset(_G, k, v); end };
-
-local t_insert, t_concat = table.insert, table.concat;
-local t_concatall = function (t, sep) local tt = {}; for k, s in pairs(t) do tt[k] = tostring(s); end return t_concat(tt, sep); end
-
-
-setmetatable(debug_env, debug_env_mt);
-
-console = {};
-
-function console:new_session(conn)
- local w = function(s) conn.write(s:gsub("\n", "\r\n")); end;
- local session = { conn = conn;
- send = function (t) w(tostring(t)); end;
- print = function (t) w("| "..tostring(t).."\n"); end;
- disconnect = function () conn.close(); end;
- };
-
- return session;
-end
-
-local sessions = {};
-
-function console_listener.listener(conn, data)
- local session = sessions[conn];
-
- if not session then
- -- Handle new connection
- session = console:new_session(conn);
- sessions[conn] = session;
- printbanner(session);
- end
- if data then
- -- Handle data
- (function(session, data)
- if data:match("[!.]$") then
- local command = data:lower();
- command = data:match("^%w+") or data:match("%p");
- if commands[command] then
- commands[command](session, data);
- return;
- end
- end
-
- local chunk, err = loadstring("return "..data);
- if not chunk then
- chunk, err = loadstring(data);
- if not chunk then
- err = err:gsub("^%[string .-%]:%d+: ", "");
- err = err:gsub("^:%d+: ", "");
- err = err:gsub("'<eof>'", "the end of the line");
- session.print("Sorry, I couldn't understand that... "..err);
- return;
- end
- end
-
- debug_env.print = session.print;
-
- setfenv(chunk, debug_env);
-
- local ret = { pcall(chunk) };
-
- if not ret[1] then
- session.print("Fatal error while running command, it did not complete");
- session.print("Error: "..ret[2]);
- return;
- end
-
- table.remove(ret, 1);
-
- local retstr = t_concatall(ret, ", ");
- if retstr ~= "" then
- session.print("Result: "..retstr);
- else
- session.print("No result, or nil");
- return;
- end
- end)(session, data);
- end
- session.send(string.char(0));
-end
-
-function console_listener.disconnect(conn, err)
-
-end
-
-connlisteners_register('debug', console_listener);
-require "net.connlisteners".start("debug");
-
--- Console commands --
--- These are simple commands, not valid standalone in Lua
-
-function commands.bye(session)
- session.print("See you! :)");
- session.disconnect();
-end
-
-commands["!"] = function (session, data)
- if data:match("^!!") then
- session.print("!> "..session.env._);
- return console_listener.listener(session.conn, session.env._);
- end
- local old, new = data:match("^!(.-[^\\])!(.-)!$");
- if old and new then
- local ok, res = pcall(string.gsub, session.env._, old, new);
- if not ok then
- session.print(res)
- return;
- end
- session.print("!> "..res);
- return console_listener.listener(session.conn, res);
- end
- session.print("Sorry, not sure what you want");
-end
-
-function printbanner(session)
-session.print [[
- ____ \ / _
- | _ \ _ __ ___ ___ _-_ __| |_ _
- | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
- | __/| | | (_) \__ \ |_| | (_| | |_| |
- |_| |_| \___/|___/\___/ \__,_|\__, |
- A study in simplicity |___/
-
-]]
-session.print("Welcome to the Prosody debug console. For a list of commands, type: help");
-session.print("You may find more help on using this console in our online documentation at ");
-session.print("http://prosody.im/doc/debugconsole\n");
-end
-
-local byte, char = string.byte, string.char;
-local gmatch, gsub = string.gmatch, string.gsub;
-
-local function vdecode(text, key)
- local keyarr = {};
- for l in gmatch(key, ".") do t_insert(keyarr, byte(l) - 32) end
- local pos, keylen = 0, #keyarr;
- return (gsub(text, ".", function (letter)
- if byte(letter) < 32 then return ""; end
- pos = (pos%keylen)+1;
- return char(((byte(letter) - 32 - keyarr[pos]) % 94) + 32);
- end));
-end
-
-local subst = {
- ["f880c08056ba7dbecb1ccfe5d7728bd6dcd654e94f7a9b21788c43397bae0bc5"] =
- [=[nRYeKR$l'5Ix%u*1Mc-K}*bwv*\ $1KLMBd$KH R38`$[6}VQ@,6Qn]=];
- ["92f718858322157202ec740698c1390e47bc819e52b6a099c54c378a9f7529d6"] =
- [=[V\Z5`WZ5,T$<)7LM'w3Z}M(7V'{pa) &'>0+{v)O(0M*V5K$$LL$|2wT}6
- 1as*")e!>]=];
- ["467b65edcc7c7cd70abf2136cc56abd037216a6cd9e17291a2219645be2e2216"] =
- [=[i#'Z,E1-"YaHW(j/0xs]I4x&%(Jx1h&18'(exNWT D3b+K{*8}w(%D {]=];
- ["f73729d7f2fbe686243a25ac088c7e6aead3d535e081329f2817438a5c78bee5"] =
- [=[,3+(Q{3+W\ftQ%wvv/C0z-l%f>ABc(vkp<bb8]=];
- ["6afa189489b096742890d0c5bd17d5bb8af8ac460c7026984b64e8f14a40404e"] =
- [=[9N{)5j34gd*}&]H&dy"I&7(",a F1v6jY+IY7&S+86)1z(Vo]=];
- ["cc5e5293ef8a1acbd9dd2bcda092c5c77ef46d3ec5aea65024fca7ed4b3c94a9"] =
- [=[_]Rc}IF'Kfa&))Ry+6|x!K2|T*Vze)%4Hwz'L3uI|OwIa)|q#uq2+Qu u7
- [V3(z(*TYY|T\1_W'2] Dwr{-{@df#W.H5^x(ydtr{c){UuV@]=];
- ["b3df231fd7ddf73f72f39cb2510b1fe39318f4724728ed58948a180663184d3e"] =
- [=[iH!"9NLS'%geYw3^R*fvWM1)MwxLS!d[zP(p0sQ|8tX{dWO{9w!+W)b"MU
- W)V8&(2Wx"'dTL9*PP%1"JV(I|Jr1^f'-Hc3U\2H3Z='K#,)dPm]=];
- }
-
-function missingglobal(name)
- if sha256 then
- local hash = sha256(name.."|"..name:reverse(), true);
-
- if subst[hash] then
- return vdecode(subst[hash], sha256(name:reverse(), true));
- end
- end
-end
diff --git a/plugins/mod_offline.lua b/plugins/mod_offline.lua
deleted file mode 100644
index c74d011e..00000000
--- a/plugins/mod_offline.lua
+++ /dev/null
@@ -1,56 +0,0 @@
--- 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.
---
-
-
-local datamanager = require "util.datamanager";
-local st = require "util.stanza";
-local datetime = require "util.datetime";
-local ipairs = ipairs;
-local jid_split = require "util.jid".split;
-
-module:add_feature("msgoffline");
-
-module:hook("message/offline/store", function(event)
- local origin, stanza = event.origin, event.stanza;
- local to = stanza.attr.to;
- local node, host;
- if to then
- node, host = jid_split(to)
- 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 true;
-end);
-
-module:hook("message/offline/broadcast", function(event)
- local origin = event.origin;
- local node, host = origin.username, origin.host;
-
- local data = datamanager.list_load(node, host, "offline");
- if not data then return true; end
- for _, stanza in ipairs(data) do
- stanza = st.deserialize(stanza);
- stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = host, stamp = stanza.attr.stamp}):up(); -- XEP-0203
- stanza:tag("x", {xmlns = "jabber:x:delay", from = host, stamp = stanza.attr.stamp_legacy}):up(); -- XEP-0091 (deprecated)
- stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;
- origin.send(stanza);
- end
- return true;
-end);
-
-module:hook("message/offline/delete", function(event)
- local origin = event.origin;
- local node, host = origin.username, origin.host;
-
- return datamanager.list_store(node, host, "offline", nil);
-end);
diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua
index bfe22867..ef03ab0f 100644
--- a/plugins/mod_pep.lua
+++ b/plugins/mod_pep.lua
@@ -37,9 +37,16 @@ end
module:add_identity("pubsub", "pep", "Prosody");
module:add_feature("http://jabber.org/protocol/pubsub#publish");
-local function publish(session, node, item)
+local function subscription_presence(user_bare, recipient)
+ local recipient_bare = jid_bare(recipient);
+ if (recipient_bare == user_bare) then return true end
+ local item = load_roster(jid_split(user_bare))[recipient_bare];
+ return item and (item.subscription == 'from' or item.subscription == 'both');
+end
+
+local function publish(session, node, id, item)
item.attr.xmlns = nil;
- local disable = #item.tags ~= 1 or #item.tags[1].tags == 0;
+ local disable = #item.tags ~= 1 or #item.tags[1] == 0;
if #item.tags == 0 then item.name = "retract"; end
local bare = session.username..'@'..session.host;
local stanza = st.message({from=bare, type='headline'})
@@ -58,9 +65,9 @@ local function publish(session, node, item)
end
else
if not user_data then user_data = {}; data[bare] = user_data; end
- user_data[node] = stanza;
+ user_data[node] = {id or "1", item};
end
-
+
-- broadcast
for recipient, notify in pairs(recipients[bare] or NULL) do
if notify[node] then
@@ -74,10 +81,14 @@ local function publish_all(user, recipient, session)
local notify = recipients[user] and recipients[user][recipient];
if d and notify then
for node in pairs(notify) do
- local message = d[node];
- if message then
- message.attr.to = recipient;
- session.send(message);
+ if d[node] then
+ local id, item = unpack(d[node]);
+ session.send(st.message({from=user, to=recipient, type='headline'})
+ :tag('event', {xmlns='http://jabber.org/protocol/pubsub#event'})
+ :tag('items', {node=node})
+ :add_child(item)
+ :up()
+ :up());
end
end
end
@@ -106,11 +117,9 @@ end
module:hook("presence/bare", function(event)
-- inbound presence to bare JID recieved
local origin, stanza = event.origin, event.stanza;
-
local user = stanza.attr.to or (origin.username..'@'..origin.host);
- local bare = jid_bare(stanza.attr.from);
- local item = load_roster(jid_split(user))[bare];
- if not stanza.attr.to or (item and (item.subscription == 'from' or item.subscription == 'both')) then
+
+ if not stanza.attr.to or subscription_presence(user, stanza.attr.from) then
local recipient = stanza.attr.from;
local current = recipients[user] and recipients[user][recipient];
local hash = get_caps_hash_from_presence(stanza, current);
@@ -135,19 +144,63 @@ end, 10);
module:hook("iq/bare/http://jabber.org/protocol/pubsub:pubsub", function(event)
local session, stanza = event.origin, event.stanza;
+ local payload = stanza.tags[1];
+
if stanza.attr.type == 'set' and (not stanza.attr.to or jid_bare(stanza.attr.from) == stanza.attr.to) then
- local payload = stanza.tags[1];
- if payload.name == 'pubsub' then -- <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+ payload = payload.tags[1];
+ if payload and (payload.name == 'publish' or payload.name == 'retract') and payload.attr.node then -- <publish node='http://jabber.org/protocol/tune'>
+ local node = payload.attr.node;
payload = payload.tags[1];
- if payload and (payload.name == 'publish' or payload.name == 'retract') and payload.attr.node then -- <publish node='http://jabber.org/protocol/tune'>
- local node = payload.attr.node;
- payload = payload.tags[1];
- if payload and payload.name == "item" then -- <item>
- session.send(st.reply(stanza));
- publish(session, node, st.clone(payload));
+ if payload and payload.name == "item" then -- <item>
+ local id = payload.attr.id;
+ session.send(st.reply(stanza));
+ publish(session, node, id, st.clone(payload));
+ return true;
+ end
+ end
+ elseif stanza.attr.type == 'get' then
+ local user = stanza.attr.to and jid_bare(stanza.attr.to) or session.username..'@'..session.host;
+ if subscription_presence(user, stanza.attr.from) then
+ local user_data = data[user];
+ local node, requested_id;
+ payload = payload.tags[1];
+ if payload and payload.name == 'items' then
+ node = payload.attr.node;
+ local item = payload.tags[1];
+ if item and item.name == "item" then
+ requested_id = item.attr.id;
+ end
+ end
+ if node and user_data and user_data[node] then -- Send the last item
+ local id, item = unpack(user_data[node]);
+ if not requested_id or id == requested_id then
+ local stanza = st.reply(stanza)
+ :tag('pubsub', {xmlns='http://jabber.org/protocol/pubsub'})
+ :tag('items', {node=node})
+ :add_child(item)
+ :up()
+ :up();
+ session.send(stanza);
+ return true;
+ else -- requested item doesn't exist
+ local stanza = st.reply(stanza)
+ :tag('pubsub', {xmlns='http://jabber.org/protocol/pubsub'})
+ :tag('items', {node=node})
+ :up();
+ session.send(stanza);
return true;
end
+ elseif node then -- node doesn't exist
+ session.send(st.error_reply(stanza, 'cancel', 'item-not-found'));
+ return true;
+ else --invalid request
+ session.send(st.error_reply(stanza, 'modify', 'bad-request'));
+ return true;
end
+ else --no presence subscription
+ session.send(st.error_reply(stanza, 'auth', 'not-authorized')
+ :tag('presence-subscription-required', {xmlns='http://jabber.org/protocol/pubsub#errors'}));
+ return true;
end
end
end);
diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
index abbc3a3d..a39d9c19 100644
--- a/plugins/mod_presence.lua
+++ b/plugins/mod_presence.lua
@@ -18,6 +18,7 @@ local st = require "util.stanza";
local jid_split = require "util.jid".split;
local jid_bare = require "util.jid".bare;
local hosts = hosts;
+local NULL = {};
local rostermanager = require "core.rostermanager";
local sessionmanager = require "core.sessionmanager";
@@ -54,16 +55,21 @@ local function select_top_resources(user)
end
return recipients;
end
-local function recalc_resource_map(origin)
- local user = hosts[origin.host].sessions[origin.username];
- user.top_resources = select_top_resources(user);
- if #user.top_resources == 0 then user.top_resources = nil; end
+local function recalc_resource_map(user)
+ if user then
+ user.top_resources = select_top_resources(user);
+ if #user.top_resources == 0 then user.top_resources = nil; end
+ end
end
function handle_normal_presence(origin, stanza, core_route_stanza)
+ if full_sessions[origin.full_jid] then -- if user is still connected
+ origin.send(stanza); -- reflect their presence back to them
+ end
local roster = origin.roster;
local node, host = origin.username, origin.host;
- for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
+ local user = bare_sessions[node.."@"..host];
+ for _, res in pairs(user and user.sessions or NULL) do -- broadcast to all resources
if res ~= origin and res.presence then -- to resource
stanza.attr.to = res.full_jid;
core_route_stanza(origin, stanza);
@@ -76,6 +82,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza)
end
end
if stanza.attr.type == nil and not origin.presence then -- initial presence
+ origin.presence = stanza; -- FIXME repeated later
local probe = st.presence({from = origin.full_jid, type = "probe"});
for jid, item in pairs(roster) do -- probe all contacts we are subscribed to
if item.subscription == "both" or item.subscription == "to" then
@@ -83,7 +90,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza)
core_route_stanza(origin, probe);
end
end
- for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
+ for _, res in pairs(user and user.sessions or NULL) do -- broadcast from all available resources
if res ~= origin and res.presence then
res.presence.attr.to = origin.full_jid;
core_route_stanza(res, res.presence);
@@ -114,7 +121,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza)
origin.presence = nil;
if origin.priority then
origin.priority = nil;
- recalc_resource_map(origin);
+ recalc_resource_map(user);
end
if origin.directed then
for jid in pairs(origin.directed) do
@@ -136,7 +143,7 @@ function handle_normal_presence(origin, stanza, core_route_stanza)
else priority = 0; end
if origin.priority ~= priority then
origin.priority = priority;
- recalc_resource_map(origin);
+ recalc_resource_map(user);
end
end
stanza.attr.to = nil; -- reset it
@@ -217,7 +224,7 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b
if stanza.attr.type == "probe" then
if rostermanager.is_contact_subscribed(node, host, from_bare) then
if 0 == send_presence_of_available_resources(node, host, st_from, origin, core_route_stanza) then
- -- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
+ core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"})); -- TODO send last activity
end
else
core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unsubscribed"}));
@@ -227,7 +234,7 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b
core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed
-- Sending presence is not clearly stated in the RFC, but it seems appropriate
if 0 == send_presence_of_available_resources(node, host, from_bare, origin, core_route_stanza) then
- -- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
+ core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"})); -- TODO send last activity
end
else
core_route_stanza(hosts[host], st.presence({from=to_bare, to=from_bare, type="unavailable"})); -- acknowledging receipt
@@ -326,6 +333,20 @@ module:hook("presence/full", function(data)
end -- resource not online, discard
return true;
end);
+module:hook("presence/host", function(data)
+ -- inbound presence to the host
+ local origin, stanza = data.origin, data.stanza;
+
+ local from_bare = jid_bare(stanza.attr.from);
+ local t = stanza.attr.type;
+ if t == "probe" then
+ core_route_stanza(hosts[module.host], st.presence({ from = module.host, to = from_bare, id = stanza.attr.id }));
+ elseif t == "subscribe" then
+ core_route_stanza(hosts[module.host], st.presence({ from = module.host, to = from_bare, id = stanza.attr.id, type = "subscribed" }));
+ core_route_stanza(hosts[module.host], st.presence({ from = module.host, to = from_bare, id = stanza.attr.id }));
+ end
+ return true;
+end);
module:hook("resource-unbind", function(event)
local session, err = event.session, event.error;
diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua
index bda40124..be1be0ae 100644
--- a/plugins/mod_register.lua
+++ b/plugins/mod_register.lua
@@ -141,7 +141,7 @@ module:add_iq_handler("c2s_unauthed", "jabber:iq:register", function (session, s
username = nodeprep(table.concat(username));
password = table.concat(password);
local host = module.host;
- if not username then
+ if not username or username == "" then
session.send(st.error_reply(stanza, "modify", "not-acceptable", "The requested username is invalid."));
elseif usermanager_user_exists(username, host) then
session.send(st.error_reply(stanza, "cancel", "conflict", "The requested username already exists."));
diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua
index e248479b..2aee2be0 100644
--- a/plugins/mod_saslauth.lua
+++ b/plugins/mod_saslauth.lua
@@ -38,13 +38,13 @@ local new_sasl = require "util.sasl".new;
local function build_reply(status, ret, err_msg)
local reply = st.stanza(status, {xmlns = xmlns_sasl});
if status == "challenge" then
- log("debug", "%s", ret or "");
+ --log("debug", "CHALLENGE: %s", ret or "");
reply:text(base64.encode(ret or ""));
elseif status == "failure" then
reply:tag(ret):up();
if err_msg then reply:tag("text"):text(err_msg); end
elseif status == "success" then
- log("debug", "%s", ret or "");
+ --log("debug", "SUCCESS: %s", ret or "");
reply:text(base64.encode(ret or ""));
else
module:log("error", "Unknown sasl status: %s", status);
@@ -124,7 +124,7 @@ local function sasl_handler(session, stanza)
local text = stanza[1];
if text then
text = base64.decode(text);
- log("debug", "%s", text);
+ --log("debug", "AUTH: %s", text:gsub("[%z\001-\008\011\012\014-\031]", " "));
if not text then
session.sasl_handler = nil;
session.send(build_reply("failure", "incorrect-encoding"));
diff --git a/plugins/mod_selftests.lua b/plugins/mod_selftests.lua
deleted file mode 100644
index 1f413634..00000000
--- a/plugins/mod_selftests.lua
+++ /dev/null
@@ -1,61 +0,0 @@
--- 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.
---
-
-module.host = "*" -- Global module
-
-local st = require "util.stanza";
-local register_component = require "core.componentmanager".register_component;
-local core_route_stanza = core_route_stanza;
-local socket = require "socket";
-local ping_hosts = module:get_option("ping_hosts") or { "coversant.interop.xmpp.org", "djabberd.interop.xmpp.org", "djabberd-trunk.interop.xmpp.org", "ejabberd.interop.xmpp.org", "openfire.interop.xmpp.org" };
-
-local open_pings = {};
-
-local t_insert = table.insert;
-
-local log = require "util.logger".init("mod_selftests");
-
-local tests_jid = "self_tests@getjabber.ath.cx";
-local host = "getjabber.ath.cx";
-
-if not (tests_jid and host) then
- for currhost in pairs(host) do
- if currhost ~= "localhost" then
- tests_jid, host = "self_tests@"..currhost, currhost;
- end
- end
-end
-
-if tests_jid and host then
- local bot = register_component(tests_jid, function(origin, stanza, ourhost)
- local time = open_pings[stanza.attr.id];
-
- if time then
- log("info", "Ping reply from %s in %fs", tostring(stanza.attr.from), socket.gettime() - time);
- else
- log("info", "Unexpected reply: %s", stanza:pretty_print());
- end
- end);
-
-
- local our_origin = hosts[host];
- module:add_event_hook("server-started",
- function ()
- local id = st.new_id();
- local ping_attr = { xmlns = 'urn:xmpp:ping' };
- local function send_ping(to)
- log("info", "Sending ping to %s", to);
- core_route_stanza(our_origin, st.iq{ to = to, from = tests_jid, id = id, type = "get" }:tag("ping", ping_attr));
- open_pings[id] = socket.gettime();
- end
-
- for _, host in ipairs(ping_hosts) do
- send_ping(host);
- end
- end);
-end
diff --git a/plugins/mod_tls.lua b/plugins/mod_tls.lua
index cceef308..67555b15 100644
--- a/plugins/mod_tls.lua
+++ b/plugins/mod_tls.lua
@@ -14,9 +14,11 @@ local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
local secure_s2s_only = module:get_option("s2s_require_encryption");
+local host = hosts[module.host];
+
module:add_handler("c2s_unauthed", "starttls", xmlns_starttls,
function (session, stanza)
- if session.conn.starttls then
+ if session.conn.starttls and host.ssl_ctx_in then
session.send(st.stanza("proceed", { xmlns = xmlns_starttls }));
session:reset_stream();
if session.host and hosts[session.host].ssl_ctx_in then
@@ -26,14 +28,15 @@ module:add_handler("c2s_unauthed", "starttls", xmlns_starttls,
session.log("info", "TLS negotiation started...");
session.secure = false;
else
- -- FIXME: What reply?
session.log("warn", "Attempt to start TLS, but TLS is not available on this connection");
+ (session.sends2s or session.send)(st.stanza("failure", { xmlns = xmlns_starttls }));
+ session:close();
end
end);
module:add_handler("s2sin_unauthed", "starttls", xmlns_starttls,
function (session, stanza)
- if session.conn.starttls then
+ if session.conn.starttls and host.ssl_ctx_in then
session.sends2s(st.stanza("proceed", { xmlns = xmlns_starttls }));
session:reset_stream();
if session.to_host and hosts[session.to_host].ssl_ctx_in then
@@ -43,8 +46,9 @@ module:add_handler("s2sin_unauthed", "starttls", xmlns_starttls,
session.log("info", "TLS negotiation started for incoming s2s...");
session.secure = false;
else
- -- FIXME: What reply?
session.log("warn", "Attempt to start TLS, but TLS is not available on this s2s connection");
+ (session.sends2s or session.send)(st.stanza("failure", { xmlns = xmlns_starttls }));
+ session:close();
end
end);
@@ -66,7 +70,7 @@ module:hook("s2s-stream-features",
function (data)
local session, features = data.session, data.features;
if session.to_host and session.conn.starttls then
- features:tag("starttls", starttls_attr):up();
+ features:tag("starttls", starttls_attr);
if secure_s2s_only then
features:tag("required"):up():up();
else
diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua
index 3a185e17..60687886 100644
--- a/plugins/muc/muc.lib.lua
+++ b/plugins/muc/muc.lib.lua
@@ -128,19 +128,21 @@ function room_mt:broadcast_presence(stanza, sid, code, nick)
end
end
function room_mt:broadcast_message(stanza, historic)
+ local to = stanza.attr.to;
for occupant, o_data in pairs(self._occupants) do
for jid in pairs(o_data.sessions) do
stanza.attr.to = jid;
self:_route_stanza(stanza);
end
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 = st.clone(stanza);
stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = datetime.datetime()}):up(); -- XEP-0203
stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
- t_insert(history, st.clone(st.preserialize(stanza)));
+ t_insert(history, st.preserialize(stanza));
while #history > history_length do t_remove(history, 1) end
end
end
@@ -461,6 +463,9 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha
if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
local occupant = self._occupants[self.jid.."/"..item.attr.nick];
if occupant then item.attr.jid = occupant.jid; end
+ elseif not item.attr.nick and item.attr.jid then
+ local nick = self._jid_nick[item.attr.jid];
+ if nick then item.attr.nick = select(3, jid_split(nick)); end
end
local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1];
if item.attr.affiliation and item.attr.jid and not item.attr.role then
@@ -492,9 +497,14 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha
-- TODO allow admins and owners not in room? Provide read-only access to everyone who can see the participants anyway?
if _rol == "none" then _rol = nil; end
local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin");
- for nick, occupant in pairs(self._occupants) do
+ for occupant_jid, occupant in pairs(self._occupants) do
if occupant.role == _rol then
- reply:tag("item", {nick = nick, role = _rol or "none", affiliation = occupant.affiliation or "none", jid = occupant.jid}):up();
+ reply:tag("item", {
+ nick = select(3, jid_split(occupant_jid)),
+ role = _rol or "none",
+ affiliation = occupant.affiliation or "none",
+ jid = occupant.jid
+ }):up();
end
end
origin.send(reply);
@@ -517,17 +527,26 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha
local from, to = stanza.attr.from, stanza.attr.to;
local room = jid_bare(to);
local current_nick = self._jid_nick[from];
- if not current_nick then -- not in room
+ local occupant = self._occupants[current_nick];
+ if not occupant then -- not in room
origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
+ elseif occupant.role == "visitor" then
+ origin.send(st.error_reply(stanza, "cancel", "forbidden"));
else
local from = stanza.attr.from;
stanza.attr.from = current_nick;
local subject = getText(stanza, {"subject"});
if subject then
- self:set_subject(current_nick, subject); -- TODO use broadcast_message_stanza
+ if occupant.role == "moderator" then
+ self:set_subject(current_nick, subject); -- TODO use broadcast_message_stanza
+ else
+ stanza.attr.from = from;
+ origin.send(st.error_reply(stanza, "cancel", "forbidden"));
+ end
else
self:broadcast_message(stanza, true);
end
+ stanza.attr.from = from;
end
elseif stanza.name == "message" and type == "error" and is_kickable_error(stanza) then
local current_nick = self._jid_nick[stanza.attr.from];
@@ -651,21 +670,21 @@ function room_mt:get_role(nick)
local session = self._occupants[nick];
return session and session.role or nil;
end
-function room_mt:set_role(actor, nick, role, callback, reason)
+function room_mt:set_role(actor, occupant_jid, role, callback, reason)
if role == "none" then role = nil; end
if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end
if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
- local occupant = self._occupants[nick];
+ local occupant = self._occupants[occupant_jid];
if not occupant then return nil, "modify", "not-acceptable"; end
if occupant.affiliation == "owner" or occupant.affiliation == "admin" then return nil, "cancel", "not-allowed"; end
- local p = st.presence({from = nick})
+ local p = st.presence({from = occupant_jid})
:tag("x", {xmlns = "http://jabber.org/protocol/muc#user"})
- :tag("item", {affiliation=occupant.affiliation or "none", nick=nick, role=role or "none"})
+ :tag("item", {affiliation=occupant.affiliation or "none", nick=select(3, jid_split(occupant_jid)), role=role or "none"})
:tag("reason"):text(reason or ""):up()
:up();
if not role then -- kick
p.attr.type = "unavailable";
- self._occupants[nick] = nil;
+ self._occupants[occupant_jid] = nil;
for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick
self._jid_nick[jid] = nil;
end
@@ -678,7 +697,7 @@ function room_mt:set_role(actor, nick, role, callback, reason)
self:_route_stanza(p);
end
if callback then callback(); end
- self:broadcast_except_nick(p, nick);
+ self:broadcast_except_nick(p, occupant_jid);
return true;
end