Software / code / prosody-modules
Comparison
mod_admin_web/admin_web/mod_admin_web.lua @ 319:ba2e78661ea8
mod_admin_web: Make module global. Host to administrate is now chooseable
| author | Florian Zeitz <florob@babelmonkeys.de> |
|---|---|
| date | Fri, 21 Jan 2011 04:10:40 +0100 |
| parent | 317:4f78f5020aa9 |
| child | 328:73001ddff453 |
comparison
equal
deleted
inserted
replaced
| 318:84caab2bc02c | 319:ba2e78661ea8 |
|---|---|
| 23 local jid_bare = require "util.jid".bare; | 23 local jid_bare = require "util.jid".bare; |
| 24 local lfs = require "lfs"; | 24 local lfs = require "lfs"; |
| 25 local open = io.open; | 25 local open = io.open; |
| 26 local stat = lfs.attributes; | 26 local stat = lfs.attributes; |
| 27 | 27 |
| 28 local host = module:get_host(); | 28 module:set_global(); |
| 29 local service; | 29 |
| 30 local service = {}; | |
| 30 | 31 |
| 31 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files"; | 32 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files"; |
| 32 | 33 |
| 33 local xmlns_adminsub = "http://prosody.im/adminsub"; | 34 local xmlns_adminsub = "http://prosody.im/adminsub"; |
| 34 local xmlns_c2s_session = "http://prosody.im/streams/c2s"; | 35 local xmlns_c2s_session = "http://prosody.im/streams/c2s"; |
| 46 css = "text/css"; | 47 css = "text/css"; |
| 47 }; | 48 }; |
| 48 | 49 |
| 49 local idmap = {}; | 50 local idmap = {}; |
| 50 | 51 |
| 51 function add_client(session) | 52 function add_client(session, host) |
| 52 local name = session.full_jid; | 53 local name = session.full_jid; |
| 53 local id = idmap[name]; | 54 local id = idmap[name]; |
| 54 if not id then | 55 if not id then |
| 55 id = uuid_generate(); | 56 id = uuid_generate(); |
| 56 idmap[name] = id; | 57 idmap[name] = id; |
| 60 item:tag("encrypted"):up(); | 61 item:tag("encrypted"):up(); |
| 61 end | 62 end |
| 62 if session.compressed then | 63 if session.compressed then |
| 63 item:tag("compressed"):up(); | 64 item:tag("compressed"):up(); |
| 64 end | 65 end |
| 65 service:publish(xmlns_c2s_session, host, id, item); | 66 service[host]:publish(xmlns_c2s_session, host, id, item); |
| 66 module:log("debug", "Added client " .. name); | 67 module:log("debug", "Added client " .. name); |
| 67 end | 68 end |
| 68 | 69 |
| 69 function del_client(session) | 70 function del_client(session, host) |
| 70 local name = session.full_jid; | 71 local name = session.full_jid; |
| 71 local id = idmap[name]; | 72 local id = idmap[name]; |
| 72 if id then | 73 if id then |
| 73 local notifier = st.stanza("retract", { id = id }); | 74 local notifier = st.stanza("retract", { id = id }); |
| 74 service:retract(xmlns_c2s_session, host, id, notifier); | 75 service[host]:retract(xmlns_c2s_session, host, id, notifier); |
| 75 end | 76 end |
| 76 end | 77 end |
| 77 | 78 |
| 78 function add_host(session, type) | 79 function add_host(session, type, host) |
| 79 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); | 80 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); |
| 80 local id = idmap[name.."_"..type]; | 81 local id = idmap[name.."_"..type]; |
| 81 if not id then | 82 if not id then |
| 82 id = uuid_generate(); | 83 id = uuid_generate(); |
| 83 idmap[name.."_"..type] = id; | 84 idmap[name.."_"..type] = id; |
| 88 item:tag("encrypted"):up(); | 89 item:tag("encrypted"):up(); |
| 89 end | 90 end |
| 90 if session.compressed then | 91 if session.compressed then |
| 91 item:tag("compressed"):up(); | 92 item:tag("compressed"):up(); |
| 92 end | 93 end |
| 93 service:publish(xmlns_s2s_session, host, id, item); | 94 service[host]:publish(xmlns_s2s_session, host, id, item); |
| 94 module:log("debug", "Added host " .. name .. " s2s" .. type); | 95 module:log("debug", "Added host " .. name .. " s2s" .. type); |
| 95 end | 96 end |
| 96 | 97 |
| 97 function del_host(session, type) | 98 function del_host(session, type, host) |
| 98 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); | 99 local name = (type == "out" and session.to_host) or (type == "in" and session.from_host); |
| 99 local id = idmap[name.."_"..type]; | 100 local id = idmap[name.."_"..type]; |
| 100 if id then | 101 if id then |
| 101 local notifier = st.stanza("retract", { id = id }); | 102 local notifier = st.stanza("retract", { id = id }); |
| 102 service:retract(xmlns_s2s_session, host, id, notifier); | 103 service[host]:retract(xmlns_s2s_session, host, id, notifier); |
| 103 end | 104 end |
| 104 end | 105 end |
| 105 | 106 |
| 106 local function preprocess_path(path) | 107 local function preprocess_path(path) |
| 107 if path:sub(1,1) ~= "/" then | 108 if path:sub(1,1) ~= "/" then |
| 135 return response_403; | 136 return response_403; |
| 136 end | 137 end |
| 137 local f, err = open(full_path, "rb"); | 138 local f, err = open(full_path, "rb"); |
| 138 if not f then return response_404; end | 139 if not f then return response_404; end |
| 139 local data = f:read("*a"); | 140 local data = f:read("*a"); |
| 140 data = data:gsub("%%ADMINSUBHOST%%", host); | |
| 141 f:close(); | 141 f:close(); |
| 142 if not data then | 142 if not data then |
| 143 return response_403; | 143 return response_403; |
| 144 end | 144 end |
| 145 local ext = path:match("%.([^.]*)$"); | 145 local ext = path:match("%.([^.]*)$"); |
| 162 | 162 |
| 163 httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" }); | 163 httpserver.new_from_config(http_conf, handle_file_request, { base = "admin" }); |
| 164 end | 164 end |
| 165 | 165 |
| 166 prosody.events.add_handler("server-started", function () | 166 prosody.events.add_handler("server-started", function () |
| 167 local host_session = prosody.hosts[host]; | 167 for host_name, host_table in pairs(hosts) do |
| 168 if not select(2, service:get_nodes(true))[xmlns_s2s_session] then | 168 service[host_name] = pubsub.new({ |
| 169 local ok, errmsg = service:create(xmlns_s2s_session, true); | 169 broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end; |
| 170 if not ok then | 170 normalize_jid = jid_bare; |
| 171 module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg)); | 171 get_affiliation = function(jid) return get_affiliation(jid, host_name) end; |
| 172 else | 172 capabilities = { |
| 173 service:set_affiliation(xmlns_s2s_session, true, host, "owner") | 173 member = { |
| 174 end | 174 create = false; |
| 175 end | 175 publish = false; |
| 176 | 176 retract = false; |
| 177 for remotehost, session in pairs(host_session.s2sout) do | 177 get_nodes = true; |
| 178 if session.type ~= "s2sout_unauthed" then | 178 |
| 179 add_host(session, "out"); | 179 subscribe = true; |
| 180 end | 180 unsubscribe = true; |
| 181 end | 181 get_subscription = true; |
| 182 for session in pairs(incoming_s2s) do | 182 get_subscriptions = true; |
| 183 if session.to_host == host then | 183 get_items = true; |
| 184 add_host(session, "in"); | 184 |
| 185 end | 185 subscribe_other = false; |
| 186 end | 186 unsubscribe_other = false; |
| 187 | 187 get_subscription_other = false; |
| 188 if not select(2, service:get_nodes(true))[xmlns_c2s_session] then | 188 get_subscriptions_other = false; |
| 189 local ok, errmsg = service:create(xmlns_c2s_session, true); | 189 |
| 190 if not ok then | 190 be_subscribed = true; |
| 191 module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg)); | 191 be_unsubscribed = true; |
| 192 else | 192 |
| 193 service:set_affiliation(xmlns_c2s_session, true, host, "owner") | 193 set_affiliation = false; |
| 194 end | 194 }; |
| 195 end | 195 |
| 196 | 196 owner = { |
| 197 for username, user in pairs(host_session.sessions or {}) do | 197 create = true; |
| 198 for resource, session in pairs(user.sessions or {}) do | 198 publish = true; |
| 199 add_client(session); | 199 retract = true; |
| 200 end | 200 get_nodes = true; |
| 201 | |
| 202 subscribe = true; | |
| 203 unsubscribe = true; | |
| 204 get_subscription = true; | |
| 205 get_subscriptions = true; | |
| 206 get_items = true; | |
| 207 | |
| 208 subscribe_other = true; | |
| 209 unsubscribe_other = true; | |
| 210 get_subscription_other = true; | |
| 211 get_subscriptions_other = true; | |
| 212 | |
| 213 be_subscribed = true; | |
| 214 be_unsubscribed = true; | |
| 215 | |
| 216 set_affiliation = true; | |
| 217 }; | |
| 218 }; | |
| 219 }); | |
| 220 | |
| 221 if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then | |
| 222 local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true); | |
| 223 if not ok then | |
| 224 module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg)); | |
| 225 else | |
| 226 service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner") | |
| 227 end | |
| 228 end | |
| 229 | |
| 230 for remotehost, session in pairs(host_table.s2sout) do | |
| 231 if session.type ~= "s2sout_unauthed" then | |
| 232 add_host(session, "out", host_name); | |
| 233 end | |
| 234 end | |
| 235 for session in pairs(incoming_s2s) do | |
| 236 if session.to_host == host_name then | |
| 237 add_host(session, "in", host_name); | |
| 238 end | |
| 239 end | |
| 240 | |
| 241 if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then | |
| 242 local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true); | |
| 243 if not ok then | |
| 244 module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg)); | |
| 245 else | |
| 246 service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner") | |
| 247 end | |
| 248 end | |
| 249 | |
| 250 for username, user in pairs(host_table.sessions or {}) do | |
| 251 for resource, session in pairs(user.sessions or {}) do | |
| 252 add_client(session, host_name); | |
| 253 end | |
| 254 end | |
| 255 | |
| 256 host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event) | |
| 257 local origin, stanza = event.origin, event.stanza; | |
| 258 local adminsub = stanza.tags[1]; | |
| 259 local action = adminsub.tags[1]; | |
| 260 local reply; | |
| 261 if action.name == "subscribe" then | |
| 262 local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); | |
| 263 if ok then | |
| 264 reply = st.reply(stanza) | |
| 265 :tag("adminsub", { xmlns = xmlns_adminsub }); | |
| 266 else | |
| 267 reply = st.error_reply(stanza, "cancel", ret); | |
| 268 end | |
| 269 elseif action.name == "unsubscribe" then | |
| 270 local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); | |
| 271 if ok then | |
| 272 reply = st.reply(stanza) | |
| 273 :tag("adminsub", { xmlns = xmlns_adminsub }); | |
| 274 else | |
| 275 reply = st.error_reply(stanza, "cancel", ret); | |
| 276 end | |
| 277 elseif action.name == "items" then | |
| 278 local node = action.attr.node; | |
| 279 local ok, ret = service[host_name]:get_items(node, stanza.attr.from); | |
| 280 if not ok then | |
| 281 return origin.send(st.error_reply(stanza, "cancel", ret)); | |
| 282 end | |
| 283 | |
| 284 local data = st.stanza("items", { node = node }); | |
| 285 for _, entry in pairs(ret) do | |
| 286 data:add_child(entry); | |
| 287 end | |
| 288 if data then | |
| 289 reply = st.reply(stanza) | |
| 290 :tag("adminsub", { xmlns = xmlns_adminsub }) | |
| 291 :add_child(data); | |
| 292 else | |
| 293 reply = st.error_reply(stanza, "cancel", "item-not-found"); | |
| 294 end | |
| 295 elseif action.name == "adminfor" then | |
| 296 local data = st.stanza("adminfor"); | |
| 297 for host_name in pairs(hosts) do | |
| 298 if is_admin(stanza.attr.from, host_name) then | |
| 299 data:tag("item"):text(host_name):up(); | |
| 300 end | |
| 301 end | |
| 302 reply = st.reply(stanza) | |
| 303 :tag("adminsub", { xmlns = xmlns_adminsub }) | |
| 304 :add_child(data); | |
| 305 else | |
| 306 reply = st.error_reply(stanza, "feature-not-implemented"); | |
| 307 end | |
| 308 return origin.send(reply); | |
| 309 end); | |
| 310 | |
| 311 host_table.events.add_handler("resource-bind", function(event) | |
| 312 add_client(event.session, host_name); | |
| 313 end); | |
| 314 | |
| 315 host_table.events.add_handler("resource-unbind", function(event) | |
| 316 del_client(event.session, host_name); | |
| 317 service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid); | |
| 318 service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid); | |
| 319 end); | |
| 320 | |
| 321 host_table.events.add_handler("s2sout-established", function(event) | |
| 322 add_host(event.session, "out", host_name); | |
| 323 end); | |
| 324 | |
| 325 host_table.events.add_handler("s2sin-established", function(event) | |
| 326 add_host(event.session, "in", host_name); | |
| 327 end); | |
| 328 | |
| 329 host_table.events.add_handler("s2sout-destroyed", function(event) | |
| 330 del_host(event.session, "out", host_name); | |
| 331 end); | |
| 332 | |
| 333 host_table.events.add_handler("s2sin-destroyed", function(event) | |
| 334 del_host(event.session, "in", host_name); | |
| 335 end); | |
| 336 | |
| 201 end | 337 end |
| 202 end); | 338 end); |
| 203 | 339 |
| 204 function simple_broadcast(node, jids, item) | 340 function simple_broadcast(node, jids, item, host) |
| 205 item = st.clone(item); | 341 item = st.clone(item); |
| 206 item.attr.xmlns = nil; -- Clear the pubsub namespace | 342 item.attr.xmlns = nil; -- Clear the pubsub namespace |
| 207 local message = st.message({ from = module.host, type = "headline" }) | 343 local message = st.message({ from = host, type = "headline" }) |
| 208 :tag("event", { xmlns = xmlns_adminsub .. "#event" }) | 344 :tag("event", { xmlns = xmlns_adminsub .. "#event" }) |
| 209 :tag("items", { node = node }) | 345 :tag("items", { node = node }) |
| 210 :add_child(item); | 346 :add_child(item); |
| 211 for jid in pairs(jids) do | 347 for jid in pairs(jids) do |
| 212 module:log("debug", "Sending notification to %s", jid); | 348 module:log("debug", "Sending notification to %s", jid); |
| 213 message.attr.to = jid; | 349 message.attr.to = jid; |
| 214 core_post_stanza(hosts[host], message); | 350 core_post_stanza(hosts[host], message); |
| 215 end | 351 end |
| 216 end | 352 end |
| 217 | 353 |
| 218 function get_affiliation(jid) | 354 function get_affiliation(jid, host) |
| 219 local bare_jid = jid_bare(jid); | 355 local bare_jid = jid_bare(jid); |
| 220 if is_admin(bare_jid, host) then | 356 if is_admin(bare_jid, host) then |
| 221 return "member"; | 357 return "member"; |
| 222 else | 358 else |
| 223 return "none"; | 359 return "none"; |
| 224 end | 360 end |
| 225 end | 361 end |
| 226 | |
| 227 module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event) | |
| 228 local origin, stanza = event.origin, event.stanza; | |
| 229 local adminsub = stanza.tags[1]; | |
| 230 local action = adminsub.tags[1]; | |
| 231 local reply; | |
| 232 if action.name == "subscribe" then | |
| 233 local ok, ret = service:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from); | |
| 234 if ok then | |
| 235 reply = st.reply(stanza) | |
| 236 :tag("adminsub", { xmlns = xmlns_adminsub }); | |
| 237 else | |
| 238 reply = st.error_reply(stanza, "cancel", ret); | |
| 239 end | |
| 240 elseif action.name == "items" then | |
| 241 local node = action.attr.node; | |
| 242 local ok, ret = service:get_items(node, stanza.attr.from); | |
| 243 if not ok then | |
| 244 return origin.send(st.error_reply(stanza, "cancel", ret)); | |
| 245 end | |
| 246 | |
| 247 local data = st.stanza("items", { node = node }); | |
| 248 for _, entry in pairs(ret) do | |
| 249 data:add_child(entry); | |
| 250 end | |
| 251 if data then | |
| 252 reply = st.reply(stanza) | |
| 253 :tag("adminsub", { xmlns = xmlns_adminsub }) | |
| 254 :add_child(data); | |
| 255 else | |
| 256 reply = st.error_reply(stanza, "cancel", "item-not-found"); | |
| 257 end | |
| 258 else | |
| 259 reply = st.error_reply(stanza, "feature-not-implemented"); | |
| 260 end | |
| 261 return origin.send(reply); | |
| 262 end); | |
| 263 | |
| 264 module:hook("resource-bind", function(event) | |
| 265 add_client(event.session); | |
| 266 end); | |
| 267 | |
| 268 module:hook("resource-unbind", function(event) | |
| 269 del_client(event.session); | |
| 270 service:remove_subscription(xmlns_c2s_session, host, event.session.full_jid); | |
| 271 service:remove_subscription(xmlns_s2s_session, host, event.session.full_jid); | |
| 272 end); | |
| 273 | |
| 274 module:hook("s2sout-established", function(event) | |
| 275 add_host(event.session, "out"); | |
| 276 end); | |
| 277 | |
| 278 module:hook("s2sin-established", function(event) | |
| 279 add_host(event.session, "in"); | |
| 280 end); | |
| 281 | |
| 282 module:hook("s2sout-destroyed", function(event) | |
| 283 del_host(event.session, "out"); | |
| 284 end); | |
| 285 | |
| 286 module:hook("s2sin-destroyed", function(event) | |
| 287 del_host(event.session, "in"); | |
| 288 end); | |
| 289 | |
| 290 service = pubsub.new({ | |
| 291 broadcaster = simple_broadcast; | |
| 292 normalize_jid = jid_bare; | |
| 293 get_affiliation = get_affiliation; | |
| 294 capabilities = { | |
| 295 member = { | |
| 296 create = false; | |
| 297 publish = false; | |
| 298 retract = false; | |
| 299 get_nodes = true; | |
| 300 | |
| 301 subscribe = true; | |
| 302 unsubscribe = true; | |
| 303 get_subscription = true; | |
| 304 get_subscriptions = true; | |
| 305 get_items = true; | |
| 306 | |
| 307 subscribe_other = false; | |
| 308 unsubscribe_other = false; | |
| 309 get_subscription_other = false; | |
| 310 get_subscriptions_other = false; | |
| 311 | |
| 312 be_subscribed = true; | |
| 313 be_unsubscribed = true; | |
| 314 | |
| 315 set_affiliation = false; | |
| 316 }; | |
| 317 | |
| 318 owner = { | |
| 319 create = true; | |
| 320 publish = true; | |
| 321 retract = true; | |
| 322 get_nodes = true; | |
| 323 | |
| 324 subscribe = true; | |
| 325 unsubscribe = true; | |
| 326 get_subscription = true; | |
| 327 get_subscriptions = true; | |
| 328 get_items = true; | |
| 329 | |
| 330 subscribe_other = true; | |
| 331 unsubscribe_other = true; | |
| 332 get_subscription_other = true; | |
| 333 get_subscriptions_other = true; | |
| 334 | |
| 335 be_subscribed = true; | |
| 336 be_unsubscribed = true; | |
| 337 | |
| 338 set_affiliation = true; | |
| 339 }; | |
| 340 }; | |
| 341 }); | |
| 342 |