aboutsummaryrefslogtreecommitdiffstats
path: root/util/roles.lua
diff options
context:
space:
mode:
authorKim Alvefur <zash@zash.se>2022-12-12 07:10:54 +0100
committerKim Alvefur <zash@zash.se>2022-12-12 07:10:54 +0100
commit080d7974bf0c1da8a1c0578d67c3172facc9d719 (patch)
tree838d6904e47ab8681928b37701ff4f1c6e89184a /util/roles.lua
parentbaff85a52c5fda705e8b3699410c770f015d89ab (diff)
parentc916ce76ee89dca32e7e653dff1ade4732462efc (diff)
downloadprosody-080d7974bf0c1da8a1c0578d67c3172facc9d719.tar.gz
prosody-080d7974bf0c1da8a1c0578d67c3172facc9d719.zip
Merge 0.12->trunk
Diffstat (limited to 'util/roles.lua')
-rw-r--r--util/roles.lua110
1 files changed, 110 insertions, 0 deletions
diff --git a/util/roles.lua b/util/roles.lua
new file mode 100644
index 00000000..2c3a5026
--- /dev/null
+++ b/util/roles.lua
@@ -0,0 +1,110 @@
+local array = require "util.array";
+local it = require "util.iterators";
+local new_short_id = require "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_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;
+};