aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2025-04-09 10:59:28 +0100
committerMatthew Wild <mwild1@gmail.com>2025-04-09 10:59:28 +0100
commit60c270f2a8f96c498c250410093bec630e2d4c30 (patch)
treeb37d9b165304e0f68971c19a93b68fae98f6425d
parentefdb9a8919d1e21761148e273041f3ee6b1463b7 (diff)
parent775a4d3cf6bf8c7675e1ded0f5edf7c35e622043 (diff)
downloadprosody-60c270f2a8f96c498c250410093bec630e2d4c30.tar.gz
prosody-60c270f2a8f96c498c250410093bec630e2d4c30.zip
Merge 13.0->trunk
-rw-r--r--core/modulemanager.lua70
-rw-r--r--plugins/mod_admin_shell.lua60
-rw-r--r--plugins/mod_authz_internal.lua6
-rw-r--r--util/pluginloader.lua9
-rw-r--r--util/prosodyctl/check.lua19
5 files changed, 131 insertions, 33 deletions
diff --git a/core/modulemanager.lua b/core/modulemanager.lua
index 7295ba25..4d144a86 100644
--- a/core/modulemanager.lua
+++ b/core/modulemanager.lua
@@ -54,50 +54,58 @@ local _G = _G;
local _ENV = nil;
-- luacheck: std none
-local loader = pluginloader.init({
- load_filter_cb = function (path, content)
- local metadata = {};
- for line in content:gmatch("([^\r\n]+)\r?\n") do
- local key, value = line:match("^%-%-%% *([%w_]+): *(.+)$");
- if key then
- value = value:gsub("%s+$", "");
- metadata[key] = value;
- end
+local function plugin_load_filter_cb(path, content)
+ local metadata = {};
+ for line in content:gmatch("([^\r\n]+)\r?\n") do
+ local key, value = line:match("^%-%-%% *([%w_]+): *(.+)$");
+ if key then
+ value = value:gsub("%s+$", "");
+ metadata[key] = value;
end
+ end
- if metadata.lua then
- local supported = false;
- for supported_lua_version in metadata.lua:gmatch("[^, ]+") do
- if supported_lua_version == lua_version then
- supported = true;
- break;
- end
+ if metadata.lua then
+ local supported = false;
+ for supported_lua_version in metadata.lua:gmatch("[^, ]+") do
+ if supported_lua_version == lua_version then
+ supported = true;
+ break;
end
- if not supported then
+ end
+ if not supported then
+ if prosody.process_type ~= "prosodyctl" then
log("warn", "Not loading module, we have Lua %s but the module requires one of (%s): %s", lua_version, metadata.lua, path);
- return; -- Don't load this module
end
+ return nil, "incompatible with Lua "..lua_version; -- Don't load this module
end
+ end
- if metadata.conflicts then
- local conflicts_features = set.new(array.collect(metadata.conflicts:gmatch("[^, ]+")));
- local conflicted_features = set.intersection(conflicts_features, core_features);
- if not conflicted_features:empty() then
- log("warn", "Not loading module, due to conflicting features '%s': %s", conflicted_features, path);
- return; -- Don't load this module
+ if metadata.conflicts then
+ local conflicts_features = set.new(array.collect(metadata.conflicts:gmatch("[^, ]+")));
+ local conflicted_features = set.intersection(conflicts_features, core_features);
+ if not conflicted_features:empty() then
+ if prosody.process_type ~= "prosodyctl" then
+ log("warn", "Not loading module, due to conflict with built-in features '%s': %s", conflicted_features, path);
end
+ return nil, "conflict with built-in feature"; -- Don't load this module
end
- if metadata.requires then
- local required_features = set.new(array.collect(metadata.requires:gmatch("[^, ]+")));
- local missing_features = required_features - core_features;
- if not missing_features:empty() then
+ end
+ if metadata.requires then
+ local required_features = set.new(array.collect(metadata.requires:gmatch("[^, ]+")));
+ local missing_features = required_features - core_features;
+ if not missing_features:empty() then
+ if prosody.process_type ~= "prosodyctl" then
log("warn", "Not loading module, due to missing features '%s': %s", missing_features, path);
- return; -- Don't load this module
end
+ return nil, "Prosody version missing required feature"; -- Don't load this module
end
+ end
- return path, content, metadata;
- end;
+ return path, content, metadata;
+end;
+
+local loader = pluginloader.init({
+ load_filter_cb = plugin_load_filter_cb;
});
local load_modules_for_host, load, unload, reload, get_module, get_items;
diff --git a/plugins/mod_admin_shell.lua b/plugins/mod_admin_shell.lua
index d6d082f3..de345484 100644
--- a/plugins/mod_admin_shell.lua
+++ b/plugins/mod_admin_shell.lua
@@ -139,6 +139,8 @@ Built-in roles are:
prosody:admin - Host administrator
prosody:operator - Server administrator
+To view roles and policies, see the commands in 'help role'.
+
Roles can be assigned using the user management commands (see 'help user').
]];
@@ -2458,6 +2460,64 @@ function def_env.debug:cert_index(path)
return true, ("Showing %d certificates in %s"):format(c, path);
end
+def_env.role = new_section("Role and access management");
+
+describe_command [[role:list(host) - List known roles]]
+function def_env.role:list(host)
+ if not host then
+ return nil, "Specify which host to list roles for";
+ end
+ local role_list = {};
+ for _, role in it.sorted_pairs(um.get_all_roles(host)) do
+ table.insert(role_list, role);
+ end
+ table.sort(role_list, function (a, b)
+ if a.priority ~= b.priority then
+ return (a.priority or 0) > (b.priority or 0);
+ end
+ return a.name < b.name;
+ end);
+ for _, role in ipairs(role_list) do
+ self.session.print(role.name);
+ end
+ return true, ("Showing %d roles on %s"):format(#role_list, host);
+end
+
+describe_command [[role:show(host, role_name) - Show information about a role]]
+function def_env.role:show(host, role_name)
+ if not host or not role_name then
+ return nil, "Specify the host and role to show";
+ end
+
+ local print = self.session.print;
+ local role = um.get_role_by_name(role_name, host);
+
+ if not role then
+ return nil, ("Unable to find role %s on host %s"):format(role_name, host);
+ end
+
+ local inherits = {};
+ for _, inherited_role in ipairs(role.inherits or {}) do
+ table.insert(inherits, inherited_role.name);
+ end
+
+ local permissions = {};
+ for permission, is_allowed in role:policies() do
+ permissions[permission] = is_allowed and "allowed" or "denied";
+ end
+
+ print("Name: ", role.name);
+ print("Inherits:", table.concat(inherits, ", "));
+ print("Policies:");
+ local c = 0;
+ for permission, policy in it.sorted_pairs(permissions) do
+ c = c + 1;
+ print(" ["..(policy == "allowed" and "+" or " ").."] " .. permission);
+ end
+ print("");
+ return true, ("Showing role %s with %d policies"):format(role.name, c);
+end
+
def_env.stats = new_section("Commands to show internal statistics");
local short_units = {
diff --git a/plugins/mod_authz_internal.lua b/plugins/mod_authz_internal.lua
index f683d90c..1282f617 100644
--- a/plugins/mod_authz_internal.lua
+++ b/plugins/mod_authz_internal.lua
@@ -298,7 +298,11 @@ function add_default_permission(role_name, action, policy)
end
function get_role_by_name(role_name)
- return assert(role_registry[role_name], role_name);
+ local role = role_registry[role_name];
+ if not role then
+ return error("Unknown role: "..role_name);
+ end
+ return role, role_name;
end
function get_all_roles()
diff --git a/util/pluginloader.lua b/util/pluginloader.lua
index 634bd6f8..4d05ea8d 100644
--- a/util/pluginloader.lua
+++ b/util/pluginloader.lua
@@ -25,6 +25,7 @@ local pluginloader_mt = { __index = pluginloader_methods };
function pluginloader_methods:load_file(names)
local file, err, path;
local load_filter_cb = self._options.load_filter_cb;
+ local last_filter_path, last_filter_err;
for i=1,#plugin_dir do
for j=1,#names do
path = plugin_dir[i]..names[j];
@@ -36,12 +37,18 @@ function pluginloader_methods:load_file(names)
if load_filter_cb then
path, content, metadata = load_filter_cb(path, content);
end
- if content and path then
+ if path and content then
return content, path, metadata;
+ else
+ last_filter_path = plugin_dir[i]..names[j];
+ last_filter_err = content or "skipped";
end
end
end
end
+ if last_filter_err then
+ return nil, err..(" (%s skipped because of %s)"):format(last_filter_path, last_filter_err);
+ end
return file, err;
end
diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua
index 622e475e..c46755af 100644
--- a/util/prosodyctl/check.lua
+++ b/util/prosodyctl/check.lua
@@ -644,6 +644,25 @@ local function check(arg)
print(" been deprecated. You can safely remove it.");
end
+ local load_failures = {};
+ for mod_name in all_modules do
+ local mod, err = modulemanager.loader:load_resource(mod_name, nil);
+ if not mod then
+ load_failures[mod_name] = err;
+ end
+ end
+
+ if next(load_failures) ~= nil then
+ print("");
+ print(" The following modules failed to load:");
+ print("");
+ for mod_name, err in it.sorted_pairs(load_failures) do
+ print((" mod_%s: %s"):format(mod_name, err));
+ end
+ print("")
+ print(" Check for typos and remove any obsolete/incompatible modules from your config.");
+ end
+
for host, host_config in pairs(config) do --luacheck: ignore 213/host
if type(rawget(host_config, "storage")) == "string" and rawget(host_config, "default_storage") then
print("");