initial commit
This commit is contained in:
commit
c260d7bab8
235 files changed
+49786
No files matched your search
@@ -0,0 +1,44 @@
|
||||
All source code in this project is released under the below MIT license. Some
|
||||
components are not authored by the Prosody maintainers, but such code is
|
||||
itself either released under a MIT license or declared public domain.
|
||||
|
||||
---
|
||||
|
||||
Copyright (C) 2008-2022 Matthew Wild
|
||||
Copyright (C) 2008-2020 Waqas Hussain
|
||||
Copyright (C) 2010-2022 Kim Alvefur
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
util-src/encodings.c:
|
||||
Parts included from Lua 5.3. Copyright (C) 1994-2015 Lua.org, PUC-Rio.
|
||||
|
||||
util-src/signal.c:
|
||||
Copyright (C) 2007 Patrick J. Donnelly (batrick@batbytes.com)
|
||||
See full copyright notice in the source file.
|
||||
|
||||
util-src/struct.c:
|
||||
Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved.
|
||||
See full copyright notice in the source file.
|
||||
|
||||
net/dns.lua:
|
||||
public domain 20080404 lua@ztact.com
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
-- 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.
|
||||
--
|
||||
|
||||
local _G = _G;
|
||||
local getmetatable, setmetatable, rawget, rawset, io, os, error, dofile, type, pairs, ipairs =
|
||||
getmetatable, setmetatable, rawget, rawset, io, os, error, dofile, type, pairs, ipairs;
|
||||
local format, math_max, t_insert = string.format, math.max, table.insert;
|
||||
|
||||
local envload = require"prosody.util.envload".envload;
|
||||
local deps = require"prosody.util.dependencies";
|
||||
local it = require"prosody.util.iterators";
|
||||
local resolve_relative_path = require"prosody.util.paths".resolve_relative_path;
|
||||
local glob_to_pattern = require"prosody.util.paths".glob_to_pattern;
|
||||
local path_sep = package.config:sub(1,1);
|
||||
local get_traceback_table = require "prosody.util.debug".get_traceback_table;
|
||||
local errors = require "prosody.util.error";
|
||||
local log = require "prosody.util.logger".init("config");
|
||||
|
||||
local encodings = deps.softreq"prosody.util.encodings";
|
||||
local nameprep = encodings and encodings.stringprep.nameprep or function (host) return host:lower(); end
|
||||
|
||||
local _M = {};
|
||||
local _ENV = nil;
|
||||
-- luacheck: std none
|
||||
|
||||
_M.resolve_relative_path = resolve_relative_path; -- COMPAT
|
||||
|
||||
local parser = nil;
|
||||
|
||||
local config_mt = { __index = function (t, _) return rawget(t, "*"); end};
|
||||
local config = setmetatable({ ["*"] = { } }, config_mt);
|
||||
local files = {};
|
||||
local credentials_directory = nil;
|
||||
local credential_fallback_fatal = true;
|
||||
|
||||
-- When host not found, use global
|
||||
local host_mt = { __index = function(_, k) return config["*"][k] end }
|
||||
|
||||
function _M.getconfig()
|
||||
return config;
|
||||
end
|
||||
|
||||
function _M.get(host, key)
|
||||
local v = config[host][key];
|
||||
if v and errors.is_error(v) then
|
||||
log("warn", "%s:%d: %s", v.context.filename, v.context.fileline, v.text);
|
||||
return nil;
|
||||
end
|
||||
return v;
|
||||
end
|
||||
function _M.rawget(host, key)
|
||||
local hostconfig = rawget(config, host);
|
||||
if hostconfig then
|
||||
return rawget(hostconfig, key);
|
||||
end
|
||||
end
|
||||
|
||||
local function set(config_table, host, key, value)
|
||||
if host and key then
|
||||
local hostconfig = rawget(config_table, host);
|
||||
if not hostconfig then
|
||||
hostconfig = rawset(config_table, host, setmetatable({}, host_mt))[host];
|
||||
end
|
||||
hostconfig[key] = value;
|
||||
return true;
|
||||
end
|
||||
return false;
|
||||
end
|
||||
|
||||
local function rawget_option(config_table, host, key)
|
||||
if host and key then
|
||||
local hostconfig = rawget(config_table, host);
|
||||
if not hostconfig then
|
||||
return nil;
|
||||
end
|
||||
return rawget(hostconfig, key);
|
||||
end
|
||||
end
|
||||
|
||||
function _M.set(host, key, value)
|
||||
return set(config, host, key, value);
|
||||
end
|
||||
|
||||
function _M.load(filename, config_format)
|
||||
config_format = config_format or filename:match("%w+$");
|
||||
|
||||
if config_format == "lua" then
|
||||
local f, err, errno = io.open(filename);
|
||||
if f then
|
||||
local new_config = setmetatable({ ["*"] = { } }, config_mt);
|
||||
local ok, err = parser.load(f:read("*a"), filename, new_config);
|
||||
f:close();
|
||||
if ok then
|
||||
config = new_config;
|
||||
end
|
||||
return ok, "parser", err;
|
||||
end
|
||||
return f, "file", err, errno;
|
||||
end
|
||||
|
||||
if not config_format then
|
||||
return nil, "file", "no parser specified";
|
||||
else
|
||||
return nil, "file", "no parser for "..(config_format);
|
||||
end
|
||||
end
|
||||
|
||||
function _M.files()
|
||||
return files;
|
||||
end
|
||||
|
||||
-- Built-in Lua parser
|
||||
do
|
||||
local pcall = _G.pcall;
|
||||
local function get_line_number(config_file)
|
||||
local tb = get_traceback_table(nil, 2);
|
||||
for i = 1, #tb do
|
||||
if tb[i].info.short_src == config_file then
|
||||
return tb[i].info.currentline;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local config_option_proxy_mt = {
|
||||
__index = setmetatable({
|
||||
append = function (self, value)
|
||||
local original_option = self:value();
|
||||
if original_option == nil then
|
||||
original_option = {};
|
||||
end
|
||||
if type(value) ~= "table" then
|
||||
error("'append' operation expects a list of values to append to the existing list", 2);
|
||||
end
|
||||
if value[1] ~= nil then
|
||||
for _, v in ipairs(value) do
|
||||
t_insert(original_option, v);
|
||||
end
|
||||
else
|
||||
for k, v in pairs(value) do
|
||||
original_option[k] = v;
|
||||
end
|
||||
end
|
||||
set(self.config_table, self.host, self.option_name, original_option);
|
||||
return self;
|
||||
end;
|
||||
value = function (self)
|
||||
return rawget_option(self.config_table, self.host, self.option_name);
|
||||
end;
|
||||
values = function (self)
|
||||
return it.values(self:value());
|
||||
end;
|
||||
}, {
|
||||
__index = function (t, k) --luacheck: ignore 212/t
|
||||
error("Unknown config option operation: '"..k.."'", 2);
|
||||
end;
|
||||
});
|
||||
|
||||
__call = function (self, v2)
|
||||
local v = self:value() or {};
|
||||
if type(v) == "table" and type(v2) == "table" then
|
||||
return self:append(v2);
|
||||
end
|
||||
|
||||
error("Invalid syntax - missing '=' perhaps?", 2);
|
||||
end;
|
||||
};
|
||||
local function is_config_option_proxy(v)
|
||||
return getmetatable(v) == config_option_proxy_mt;
|
||||
end
|
||||
|
||||
-- For reading config values out of files.
|
||||
local function filereader(basepath, defaultmode)
|
||||
return function(filename, mode)
|
||||
local f, err = io.open(resolve_relative_path(basepath, filename));
|
||||
if not f then error(err, 2); end
|
||||
local content, err = f:read(mode or defaultmode);
|
||||
f:close();
|
||||
if not content then error(err, 2); end
|
||||
return content;
|
||||
end
|
||||
end
|
||||
|
||||
-- Collect lines into an array
|
||||
local function linereader(basepath)
|
||||
return function(filename)
|
||||
local ret = {};
|
||||
for line in io.lines(resolve_relative_path(basepath, filename)) do
|
||||
t_insert(ret, line);
|
||||
end
|
||||
return ret;
|
||||
end
|
||||
end
|
||||
|
||||
parser = {};
|
||||
function parser.load(data, config_file, config_table)
|
||||
local set_options = {}; -- set_options[host.."/"..option_name] = true (when the option has been set already in this file)
|
||||
local warnings = {};
|
||||
local env;
|
||||
local config_path = config_file:gsub("[^"..path_sep.."]+$", "");
|
||||
|
||||
-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
|
||||
env = setmetatable({
|
||||
Host = true, host = true, VirtualHost = true,
|
||||
Component = true, component = true,
|
||||
FileContents = true,
|
||||
FileLine = true,
|
||||
FileLines = true,
|
||||
Credential = true,
|
||||
Include = true, include = true, RunScript = true }, {
|
||||
__index = function (_, k)
|
||||
if k:match("^ENV_") then
|
||||
return os.getenv(k:sub(5));
|
||||
end
|
||||
if k == "Lua" then
|
||||
return _G;
|
||||
end
|
||||
local val = rawget_option(config_table, env.__currenthost or "*", k);
|
||||
|
||||
local g_val = rawget(_G, k);
|
||||
|
||||
if val ~= nil or g_val == nil then
|
||||
if type(val) == "table" then
|
||||
return setmetatable({
|
||||
config_table = config_table;
|
||||
host = env.__currenthost or "*";
|
||||
option_name = k;
|
||||
}, config_option_proxy_mt);
|
||||
elseif val == nil then
|
||||
t_insert(
|
||||
warnings,
|
||||
("%s: %d: unrecognized value: %s (you may be missing quotes around it)"):format(
|
||||
config_file,
|
||||
get_line_number(config_file),
|
||||
k
|
||||
)
|
||||
);
|
||||
end
|
||||
|
||||
return val;
|
||||
end
|
||||
|
||||
if g_val ~= nil then
|
||||
t_insert(
|
||||
warnings,
|
||||
("%s:%d: direct usage of the Lua API is deprecated - replace `%s` with `Lua.%s`"):format(
|
||||
config_file,
|
||||
get_line_number(config_file),
|
||||
k,
|
||||
k
|
||||
)
|
||||
);
|
||||
end
|
||||
|
||||
return g_val;
|
||||
end,
|
||||
__newindex = function (_, k, v)
|
||||
local host = env.__currenthost or "*";
|
||||
local option_path = host.."/"..k;
|
||||
if set_options[option_path] then
|
||||
t_insert(warnings, ("%s:%d: Duplicate option '%s'"):format(config_file, get_line_number(config_file), k));
|
||||
end
|
||||
set_options[option_path] = true;
|
||||
if is_config_option_proxy(v) then
|
||||
setmetatable(v, nil);
|
||||
end
|
||||
set(config_table, env.__currenthost or "*", k, v);
|
||||
end
|
||||
});
|
||||
|
||||
rawset(env, "__currenthost", "*") -- Default is global
|
||||
function env.VirtualHost(name)
|
||||
if not name then
|
||||
error("Host must have a name", 2);
|
||||
end
|
||||
local prepped_name = nameprep(name);
|
||||
if not prepped_name then
|
||||
error(format("Name of Host %q contains forbidden characters", name), 0);
|
||||
end
|
||||
name = prepped_name;
|
||||
if rawget(config_table, name) and rawget(config_table[name], "component_module") then
|
||||
error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
|
||||
name, config_table[name].component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
|
||||
end
|
||||
rawset(env, "__currenthost", name);
|
||||
-- Needs at least one setting to logically exist :)
|
||||
set(config_table, name or "*", "defined", true);
|
||||
return function (config_options)
|
||||
rawset(env, "__currenthost", "*"); -- Return to global scope
|
||||
if type(config_options) == "string" then
|
||||
error(format("VirtualHost entries do not accept a module name (module '%s' provided for host '%s')", config_options, name), 2);
|
||||
elseif type(config_options) ~= "table" then
|
||||
error("Invalid syntax following VirtualHost, expected options but received a "..type(config_options), 2);
|
||||
end
|
||||
for option_name, option_value in pairs(config_options) do
|
||||
set(config_table, name or "*", option_name, option_value);
|
||||
end
|
||||
end;
|
||||
end
|
||||
env.Host, env.host = env.VirtualHost, env.VirtualHost;
|
||||
|
||||
function env.Component(name)
|
||||
if not name then
|
||||
error("Component must have a name", 2);
|
||||
end
|
||||
local prepped_name = nameprep(name);
|
||||
if not prepped_name then
|
||||
error(format("Name of Component %q contains forbidden characters", name), 0);
|
||||
end
|
||||
name = prepped_name;
|
||||
if rawget(config_table, name) and rawget(config_table[name], "defined")
|
||||
and not rawget(config_table[name], "component_module") then
|
||||
error(format("Component %q clashes with previously defined VirtualHost %q, for services use a sub-domain like conference.%s",
|
||||
name, name, name), 0);
|
||||
end
|
||||
set(config_table, name, "component_module", "component");
|
||||
-- Don't load the global modules by default
|
||||
set(config_table, name, "load_global_modules", false);
|
||||
rawset(env, "__currenthost", name);
|
||||
local function handle_config_options(config_options)
|
||||
rawset(env, "__currenthost", "*"); -- Return to global scope
|
||||
for option_name, option_value in pairs(config_options) do
|
||||
set(config_table, name or "*", option_name, option_value);
|
||||
end
|
||||
end
|
||||
|
||||
return function (module)
|
||||
if type(module) == "string" then
|
||||
set(config_table, name, "component_module", module);
|
||||
return handle_config_options;
|
||||
end
|
||||
return handle_config_options(module);
|
||||
end
|
||||
end
|
||||
env.component = env.Component;
|
||||
|
||||
function env.Include(file)
|
||||
-- Check whether this is a wildcard Include
|
||||
if file:match("[*?]") then
|
||||
local lfs = deps.softreq "lfs";
|
||||
if not lfs then
|
||||
error(format("Error expanding wildcard pattern in Include %q - LuaFileSystem not available", file));
|
||||
end
|
||||
local path_pos, glob = file:match("()([^"..path_sep.."]+)$");
|
||||
local path = file:sub(1, math_max(path_pos-2,0));
|
||||
if #path > 0 then
|
||||
path = resolve_relative_path(config_path, path);
|
||||
else
|
||||
path = config_path;
|
||||
end
|
||||
local patt = glob_to_pattern(glob);
|
||||
for f in lfs.dir(path) do
|
||||
if f:sub(1,1) ~= "." and f:match(patt) then
|
||||
env.Include(path..path_sep..f);
|
||||
end
|
||||
end
|
||||
return;
|
||||
end
|
||||
-- Not a wildcard, so resolve (potentially) relative path and run through config parser
|
||||
file = resolve_relative_path(config_path, file);
|
||||
local f, err = io.open(file);
|
||||
if f then
|
||||
local ret, err = parser.load(f:read("*a"), file, config_table);
|
||||
if not ret then error(err:gsub("%[string.-%]", file), 0); end
|
||||
if err then
|
||||
for _, warning in ipairs(err) do
|
||||
t_insert(warnings, warning);
|
||||
end
|
||||
end
|
||||
end
|
||||
if not f then error("Error loading included "..file..": "..err, 0); end
|
||||
return f, err;
|
||||
end
|
||||
env.include = env.Include;
|
||||
|
||||
function env.RunScript(file)
|
||||
return dofile(resolve_relative_path(config_path, file));
|
||||
end
|
||||
|
||||
env.FileContents = filereader(config_path, "*a");
|
||||
env.FileLine = filereader(config_path, "*l");
|
||||
env.FileLines = linereader(config_path);
|
||||
|
||||
if credentials_directory then
|
||||
env.Credential = filereader(credentials_directory, "*a");
|
||||
elseif credential_fallback_fatal then
|
||||
env.Credential = function() error("Credential() requires the $CREDENTIALS_DIRECTORY environment variable to be set", 2) end
|
||||
else
|
||||
env.Credential = function()
|
||||
return errors.new({
|
||||
type = "continue";
|
||||
text = "Credential() requires the $CREDENTIALS_DIRECTORY environment variable to be set";
|
||||
}, { filename = config_file; fileline = get_line_number(config_file) });
|
||||
end
|
||||
end
|
||||
|
||||
local chunk, err = envload(data, "@"..config_file, env);
|
||||
|
||||
if not chunk then
|
||||
return nil, err;
|
||||
end
|
||||
|
||||
local ok, err = pcall(chunk);
|
||||
|
||||
if not ok then
|
||||
return nil, err;
|
||||
end
|
||||
|
||||
t_insert(files, config_file);
|
||||
|
||||
return true, warnings;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function _M.set_credentials_directory(directory)
|
||||
credentials_directory = directory;
|
||||
end
|
||||
|
||||
function _M.set_credential_fallback_mode(mode)
|
||||
credential_fallback_fatal = mode == "error";
|
||||
end
|
||||
|
||||
return _M;
|
||||
Reference in new issue
Block a user