Mercurial > prosody-modules
comparison mod_compat_roles/mod_compat_roles.lua @ 4983:7c77058a1ac5
mod_compat_roles: New module providing compat shim for trunk's new role API
The new role API is translated to is_admin() calls on older versions. On newer
versions (which have the role API) this module does nothing.
It allows modules to drop their use of is_admin() (which is not available in
trunk) and switch to the new role API, while remaining compatible with
previous Prosody versions.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Thu, 11 Aug 2022 17:49:33 +0100 |
| parents | |
| children | d414fa8b37dc |
comparison
equal
deleted
inserted
replaced
| 4982:8a4b17e2e984 | 4983:7c77058a1ac5 |
|---|---|
| 1 -- Export a module:may() that works on Prosody 0.12 and earlier | |
| 2 -- (i.e. backed by is_admin). | |
| 3 | |
| 4 -- This API is safe because Prosody 0.12 and earlier do not support | |
| 5 -- per-session roles - all authorization is based on JID alone. It is not | |
| 6 -- safe on versions that support per-session authorization. | |
| 7 | |
| 8 module:set_global(); | |
| 9 | |
| 10 local moduleapi = require "core.moduleapi"; | |
| 11 | |
| 12 -- If module.may already exists, abort | |
| 13 if moduleapi.may then return; end | |
| 14 | |
| 15 local jid_split = require "util.jid".split; | |
| 16 local um_is_admin = require "core.usermanager".is_admin; | |
| 17 | |
| 18 local function get_jid_role_name(jid, host) | |
| 19 if um_is_admin(jid, "*") then | |
| 20 return "prosody:operator"; | |
| 21 elseif um_is_admin(jid, host) then | |
| 22 return "prosody:admin"; | |
| 23 end | |
| 24 return nil; | |
| 25 end | |
| 26 | |
| 27 local function get_user_role_name(username, host) | |
| 28 return get_jid_role_name(username.."@"..host, host); | |
| 29 end | |
| 30 | |
| 31 -- permissions[host][permission_name] = permitted_role_name | |
| 32 local permissions = {}; | |
| 33 | |
| 34 local function role_may(role_name, permission) | |
| 35 local role_permissions = permissions[role_name]; | |
| 36 if not role_permissions then | |
| 37 return false; | |
| 38 end | |
| 39 return not not permissions[role_name][permission]; | |
| 40 end | |
| 41 | |
| 42 function moduleapi.may(self, action, context) | |
| 43 if action:byte(1) == 58 then -- action begins with ':' | |
| 44 action = self.name..action; -- prepend module name | |
| 45 end | |
| 46 if type(context) == "string" then -- check JID permissions | |
| 47 local role; | |
| 48 local node, host = jid_split(context); | |
| 49 if host == self.host then | |
| 50 role = get_user_role_name(node, self.host); | |
| 51 else | |
| 52 role = get_jid_role_name(context, self.host); | |
| 53 end | |
| 54 if not role then | |
| 55 self:log("debug", "Access denied: JID <%s> may not %s (no role found)", context, action); | |
| 56 return false; | |
| 57 end | |
| 58 | |
| 59 local permit = role_may(role, action); | |
| 60 if not permit then | |
| 61 self:log("debug", "Access denied: JID <%s> may not %s (not permitted by role %s)", context, action, role.name); | |
| 62 end | |
| 63 return permit; | |
| 64 end | |
| 65 | |
| 66 local session = context.origin or context.session; | |
| 67 if type(session) ~= "table" then | |
| 68 error("Unable to identify actor session from context"); | |
| 69 end | |
| 70 if session.type == "s2sin" or (session.type == "c2s" and session.host ~= self.host) then | |
| 71 local actor_jid = context.stanza.attr.from; | |
| 72 local role_name = get_jid_role_name(actor_jid); | |
| 73 if not role_name then | |
| 74 self:log("debug", "Access denied: JID <%s> may not %s (no role found)", actor_jid, action); | |
| 75 return false; | |
| 76 end | |
| 77 local permit = role_may(role_name, action, context); | |
| 78 if not permit then | |
| 79 self:log("debug", "Access denied: JID <%s> may not %s (not permitted by role %s)", actor_jid, action, role_name); | |
| 80 end | |
| 81 return permit; | |
| 82 end | |
| 83 end | |
| 84 | |
| 85 function moduleapi.default_permission(self, role_name, permission) | |
| 86 local r = permissions[self.host][role_name]; | |
| 87 if not r then | |
| 88 r = {}; | |
| 89 permissions[self.host][role_name] = r; | |
| 90 end | |
| 91 r[permission] = true; | |
| 92 end | |
| 93 | |
| 94 function moduleapi.default_permissions(self, role_name, permission_list) | |
| 95 for _, permission in ipairs(permission_list) do | |
| 96 self:default_permission(role_name, permission); | |
| 97 end | |
| 98 end | |
| 99 | |
| 100 function module.add_host(host_module) | |
| 101 permissions[host_module.host] = {}; | |
| 102 function host_module.unload() | |
| 103 permissions[host_module.host] = nil; | |
| 104 end | |
| 105 end |
