comparison mod_admin_web/admin_web/mod_admin_web.lua @ 288:9233d7ee3c09

mod_admin_web: Initial PoC commit
author Florian Zeitz <florob@babelmonkeys.de>
date Fri, 17 Dec 2010 03:34:53 +0100
parents
children a9e69088e678
comparison
equal deleted inserted replaced
287:6144fe6161f1 288:9233d7ee3c09
1 -- Copyright (C) 2010 Florian Zeitz
2 --
3 -- This file is MIT/X11 licensed. Please see the
4 -- COPYING file in the source package for more information.
5 --
6
7 -- <session xmlns="http://prosody.im/streams/s2s" jid="example.com">
8 -- <encrypted/>
9 -- <compressed/>
10 -- <in/> / <out/>
11 -- </session>
12
13 local stanza = require "util.stanza";
14 local uuid_generate = require "util.uuid".generate;
15 local httpserver = require "net.httpserver";
16 local lfs = require "lfs";
17 local open = io.open;
18 local stat = lfs.attributes;
19
20 local host = module:get_host();
21 local service = config.get("*", "core", "webadmin_pubsub_host") or ("pubsub." .. host);
22
23 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files";
24
25 local xmlns_sessions = "http://prosody.im/streams/s2s";
26
27 local response_400 = { status = "400 Bad Request", body = "<h1>Bad Request</h1>Sorry, we didn't understand your request :(" };
28 local response_403 = { status = "403 Forbidden", body = "<h1>Forbidden</h1>You don't have permission to view the contents of this directory :(" };
29 local response_404 = { status = "404 Not Found", body = "<h1>Page Not Found</h1>Sorry, we couldn't find what you were looking for :(" };
30
31 local mime_map = {
32 html = "text/html";
33 xml = "text/xml";
34 js = "text/javascript";
35 css = "text/css";
36 };
37
38 local idmap = {};
39
40 function add_host(session, type)
41 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
42 local id = idmap[name.."_"..type];
43 if not id then
44 id = uuid_generate();
45 idmap[name.."_"..type] = id;
46 end
47 local item = stanza.stanza("item", { id = id }):tag("session", {xmlns = xmlns_sessions, jid = name})
48 :tag(type):up();
49 if session.secure then
50 item:tag("encrypted"):up();
51 end
52 if session.compressed then
53 item:tag("compressed"):up();
54 end
55 hosts[service].modules.pubsub.service:publish(xmlns_sessions, host, id, item);
56 module:log("debug", "Added host " .. name .. " s2s" .. type);
57 end
58
59 function del_host(session, type)
60 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
61 local id = idmap[name.."_"..type];
62 if id then
63 local notifier = stanza.stanza("retract", { id = id });
64 hosts[service].modules.pubsub.service:retract(xmlns_sessions, host, id, notifier);
65 end
66 end
67
68 local function preprocess_path(path)
69 if path:sub(1,1) ~= "/" then
70 path = "/"..path;
71 end
72 local level = 0;
73 for component in path:gmatch("([^/]+)/") do
74 if component == ".." then
75 level = level - 1;
76 elseif component ~= "." then
77 level = level + 1;
78 end
79 if level < 0 then
80 return nil;
81 end
82 end
83 return path;
84 end
85
86 function serve_file(path)
87 local full_path = http_base..path;
88 if stat(full_path, "mode") == "directory" then
89 if stat(full_path.."/index.html", "mode") == "file" then
90 return serve_file(path.."/index.html");
91 end
92 return response_403;
93 end
94 local f, err = open(full_path, "rb");
95 if not f then return response_404; end
96 local data = f:read("*a");
97 f:close();
98 if not data then
99 return response_403;
100 end
101 local ext = path:match("%.([^.]*)$");
102 local mime = mime_map[ext]; -- Content-Type should be nil when not known
103 return {
104 headers = { ["Content-Type"] = mime; };
105 body = data;
106 };
107 end
108
109 local function handle_file_request(method, body, request)
110 local path = preprocess_path(request.url.path);
111 if not path then return response_400; end
112 path = path:gsub("^/[^/]+", ""); -- Strip /admin/
113 return serve_file(path);
114 end
115
116 function module.load()
117 local host_session = prosody.hosts[host];
118 local http_conf = config.get("*", "core", "webadmin_http_ports");
119
120 hosts[service].modules.pubsub.service:create(xmlns_sessions, host);
121
122 for remotehost, session in pairs(host_session.s2sout) do
123 if session.type ~= "s2sout_unauthed" then
124 add_host(session, "out");
125 end
126 end
127 for session in pairs(incoming_s2s) do
128 if session.to_host == host then
129 add_host(session, "in");
130 end
131 end
132
133 httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" });
134 end
135
136 module:hook("s2sout-established", function(event)
137 add_host(event.session, "out");
138 end);
139
140 module:hook("s2sin-established", function(event)
141 add_host(event.session, "in");
142 end);
143
144 module:hook("s2sout-destroyed", function(event)
145 del_host(event.session, "out");
146 end);
147
148 module:hook("s2sin-destroyed", function(event)
149 del_host(event.session, "in");
150 end);