aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/usermanager.lua7
-rw-r--r--plugins/mod_admin_adhoc.lua3
-rw-r--r--plugins/mod_c2s.lua10
-rw-r--r--plugins/mod_http.lua21
-rw-r--r--plugins/mod_register.lua31
-rw-r--r--plugins/mod_roster.lua18
-rwxr-xr-xprosodyctl2
-rwxr-xr-xtools/xep227toprosody.lua12
-rw-r--r--util/datamanager.lua19
-rw-r--r--util/prosodyctl.lua4
-rw-r--r--util/stanza.lua2
11 files changed, 78 insertions, 51 deletions
diff --git a/core/usermanager.lua b/core/usermanager.lua
index efc15b7c..2ca0aef1 100644
--- a/core/usermanager.lua
+++ b/core/usermanager.lua
@@ -90,14 +90,9 @@ function create_user(username, password, host)
end
function delete_user(username, host)
- local user = hosts[host].sessions[username];
- if user and user.sessions then
- for jid, session in pairs(user.sessions) do
- session:close{ condition = "not-authorized", text = "Account deleted" };
- end
- end
local ok, err = hosts[host].users.delete_user(username);
if not ok then return nil, err; end
+ prosody.events.fire_event("user-deleted", { username = username, host = host });
return storagemanager.get_driver(host):purge(username);
end
diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua
index a6cf78cf..a13c7312 100644
--- a/plugins/mod_admin_adhoc.lua
+++ b/plugins/mod_admin_adhoc.lua
@@ -14,6 +14,7 @@ local iterators = require "util.iterators";
local keys, values = iterators.keys, iterators.values;
local usermanager_user_exists = require "core.usermanager".user_exists;
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 is_admin = require "core.usermanager".is_admin;
@@ -142,7 +143,7 @@ function delete_user_command_handler(self, data, state)
local succeeded = {};
for _, aJID in ipairs(fields.accountjids) do
local username, host, resource = jid.split(aJID);
- if (host == data.to) and usermanager_user_exists(username, host) and disconnect_user(aJID) and usermanager_create_user(username, nil, host) then
+ if (host == data.to) and usermanager_user_exists(username, host) and usermanager_delete_user(username, host) then
module:log("debug", "User %s has been deleted", aJID);
succeeded[#succeeded+1] = aJID;
else
diff --git a/plugins/mod_c2s.lua b/plugins/mod_c2s.lua
index 2318ecad..e9b24f69 100644
--- a/plugins/mod_c2s.lua
+++ b/plugins/mod_c2s.lua
@@ -169,6 +169,16 @@ local function session_close(session, reason)
end
end
+module:hook_global("user-deleted", function(event)
+ local username, host = event.username, event.host;
+ local user = hosts[host].sessions[username];
+ if user and user.sessions then
+ for jid, session in pairs(user.sessions) do
+ session:close{ condition = "not-authorized", text = "Account deleted" };
+ end
+ end
+end, 200);
+
--- Port listener
function listener.onconnect(conn)
local session = sm_new_session(conn);
diff --git a/plugins/mod_http.lua b/plugins/mod_http.lua
index 53993f29..090b522b 100644
--- a/plugins/mod_http.lua
+++ b/plugins/mod_http.lua
@@ -11,6 +11,7 @@ module:depends("http_errors");
local moduleapi = require "core.moduleapi";
local url_parse = require "socket.url".parse;
+local url_build = require "socket.url".build;
local server = require "net.http.server";
@@ -30,6 +31,9 @@ local function get_http_event(host, app_path, key)
if method:sub(1,1) == "/" then
return nil;
end
+ if app_path == "/" and path:sub(1,1) == "/" then
+ app_path = "";
+ end
return method:upper().." "..host..app_path..path;
end
@@ -39,6 +43,8 @@ local function get_base_path(host_module, app_name, default_app_path)
or default_app_path); -- Default
end
+local ports_by_scheme = { http = 80, https = 443, };
+
-- Helper to deduce a module's external URL
function moduleapi.http_url(module, app_name, default_path)
app_name = app_name or (module.name:gsub("^http_", ""));
@@ -47,12 +53,15 @@ function moduleapi.http_url(module, app_name, default_path)
local http_services = services:get("https") or services:get("http") or {};
for interface, ports in pairs(http_services) do
for port, services in pairs(ports) do
- local path = get_base_path(module, app_name, default_path or "/"..app_name);
- port = tonumber(ext.port) or port or 80;
- if port == 80 then port = ""; else port = ":"..port; end
- return (ext.scheme or services[1].service.name).."://"
- ..(ext.host or module.host)..port
- ..normalize_path(ext.path or "/")..(path:sub(2));
+ local url = {
+ scheme = (ext.scheme or services[1].service.name);
+ host = (ext.host or module.host);
+ port = tonumber(ext.port) or port or 80;
+ path = normalize_path(ext.path or "/")..
+ (get_base_path(module, app_name, default_path or "/"..app_name):sub(2));
+ }
+ if ports_by_scheme[url.scheme] == url.port then url.port = nil end
+ return url_build(url);
end
end
end
diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua
index 6c690c3b..dfc8c49b 100644
--- a/plugins/mod_register.lua
+++ b/plugins/mod_register.lua
@@ -95,40 +95,23 @@ local function handle_registration_stanza(event)
session.send(reply);
else -- stanza.attr.type == "set"
if query.tags[1] and query.tags[1].name == "remove" then
- -- TODO delete user auth data, send iq response, kick all user resources with a <not-authorized/>, delete all user data
local username, host = session.username, session.host;
+
+ local old_session_close = session.close;
+ session.close = function(session, ...)
+ 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
- session.send(st.reply(stanza));
- local roster = session.roster;
- for _, session in pairs(hosts[host].sessions[username].sessions) do -- disconnect all resources
- session:close({condition = "not-authorized", text = "Account deleted"});
- end
- -- TODO datamanager should be able to delete all user data itself
- datamanager.store(username, host, "vcard", nil);
- datamanager.store(username, host, "private", nil);
- datamanager.store(username, host, "account_details", nil);
- datamanager.list_store(username, host, "offline", nil);
- local bare = username.."@"..host;
- for jid, item in pairs(roster) do
- if jid and jid ~= "pending" then
- if item.subscription == "both" or item.subscription == "from" or (roster.pending and roster.pending[jid]) then
- module:send(st.presence({type="unsubscribed", from=bare, to=jid}));
- end
- if item.subscription == "both" or item.subscription == "to" or item.ask then
- module:send(st.presence({type="unsubscribe", from=bare, to=jid}));
- end
- end
- end
- datamanager.store(username, host, "roster", nil);
- datamanager.store(username, host, "privacy", nil);
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
diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua
index bfb2d927..40d95be7 100644
--- a/plugins/mod_roster.lua
+++ b/plugins/mod_roster.lua
@@ -15,6 +15,7 @@ local t_concat = table.concat;
local tonumber = tonumber;
local pairs, ipairs = pairs, ipairs;
+local rm_load_roster = require "core.rostermanager".load_roster;
local rm_remove_from_roster = require "core.rostermanager".remove_from_roster;
local rm_add_to_roster = require "core.rostermanager".add_to_roster;
local rm_roster_push = require "core.rostermanager".roster_push;
@@ -137,3 +138,20 @@ module:hook("iq/self/jabber:iq:roster:query", function(event)
end
return true;
end);
+
+module:hook_global("user-deleted", function(event)
+ local username, host = event.username, event.host;
+ if host ~= module.host then return end
+ local bare = username .. "@" .. host;
+ local roster = rm_load_roster(username, host);
+ for jid, item in pairs(roster) do
+ if jid and jid ~= "pending" then
+ if item.subscription == "both" or item.subscription == "from" or (roster.pending and roster.pending[jid]) then
+ module:send(st.presence({type="unsubscribed", from=bare, to=jid}));
+ end
+ if item.subscription == "both" or item.subscription == "to" or item.ask then
+ module:send(st.presence({type="unsubscribe", from=bare, to=jid}));
+ end
+ end
+ end
+end, 300);
diff --git a/prosodyctl b/prosodyctl
index c658921b..25570fc4 100755
--- a/prosodyctl
+++ b/prosodyctl
@@ -366,7 +366,7 @@ function commands.deluser(arg)
return 1;
end
- local ok, msg = prosodyctl.passwd { user = user, host = host };
+ local ok, msg = prosodyctl.deluser { user = user, host = host };
if ok then return 0; end
diff --git a/tools/xep227toprosody.lua b/tools/xep227toprosody.lua
index 23e5948b..b5156f45 100755
--- a/tools/xep227toprosody.lua
+++ b/tools/xep227toprosody.lua
@@ -64,11 +64,11 @@ function store_roster(username, host, roster_items)
-- fetch current roster-table for username@host if he already has one
local roster = dm.load(username, host, "roster") or {};
-- merge imported roster-items with loaded roster
- for item_tag in roster_items:childtags() do
+ for item_tag in roster_items:childtags("item") do
-- jid for this roster-item
local item_jid = item_tag.attr.jid
-- validate item stanzas
- if (item_tag.name == "item") and (item_jid ~= "") then
+ if (item_jid ~= "") then
-- prepare roster item
-- TODO: is the subscription attribute optional?
local item = {subscription = item_tag.attr.subscription, groups = {}};
@@ -77,9 +77,9 @@ function store_roster(username, host, roster_items)
item.name = item_tag.attr.name;
end
-- optional: iterate over group stanzas inside item stanza
- for group_tag in item_tag:childtags() do
+ for group_tag in item_tag:childtags("group") do
local group_name = group_tag:get_text();
- if (group_tag.name == "group") and (group_name ~= "") then
+ if (group_name ~= "") then
item.groups[group_name] = true;
else
print("[error] invalid group stanza: "..group_tag:pretty_print());
@@ -100,7 +100,7 @@ end
function store_private(username, host, private_items)
local private = dm.load(username, host, "private") or {};
- for ch in private_items:childtags() do
+ for _, ch in ipairs(private_items.tags) do
--print("private :"..ch:pretty_print());
private[ch.name..":"..ch.attr.xmlns] = st.preserialize(ch);
print("[success] private item: " ..username.."@"..host.." - "..ch.name);
@@ -112,7 +112,7 @@ end
function store_offline_messages(username, host, offline_messages)
-- TODO: maybe use list_load(), append and list_store() instead
-- of constantly reopening the file with list_append()?
- for ch in offline_messages:childtags() do
+ for ch in offline_messages:childtags("message", "jabber:client") do
--print("message :"..ch:pretty_print());
local ret, err = dm.list_append(username, host, "offline", st.preserialize(ch));
print("["..(err or "success").."] stored offline message: " ..username.."@"..host.." - "..ch.attr.from);
diff --git a/util/datamanager.lua b/util/datamanager.lua
index 9f7600ee..17c614ed 100644
--- a/util/datamanager.lua
+++ b/util/datamanager.lua
@@ -309,18 +309,29 @@ function list_stores(username, host)
return list;
end
+local function do_remove(path)
+ local ok, err = os_remove(path);
+ if not ok and lfs.attributes(path, "mode") then
+ return ok, err;
+ end
+ return true
+end
+
function purge(username, host)
local host_dir = format("%s/%s/", data_path, encode(host));
local deleted = 0;
+ local errs = {};
for file in lfs.dir(host_dir) do
if lfs.attributes(host_dir..file, "mode") == "directory" then
local store = decode(file);
- deleted = deleted + (os_remove(getpath(username, host, store)) and 1 or 0);
- deleted = deleted + (os_remove(getpath(username, host, store, "list")) and 1 or 0);
- -- We this will generate loads of "No such file or directory", but do we care?
+ local ok, err = do_remove(getpath(username, host, store));
+ if not ok then errs[#errs+1] = err; end
+
+ local ok, err = do_remove(getpath(username, host, store, "list"));
+ if not ok then errs[#errs+1] = err; end
end
end
- return deleted > 0, deleted;
+ return #errs == 0, t_concat(errs, ", ");
end
return _M;
diff --git a/util/prosodyctl.lua b/util/prosodyctl.lua
index a598a44a..e38f85d4 100644
--- a/util/prosodyctl.lua
+++ b/util/prosodyctl.lua
@@ -176,9 +176,9 @@ function deluser(params)
if not _M.user_exists(params) then
return false, "no-such-user";
end
- params.password = nil;
+ local user, host = nodeprep(params.user), nameprep(params.host);
- return _M.adduser(params);
+ return usermanager.delete_user(user, host);
end
function getpid()
diff --git a/util/stanza.lua b/util/stanza.lua
index 5c430f1d..a0ab2a5a 100644
--- a/util/stanza.lua
+++ b/util/stanza.lua
@@ -237,7 +237,7 @@ function stanza_mt.get_error(stanza)
end
type = error_tag.attr.type;
- for child in error_tag:childtags() do
+ for _, child in ipairs(error_tag.tags) do
if child.attr.xmlns == xmlns_stanzas then
if not text and child.name == "text" then
text = child:get_text();