Merge 0.9->0.10
authorMatthew Wild <mwild1@gmail.com>
Sat, 18 Jan 2014 18:46:12 +0000 (18:46 +0000)
committerMatthew Wild <mwild1@gmail.com>
Sat, 18 Jan 2014 18:46:12 +0000 (18:46 +0000)
1  2 
plugins/mod_tls.lua
tools/ejabberd2prosody.lua
tools/ejabberdsql2prosody.lua

diff --combined plugins/mod_tls.lua
index bab2202ea7eb01b0216944e40aa2359ca6a9a07c,2741b8d401f04a1ebee22a66a543b96ae3cb058a..7c3d79be069bb87ad8bf2c5864e2b1bc08433e8d
@@@ -1,7 -1,7 +1,7 @@@
  -- Prosody IM
  -- Copyright (C) 2008-2010 Matthew Wild
  -- Copyright (C) 2008-2010 Waqas Hussain
 --- 
 +--
  -- This project is MIT/X11 licensed. Please see the
  -- COPYING file in the source package for more information.
  --
@@@ -10,9 -10,15 +10,15 @@@ local config = require "core.configmana
  local create_context = require "core.certmanager".create_context;
  local st = require "util.stanza";
  
- local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
- local secure_s2s_only = module:get_option("s2s_require_encryption");
+ local c2s_require_encryption = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
+ local s2s_require_encryption = module:get_option("s2s_require_encryption");
  local allow_s2s_tls = module:get_option("s2s_allow_encryption") ~= false;
+ local s2s_secure_auth = module:get_option("s2s_secure_auth");
+ if s2s_secure_auth and s2s_require_encryption == false then
+       module:log("warn", "s2s_secure_auth implies s2s_require_encryption, but s2s_require_encryption is set to false");
+       s2s_require_encryption = true;
+ end
  
  local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
  local starttls_attr = { xmlns = xmlns_starttls };
