annotate mod_protect_last_admin/mod_protect_last_admin.lua @ 6513:5fb466693e85

mod_storage_xmlarchive: Ensure list index files are removed using os.remove() on the list files leaves the new index files behind since util.datamanager does not know they are removed. Thanks Link Mauve
author Kim Alvefur <zash@zash.se>
date Tue, 07 Apr 2026 21:10:54 +0200
parents d1f64ffca879
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
6326
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1 module:set_global();
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
2
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
3 local um = require "prosody.core.usermanager";
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
4
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
5 local set = require "prosody.util.set";
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
6
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
7 local protected_roles = module:get_option_set("protect_last_admin_roles", { "prosody:admin", "prosody:operator" });
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8
6327
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
9 local errors = require "prosody.util.error".init(module.name, {
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
10 ["cannot-remove-only-admin"] = {
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
11 code = 400;
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
12 type = "cancel";
6328
187b957dc528 mod_protect_last_admin: Switch to service-unavailable rather than policy-violation
Matthew Wild <mwild1@gmail.com>
parents: 6327
diff changeset
13 condition = "service-unavailable";
6327
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
14 text = "Cannot remove the only administrator";
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
15 extra = {
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
16 namespace = "https://prosody.im/protocol/errors";
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
17 condition = "cannot-remove-only-admin";
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
18 };
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
19 };
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
20 });
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
21
6326
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
22 local function other_protected_users(username, host)
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
23 local protected_users = set.new();
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
24 for protected_role in protected_roles do
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
25 local users = um.get_users_with_role(protected_role, host);
6437
d1f64ffca879 mod_protect_last_admin: Replace util.serialization.serialize with %q
Link Mauve <linkmauve@linkmauve.fr>
parents: 6328
diff changeset
26 module:log("debug", "Role %s: %q", protected_role, users);
6326
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
27 protected_users:add_list(um.get_users_with_role(protected_role, host));
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
28 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
29 protected_users:remove(username);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
30 return not protected_users:empty();
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
31 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
32
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
33 function check_last_admin(event)
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
34 local username, host = event.username, event.host;
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
35
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
36 local current_role = um.get_user_role(username, host);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
37 if not current_role then
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
38 module:log("warn", "Couldn't detect role for %s@%s", username, host);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
39 return;
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
40 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
41
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
42 module:log("debug", "Checking whether to allow this event...");
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
43
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
44 if event.role_name and protected_roles:contains(event.role_name) then
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
45 module:log("debug", "Permitting role change to %s", event.role_name);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
46 return; -- Switching to another protected role is fine
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
47 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
48
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
49 if not protected_roles:contains(current_role.name) then
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
50 module:log("debug", "Permitting event, role %s is not protected", current_role.name);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
51 return; -- This is not a protected user
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
52 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
53
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
54 if not other_protected_users(username, host) then
6327
4f6fb56572f7 mod_protect_last_admin: Return util.error object to provide more information
Matthew Wild <mwild1@gmail.com>
parents: 6326
diff changeset
55 event.reason = errors.new("cannot-remove-only-admin");
6326
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
56 return false;
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
57 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
58 module:log("debug", "Permitting event, no reason not to!");
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
59 end
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
60
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
61 module:hook("pre-delete-user", check_last_admin);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
62 module:hook("pre-disable-user", check_last_admin);
2623515d8507 mod_protect_last_admin: New module to ensure the last admin account on a server cannot be demoted or removed
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
63 module:hook("pre-user-role-change", check_last_admin);