aboutsummaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/array.lua49
-rw-r--r--util/dataforms.lua22
-rw-r--r--util/datamanager.lua6
-rw-r--r--util/debug.lua1
-rw-r--r--util/dependencies.lua8
-rw-r--r--util/ip.lua176
-rw-r--r--util/iterators.lua2
-rw-r--r--util/rfc3484.lua133
-rw-r--r--util/stanza.lua5
-rw-r--r--util/xmppstream.lua15
10 files changed, 377 insertions, 40 deletions
diff --git a/util/array.lua b/util/array.lua
index 5dbd3037..5dc604ba 100644
--- a/util/array.lua
+++ b/util/array.lua
@@ -9,6 +9,11 @@
local t_insert, t_sort, t_remove, t_concat
= table.insert, table.sort, table.remove, table.concat;
+local setmetatable = setmetatable;
+local math_random = math.random;
+local pairs, ipairs = pairs, ipairs;
+local tostring = tostring;
+
local array = {};
local array_base = {};
local array_methods = {};
@@ -25,6 +30,15 @@ end
setmetatable(array, { __call = new_array });
+-- Read-only methods
+function array_methods:random()
+ return self[math_random(1,#self)];
+end
+
+-- These methods can be called two ways:
+-- array.method(existing_array, [params [, ...]]) -- Create new array for result
+-- existing_array:method([params, ...]) -- Transform existing array into result
+--
function array_base.map(outa, ina, func)
for k,v in ipairs(ina) do
outa[k] = func(v);
@@ -60,15 +74,18 @@ function array_base.sort(outa, ina, ...)
return outa;
end
---- These methods only mutate
-function array_methods:random()
- return self[math.random(1,#self)];
+function array_base.pluck(outa, ina, key)
+ for i=1,#ina do
+ outa[i] = ina[i][key];
+ end
+ return outa;
end
+--- These methods only mutate the array
function array_methods:shuffle(outa, ina)
local len = #self;
for i=1,#self do
- local r = math.random(i,len);
+ local r = math_random(i,len);
self[i], self[r] = self[r], self[i];
end
return self;
@@ -91,10 +108,24 @@ function array_methods:append(array)
return self;
end
-array_methods.push = table.insert;
-array_methods.pop = table.remove;
-array_methods.concat = table.concat;
-array_methods.length = function (t) return #t; end
+function array_methods:push(x)
+ t_insert(self, x);
+ return self;
+end
+
+function array_methods:pop(x)
+ local v = self[x];
+ t_remove(self, x);
+ return v;
+end
+
+function array_methods:concat(sep)
+ return t_concat(array.map(self, tostring), sep);
+end
+
+function array_methods:length()
+ return #self;
+end
--- These methods always create a new array
function array.collect(f, s, var)
@@ -102,7 +133,7 @@ function array.collect(f, s, var)
while true do
var = f(s, var);
if var == nil then break; end
- table.insert(t, var);
+ t_insert(t, var);
end
return setmetatable(t, array_mt);
end
diff --git a/util/dataforms.lua b/util/dataforms.lua
index e4d24cf6..d4a1865c 100644
--- a/util/dataforms.lua
+++ b/util/dataforms.lua
@@ -120,12 +120,18 @@ function form_t.data(layout, stanza)
end
end
- local reader = field_readers[field.type];
- local verifier = field.verifier or field_verifiers[field.type];
- if reader then
- data[field.name] = reader(tag);
- if verifier then
- errors[field.name] = verifier(data[field.name], tag, field.required);
+ if not tag then
+ if field.required then
+ errors[field.name] = "Required value missing";
+ end
+ else
+ local reader = field_readers[field.type];
+ local verifier = field.verifier or field_verifiers[field.type];
+ if reader then
+ data[field.name] = reader(tag);
+ if verifier then
+ errors[field.name] = verifier(data[field.name], tag, field.required);
+ end
end
end
end
@@ -161,7 +167,7 @@ field_readers["jid-single"] =
field_verifiers["jid-single"] =
function (data, field_tag, required)
- if #data == 0 and required then
+ if ((not data) or (#data == 0)) and required then
return "Required value missing";
end
if not jid_prep(data) then
@@ -246,7 +252,7 @@ field_readers["boolean"] =
field_verifiers["boolean"] =
function (data, field_tag, required)
data = field_readers["text-single"](field_tag);
- if #data == 0 and required then
+ if ((not data) or (#data == 0)) and required then
return "Required value missing";
end
if data ~= "1" and data ~= "true" and data ~= "0" and data ~= "false" then
diff --git a/util/datamanager.lua b/util/datamanager.lua
index d5e9c88c..a5d676cc 100644
--- a/util/datamanager.lua
+++ b/util/datamanager.lua
@@ -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.
--
@@ -20,7 +20,7 @@ local error = error;
local next = next;
local t_insert = table.insert;
local append = require "util.serialization".append;
-local path_separator = "/"; if os.getenv("WINDIR") then path_separator = "\\" end
+local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua)
local lfs = require "lfs";
local prosody = prosody;
local raw_mkdir;
@@ -72,7 +72,7 @@ local function callback(username, host, datastore, data)
username, host, datastore, data = f(username, host, datastore, data);
if username == false then break; end
end
-
+
return username, host, datastore, data;
end
function add_callback(func)
diff --git a/util/debug.lua b/util/debug.lua
index 22d02bf2..2170a6d1 100644
--- a/util/debug.lua
+++ b/util/debug.lua
@@ -9,6 +9,7 @@ local censored_names = {
};
local function get_locals_table(level)
+ level = level + 1; -- Skip this function itself
local locals = {};
for local_num = 1, math.huge do
local name, value = debug.getlocal(level, local_num);
diff --git a/util/dependencies.lua b/util/dependencies.lua
index 5baea942..53d2719d 100644
--- a/util/dependencies.lua
+++ b/util/dependencies.lua
@@ -136,6 +136,14 @@ function log_warnings()
log("error", "This version of LuaSec contains a known bug that causes disconnects, see http://prosody.im/doc/depends");
end
end
+ if lxp then
+ if not pcall(lxp.new, { StartDoctypeDecl = false }) then
+ log("error", "The version of LuaExpat on your system leaves Prosody "
+ .."vulnerable to denial-of-service attacks. You should upgrade to "
+ .."LuaExpat 1.1.1 or higher as soon as possible. See "
+ .."http://prosody.im/doc/depends#luaexpat for more information.");
+ end
+ end
end
return _M;
diff --git a/util/ip.lua b/util/ip.lua
new file mode 100644
index 00000000..2f09c034
--- /dev/null
+++ b/util/ip.lua
@@ -0,0 +1,176 @@
+-- Prosody IM
+-- Copyright (C) 2008-2011 Florian Zeitz
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+local ip_methods = {};
+local ip_mt = { __index = function (ip, key) return (ip_methods[key])(ip); end,
+ __tostring = function (ip) return ip.addr; end,
+ __eq = function (ipA, ipB) return ipA.addr == ipB.addr; end};
+local hex2bits = { ["0"] = "0000", ["1"] = "0001", ["2"] = "0010", ["3"] = "0011", ["4"] = "0100", ["5"] = "0101", ["6"] = "0110", ["7"] = "0111", ["8"] = "1000", ["9"] = "1001", ["A"] = "1010", ["B"] = "1011", ["C"] = "1100", ["D"] = "1101", ["E"] = "1110", ["F"] = "1111" };
+
+local function new_ip(ipStr, proto)
+ if proto ~= "IPv4" and proto ~= "IPv6" then
+ return nil, "invalid protocol";
+ end
+
+ return setmetatable({ addr = ipStr, proto = proto }, ip_mt);
+end
+
+local function toBits(ip)
+ local result = "";
+ local fields = {};
+ if ip.proto == "IPv4" then
+ ip = ip.toV4mapped;
+ end
+ ip = (ip.addr):upper();
+ ip:gsub("([^:]*):?", function (c) fields[#fields + 1] = c end);
+ if not ip:match(":$") then fields[#fields] = nil; end
+ for i, field in ipairs(fields) do
+ if field:len() == 0 and i ~= 1 and i ~= #fields then
+ for i = 1, 16 * (9 - #fields) do
+ result = result .. "0";
+ end
+ else
+ for i = 1, 4 - field:len() do
+ result = result .. "0000";
+ end
+ for i = 1, field:len() do
+ result = result .. hex2bits[field:sub(i,i)];
+ end
+ end
+ end
+ return result;
+end
+
+local function commonPrefixLength(ipA, ipB)
+ ipA, ipB = toBits(ipA), toBits(ipB);
+ for i = 1, 128 do
+ if ipA:sub(i,i) ~= ipB:sub(i,i) then
+ return i-1;
+ end
+ end
+ return 128;
+end
+
+local function v4scope(ip)
+ local fields = {};
+ ip:gsub("([^.]*).?", function (c) fields[#fields + 1] = tonumber(c) end);
+ -- Loopback:
+ if fields[1] == 127 then
+ return 0x2;
+ -- Link-local unicast:
+ elseif fields[1] == 169 and fields[2] == 254 then
+ return 0x2;
+ -- Site-local unicast:
+ elseif (fields[1] == 10) or (fields[1] == 192 and fields[2] == 168) or (fields[1] == 172 and (fields[2] >= 16 and fields[2] < 32)) then
+ return 0x5;
+ -- Global unicast:
+ else
+ return 0xE;
+ end
+end
+
+local function v6scope(ip)
+ -- Loopback:
+ if ip:match("^[0:]*1$") then
+ return 0x2;
+ -- Link-local unicast:
+ elseif ip:match("^[Ff][Ee][89ABab]") then
+ return 0x2;
+ -- Site-local unicast:
+ elseif ip:match("^[Ff][Ee][CcDdEeFf]") then
+ return 0x5;
+ -- Multicast:
+ elseif ip:match("^[Ff][Ff]") then
+ return tonumber("0x"..ip:sub(4,4));
+ -- Global unicast:
+ else
+ return 0xE;
+ end
+end
+
+local function label(ip)
+ if commonPrefixLength(ip, new_ip("::1", "IPv6")) == 128 then
+ return 0;
+ elseif commonPrefixLength(ip, new_ip("2002::", "IPv6")) >= 16 then
+ return 2;
+ elseif commonPrefixLength(ip, new_ip("::", "IPv6")) >= 96 then
+ return 3;
+ elseif commonPrefixLength(ip, new_ip("::ffff:0:0", "IPv6")) >= 96 then
+ return 4;
+ else
+ return 1;
+ end
+end
+
+local function precedence(ip)
+ if commonPrefixLength(ip, new_ip("::1", "IPv6")) == 128 then
+ return 50;
+ elseif commonPrefixLength(ip, new_ip("2002::", "IPv6")) >= 16 then
+ return 30;
+ elseif commonPrefixLength(ip, new_ip("::", "IPv6")) >= 96 then
+ return 20;
+ elseif commonPrefixLength(ip, new_ip("::ffff:0:0", "IPv6")) >= 96 then
+ return 10;
+ else
+ return 40;
+ end
+end
+
+local function toV4mapped(ip)
+ local fields = {};
+ local ret = "::ffff:";
+ ip:gsub("([^.]*).?", function (c) fields[#fields + 1] = tonumber(c) end);
+ ret = ret .. ("%02x"):format(fields[1]);
+ ret = ret .. ("%02x"):format(fields[2]);
+ ret = ret .. ":"
+ ret = ret .. ("%02x"):format(fields[3]);
+ ret = ret .. ("%02x"):format(fields[4]);
+ return new_ip(ret, "IPv6");
+end
+
+function ip_methods:toV4mapped()
+ if self.proto ~= "IPv4" then return nil, "No IPv4 address" end
+ local value = toV4mapped(self.addr);
+ self.toV4mapped = value;
+ return value;
+end
+
+function ip_methods:label()
+ local value;
+ if self.proto == "IPv4" then
+ value = label(self.toV4mapped);
+ else
+ value = label(self);
+ end
+ self.label = value;
+ return value;
+end
+
+function ip_methods:precedence()
+ local value;
+ if self.proto == "IPv4" then
+ value = precedence(self.toV4mapped);
+ else
+ value = precedence(self);
+ end
+ self.precedence = value;
+ return value;
+end
+
+function ip_methods:scope()
+ local value;
+ if self.proto == "IPv4" then
+ value = v4scope(self.addr);
+ else
+ value = v6scope(self.addr);
+ end
+ self.scope = value;
+ return value;
+end
+
+return {new_ip = new_ip,
+ commonPrefixLength = commonPrefixLength};
diff --git a/util/iterators.lua b/util/iterators.lua
index 2a87e97a..aa0b172b 100644
--- a/util/iterators.lua
+++ b/util/iterators.lua
@@ -140,7 +140,7 @@ end
-- Treat the return of an iterator as key,value pairs,
-- and build a table
function it2table(f, s, var)
- local t, var = {};
+ local t, var2 = {};
while true do
var, var2 = f(s, var);
if var == nil then break; end
diff --git a/util/rfc3484.lua b/util/rfc3484.lua
new file mode 100644
index 00000000..dd855a84
--- /dev/null
+++ b/util/rfc3484.lua
@@ -0,0 +1,133 @@
+-- Prosody IM
+-- Copyright (C) 2008-2011 Florian Zeitz
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+local commonPrefixLength = require"util.ip".commonPrefixLength
+local new_ip = require"util.ip".new_ip;
+
+local function t_sort(t, comp)
+ for i = 1, (#t - 1) do
+ for j = (i + 1), #t do
+ local a, b = t[i], t[j];
+ if not comp(a,b) then
+ t[i], t[j] = b, a;
+ end
+ end
+ end
+end
+
+function source(dest, candidates)
+ local function comp(ipA, ipB)
+ -- Rule 1: Prefer same address
+ if dest == ipA then
+ return true;
+ elseif dest == ipB then
+ return false;
+ end
+
+ -- Rule 2: Prefer appropriate scope
+ if ipA.scope < ipB.scope then
+ if ipA.scope < dest.scope then
+ return false;
+ else
+ return true;
+ end
+ elseif ipA.scope > ipB.scope then
+ if ipB.scope < dest.scope then
+ return true;
+ else
+ return false;
+ end
+ end
+
+ -- Rule 3: Avoid deprecated addresses
+ -- XXX: No way to determine this
+ -- Rule 4: Prefer home addresses
+ -- XXX: Mobility Address related, no way to determine this
+ -- Rule 5: Prefer outgoing interface
+ -- XXX: Interface to address relation. No way to determine this
+ -- Rule 6: Prefer matching label
+ if ipA.label == dest.label and ipB.label ~= dest.label then
+ return true;
+ elseif ipB.label == dest.label and ipA.label ~= dest.label then
+ return false;
+ end
+
+ -- Rule 7: Prefer public addresses (over temporary ones)
+ -- XXX: No way to determine this
+ -- Rule 8: Use longest matching prefix
+ if commonPrefixLength(ipA, dest) > commonPrefixLength(ipB, dest) then
+ return true;
+ else
+ return false;
+ end
+ end
+
+ t_sort(candidates, comp);
+ return candidates[1];
+end
+
+function destination(candidates, sources)
+ local sourceAddrs = {};
+ local function comp(ipA, ipB)
+ local ipAsource = sourceAddrs[ipA];
+ local ipBsource = sourceAddrs[ipB];
+ -- Rule 1: Avoid unusable destinations
+ -- XXX: No such information
+ -- Rule 2: Prefer matching scope
+ if ipA.scope == ipAsource.scope and ipB.scope ~= ipBsource.scope then
+ return true;
+ elseif ipA.scope ~= ipAsource.scope and ipB.scope == ipBsource.scope then
+ return false;
+ end
+
+ -- Rule 3: Avoid deprecated addresses
+ -- XXX: No way to determine this
+ -- Rule 4: Prefer home addresses
+ -- XXX: Mobility Address related, no way to determine this
+ -- Rule 5: Prefer matching label
+ if ipAsource.label == ipA.label and ipBsource.label ~= ipB.label then
+ return true;
+ elseif ipBsource.label == ipB.label and ipAsource.label ~= ipA.label then
+ return false;
+ end
+
+ -- Rule 6: Prefer higher precedence
+ if ipA.precedence > ipB.precedence then
+ return true;
+ elseif ipA.precedence < ipB.precedence then
+ return false;
+ end
+
+ -- Rule 7: Prefer native transport
+ -- XXX: No way to determine this
+ -- Rule 8: Prefer smaller scope
+ if ipA.scope < ipB.scope then
+ return true;
+ elseif ipA.scope > ipB.scope then
+ return false;
+ end
+
+ -- Rule 9: Use longest matching prefix
+ if commonPrefixLength(ipA, ipAsource) > commonPrefixLength(ipB, ipBsource) then
+ return true;
+ elseif commonPrefixLength(ipA, ipAsource) < commonPrefixLength(ipB, ipBsource) then
+ return false;
+ end
+
+ -- Rule 10: Otherwise, leave order unchanged
+ return true;
+ end
+ for _, ip in ipairs(candidates) do
+ sourceAddrs[ip] = source(ip, sources);
+ end
+
+ t_sort(candidates, comp);
+ return candidates;
+end
+
+return {source = source,
+ destination = destination};
diff --git a/util/stanza.lua b/util/stanza.lua
index de83977f..600212a4 100644
--- a/util/stanza.lua
+++ b/util/stanza.lua
@@ -258,11 +258,6 @@ function stanza_mt.get_error(stanza)
return type, condition or "undefined-condition", text;
end
-function stanza_mt.__add(s1, s2)
- return s1:add_direct_child(s2);
-end
-
-
do
local id = 0;
function new_id()
diff --git a/util/xmppstream.lua b/util/xmppstream.lua
index e5271b72..0f80742d 100644
--- a/util/xmppstream.lua
+++ b/util/xmppstream.lua
@@ -11,26 +11,16 @@ local lxp = require "lxp";
local st = require "util.stanza";
local stanza_mt = st.stanza_mt;
+local error = error;
local tostring = tostring;
local t_insert = table.insert;
local t_concat = table.concat;
local t_remove = table.remove;
local setmetatable = setmetatable;
-local default_log = require "util.logger".init("xmppstream");
-
-- COMPAT: w/LuaExpat 1.1.0
local lxp_supports_doctype = pcall(lxp.new, { StartDoctypeDecl = false });
-if not lxp_supports_doctype then
- default_log("warn", "The version of LuaExpat on your system leaves Prosody "
- .."vulnerable to denial-of-service attacks. You should upgrade to "
- .."LuaExpat 1.1.1 or higher as soon as possible. See "
- .."http://prosody.im/doc/depends#luaexpat for more information.");
-end
-
-local error = error;
-
module "xmppstream"
local new_parser = lxp.new;
@@ -50,8 +40,6 @@ _M.ns_pattern = ns_pattern;
function new_sax_handlers(session, stream_callbacks)
local xml_handlers = {};
- local log = session.log or default_log;
-
local cb_streamopened = stream_callbacks.streamopened;
local cb_streamclosed = stream_callbacks.streamclosed;
local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end;
@@ -188,7 +176,6 @@ function new_sax_handlers(session, stream_callbacks)
local function set_session(stream, new_session)
session = new_session;
- log = new_session.log or default_log;
end
return xml_handlers, { reset = reset, set_session = set_session };