annotate mod_protect_last_admin/mod_protect_last_admin.lua @ 6554:0002c727e918

mod_firewall: Use module:add_timer() for HTTP polling This ensures that polling stops when the module is unloaded.
author Matthew Wild <mwild1@gmail.com>
date Sun, 24 May 2026 19:35:52 +0100
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);