--- a/mod_admin_web/admin_web/mod_admin_web.lua Sun Jul 22 19:52:45 2012 +0100
+++ b/mod_admin_web/admin_web/mod_admin_web.lua Tue Jul 24 15:33:55 2012 +0100
@@ -21,7 +21,6 @@
local uuid_generate = require "util.uuid".generate;
local is_admin = require "core.usermanager".is_admin;
local pubsub = require "util.pubsub";
-local httpserver = require "net.httpserver";
local jid_bare = require "util.jid".bare;
local lfs = require "lfs";
local open = io.open;
@@ -31,17 +30,12 @@
local service = {};
-local http_base = module.path:gsub("/[^/]+$","") .. "/www_files";
+local http_base = module.path:gsub("/[^/]+$","") .. "/www_files/";
local xmlns_adminsub = "http://prosody.im/adminsub";
local xmlns_c2s_session = "http://prosody.im/streams/c2s";
local xmlns_s2s_session = "http://prosody.im/streams/s2s";
-local response_301 = { status = "301 Moved Permanently" };
-local response_400 = { status = "400 Bad Request", body = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(" };
-local response_403 = { status = "403 Forbidden", body = "<h1>Forbidden</h1>You don't have permission to view the contents of this directory :(" };
-local response_404 = { status = "404 Not Found", body = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(" };
-
local mime_map = {
html = "text/html";
xml = "text/xml";
@@ -110,238 +104,222 @@
end
end
-local function preprocess_path(path)
- if path:sub(1,1) ~= "/" then
- path = "/"..path;
- end
- local level = 0;
- for component in path:gmatch("([^/]+)/") do
- if component == ".." then
- level = level - 1;
- elseif component ~= "." then
- level = level + 1;
+function serve_file(event, path)
+ local full_path = http_base .. path;
+
+ if stat(full_path, "mode") == "directory" then
+ if stat(full_path.."/index.html", "mode") == "file" then
+ return serve_file(event, path.."/index.html");
end
- if level < 0 then
- return nil;
- end
+ return 403;
end
- return path;
-end
-function serve_file(path, base)
- local full_path = http_base..path;
- if stat(full_path, "mode") == "directory" then
- if not path:find("/$") then
- local response = response_301;
- response.headers = { ["Location"] = base .. "/" };
- return response;
- end
- if stat(full_path.."/index.html", "mode") == "file" then
- return serve_file(path.."/index.html");
- end
- return response_403;
+ local f, err = open(full_path, "rb");
+ if not f then
+ return 404;
end
- local f, err = open(full_path, "rb");
- if not f then return response_404; end
+
local data = f:read("*a");
f:close();
if not data then
- return response_403;
+ return 403;
end
- local ext = path:match("%.([^.]*)$");
- local mime = mime_map[ext]; -- Content-Type should be nil when not known
- return {
- headers = { ["Content-Type"] = mime; };
- body = data;
- };
-end
-local function handle_file_request(method, body, request)
- local path = preprocess_path(request.url.path);
- if not path then return response_400; end
- path_stripped = path:gsub("^/[^/]+", ""); -- Strip /admin/
- return serve_file(path_stripped, path);
-end
-
-function module.load()
- local http_conf = config.get("*", "core", "webadmin_http_ports");
-
- httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" });
+ local ext = path:match("%.([^.]*)$");
+ event.response.headers.content_type = mime_map[ext]; -- Content-Type should be nil when not known
+ return data;
end
-prosody.events.add_handler("server-started", function ()
- for host_name, host_table in pairs(hosts) do
- service[host_name] = pubsub.new({
- broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end;
- normalize_jid = jid_bare;
- get_affiliation = function(jid) return get_affiliation(jid, host_name) end;
- capabilities = {
- member = {
- create = false;
- publish = false;
- retract = false;
- get_nodes = true;
+function module.add_host(module)
+ -- Setup HTTP server
+ module:depends("http");
+ module:provides("http", {
+ name = "admin";
+ route = {
+ ["GET"] = function(event)
+ event.response.headers.location = event.request.path .. "/";
+ return 301;
+ end;
+ ["GET /*"] = serve_file;
+ }
+ });
+
+ -- Setup adminsub service
+ local ok, err;
+ service[module.host] = pubsub.new({
+ broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, module.host) end;
+ normalize_jid = jid_bare;
+ get_affiliation = function(jid) return get_affiliation(jid, module.host) end;
+ capabilities = {
+ member = {
+ create = false;
+ publish = false;
+ retract = false;
+ get_nodes = true;
- subscribe = true;
- unsubscribe = true;
- get_subscription = true;
- get_subscriptions = true;
- get_items = 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;
- subscribe_other = false;
- unsubscribe_other = false;
- get_subscription_other = false;
- get_subscriptions_other = false;
+ set_affiliation = false;
+ };
- be_subscribed = true;
- be_unsubscribed = true;
+ owner = {
+ create = true;
+ publish = true;
+ retract = true;
+ get_nodes = true;
- set_affiliation = false;
- };
+ subscribe = true;
+ unsubscribe = true;
+ get_subscription = true;
+ get_subscriptions = true;
+ get_items = true;
- owner = {
- create = true;
- publish = true;
- retract = true;
- get_nodes = true;
+ subscribe_other = true;
+ unsubscribe_other = true;
+ get_subscription_other = true;
+ get_subscriptions_other = true;
+
+ be_subscribed = true;
+ be_unsubscribed = true;
+
+ set_affiliation = true;
+ };
+ };
+ });
- subscribe = true;
- unsubscribe = true;
- get_subscription = true;
- get_subscriptions = true;
- get_items = true;
+ -- Create node for s2s sessions
+ ok, err = service[module.host]:create(xmlns_s2s_session, true);
+ if not ok then
+ module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(err));
+ else
+ service[module.host]:set_affiliation(xmlns_s2s_session, true, module.host, "owner")
+ end
- subscribe_other = true;
- unsubscribe_other = true;
- get_subscription_other = true;
- get_subscriptions_other = true;
+ -- Add outgoing s2s sessions
+ for remotehost, session in pairs(hosts[module.host].s2sout) do
+ if session.type ~= "s2sout_unauthed" then
+ add_host(session, "out", module.host);
+ end
+ end
- be_subscribed = true;
- be_unsubscribed = true;
+ -- Add incomming s2s sessions
+ for session in pairs(incoming_s2s) do
+ if session.to_host == module.host then
+ add_host(session, "in", module.host);
+ end
+ end
- set_affiliation = true;
- };
- };
- });
+ -- Create node for c2s sessions
+ ok, err = service[module.host]:create(xmlns_c2s_session, true);
+ if not ok then
+ module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(err));
+ else
+ service[module.host]:set_affiliation(xmlns_c2s_session, true, module.host, "owner")
+ end
- if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then
- local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true);
- if not ok then
- module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
+ -- Add c2s sessions
+ for username, user in pairs(hosts[module.host].sessions or {}) do
+ for resource, session in pairs(user.sessions or {}) do
+ add_client(session, module.host);
+ end
+ end
+
+ -- Register adminsub handler
+ module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event)
+ local origin, stanza = event.origin, event.stanza;
+ local adminsub = stanza.tags[1];
+ local action = adminsub.tags[1];
+ local reply;
+ if action.name == "subscribe" then
+ local ok, ret = service[module.host]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+ if ok then
+ reply = st.reply(stanza)
+ :tag("adminsub", { xmlns = xmlns_adminsub });
else
- service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner")
- end
- end
-
- for remotehost, session in pairs(host_table.s2sout) do
- if session.type ~= "s2sout_unauthed" then
- add_host(session, "out", host_name);
+ reply = st.error_reply(stanza, "cancel", ret);
end
- end
- for session in pairs(incoming_s2s) do
- if session.to_host == host_name then
- add_host(session, "in", host_name);
+ elseif action.name == "unsubscribe" then
+ local ok, ret = service[module.host]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+ if ok then
+ reply = st.reply(stanza)
+ :tag("adminsub", { xmlns = xmlns_adminsub });
+ else
+ reply = st.error_reply(stanza, "cancel", ret);
end
- end
-
- if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then
- local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true);
+ elseif action.name == "items" then
+ local node = action.attr.node;
+ local ok, ret = service[module.host]:get_items(node, stanza.attr.from);
if not ok then
- module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
- else
- service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner")
+ return origin.send(st.error_reply(stanza, "cancel", ret));
end
- end
-
- for username, user in pairs(host_table.sessions or {}) do
- for resource, session in pairs(user.sessions or {}) do
- add_client(session, host_name);
- end
- end
- host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event)
- local origin, stanza = event.origin, event.stanza;
- local adminsub = stanza.tags[1];
- local action = adminsub.tags[1];
- local reply;
- if action.name == "subscribe" then
- local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
- if ok then
- reply = st.reply(stanza)
- :tag("adminsub", { xmlns = xmlns_adminsub });
- else
- reply = st.error_reply(stanza, "cancel", ret);
- end
- elseif action.name == "unsubscribe" then
- local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
- if ok then
- reply = st.reply(stanza)
- :tag("adminsub", { xmlns = xmlns_adminsub });
- else
- reply = st.error_reply(stanza, "cancel", ret);
- end
- elseif action.name == "items" then
- local node = action.attr.node;
- local ok, ret = service[host_name]:get_items(node, stanza.attr.from);
- if not ok then
- return origin.send(st.error_reply(stanza, "cancel", ret));
- end
-
- local data = st.stanza("items", { node = node });
- for _, entry in pairs(ret) do
- data:add_child(entry);
- end
- if data then
- reply = st.reply(stanza)
- :tag("adminsub", { xmlns = xmlns_adminsub })
- :add_child(data);
- else
- reply = st.error_reply(stanza, "cancel", "item-not-found");
- end
- elseif action.name == "adminfor" then
- local data = st.stanza("adminfor");
- for host_name in pairs(hosts) do
- if is_admin(stanza.attr.from, host_name) then
- data:tag("item"):text(host_name):up();
- end
- end
+ local data = st.stanza("items", { node = node });
+ for _, entry in pairs(ret) do
+ data:add_child(entry);
+ end
+ if data then
reply = st.reply(stanza)
:tag("adminsub", { xmlns = xmlns_adminsub })
:add_child(data);
else
- reply = st.error_reply(stanza, "feature-not-implemented");
+ reply = st.error_reply(stanza, "cancel", "item-not-found");
+ end
+ elseif action.name == "adminfor" then
+ local data = st.stanza("adminfor");
+ for host_name in pairs(hosts) do
+ if is_admin(stanza.attr.from, host_name) then
+ data:tag("item"):text(host_name):up();
+ end
end
- return origin.send(reply);
- end);
+ reply = st.reply(stanza)
+ :tag("adminsub", { xmlns = xmlns_adminsub })
+ :add_child(data);
+ else
+ reply = st.error_reply(stanza, "feature-not-implemented");
+ end
+ return origin.send(reply);
+ end);
- host_table.events.add_handler("resource-bind", function(event)
- add_client(event.session, host_name);
- end);
-
- host_table.events.add_handler("resource-unbind", function(event)
- del_client(event.session, host_name);
- service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid);
- service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid);
- end);
+ -- Add/remove c2s sessions
+ module:hook("resource-bind", function(event)
+ add_client(event.session, module.host);
+ end);
- host_table.events.add_handler("s2sout-established", function(event)
- add_host(event.session, "out", host_name);
- end);
+ module:hook("resource-unbind", function(event)
+ del_client(event.session, module.host);
+ service[module.host]:remove_subscription(xmlns_c2s_session, module.host, event.session.full_jid);
+ service[module.host]:remove_subscription(xmlns_s2s_session, module.host, event.session.full_jid);
+ end);
- host_table.events.add_handler("s2sin-established", function(event)
- add_host(event.session, "in", host_name);
- end);
+ -- Add/remove s2s sessions
+ module:hook("s2sout-established", function(event)
+ add_host(event.session, "out", module.host);
+ end);
- host_table.events.add_handler("s2sout-destroyed", function(event)
- del_host(event.session, "out", host_name);
- end);
+ module:hook("s2sin-established", function(event)
+ add_host(event.session, "in", module.host);
+ end);
- host_table.events.add_handler("s2sin-destroyed", function(event)
- del_host(event.session, "in", host_name);
- end);
+ module:hook("s2sout-destroyed", function(event)
+ del_host(event.session, "out", module.host);
+ end);
- end
-end);
+ module:hook("s2sin-destroyed", function(event)
+ del_host(event.session, "in", module.host);
+ end);
+end
function simple_broadcast(node, jids, item, host)
item = st.clone(item);