Mercurial > prosody-modules
comparison mod_admin_web/admin_web/mod_admin_web_timber.lua @ 636:b3a3199255d7
mod_admin_web: Add timber version. Separate for now
author | Florian Zeitz <florob@babelmonkeys.de> |
---|---|
date | Fri, 27 Apr 2012 03:30:47 +0200 |
parents | |
children | 210f4ce2697c |
comparison
equal
deleted
inserted
replaced
635:30be50d2537f | 636:b3a3199255d7 |
---|---|
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/c2s" jid="alice@example.com/brussels"> | |
8 -- <encrypted/> | |
9 -- <compressed/> | |
10 -- </session> | |
11 | |
12 -- <session xmlns="http://prosody.im/streams/s2s" jid="example.com"> | |
13 -- <encrypted> | |
14 -- <valid/> / <invalid/> | |
15 -- </encrypted> | |
16 -- <compressed/> | |
17 -- <in/> / <out/> | |
18 -- </session> | |
19 | |
20 local st = require "util.stanza"; | |
21 local uuid_generate = require "util.uuid".generate; | |
22 local is_admin = require "usermanager".is_admin; | |
23 local pubsub = require "util.pubsub"; | |
24 local jid_bare = require "util.jid".bare; | |
25 local lfs = require "lfs"; | |
26 local open = io.open; | |
27 local stat = lfs.attributes; | |
28 | |
29 module:set_global(); | |
30 | |
31 local service = {}; | |
32 | |
33 local http_base = module.path:gsub("/[^/]+$","") .. "/www_files/"; | |
34 | |
35 local xmlns_adminsub = "http://prosody.im/adminsub"; | |
36 local xmlns_c2s_session = "http://prosody.im/streams/c2s"; | |
37 local xmlns_s2s_session = "http://prosody.im/streams/s2s"; | |
38 | |
39 local mime_map = { | |
40 html = "text/html"; | |
41 xml = "text/xml"; | |
42 js = "text/javascript"; | |
43 css = "text/css"; | |
44 }; | |
45 | |
46 local idmap = {}; | |
47 | |
48 function add_client(session, host) | |
49 local name = session.full_jid; | |
50 local id = idmap[name]; | |
51 if not id then | |
52 id = uuid_generate(); | |
53 idmap[name] = id; | |
54 end | |
55 local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_c2s_session, jid = name}):up(); | |
56 if session.secure then | |
57 item:tag("encrypted"):up(); | |
58 end | |
59 if session.compressed then | |
60 item:tag("compressed"):up(); | |
61 end | |
62 service[host]:publish(xmlns_c2s_session, host, id, item); | |
63 module:log("debug", "Added client " .. name); | |
64 end | |
65 | |
66 function del_client(session, host) | |
67 local name = session.full_jid; | |
68 local id = idmap[name]; | |
69 if id then | |
70 local notifier = st.stanza("retract", { id = id }); | |
71 service[host]:retract(xmlns_c2s_session, host, id, notifier); | |
72 end | |
73 end | |
74 | |
75 function add_host(session, type, host) | |
76 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); | |
77 local id = idmap[name.."_"..type]; | |
78 if not id then | |
79 id = uuid_generate(); | |
80 idmap[name.."_"..type] = id; | |
81 end | |
82 local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_s2s_session, jid = name}) | |
83 :tag(type):up(); | |
84 if session.secure then | |
85 if session.cert_identity_status == "valid" then | |
86 item:tag("encrypted"):tag("valid"):up():up(); | |
87 else | |
88 item:tag("encrypted"):tag("invalid"):up():up(); | |
89 end | |
90 end | |
91 if session.compressed then | |
92 item:tag("compressed"):up(); | |
93 end | |
94 service[host]:publish(xmlns_s2s_session, host, id, item); | |
95 module:log("debug", "Added host " .. name .. " s2s" .. type); | |
96 end | |
97 | |
98 function del_host(session, type, host) | |
99 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); | |
100 local id = idmap[name.."_"..type]; | |
101 if id then | |
102 local notifier = st.stanza("retract", { id = id }); | |
103 service[host]:retract(xmlns_s2s_session, host, id, notifier); | |
104 end | |
105 end | |
106 | |
107 function serve_file(event, path) | |
108 local full_path = http_base .. path; | |
109 | |
110 if stat(full_path, "mode") == "directory" then | |
111 if stat(full_path.."/index.html", "mode") == "file" then | |
112 return serve_file(event, path.."/index.html"); | |
113 end | |
114 return 403; | |
115 end | |
116 | |
117 local f, err = open(full_path, "rb"); | |
118 if not f then | |
119 return 404; | |
120 end | |
121 | |
122 local data = f:read("*a"); | |
123 f:close(); | |
124 if not data then | |
125 return 403; | |
126 end | |
127 | |
128 local ext = path:match("%.([^.]*)$"); | |
129 event.response.headers.content_type = mime_map[ext]; -- Content-Type should be nil when not known | |
130 return data; | |
131 end | |
132 | |
133 function module.add_host(module) | |
134 module:depends("http"); | |
135 module:provides("http", { | |
136 name = "admin"; | |
137 route = { | |
138 ["/"] = function(event) | |
139 event.response.headers.location = event.request.path .. "/"; | |
140 return 301; | |
141 end; | |
142 ["/*"] = serve_file; | |
143 } | |
144 }); | |
145 end | |
146 | |
147 prosody.events.add_handler("server-started", function () | |
148 for host_name, host_table in pairs(hosts) do | |
149 service[host_name] = pubsub.new({ | |
150 broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end; | |
151 normalize_jid = jid_bare; | |
152 get_affiliation = function(jid) return get_affiliation(jid, host_name) end; | |
153 capabilities = { | |
154 member = { | |
155 create = false; | |
156 publish = false; | |
157 retract = false; | |
158 get_nodes = true; | |
159 | |
160 subscribe = true; | |
161 unsubscribe = true; | |
162 get_subscription = true; | |
163 get_subscriptions = true; | |
164 get_items = true; | |
165 | |
166 subscribe_other = false; | |
167 unsubscribe_other = false; | |
168 get_subscription_other = false; | |
169 get_subscriptions_other = false; | |
170 | |
171 be_subscribed = true; | |
172 be_unsubscribed = true; | |
173 | |
174 set_affiliation = false; | |
175 }; | |
176 | |
177 owner = { | |
178 create = true; | |
179 publish = true; | |
180 retract = true; | |
181 get_nodes = true; | |
182 | |
183 subscribe = true; | |
184 unsubscribe = true; | |
185 get_subscription = true; | |
186 get_subscriptions = true; | |
187 get_items = true; | |
188 | |
189 subscribe_other = true; | |
190 unsubscribe_other = true; | |
191 get_subscription_other = true; | |
192 get_subscriptions_other = true; | |
193 | |
194 be_subscribed = true; | |
195 be_unsubscribed = true; | |
196 | |
197 set_affiliation = true; | |
198 }; | |
199 }; | |
200 }); | |
201 | |
202 if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then | |
203 local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true); | |
204 if not ok then | |
205 module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg)); | |
206 else | |
207 service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner") | |
208 end | |
209 end | |
210 | |
211 for remotehost, session in pairs(host_table.s2sout) do | |
212 if session.type ~= "s2sout_unauthed" then | |
213 add_host(session, "out", host_name); | |
214 end | |
215 end | |
216 for session in pairs(incoming_s2s) do | |
217 if session.to_host == host_name then | |
218 add_host(session, "in", host_name); | |
219 end | |
220 end | |
221 | |
222 if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then | |
223 local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true); | |
224 if not ok then | |
225 module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg)); | |
226 else | |
227 service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner") | |
228 end | |
229 end | |
230 | |
231 for username, user in pairs(host_table.sessions or {}) do | |
232 for resource, session in pairs(user.sessions or {}) do | |
233 add_client(session, host_name); | |
234 end | |
235 end | |
236 | |
237 host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event) | |
238 local origin, stanza = event.origin, event.stanza; | |
239 local adminsub = stanza.tags[1]; | |
240 local action = adminsub.tags[1]; | |
241 local reply; | |
242 if action.name == "subscribe" then | |
243 local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); | |
244 if ok then | |
245 reply = st.reply(stanza) | |
246 :tag("adminsub", { xmlns = xmlns_adminsub }); | |
247 else | |
248 reply = st.error_reply(stanza, "cancel", ret); | |
249 end | |
250 elseif action.name == "unsubscribe" then | |
251 local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); | |
252 if ok then | |
253 reply = st.reply(stanza) | |
254 :tag("adminsub", { xmlns = xmlns_adminsub }); | |
255 else | |
256 reply = st.error_reply(stanza, "cancel", ret); | |
257 end | |
258 elseif action.name == "items" then | |
259 local node = action.attr.node; | |
260 local ok, ret = service[host_name]:get_items(node, stanza.attr.from); | |
261 if not ok then | |
262 return origin.send(st.error_reply(stanza, "cancel", ret)); | |
263 end | |
264 | |
265 local data = st.stanza("items", { node = node }); | |
266 for _, entry in pairs(ret) do | |
267 data:add_child(entry); | |
268 end | |
269 if data then | |
270 reply = st.reply(stanza) | |
271 :tag("adminsub", { xmlns = xmlns_adminsub }) | |
272 :add_child(data); | |
273 else | |
274 reply = st.error_reply(stanza, "cancel", "item-not-found"); | |
275 end | |
276 elseif action.name == "adminfor" then | |
277 local data = st.stanza("adminfor"); | |
278 for host_name in pairs(hosts) do | |
279 if is_admin(stanza.attr.from, host_name) then | |
280 data:tag("item"):text(host_name):up(); | |
281 end | |
282 end | |
283 reply = st.reply(stanza) | |
284 :tag("adminsub", { xmlns = xmlns_adminsub }) | |
285 :add_child(data); | |
286 else | |
287 reply = st.error_reply(stanza, "feature-not-implemented"); | |
288 end | |
289 return origin.send(reply); | |
290 end); | |
291 | |
292 host_table.events.add_handler("resource-bind", function(event) | |
293 add_client(event.session, host_name); | |
294 end); | |
295 | |
296 host_table.events.add_handler("resource-unbind", function(event) | |
297 del_client(event.session, host_name); | |
298 service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid); | |
299 service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid); | |
300 end); | |
301 | |
302 host_table.events.add_handler("s2sout-established", function(event) | |
303 add_host(event.session, "out", host_name); | |
304 end); | |
305 | |
306 host_table.events.add_handler("s2sin-established", function(event) | |
307 add_host(event.session, "in", host_name); | |
308 end); | |
309 | |
310 host_table.events.add_handler("s2sout-destroyed", function(event) | |
311 del_host(event.session, "out", host_name); | |
312 end); | |
313 | |
314 host_table.events.add_handler("s2sin-destroyed", function(event) | |
315 del_host(event.session, "in", host_name); | |
316 end); | |
317 | |
318 end | |
319 end); | |
320 | |
321 function simple_broadcast(node, jids, item, host) | |
322 item = st.clone(item); | |
323 item.attr.xmlns = nil; -- Clear the pubsub namespace | |
324 local message = st.message({ from = host, type = "headline" }) | |
325 :tag("event", { xmlns = xmlns_adminsub .. "#event" }) | |
326 :tag("items", { node = node }) | |
327 :add_child(item); | |
328 for jid in pairs(jids) do | |
329 module:log("debug", "Sending notification to %s", jid); | |
330 message.attr.to = jid; | |
331 core_post_stanza(hosts[host], message); | |
332 end | |
333 end | |
334 | |
335 function get_affiliation(jid, host) | |
336 local bare_jid = jid_bare(jid); | |
337 if is_admin(bare_jid, host) then | |
338 return "member"; | |
339 else | |
340 return "none"; | |
341 end | |
342 end |