From 5dddfeb8767b5efae12cbc160508493860a67c4d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 8 Nov 2021 12:51:14 +0000 Subject: [PATCH 1/7] prosody: Prevent federation for users with prosody:restricted role (#37) --- ansible/files/prosody.cfg.lua | 4 ++++ ansible/tasks/prosody.yml | 2 ++ .../mod_snikket_restricted_users.lua | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 962a3e1..a63ec33 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -75,6 +75,7 @@ modules_enabled = { "update_notify"; "turncredentials"; "admin_shell"; + "isolate_host"; "snikket_client_id"; "snikket_ios_preserve_push"; @@ -203,6 +204,9 @@ if ENV_SNIKKET_TWEAK_TURNSERVER ~= "0" or ENV_SNIKKET_TWEAK_TURNSERVER_DOMAIN th turncredentials_secret = ENV_SNIKKET_TWEAK_TURNSERVER_SECRET or assert(io.open("/snikket/prosody/turn-auth-secret-v2")):read("*l"); end +-- Allow restricted users access to push notification servers +isolate_except_domains = { "push.snikket.net", "push-ios.snikket.net" } + VirtualHost (DOMAIN) authentication = "internal_hashed" diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index 9921571..ee3c406 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -122,6 +122,7 @@ - mod_prometheus - mod_spam_reporting - mod_watch_spam_reports + - mod_isolate_host - name: Enable wanted modules (snikket-modules) file: @@ -135,6 +136,7 @@ - mod_invites_bootstrap - mod_snikket_client_id - mod_snikket_ios_preserve_push + - mod_snikket_restricted_users - name: "Install lua-ossl for encrypted push notifications" apt: diff --git a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua new file mode 100644 index 0000000..58a42f2 --- /dev/null +++ b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua @@ -0,0 +1,16 @@ +local jid_bare = require "util.jid".bare; +local um_get_roles = require "core.usermanager".get_roles; + +local function check_user_isolated(event) + local session = event.session; + if not session.no_host_isolation then + local bare_jid = jid_bare(session.full_jid); + local roles = um_get_roles(bare_jid, module.host); + if roles and not roles["prosody:restricted"] then + -- Bypass isolation for all unrestricted users + session.no_host_isolation = true; + end + end +end + +module:hook("resource-bind", check_user_isolated, -0.5); From 0294b0e7e0b834b46d400779ad9f53f9e83ec6bc Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 8 Nov 2021 16:13:07 +0000 Subject: [PATCH 2/7] prosody: Prevent restricted users from creating public channels (#37) --- ansible/files/prosody.cfg.lua | 5 +- .../mod_snikket_restricted_users.lua | 52 +++++++++++++++---- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index a63ec33..e448264 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -241,8 +241,11 @@ Component ("groups."..DOMAIN) "muc" } restrict_room_creation = "local" muc_local_only = { "general@groups."..DOMAIN } - muc_room_default_persistent = true + + -- Default configuration for rooms (typically overwritten by the client) muc_room_default_allow_member_invites = true + muc_room_default_persistent = true + muc_room_default_public = false default_mucs = { { diff --git a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua index 58a42f2..80dfe3e 100644 --- a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua +++ b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua @@ -1,16 +1,50 @@ local jid_bare = require "util.jid".bare; local um_get_roles = require "core.usermanager".get_roles; -local function check_user_isolated(event) - local session = event.session; - if not session.no_host_isolation then - local bare_jid = jid_bare(session.full_jid); - local roles = um_get_roles(bare_jid, module.host); - if roles and not roles["prosody:restricted"] then - -- Bypass isolation for all unrestricted users - session.no_host_isolation = true; +local function load_main_host(module) + local function check_user_isolated(event) + local session = event.session; + if not session.no_host_isolation then + local bare_jid = jid_bare(session.full_jid); + local roles = um_get_roles(bare_jid, module.host); + if roles and not roles["prosody:restricted"] then + -- Bypass isolation for all unrestricted users + session.no_host_isolation = true; + end end end + + module:hook("resource-bind", check_user_isolated, -0.5); end -module:hook("resource-bind", check_user_isolated, -0.5); +local function load_groups_host(module) + local primary_host = module.host:gsub("^%a+%.", ""); + + local function is_restricted(user_jid) + local roles = um_get_roles(user_jid, primary_host); + return not roles or roles["prosody:restricted"]; + end + + module:hook("muc-config-submitted/muc#roomconfig_publicroom", function (event) + if not is_restricted(event.stanza.attr.from) then return; end + -- Don't allow modification of this value by restricted users + return true; + end, 5); + + module:hook("muc-config-form", function (event) + if not is_restricted(event.stanza.attr.from) then return; end -- Don't restrict admins + -- Hide the option from the config form for restricted users + local form = event.form; + for i = #form, 1, -1 do + if form[i].name == "muc#roomconfig_publicroom" then + table.remove(form, i); + end + end + end); +end + +if module:get_host_type() == "component" and module:get_option_string("component_module") == "muc" then + load_groups_host(module); +else + load_main_host(module); +end From 2f997d50b50300f56cfb27540d56ce0ac1d2d232 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 11:23:19 +0000 Subject: [PATCH 3/7] prosody: Enable mod_snikket_restricted_users on MUC host to enforce channel creation --- ansible/files/prosody.cfg.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index e448264..c587ead 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -238,6 +238,7 @@ Component ("groups."..DOMAIN) "muc" "vcard_muc"; "muc_defaults"; "muc_offline_delivery"; + "snikket_restricted_users"; } restrict_room_creation = "local" muc_local_only = { "general@groups."..DOMAIN } From d47a6ddbc0cc35e18307291c7a64966ee7b47d6b Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 11:23:49 +0000 Subject: [PATCH 4/7] mod_snikket_restricted_users: Use event.actor, which is preferred and always present --- .../mod_snikket_restricted_users.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua index 80dfe3e..f284089 100644 --- a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua +++ b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua @@ -26,13 +26,13 @@ local function load_groups_host(module) end module:hook("muc-config-submitted/muc#roomconfig_publicroom", function (event) - if not is_restricted(event.stanza.attr.from) then return; end + if not is_restricted(event.actor) then return; end -- Don't allow modification of this value by restricted users return true; end, 5); module:hook("muc-config-form", function (event) - if not is_restricted(event.stanza.attr.from) then return; end -- Don't restrict admins + if not is_restricted(event.actor) then return; end -- Don't restrict admins -- Hide the option from the config form for restricted users local form = event.form; for i = #form, 1, -1 do From 263d5cf286c8ed98da360e80e0f63431efcfb332 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 11:51:16 +0000 Subject: [PATCH 5/7] prosody: Bump to trunk build 1535 + prosody-modules 8bd36bba2292 --- ansible/snikket.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ansible/snikket.yml b/ansible/snikket.yml index 2d20a87..d9c45cc 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -7,9 +7,9 @@ vars: prosody: package: "prosody-trunk" - build: "1521" + build: "1535" prosody_modules: - revision: "8b3e91249cff" + revision: "8bd36bba2292" tasks: - import_tasks: tasks/prosody.yml - import_tasks: tasks/supervisor.yml From 40daaa883b5f513fcb4d690f1d6a9d9572d35f2a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 12:01:59 +0000 Subject: [PATCH 6/7] prosody: Disable user invitations for restricted users Note that this currently has no effect, because user and contact invitations are disabled globally for non-admins. --- ansible/files/prosody.cfg.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index c587ead..ce8c090 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -141,6 +141,9 @@ registration_invite_only = true -- over what happens when a user invites someone. allow_contact_invites = false +-- Disallow restricted users to create invitations to the server +deny_user_invites_by_roles = { "prosody:restricted" } + invites_page = ENV_SNIKKET_INVITE_URL or ("https://"..DOMAIN.."/invite/{invite.token}/"); invites_page_external = true From a5084a289eb60b0adfe234a1fdcd54f049c4a77a Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 12:28:50 +0000 Subject: [PATCH 7/7] mod_snikket_restricted_users: Add some explanatory comments --- .../mod_snikket_restricted_users.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua index f284089..a7d5f80 100644 --- a/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua +++ b/snikket-modules/mod_snikket_restricted_users/mod_snikket_restricted_users.lua @@ -2,6 +2,8 @@ local jid_bare = require "util.jid".bare; local um_get_roles = require "core.usermanager".get_roles; local function load_main_host(module) + -- Check whether a user should be isolated from remote JIDs + -- If not, set a session flag that allows them to bypass mod_isolate_host local function check_user_isolated(event) local session = event.session; if not session.no_host_isolation then @@ -14,6 +16,8 @@ local function load_main_host(module) end end + -- Add low-priority hook to run after the check_user_isolated default + -- behaviour in mod_isolate_host module:hook("resource-bind", check_user_isolated, -0.5); end