prosodyctl check: Warn about invalid domain names in the config file
This ensures that domain names of virtual hosts and components are valid in
XMPP, and that they are encoded correctly.
local id = require "util.id";
local util_debug; -- only imported on-demand
-- Library configuration (see configure())
local auto_inject_traceback = false;
local error_mt = { __name = "error" };
function error_mt:__tostring()
return ("error<%s:%s:%s>"):format(self.type, self.condition, self.text or "");
end
local function is_error(e)
return getmetatable(e) == error_mt;
end
local function configure(opt)
if opt.auto_inject_traceback ~= nil then
auto_inject_traceback = opt.auto_inject_traceback;
if auto_inject_traceback then
util_debug = require "util.debug";
end
end
end
-- Do we want any more well-known fields?
-- Or could we just copy all fields from `e`?
-- Sometimes you want variable details in the `text`, how to handle that?
-- Translations?
-- Should the `type` be restricted to the stanza error types or free-form?
-- What to set `type` to for stream errors or SASL errors? Those don't have a 'type' attr.
local function new(e, context, registry, source)
if is_error(e) then return e; end
local template = registry and registry[e];
if not template then
if type(e) == "table" then
template = {
code = e.code;
type = e.type;
condition = e.condition;
text = e.text;
extra = e.extra;
};
else
template = {};
end
end
context = context or {};
if auto_inject_traceback then
context.traceback = util_debug.get_traceback_table(nil, 2);
end
local error_instance = setmetatable({
instance_id = id.short();
type = template.type or "cancel";
condition = template.condition or "undefined-condition";
text = template.text;
code = template.code;
extra = template.extra;
context = context;
source = source;
}, error_mt);
return error_instance;
end
-- compact --> normal form
local function expand_registry(namespace, registry)
local mapped = {}
for err,template in pairs(registry) do
local e = {
type = template[1];
condition = template[2];
text = template[3];
};
if namespace and template[4] then
e.extra = { namespace = namespace, condition = template[4] };
end
mapped[err] = e;
end
return mapped;
end
local function init(source, namespace, registry)
if type(namespace) == "table" then
-- registry can be given as second argument if namespace is not used
registry, namespace = namespace, nil;
end
local _, protoerr = next(registry, nil);
if protoerr and type(next(protoerr)) == "number" then
registry = expand_registry(namespace, registry);
end
local function wrap(e, context)
if is_error(e) then
return e;
end
local err = new(registry[e] or {
type = "cancel", condition = "undefined-condition"
}, context, registry, source);
err.context.wrapped_error = e;
return err;
end
return {
source = source;
registry = registry;
new = function (e, context)
return new(e, context, registry, source);
end;
coerce = function (ok, err, ...)
if ok then
return ok, err, ...;
end
return nil, wrap(err);
end;
wrap = wrap;
is_error = is_error;
};
end
local function coerce(ok, err, ...)
if ok or is_error(err) then
return ok, err, ...;
end
local new_err = new({
type = "cancel", condition = "undefined-condition"
}, { wrapped_error = err });
return ok, new_err, ...;
end
local function from_stanza(stanza, context, source)
local error_type, condition, text, extra_tag = stanza:get_error();
local error_tag = stanza:get_child("error");
context = context or {};
context.stanza = stanza;
context.by = error_tag and error_tag.attr.by or stanza.attr.from;
local uri;
if condition == "gone" or condition == "redirect" then
uri = error_tag:get_child_text(condition, "urn:ietf:params:xml:ns:xmpp-stanzas");
end
return new({
type = error_type or "cancel";
condition = condition or "undefined-condition";
text = text;
extra = (extra_tag or uri) and {
uri = uri;
tag = extra_tag;
} or nil;
}, context, nil, source);
end
return {
new = new;
init = init;
coerce = coerce;
is_error = is_error;
is_err = is_error; -- COMPAT w/ older 0.12 trunk
from_stanza = from_stanza;
configure = configure;
}