pax_global_header 0000666 0000000 0000000 00000000064 12564167603 0014524 g ustar 00root root 0000000 0000000 52 comment=b662fca299b02407504319709c7b1c4f452cd280
prosody-modules-0.0~hg20150813.12ac88940fe3/ 0000775 0000000 0000000 00000000000 12564167603 0017631 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/.hgtags 0000664 0000000 0000000 00000000065 12564167603 0021110 0 ustar 00root root 0000000 0000000 2c07bcf56a36d6e74dc0f5422e89bd61f4d31239 0.8-diverge
prosody-modules-0.0~hg20150813.12ac88940fe3/CONTRIBUTING 0000664 0000000 0000000 00000001331 12564167603 0021461 0 ustar 00root root 0000000 0000000 Contributing
============
Guidelines for developers
-------------------------
* Each module should be contained in a folder of its name (e.g.
`mod_ping/mod_ping.lua`)
* Each module should have a wiki page with a description,
usage, configuration and todo sections (feel free to copy an
existing one as a template)
* Commit messages should begin with the name of the plugin they
are for (e.g. `mod_ping: Set correct namespace on pongs`)
Instructions on cloning the repository are at
http://code.google.com/p/prosody-modules/source/checkout - if you have
commit access you will also see a link on that page to view your Google
Code password (not the same as your Google account password) to push your
changes.
prosody-modules-0.0~hg20150813.12ac88940fe3/COPYING 0000664 0000000 0000000 00000002156 12564167603 0020670 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2009-2015 Various Contributors (see individual files and source control)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
prosody-modules-0.0~hg20150813.12ac88940fe3/README 0000664 0000000 0000000 00000002650 12564167603 0020514 0 ustar 00root root 0000000 0000000 prosody-modules
===============
*Add-on modules for Prosody IM Server*
--------------------------------------------------------------------------
Community repository for non-core, unofficial and/or experimental plugins
for [Prosody][].
If you are a developer and would like to host your Prosody module in this
repository, or want to contribute to existing modules, simply introduce
yourself and request commit access on our [mailing list][].
Notes for users
----------------
There are lots of fun and exciting modules to be found here, we know
you'll like it. However please note that each module is in a different
state of development. Some are proof-of-concept, others are quite stable
and ready for production use. Be sure to read the wiki page of any
module before installing it on your server.
We are working on methods to easily download and install modules from
this repository. In the meantime most modules are either a single file
and easy to install, or contain installation instructions on their wiki
page. You can browse the files stored in this repository at
.
Prosody 0.8x compatibility
--------------------------
Due to a number of backwards-incompatible API changes in Prosody 0.9,
prosody-modules for 0.8 are now maintained separately at
.
[Prosody]: http://prosody.im/
[mailing list]: http://prosody.im/discuss
prosody-modules-0.0~hg20150813.12ac88940fe3/misc/ 0000775 0000000 0000000 00000000000 12564167603 0020564 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/misc/munin/ 0000775 0000000 0000000 00000000000 12564167603 0021712 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/misc/munin/prosody_.lua 0000664 0000000 0000000 00000006425 12564167603 0024262 0 ustar 00root root 0000000 0000000 #!/usr/bin/env lua
local print = print;
local pairs = pairs;
local socket = require"socket";
local stats = {};
stats.c2s = {
graph_title = "Prosody C2S Connections";
graph_vlabel = "users";
graph_category = "Prosody";
all_client_connections = {
label = "client connections";
_key = "total_c2s";
}
}
stats.s2s = {
graph_title = "Prosody S2S Connections";
graph_vlabel = "servers";
graph_category = "Prosody";
outgoing_connections = {
label = "outgoing connections";
_key = "total_s2sout";
};
incoming_connections = {
label = "incoming connections";
_key = "total_s2sin";
}
}
stats.mem = {
graph_title = "Prosody Memory Usage";
graph_vlabel = "Bytes";
graph_args = "--base 1024 -l 0";
graph_category = "Prosody"; --memory_unused
graph_order = "memory_total memory_rss memory_allocated memory_used memory_lua memory_returnable";
memory_allocated = { label = "Allocated", draw = "AREA" };
memory_lua = { label = "Lua", draw = "AREA" };
memory_rss = { label = "RSS", draw = "AREA" };
memory_total = { label = "Total", draw = "AREA" };
-- memory_unused = { label = "Unused", draw = "AREA" };
memory_used = { label = "Used", draw = "AREA" };
memory_returnable = { label = "Returnable", draw = "AREA" };
}
stats.cpu = {
graph_title = "Prosody CPU Usage";
graph_category = "Prosody";
graph_args = "-l 0";
graph_vlabel = "CPU time used in milliseconds";
cpu_total = { label = "CPU"; type = "DERIVE"; min = 0; };
}
stats.auth = {
graph_title = "Prosody Authentications";
graph_category = "Prosody";
graph_args = "--base 1000";
c2s_auth = {
label = "Logins";
type = "DERIVE";
min = 0;
};
c2s_authfail = {
label = "Failed logins";
type = "DERIVE";
min = 0;
};
}
local function onerror(msg, err, exit)
io.stderr:write(msg, '\n');
if err then
io.stderr:write(err, '\n');
end
os.exit(exit or 1);
end
local function connect()
local conn, err = socket.connect(os.getenv"host" or "localhost", os.getenv"port" or 5782);
if not conn then onerror("Could not connect to prosody", err); end
conn:settimeout(1);
return conn;
end
local function get_config(item)
for k,v in pairs(item) do
if type(v) == "string" then
print(k .. " " .. v);
elseif type(v) == "table" then
for sk,v in pairs(v) do
if not sk:match("^_") then
print(k.."."..sk.." "..v);
end
end
end
end
end
local function get_stats(item)
local labels = {};
for key, val in pairs(item) do
if type(val) == "table" and val.label then
labels[val._key or key] = key;
end
end
local conn = connect();
local line, err = conn:receive("*l");
local stat, value, label;
while line and line ~= "" and next(labels) ~= nil do
stat, value = line:match('^STAT%s+"([^"]*)"%s*(%b())');
label = stat and labels[stat];
if label then
print(label..".value "..tonumber(value:sub(2,-2)));
labels[stat] = nil;
end
line, err = conn:receive("*l");
end
if err then onerror(err); end
end
local function main(stat, mode)
if mode == "suggest" then
for available_stat in pairs(stats) do
print(available_stat);
end
elseif mode == "config" then
return get_config(stats[stat]);
elseif stats[stat] then
return get_stats(stats[stat]);
end
end
if arg then return main(arg[0]:match("prosody_(%w*)"), ...); end
return {
stats = stats,
get_stats = get_stats,
get_config = get_config,
}
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_addressing/ 0000775 0000000 0000000 00000000000 12564167603 0022613 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_addressing/mod_addressing.lua 0000664 0000000 0000000 00000003441 12564167603 0026302 0 ustar 00root root 0000000 0000000 -- TODO Querying other servers for support, needs to keep track of remote
-- server disco features
local xmlns_address = 'http://jabber.org/protocol/address';
local function handle_extended_addressing(data)
local stanza = data.stanza;
if stanza.attr.type == "error" then
return -- so we don't process bounces
end
local orig_to = stanza.attr.to;
local addresses = stanza:get_child("addresses", xmlns_address);
if addresses then
module:log("debug", "Extended addressing found");
local destinations = {};
addresses:maptags(function(address)
if address.attr.xmlns == xmlns_address and address.name == "address" then
local type, jid, delivered = address.attr.type, address.attr.jid, address.attr.delivered;
if (type == "cc" or type == "bcc" or type == "to")
and jid and not delivered then
destinations[#destinations+1] = jid;
module:log("debug", "%s to %s", type, jid)
if type == "to" or type == "cc" then
address.attr.delivered = "true";
return address;
elseif type == "bcc" then
return nil;
end
end
end
return address; -- unsupported stuff goes right back
end);
for i=1,#destinations do
stanza.attr.to = destinations[i];
module:log("debug", "posting stanza to %s", destinations[i])
module:send(stanza);
end
stanza.attr.to = orig_to;
return stanza.attr.to == module.host or nil;
end
end
module:hook("message/host", handle_extended_addressing, 10);
module:hook("message/bare", handle_extended_addressing, 10);
module:hook("message/full", handle_extended_addressing, 10);
module:hook("presence/host", handle_extended_addressing, 10);
module:hook("presence/bare", handle_extended_addressing, 10);
module:hook("presence/full", handle_extended_addressing, 10);
-- IQ stanzas makes no sense
module:add_feature(xmlns_address);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_adhoc_account_management/ 0000775 0000000 0000000 00000000000 12564167603 0025456 5 ustar 00root root 0000000 0000000 mod_adhoc_account_management.lua 0000664 0000000 0000000 00000007571 12564167603 0033741 0 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_adhoc_account_management local dataforms_new = require "util.dataforms".new;
local usermanager_set_password = require "core.usermanager".set_password;
local usermanager_test_password = require "core.usermanager".test_password;
local jid_split = require"util.jid".split;
local close_others = module:get_option_boolean("close_sessions_on_password_change", true)
local require_confirm = module:get_option_boolean("require_confirm_password", true)
local require_current = module:get_option_boolean("require_current_password", true)
local change_password_layout = {
title = "Changing Your Password";
instructions = "Fill out this form to change a your password.";
{
-- This is meta
name = "FORM_TYPE",
type = "hidden",
-- Reuses form type from XEP 77
value = "jabber:iq:register:changepassword",
};
{
name = "password",
type = "text-private",
required = true,
label = "New Password",
};
};
if require_confirm then
table.insert(change_password_layout, {
name = "password-confirm",
type = "text-private",
required = true,
label = "Confirm new password",
});
end
if require_current then
table.insert(change_password_layout, 2, {
name = "password-current",
type = "text-private",
required = true,
label = "Current password",
});
end
change_password_layout = dataforms_new(change_password_layout);
function change_password_command_handler(self, data, state)
if not state then -- New session, send the form
return { status = "executing", actions = { "complete" }, form = change_password_layout }, true;
else
if data.action == "cancel" then
return { status = "canceled" };
end
-- Who are we talking to?
local username, hostname = jid_split(data.from);
if not username or hostname ~= module.host then
return { status = "error", error = { type = "cancel",
condition = "forbidden", message = "Invalid user or hostname." } };
end
-- Extract data from the form
local fields = change_password_layout:data(data.form);
-- Validate
if require_current then
if not fields["password-current"] or #fields["password-current"] == 0 then
return { status = "error", error = { type = "modify",
condition = "bad-request", message = "Please enter your current password" } };
elseif not usermanager_test_password(username, hostname, fields["password-current"]) then
return { status = "error", error = { type = "modify",
condition = "bad-request", message = "Your current password was incorrect" } };
end
end
if require_confirm and fields["password-confirm"] ~= fields["password"] then
return { status = "error", error = { type = "modify",
condition = "bad-request", message = "New password didn't match the confirmation" } };
end
if not fields.password or #fields.password == 0 then
return { status = "error", error = { type = "modify",
condition = "bad-request", message = "Please enter a new password" } };
end
-- All is good, so change password.
module:log("debug", "About to usermanager.set_password(%q, password, %q)", username, hostname);
local ok, err = usermanager_set_password(username, fields.password, hostname);
if ok then
if close_others then
for _, sess in pairs(hosts[hostname].sessions[username].sessions) do
if sess.full_jid ~= data.from then
sess:close{ condition = "reset", text = "Password changed" }
end
end
end
return { status = "completed", info = "Password successfully changed" };
else
module:log("warn", "%s@%s could not change password: %s", username, hostname, tostring(err));
return { status = "error", error = { type = "cancel",
condition = "internal-server-error", message = "Could not save new password: "..tostring(err) } };
end
end
end
-- Feature requests? What could fit under account management?
local adhoc_new = module:require "adhoc".new;
local adhoc_passwd = adhoc_new("Change Password", "passwd", change_password_command_handler, "user");
module:add_item ("adhoc", adhoc_passwd);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_adhoc_blacklist/ 0000775 0000000 0000000 00000000000 12564167603 0023576 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_adhoc_blacklist/mod_adhoc_blacklist.lua 0000664 0000000 0000000 00000004746 12564167603 0030261 0 ustar 00root root 0000000 0000000 -- mod_adhoc_blacklist
--
-- http://xmpp.org/extensions/xep-0133.html#edit-blacklist
--
-- Copyright (C) 2015 Kim Alvefur
--
-- This file is MIT/X11 licensed.
--
module:depends("adhoc");
local adhoc = module:require "adhoc";
local st = require"util.stanza";
local set = require"util.set";
local dataform = require"util.dataforms";
local adhoc_inital_data = require "util.adhoc".new_initial_data_form;
local blocklist_form = dataform.new {
title = "Editing the Blacklist";
instructions = "Fill out this form to edit the list of entities with whom communications are disallowed.";
{
type = "hidden";
name = "FORM_TYPE";
value = "http://jabber.org/protocol/admin";
};
{
type = "jid-multi";
name = "blacklistjids";
label = "The blacklist";
};
}
local blocklists = module:open_store("blocklist");
local blocklist_handler = adhoc_inital_data(blocklist_form, function ()
local blacklistjids = {};
local blacklist = blocklists:get();
if blacklist then
for jid in pairs(blacklist) do
table.insert(blacklistjids, jid);
end
end
return { blacklistjids = blacklistjids };
end, function(fields, form_err)
if form_err then
return { status = "completed", error = { message = "Problem in submitted form" } };
end
local blacklistjids = set.new(fields.blacklistjids);
local ok, err = blocklists:set(nil, blacklistjids._items);
if ok then
return { status = "completed", info = "Blacklist updated" };
else
return { status = "completed", error = { message = "Error saving blacklist: "..err } };
end
end);
module:add_item("adhoc", adhoc.new("Edit Blacklist", "http://jabber.org/protocol/admin#edit-blacklist", blocklist_handler, "admin"));
local function is_blocked(host)
local blacklistjids = blocklists:get();
return blacklistjids and blacklistjids[host];
end
module:hook("route/remote", function (event)
local origin, stanza = event.origin, event.stanza;
if is_blocked(event.to_host) then
if origin and stanza then
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "Communication with this domain is not allowed"));
return true;
end
return false;
end
end, 1000);
module:hook("s2s-stream-features", function (event)
local session = event.origin;
if is_blocked(session.from_host) then
session:close("policy-violation");
return false;
end
end, 1000);
module:hook("stanza/http://etherx.jabber.org/streams:features", function (event)
local session = event.origin;
if is_blocked(session.to_host) then
session:close("policy-violation");
return true;
end
end, 1000);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_blocklist/ 0000775 0000000 0000000 00000000000 12564167603 0023626 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_blocklist/mod_admin_blocklist.lua 0000664 0000000 0000000 00000002656 12564167603 0030337 0 ustar 00root root 0000000 0000000 -- mod_admin_blocklist
--
-- If a local admin has blocked a domain, don't allow s2s to that domain
--
-- Copyright (C) 2015 Kim Alvefur
--
-- This file is MIT/X11 licensed.
--
module:depends("blocklist");
local st = require"util.stanza";
local jid_split = require"util.jid".split;
local admins = module:get_option_inherited_set("admins", {}) /
function (admin) -- Filter out non-local admins
local user, host = jid_split(admin);
if host == module.host then return user; end
end
local blocklists = module:open_store("blocklist");
local function is_blocked(host)
for admin in admins do
local blocklist = blocklists:get(admin);
if blocklist and blocklist[host] then
return true;
end
end
end
module:hook("route/remote", function (event)
local origin, stanza = event.origin, event.stanza;
if is_blocked(event.to_host) then
if origin and stanza then
origin.send(st.error_reply(stanza, "cancel", "not-allowed", "Communication with this domain is not allowed"));
return true;
end
return false;
end
end, 1000);
module:hook("s2s-stream-features", function (event)
local session = event.origin;
if is_blocked(session.from_host) then
session:close("policy-violation");
return false;
end
end, 1000);
module:hook("stanza/http://etherx.jabber.org/streams:features", function (event)
local session = event.origin;
if is_blocked(session.to_host) then
session:close("policy-violation");
return true;
end
end, 1000);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_message/ 0000775 0000000 0000000 00000000000 12564167603 0023264 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_message/mod_admin_message.lua 0000664 0000000 0000000 00000007370 12564167603 0027431 0 ustar 00root root 0000000 0000000 -- Prosody IM
--
-- mod_admin_message -- Console-over-XMPP implementation.
--
-- This module depends on Prosody's admin_telnet module
--
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
-- Copyright (C) 2012-2013 Mikael Berthe
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local st = require "util.stanza";
local um_is_admin = require "core.usermanager".is_admin;
local admin_telnet = module:depends("admin_telnet");
local telnet_def_env = module:shared("/*/admin_telnet/env");
local telnet_commands = module:shared("/*/admin_telnet/commands");
local default_env_mt = { __index = telnet_def_env };
local host = module.host;
-- Create our own session. print() will store the results in a text
-- string. send(), quit(), disconnect() are no-op.
local function new_session ()
local session = {
send = function () end;
quit = function () end;
disconnect = function () end;
};
session.print = function (...)
local t = {};
for i=1,select("#", ...) do
t[i] = tostring(select(i, ...));
end
local text = "| "..table.concat(t, "\t");
if session.fulltext then
session.fulltext = session.fulltext .. "\n" .. text;
else
session.fulltext = text;
end
end
session.env = setmetatable({}, default_env_mt);
-- Load up environment with helper objects
for name, t in pairs(telnet_def_env) do
if type(t) == "table" then
session.env[name] = setmetatable({ session = session },
{ __index = t });
end
end
return session;
end
local function on_message(event)
-- Check the type of the incoming stanza to avoid loops:
if event.stanza.attr.type == "error" then
return; -- We do not want to reply to these, so leave.
end
local userjid = event.stanza.attr.from;
local bodytag = event.stanza:get_child("body");
local body = bodytag and bodytag:get_text() or "";
if not body or body == "" then
-- We do not reply to empty messages (chatstates, etc.)
return true;
end
-- Check the requester is an admin user
if not um_is_admin(userjid, module.host) then
module:log("info", "Ignored request from non-admin: %s",
userjid);
return;
end
-- Create a session in order to use an admin_telnet-like environment
local session = new_session();
-- Process the message using admin_telnet's onincoming function
admin_telnet.console:process_line(session, body.."\n");
-- Strip trailing blank line
session.fulltext = tostring(session.fulltext):gsub("\n\|%s*$", "")
-- Send the reply stanza
local reply_stanza = st.message({ from = host, to = userjid,
type = "chat" });
reply_stanza = reply_stanza:body(session.fulltext);
module:send(reply_stanza);
return true;
end
local function on_presence(event)
local send_presence = false;
local userjid = event.stanza.attr.from;
-- Check the requester is an admin user
if not um_is_admin(userjid, module.host) then
module:log("info", "Ignored presence from non-admin: %s",
userjid);
return;
end
if (event.stanza.attr.type == "subscribe") then
module:log("info", "Subscription request from %s", userjid);
send_presence = true;
-- Send a subscription ack
local presence_stanza = st.presence({ from = host,
to = userjid, type = "subscribed",
id = event.stanza.attr.id });
module:send(presence_stanza);
elseif (event.stanza.attr.type == "probe") then
send_presence = true;
elseif (event.stanza.attr.type == "unsubscribe") then
-- For information only...
module:log("info", "Unsubscription request from %s", userjid);
end
if (send_presence == true) then
-- Send a presence stanza
module:send(st.presence({ from = host, to = userjid }));
end
return true;
end
module:hook("message/bare", on_message);
module:hook("presence/bare", on_presence);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_probe/ 0000775 0000000 0000000 00000000000 12564167603 0022747 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_probe/mod_admin_probe.lua 0000664 0000000 0000000 00000001770 12564167603 0026575 0 ustar 00root root 0000000 0000000 -- Prosody IM
-- Copyright (C) 2014 Florian Zeitz
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local presence = module:depends("presence");
local send_presence_of_available_resources = presence.send_presence_of_available_resources;
local hosts = prosody.hosts;
local core_post_stanza = prosody.core_post_stanza;
local st = require "util.stanza";
local is_admin = require "core.usermanager".is_admin;
local jid_split = require "util.jid".split;
module:hook("presence/bare", function(data)
local origin, stanza = data.origin, data.stanza;
local to, from, type = stanza.attr.to, stanza.attr.from, stanza.attr.type;
local node, host = jid_split(to);
if type ~= "probe" then return; end
if not is_admin(from, module.host) then return; end
if 0 == send_presence_of_available_resources(node, host, from, origin) then
core_post_stanza(hosts[host], st.presence({from=to, to=from, type="unavailable"}), true);
end
return true;
end, 10);
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/ 0000775 0000000 0000000 00000000000 12564167603 0022415 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/ 0000775 0000000 0000000 00000000000 12564167603 0024342 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/get_deps.sh 0000775 0000000 0000000 00000001553 12564167603 0026477 0 ustar 00root root 0000000 0000000 #!/bin/sh
JQUERY_VERSION="1.10.2"
STROPHE_VERSION="1.1.2"
BOOTSTRAP_VERSION="1.4.0"
ADHOC_COMMITISH="87bfedccdb91e2ff7cfb165e989e5259c155b513"
cd www_files/js
rm -f jquery-$JQUERY_VERSION.min.js
wget http://code.jquery.com/jquery-$JQUERY_VERSION.min.js || exit 1
rm -f adhoc.js
wget -O adhoc.js "http://git.babelmonkeys.de/?p=adhocweb.git;a=blob_plain;f=js/adhoc.js;hb=$ADHOC_COMMITISH" || exit 1
rm -f strophe.min.js
wget https://raw.github.com/strophe/strophe.im/gh-pages/strophejs/downloads/strophejs-$STROPHE_VERSION.tar.gz && tar xzf strophejs-$STROPHE_VERSION.tar.gz strophejs-$STROPHE_VERSION/strophe.min.js --strip-components=1 && rm strophejs-$STROPHE_VERSION.tar.gz || exit 1
cd ../css
rm -f bootstrap-$BOOTSTRAP_VERSION.min.css
wget https://raw.github.com/twbs/bootstrap/v$BOOTSTRAP_VERSION/bootstrap.min.css -O bootstrap-$BOOTSTRAP_VERSION.min.css || exit 1
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/mod_admin_web.lua 0000664 0000000 0000000 00000022321 12564167603 0027631 0 ustar 00root root 0000000 0000000 -- Copyright (C) 2010 Florian Zeitz
--
-- This file is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
--
--
--
--
--
--
-- /
--
--
-- /
--
local st = require "util.stanza";
local uuid_generate = require "util.uuid".generate;
local is_admin = require "core.usermanager".is_admin;
local pubsub = require "util.pubsub";
local jid_bare = require "util.jid".bare;
local hosts = prosody.hosts;
local incoming_s2s = prosody.incoming_s2s;
module:set_global();
local service = {};
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 idmap = {};
local function add_client(session, host)
local name = session.full_jid;
local id = idmap[name];
if not id then
id = uuid_generate();
idmap[name] = id;
end
local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_c2s_session, jid = name}):up();
if session.secure then
local encrypted = item:tag("encrypted");
local sock = session.conn and session.conn.socket and session.conn:socket()
local info = sock and sock.info and sock:info();
for k, v in pairs(info or {}) do
encrypted:tag("info", { name = k }):text(tostring(v)):up();
end
end
if session.compressed then
item:tag("compressed"):up();
end
service[host]:publish(xmlns_c2s_session, host, id, item);
module:log("debug", "Added client " .. name);
end
local function del_client(session, host)
local name = session.full_jid;
local id = idmap[name];
if id then
local notifier = st.stanza("retract", { id = id });
service[host]:retract(xmlns_c2s_session, host, id, notifier);
end
end
local function add_host(session, type, host)
local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
local id = idmap[name.."_"..type];
if not id then
id = uuid_generate();
idmap[name.."_"..type] = id;
end
local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_s2s_session, jid = name})
:tag(type):up();
if session.secure then
local encrypted = item:tag("encrypted");
local sock = session.conn and session.conn.socket and session.conn:socket()
local info = sock and sock.info and sock:info();
for k, v in pairs(info or {}) do
encrypted:tag("info", { name = k }):text(tostring(v)):up();
end
if session.cert_identity_status == "valid" then
encrypted:tag("valid");
else
encrypted:tag("invalid");
end
end
if session.compressed then
item:tag("compressed"):up();
end
service[host]:publish(xmlns_s2s_session, host, id, item);
module:log("debug", "Added host " .. name .. " s2s" .. type);
end
local function del_host(session, type, host)
local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
local id = idmap[name.."_"..type];
if id then
local notifier = st.stanza("retract", { id = id });
service[host]:retract(xmlns_s2s_session, host, id, notifier);
end
end
local function get_affiliation(jid, host)
local bare_jid = jid_bare(jid);
if is_admin(bare_jid, host) then
return "member";
else
return "none";
end
end
function module.add_host(module)
-- Dependencies
module:depends("bosh");
module:depends("admin_adhoc");
module:depends("http");
local serve_file = module:depends("http_files").serve {
path = module:get_directory() .. "/www_files";
};
-- Setup HTTP server
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 function simple_broadcast(kind, node, jids, item)
if item then
item = st.clone(item);
item.attr.xmlns = nil; -- Clear the pubsub namespace
end
local message = st.message({ from = module.host, type = "headline" })
:tag("event", { xmlns = xmlns_adminsub .. "#event" })
:tag(kind, { node = node })
:add_child(item);
for jid in pairs(jids) do
module:log("debug", "Sending notification to %s", jid);
message.attr.to = jid;
module:send(message);
end
end
service[module.host] = pubsub.new({
broadcaster = simple_broadcast;
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_other = false;
unsubscribe_other = false;
get_subscription_other = false;
get_subscriptions_other = false;
be_subscribed = true;
be_unsubscribed = true;
set_affiliation = false;
};
owner = {
create = true;
publish = true;
retract = true;
get_nodes = true;
subscribe = true;
unsubscribe = true;
get_subscription = true;
get_subscriptions = true;
get_items = true;
subscribe_other = true;
unsubscribe_other = true;
get_subscription_other = true;
get_subscriptions_other = true;
be_subscribed = true;
be_unsubscribed = true;
set_affiliation = true;
};
};
});
-- Create node for s2s sessions
local 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
-- Add outgoing s2s sessions
for _, session in pairs(hosts[module.host].s2sout) do
if session.type ~= "s2sout_unauthed" then
add_host(session, "out", module.host);
end
end
-- 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
-- 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
-- Add c2s sessions
for _, user in pairs(hosts[module.host].sessions or {}) do
for _, 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
reply = st.error_reply(stanza, "cancel", ret);
end
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
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
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
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);
-- Add/remove c2s sessions
module:hook("resource-bind", function(event)
add_client(event.session, module.host);
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);
-- Add/remove s2s sessions
module:hook("s2sout-established", function(event)
add_host(event.session, "out", module.host);
end);
module:hook("s2sin-established", function(event)
add_host(event.session, "in", module.host);
end);
module:hook("s2sout-destroyed", function(event)
del_host(event.session, "out", module.host);
end);
module:hook("s2sin-destroyed", function(event)
del_host(event.session, "in", module.host);
end);
end
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/ 0000775 0000000 0000000 00000000000 12564167603 0026350 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/css/ 0000775 0000000 0000000 00000000000 12564167603 0027140 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/css/style.css 0000664 0000000 0000000 00000002355 12564167603 0031017 0 ustar 00root root 0000000 0000000 body {
margin: 0
}
a {
color: #0000FF
}
#adhocCommands > ul {
margin: 0
}
.btn {
margin-right: 0.3em
}
.btn:last-child {
margin-right: 0
}
#log_container {
clear: both;
display: none
}
#adhocCommands {
border-right: solid 1px
}
#adhocCommands li {
list-style: inside
}
#login {
float: left;
margin: 1em 2em 0 1em;
padding-right: 1em;
border: solid 1px;
background: #eef0f2;
color: #000000
}
#main {
display: none;
margin: 1em
}
#main p {
margin: 0
}
#top {
clear: both;
width: 100%;
padding: 0;
}
@media screen and (min-width: 757px) {
#header {
background: url(../images/blue_orange.png) repeat-x
}
}
#header img {
max-width: 100%;
height: auto
}
#menu {
display: none;
color: #454748;
font-size: 1.1em;
background: #eef0f2;
width: 100%;
}
#menu ul {
display: inline;
list-style-type: none;
margin: 0;
padding: 0.5em 0
}
#menu li {
display: inline;
padding: 0 0.5em
}
#menu a {
color: #454748;
text-decoration: none
}
#menu li a:hover {
color: #6197DF;
text-decoration: underline
}
#selector {
display: inline-block
}
#s2sList h2, #c2sList h2 {
color: #4b8ade;
margin: 0
}
#s2sList li, #c2sList li {
cursor: pointer
}
#host {
margin: 0.25em;
}
prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/images/ 0000775 0000000 0000000 00000000000 12564167603 0027615 5 ustar 00root root 0000000 0000000 prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/images/blue_orange.png0000664 0000000 0000000 00000000236 12564167603 0032606 0 ustar 00root root 0000000 0000000 PNG
IHDR ZW
bKGD pHYs tIME
84 7i +IDAT(cH~?(1J?"O [Ll2#7 R4 rm IENDB` prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/images/compressed.png 0000664 0000000 0000000 00000001267 12564167603 0032475 0 ustar 00root root 0000000 0000000 PNG
IHDR Ĵl; bKGD C pHYs
B(x tIME
% DIDAT8kSA;1IR#>6R|TܸB+%+_
)(k1;.taQ"颭
-h+ZbwEThN ^|@Ypt'ZZ#7%F{p+3Xf(ٯ(r Ҳp
ru)
eJZQ.9NvCH'9?S`Fڡ*nm(;p/
`~n7`4h\1Z}*8zB06Rx3/+mGM.vY0U- Zjݮ/21gcn)Zdcʬ~d">ߠm @d{S`G " @$+KV> ;mli 1d!W*8t %sn+V a kX]8@+@mo6c IENDB` prosody-modules-0.0~hg20150813.12ac88940fe3/mod_admin_web/admin_web/www_files/images/encrypted.png 0000664 0000000 0000000 00000002275 12564167603 0032326 0 ustar 00root root 0000000 0000000 PNG
IHDR Ĵl; sRGB bKGD pHYs
B(x tIME4 =IDAT8˵[h\E3mc5i6QHlMZ-O>(R(@K
Mb4ݘKUvd}sa7k|o}?r'JmmoŲ ̆CTkk{$.E[P?
BN