mirror of
https://github.com/bjc/prosody.git
synced 2025-04-01 20:27:39 +03:00
Should be able to roundtrip trough serialization. Also nice for debug and logging purposes where you might want more details than what the __tostring method provides.
123 lines
2.9 KiB
Lua
123 lines
2.9 KiB
Lua
local array = require "prosody.util.array";
|
|
local it = require "prosody.util.iterators";
|
|
local new_short_id = require "prosody.util.id".short;
|
|
|
|
local role_methods = {};
|
|
local role_mt = {
|
|
__index = role_methods;
|
|
__name = "role";
|
|
__add = nil;
|
|
};
|
|
|
|
local function is_role(o)
|
|
local mt = getmetatable(o);
|
|
return mt == role_mt;
|
|
end
|
|
|
|
local function _new_may(permissions, inherited_mays)
|
|
local n_inherited = inherited_mays and #inherited_mays;
|
|
return function (role, action, context)
|
|
-- Note: 'role' may be a descendent role, not only the one we're attached to
|
|
local policy = permissions[action];
|
|
if policy ~= nil then
|
|
return policy;
|
|
end
|
|
if n_inherited then
|
|
for i = 1, n_inherited do
|
|
policy = inherited_mays[i](role, action, context);
|
|
if policy ~= nil then
|
|
return policy;
|
|
end
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
end
|
|
|
|
local permissions_key = {};
|
|
|
|
-- {
|
|
-- Required:
|
|
-- name = "My fancy role";
|
|
--
|
|
-- Optional:
|
|
-- inherits = { role_obj... }
|
|
-- default = true
|
|
-- priority = 100
|
|
-- permissions = {
|
|
-- ["foo"] = true; -- allow
|
|
-- ["bar"] = false; -- deny
|
|
-- }
|
|
-- }
|
|
local function new(base_config, overrides)
|
|
local config = setmetatable(overrides or {}, { __index = base_config });
|
|
local permissions = {};
|
|
local inherited_mays;
|
|
if config.inherits then
|
|
inherited_mays = array.pluck(config.inherits, "may");
|
|
end
|
|
local new_role = {
|
|
id = new_short_id();
|
|
name = config.name;
|
|
description = config.description;
|
|
default = config.default;
|
|
priority = config.priority;
|
|
may = _new_may(permissions, inherited_mays);
|
|
inherits = config.inherits;
|
|
[permissions_key] = permissions;
|
|
};
|
|
local desired_permissions = config.permissions or config[permissions_key];
|
|
for k, v in pairs(desired_permissions or {}) do
|
|
permissions[k] = v;
|
|
end
|
|
return setmetatable(new_role, role_mt);
|
|
end
|
|
|
|
function role_mt:__freeze()
|
|
local t = {
|
|
id = self.id;
|
|
name = self.name;
|
|
description = self.description;
|
|
default = self.default;
|
|
priority = self.priority;
|
|
inherits = self.inherits;
|
|
permissions = self[permissions_key];
|
|
};
|
|
return t;
|
|
end
|
|
|
|
function role_methods:clone(overrides)
|
|
return new(self, overrides);
|
|
end
|
|
|
|
function role_methods:set_permission(permission_name, policy, overwrite)
|
|
local permissions = self[permissions_key];
|
|
if overwrite ~= true and permissions[permission_name] ~= nil and permissions[permission_name] ~= policy then
|
|
return false, "policy-already-exists";
|
|
end
|
|
permissions[permission_name] = policy;
|
|
return true;
|
|
end
|
|
|
|
function role_methods:policies()
|
|
local policy_iterator, s, v = it.join(pairs(self[permissions_key]));
|
|
if self.inherits then
|
|
for _, inherited_role in ipairs(self.inherits) do
|
|
policy_iterator:append(inherited_role:policies());
|
|
end
|
|
end
|
|
return policy_iterator, s, v;
|
|
end
|
|
|
|
function role_mt.__tostring(self)
|
|
return ("role<[%s] %s>"):format(self.id or "nil", self.name or "[no name]");
|
|
end
|
|
|
|
function role_mt.__pairs(self)
|
|
return it.filter(permissions_key, next, self);
|
|
end
|
|
|
|
return {
|
|
is_role = is_role;
|
|
new = new;
|
|
};
|