diff options
-rw-r--r-- | core/usermanager.lua | 7 | ||||
-rw-r--r-- | plugins/mod_admin_adhoc.lua | 3 | ||||
-rw-r--r-- | plugins/mod_c2s.lua | 10 | ||||
-rw-r--r-- | plugins/mod_http.lua | 21 | ||||
-rw-r--r-- | plugins/mod_register.lua | 31 | ||||
-rw-r--r-- | plugins/mod_roster.lua | 18 | ||||
-rwxr-xr-x | prosodyctl | 2 | ||||
-rwxr-xr-x | tools/xep227toprosody.lua | 12 | ||||
-rw-r--r-- | util/datamanager.lua | 19 | ||||
-rw-r--r-- | util/prosodyctl.lua | 4 | ||||
-rw-r--r-- | util/stanza.lua | 2 |
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); @@ -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(); |