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 |
