mirror of
https://github.com/bjc/prosody.git
synced 2025-04-05 14:17:37 +03:00
This commit was too awkward to split (hg record didn't like it), so: - Switch to the new util.roles lib to provide a consistent representation of a role object. - Change API method from get_role_info() to get_role_by_name() (touches sessionmanager and usermanager) - Change get_roles() to get_user_roles(), take a username instead of a JID This is more consistent with all other usermanager API methods. - Support configuration of custom roles and permissions via the config file (to be documented).
205 lines
6.1 KiB
Lua
205 lines
6.1 KiB
Lua
local array = require "util.array";
|
|
local it = require "util.iterators";
|
|
local set = require "util.set";
|
|
local jid_split, jid_bare = require "util.jid".split, require "util.jid".bare;
|
|
local normalize = require "util.jid".prep;
|
|
local roles = require "util.roles";
|
|
|
|
local config_global_admin_jids = module:context("*"):get_option_set("admins", {}) / normalize;
|
|
local config_admin_jids = module:get_option_inherited_set("admins", {}) / normalize;
|
|
local host = module.host;
|
|
local role_store = module:open_store("roles");
|
|
local role_map_store = module:open_store("roles", "map");
|
|
|
|
local role_registry = {};
|
|
|
|
function register_role(role)
|
|
if role_registry[role.name] ~= nil then
|
|
return error("A role '"..role.name.."' is already registered");
|
|
end
|
|
if not roles.is_role(role) then
|
|
-- Convert table syntax to real role object
|
|
for i, inherited_role in ipairs(role.inherits or {}) do
|
|
if type(inherited_role) == "string" then
|
|
role.inherits[i] = assert(role_registry[inherited_role], "The named role '"..inherited_role.."' is not registered");
|
|
end
|
|
end
|
|
if not role.permissions then role.permissions = {}; end
|
|
for _, allow_permission in ipairs(role.allow or {}) do
|
|
role.permissions[allow_permission] = true;
|
|
end
|
|
for _, deny_permission in ipairs(role.deny or {}) do
|
|
role.permissions[deny_permission] = false;
|
|
end
|
|
role = roles.new(role);
|
|
end
|
|
role_registry[role.name] = role;
|
|
end
|
|
|
|
-- Default roles
|
|
register_role {
|
|
name = "prosody:restricted";
|
|
priority = 15;
|
|
};
|
|
|
|
register_role {
|
|
name = "prosody:user";
|
|
priority = 25;
|
|
inherits = { "prosody:restricted" };
|
|
};
|
|
|
|
register_role {
|
|
name = "prosody:admin";
|
|
priority = 50;
|
|
inherits = { "prosody:user" };
|
|
};
|
|
|
|
register_role {
|
|
name = "prosody:operator";
|
|
priority = 75;
|
|
inherits = { "prosody:admin" };
|
|
};
|
|
|
|
|
|
-- Process custom roles from config
|
|
|
|
local custom_roles = module:get_option("custom_roles", {});
|
|
for n, role_config in ipairs(custom_roles) do
|
|
local ok, err = pcall(register_role, role_config);
|
|
if not ok then
|
|
module:log("error", "Error registering custom role %s: %s", role_config.name or tostring(n), err);
|
|
end
|
|
end
|
|
|
|
-- Process custom permissions from config
|
|
|
|
local config_add_perms = module:get_option("add_permissions", {});
|
|
local config_remove_perms = module:get_option("remove_permissions", {});
|
|
|
|
for role_name, added_permissions in pairs(config_add_perms) do
|
|
if not role_registry[role_name] then
|
|
module:log("error", "Cannot add permissions to unknown role '%s'", role_name);
|
|
else
|
|
for _, permission in ipairs(added_permissions) do
|
|
role_registry[role_name]:set_permission(permission, true, true);
|
|
end
|
|
end
|
|
end
|
|
|
|
for role_name, removed_permissions in pairs(config_remove_perms) do
|
|
if not role_registry[role_name] then
|
|
module:log("error", "Cannot remove permissions from unknown role '%s'", role_name);
|
|
else
|
|
for _, permission in ipairs(removed_permissions) do
|
|
role_registry[role_name]:set_permission(permission, false, true);
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Public API
|
|
|
|
local config_operator_role_set = {
|
|
["prosody:operator"] = role_registry["prosody:operator"];
|
|
};
|
|
local config_admin_role_set = {
|
|
["prosody:admin"] = role_registry["prosody:admin"];
|
|
};
|
|
local default_role_set = {
|
|
["prosody:user"] = role_registry["prosody:user"];
|
|
};
|
|
|
|
function get_user_roles(user)
|
|
local bare_jid = user.."@"..host;
|
|
if config_global_admin_jids:contains(bare_jid) then
|
|
return config_operator_role_set;
|
|
elseif config_admin_jids:contains(bare_jid) then
|
|
return config_admin_role_set;
|
|
end
|
|
local role_names = role_store:get(user);
|
|
if not role_names then return default_role_set; end
|
|
local user_roles = {};
|
|
for role_name in pairs(role_names) do
|
|
user_roles[role_name] = role_registry[role_name];
|
|
end
|
|
return user_roles;
|
|
end
|
|
|
|
function set_user_roles(user, user_roles)
|
|
role_store:set(user, user_roles)
|
|
return true;
|
|
end
|
|
|
|
function get_user_default_role(user)
|
|
local user_roles = get_user_roles(user);
|
|
if not user_roles then return nil; end
|
|
local default_role;
|
|
for role_name, role_info in pairs(user_roles) do --luacheck: ignore 213/role_name
|
|
if role_info.default ~= false and (not default_role or role_info.priority > default_role.priority) then
|
|
default_role = role_info;
|
|
end
|
|
end
|
|
if not default_role then return nil; end
|
|
return default_role;
|
|
end
|
|
|
|
function get_users_with_role(role_name)
|
|
local storage_role_users = it.to_array(it.keys(role_map_store:get_all(role_name) or {}));
|
|
local config_set;
|
|
if role_name == "prosody:admin" then
|
|
config_set = config_admin_jids;
|
|
elseif role_name == "prosody:operator" then
|
|
config_set = config_global_admin_jids;
|
|
end
|
|
if config_set then
|
|
local config_admin_users = config_set / function (admin_jid)
|
|
local j_node, j_host = jid_split(admin_jid);
|
|
if j_host == host then
|
|
return j_node;
|
|
end
|
|
end;
|
|
return it.to_array(config_admin_users + set.new(storage_role_users));
|
|
end
|
|
return storage_role_users;
|
|
end
|
|
|
|
function get_jid_role(jid)
|
|
local bare_jid = jid_bare(jid);
|
|
if config_global_admin_jids:contains(bare_jid) then
|
|
return role_registry["prosody:operator"];
|
|
elseif config_admin_jids:contains(bare_jid) then
|
|
return role_registry["prosody:admin"];
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
function set_jid_role(jid, role_name) -- luacheck: ignore 212
|
|
return false;
|
|
end
|
|
|
|
function get_jids_with_role(role_name)
|
|
-- Fetch role users from storage
|
|
local storage_role_jids = array.map(get_users_with_role(role_name), function (username)
|
|
return username.."@"..host;
|
|
end);
|
|
if role_name == "prosody:admin" then
|
|
return it.to_array(config_admin_jids + set.new(storage_role_jids));
|
|
elseif role_name == "prosody:operator" then
|
|
return it.to_array(config_global_admin_jids + set.new(storage_role_jids));
|
|
end
|
|
return storage_role_jids;
|
|
end
|
|
|
|
function add_default_permission(role_name, action, policy)
|
|
local role = role_registry[role_name];
|
|
if not role then
|
|
module:log("warn", "Attempt to add default permission for unknown role: %s", role_name);
|
|
return nil, "no-such-role";
|
|
end
|
|
if policy == nil then policy = true; end
|
|
module:log("debug", "Adding policy %s for permission %s on role %s", policy, action, role_name);
|
|
return role:set_permission(action, policy);
|
|
end
|
|
|
|
function get_role_by_name(role_name)
|
|
return assert(role_registry[role_name], role_name);
|
|
end
|