@@@ -20,50 -26,23 +26,50 @@@ local starttls_proceed = st.stanza("pro
  local starttls_failure = st.stanza("failure", starttls_attr);
  local c2s_feature = st.stanza("starttls", starttls_attr);
  local s2s_feature = st.stanza("starttls", starttls_attr);
- if secure_auth_only then c2s_feature:tag("required"):up(); end
- if secure_s2s_only then s2s_feature:tag("required"):up(); end
+ if c2s_require_encryption then c2s_feature:tag("required"):up(); end
+ if s2s_require_encryption then s2s_feature:tag("required"):up(); end
  
 -local global_ssl_ctx = prosody.global_ssl_ctx;
 -
  local hosts = prosody.hosts;
  local host = hosts[module.host];
  
 +local ssl_ctx_c2s, ssl_ctx_s2sout, ssl_ctx_s2sin;
 +do
 +      local function get_ssl_cfg(typ)
 +              local cfg_key = (typ and typ.."_" or "").."ssl";
 +              local ssl_config = config.rawget(module.host, cfg_key);
 +              if not ssl_config then
 +                      local base_host = module.host:match("%.(.*)");
 +                      ssl_config = config.get(base_host, cfg_key);
 +              end
 +              return ssl_config or typ and get_ssl_cfg();
 +      end
 +
 +      local ssl_config, err = get_ssl_cfg("c2s");
 +      ssl_ctx_c2s, err = create_context(host.host, "server", ssl_config); -- for incoming client connections
 +      if err then module:log("error", "Error creating context for c2s: %s", err); end
 +
 +      ssl_config = get_ssl_cfg("s2s");
 +      ssl_ctx_s2sin, err = create_context(host.host, "server", ssl_config); -- for incoming server connections
 +      ssl_ctx_s2sout = create_context(host.host, "client", ssl_config); -- for outgoing server connections
 +      if err then module:log("error", "Error creating context for s2s: %s", err); end -- Both would have the same issue
 +end
 +
  local function can_do_tls(session)
 +      if not session.conn.starttls then
 +              return false;
 +      elseif session.ssl_ctx then
 +              return true;
 +      end
        if session.type == "c2s_unauthed" then
 -              return session.conn.starttls and host.ssl_ctx_in;
 +              session.ssl_ctx = ssl_ctx_c2s;
        elseif session.type == "s2sin_unauthed" and allow_s2s_tls then
 -              return session.conn.starttls and host.ssl_ctx_in;
 +              session.ssl_ctx = ssl_ctx_s2sin;
        elseif session.direction == "outgoing" and allow_s2s_tls then
 -              return session.conn.starttls and host.ssl_ctx;
 +              session.ssl_ctx = ssl_ctx_s2sout;
 +      else
 +              return false;
        end
 -      return false;
 +      return session.ssl_ctx;
  end
  
  -- Hook <starttls/>
@@@ -72,7 -51,9 +78,7 @@@ module:hook("stanza/urn:ietf:params:xml
        if can_do_tls(origin) then
                (origin.sends2s or origin.send)(starttls_proceed);
                origin:reset_stream();
 -              local host = origin.to_host or origin.host;
 -              local ssl_ctx = host and hosts[host].ssl_ctx_in or global_ssl_ctx;
 -              origin.conn:starttls(ssl_ctx);
 +              origin.conn:starttls(origin.ssl_ctx);
                origin.log("debug", "TLS negotiation started for %s...", origin.type);
                origin.secure = false;
        else
@@@ -110,7 -91,30 +116,7 @@@ end, 500)
  module:hook_stanza(xmlns_starttls, "proceed", function (session, stanza)
        module:log("debug", "Proceeding with TLS on s2sout...");
        session:reset_stream();
 -      local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx;
 -      session.conn:starttls(ssl_ctx);
 +      session.conn:starttls(session.ssl_ctx);
        session.secure = false;
        return true;
  end);
 -
 -local function assert_log(ret, err)
 -      if not ret then
 -              module:log("error", "Unable to initialize TLS: %s", err);
 -      end
 -      return ret;
 -end
 -
 -function module.load()
 -      local ssl_config = config.rawget(module.host, "ssl");
 -      if not ssl_config then
 -              local base_host = module.host:match("%.(.*)");
 -              ssl_config = config.get(base_host, "ssl");
 -      end
 -      host.ssl_ctx = assert_log(create_context(host.host, "client", ssl_config)); -- for outgoing connections
 -      host.ssl_ctx_in = assert_log(create_context(host.host, "server", ssl_config)); -- for incoming connections
 -end
 -
 -function module.unload()
 -      host.ssl_ctx = nil;
 -      host.ssl_ctx_in = nil;
 -end
index 0a6736d782b11e52389a25cc4fd26dea21ef3301,a8bfad0e059d99da7ade7d6cb801ae89f1178bc9..4bc15eb7bb8d6a04d2242b5d791aa73970d7ddbc
@@@ -2,7 -2,7 +2,7 @@@
  -- Prosody IM
  -- Copyright (C) 2008-2010 Matthew Wild
  -- Copyright (C) 2008-2010 Waqas Hussain
 --- 
 +--
  -- This project is MIT/X11 licensed. Please see the
  -- COPYING file in the source package for more information.
  --
@@@ -152,6 -152,48 +152,48 @@@ function privacy(node, host, default, l
        local ret, err = dm.store(node, host, "privacy", privacy);
        print("["..(err or "success").."] privacy: " ..node.."@"..host.." - "..count.." list(s)");
  end
+ local function _table_to_jid(t)
+       if type(t[2]) == "string" then
+               local jid = t[2];
+               if type(t[1]) == "string" then jid = t[1].."@"..jid; end
+               if type(t[3]) == "string" then jid = jid.."/"..t[3]; end
+               return jid;
+       end
+ end
+ function muc_room(node, host, properties)
+       local store = { jid = node.."@"..host, _data = {}, _affiliations = {} };
+       for _,aff in ipairs(properties.affiliations) do
+               store._affiliations[_table_to_jid(aff[1])] = aff[2];
+       end
+       store._data.subject = properties.subject;
+       if properties.subject_author then
+               store._data.subject_from = store.jid .. "/" .. properties.subject_author;
+       end
+       store._data.name = properties.title;
+       store._data.description = properties.description;
+       store._data.password = properties.password;
+       store._data.moderated = (properties.moderated == "true") or nil;
+       store._data.members_only = (properties.members_only == "true") or nil;
+       store._data.persistent = (properties.persistent == "true") or nil;
+       store._data.changesubject = (properties.allow_change_subj == "true") or nil;
+       store._data.whois = properties.anonymous == "true" and "moderators" or "anyone";
+       store._data.hidden = (properties.public_list == "false") or nil;
+       if not store._data.persistent then
+               return print("[error] muc_room: skipping non-persistent room: "..node.."@"..host);
+       end
+       local ret, err = dm.store(node, host, "config", store);
+       if ret then
+               ret, err = dm.load(nil, host, "persistent");
+               if ret or not err then
+                       ret = ret or {};
+                       ret[store.jid] = true;
+                       ret, err = dm.store(nil, host, "persistent", ret);
+               end
+       end
+       print("["..(err or "success").."] muc_room: " ..node.."@"..host);
+ end
  
  
  local filters = {
        privacy = function(tuple)
                privacy(tuple[2][1], tuple[2][2], tuple[3], tuple[4]);
        end;
+       muc_room = function(tuple)
+               local properties = {};
+               for _,pair in ipairs(tuple[3]) do
+                       if not(type(pair[2]) == "table" and #pair[2] == 0) then -- skip nil values
+                               properties[pair[1]] = pair[2];
+                       end
+               end
+               muc_room(tuple[2][1], tuple[2][2], properties);
+       end;
        config = function(tuple)
                if tuple[2] == "hosts" then
                        local output = io.output(); io.output("prosody.cfg.lua");
index 930d5a6b787dd4204ea0de476199525d4d9fb8ff,40be8190dbe9e6fc13ae798a5ef230e7f239cc32..69c8cfe813fed6f0880d3f246e13898b50fa3cf5
@@@ -2,7 -2,7 +2,7 @@@
  -- Prosody IM
  -- Copyright (C) 2008-2010 Matthew Wild
  -- Copyright (C) 2008-2010 Waqas Hussain
 --- 
 +--
  -- This project is MIT/X11 licensed. Please see the
  -- COPYING file in the source package for more information.
  --
@@@ -291,11 -291,21 +291,21 @@@ for i, row in ipairs(t["rostergroups"] 
        roster_group(row.username, host, row.jid, row.grp);
  end
  for i, row in ipairs(t["vcard"] or NULL) do
-       local ret, err = dm.store(row.username, host, "vcard", st.preserialize(parse_xml(row.vcard)));
-       print("["..(err or "success").."] vCard: "..row.username.."@"..host);
+       local stanza, err = parse_xml(row.vcard);
+       if stanza then
+               local ret, err = dm.store(row.username, host, "vcard", st.preserialize(stanza));
+               print("["..(err or "success").."] vCard: "..row.username.."@"..host);
+       else
+               print("[error] vCard XML parse failed: "..row.username.."@"..host);
+       end
  end
  for i, row in ipairs(t["private_storage"] or NULL) do
-       private_storage(row.username, host, row.namespace, parse_xml(row.data));
+       local stanza, err = parse_xml(row.data);
+       if stanza then
+               private_storage(row.username, host, row.namespace, stanza);
+       else
+               print("[error] Private XML parse failed: "..row.username.."@"..host);
+       end
  end
  table.sort(t["spool"] or NULL, function(a,b) return a.seq < b.seq; end); -- sort by sequence number, just in case
  local time_offset = os.difftime(os.time(os.date("!*t")), os.time(os.date("*t"))) -- to deal with timezones
@@@ -304,11 -314,15 +314,15 @@@ local date_parse = function(s
        return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec-time_offset});
  end
  for i, row in ipairs(t["spool"] or NULL) do
-       local stanza = parse_xml(row.xml);
-       local last_child = stanza.tags[#stanza.tags];
-       if not last_child or last_child ~= stanza[#stanza] then error("Last child of offline message is not a tag"); end
-       if last_child.name ~= "x" and last_child.attr.xmlns ~= "jabber:x:delay" then error("Last child of offline message is not a timestamp"); end
-       stanza[#stanza], stanza.tags[#stanza.tags] = nil, nil;
-       local t = date_parse(last_child.attr.stamp);
-       offline_msg(row.username, host, t, stanza);
+       local stanza, err = parse_xml(row.xml);
+       if stanza then
+               local last_child = stanza.tags[#stanza.tags];
+               if not last_child or last_child ~= stanza[#stanza] then error("Last child of offline message is not a tag"); end
+               if last_child.name ~= "x" and last_child.attr.xmlns ~= "jabber:x:delay" then error("Last child of offline message is not a timestamp"); end
+               stanza[#stanza], stanza.tags[#stanza.tags] = nil, nil;
+               local t = date_parse(last_child.attr.stamp);
+               offline_msg(row.username, host, t, stanza);
+       else
+               print("[error] Offline message XML parsing failed: "..row.username.."@"..host);
+       end
  end