From 00ad72bcf12e342ceb826a3bbf1697805c8414f6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 2 Nov 2021 12:52:51 +0000 Subject: [PATCH 01/23] prosody: add symlink for mod_cloud_notify_extensions --- ansible/tasks/prosody.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index 76a698b..9921571 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -79,6 +79,7 @@ loop: - mod_smacks - mod_cloud_notify + - mod_cloud_notify_extensions - mod_cloud_notify_encrypted - mod_cloud_notify_priority_tag - mod_cloud_notify_filters From 5dddfeb8767b5efae12cbc160508493860a67c4d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 8 Nov 2021 12:51:14 +0000 Subject: [PATCH 02/23] 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 03/23] 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 04/23] 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 05/23] 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 06/23] 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 07/23] 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 08/23] 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 From ca242ce8a4a5ff2588c64c5813e91e96d96d1aa7 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 9 Nov 2021 14:25:56 +0000 Subject: [PATCH 09/23] prosody: Add 16 bytes to upload limit to allow for appended GCM tag (XEP-0454) --- ansible/files/prosody.cfg.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 962a3e1..b55c6b9 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -263,8 +263,13 @@ Component ("share."..DOMAIN) "http_file_share" http_host = "share."..DOMAIN http_external_url = "https://share."..DOMAIN.."/" end - http_file_share_size_limit = 1024 * 1024 * 100 -- 100MB + + -- 128 bits (i.e. 16 bytes) is the maximum length of a GCM auth tag, which + -- is appended to encrypted uploads according to XEP-0454. This ensures we + -- allow files up to the size limit even if they are encrypted. + http_file_share_size_limit = (1024 * 1024 * 100) + 16 -- 100MB + 16 bytes http_file_share_expire_after = 60 * 60 * 24 * RETENTION_DAYS -- N days + if UPLOAD_STORAGE_GB then http_file_share_global_quota = 1024 * 1024 * 1024 * UPLOAD_STORAGE_GB end From f85250461cffc8cb49294f8e19922ba2b4766e1d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 10 Nov 2021 14:41:44 +0000 Subject: [PATCH 10/23] CHANGELOG: Add unreleased changes --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a76142..0bf0c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Snikket Server changelog +## UNRELEASED + +- Increase shared file size limit from 16MB to 100MB +- Allow configurable storage quota for shared files +- Initial support for "limited" user accounts +- Support for group chat notifications on iOS +- Configurable port range for TURN service +- Ability to see basic server metrics in the web admin interface +- Support for advanced monitoring/alerting via Prometheus + +### Upgrading + +If you are using a reverse proxy in front of Snikket, ensure it can +handle the new upload limit (for example, in nginx the `client_max_body_size` +option). + ## beta.20210519 - Allow custom HTTP bind interface From 457096a13d798137dd8ad8ea331fac07a8f32828 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 10 Nov 2021 17:27:09 +0000 Subject: [PATCH 11/23] mod_snikket_restricted_users: Don't isolate users with no roles The code was originally written to fail safe in the event of failure, hence the 'if roles and ...'. However a user with no roles (which is normal for a normal user, especially on upgrade) can return nil. Failure is signified by 'false', so now we explicitly catch this and return early without bypassing isolation. Users with no roles (nil) or with roles but not prosody:restricted bypass isolation. --- .../mod_snikket_restricted_users.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 a7d5f80..75c0396 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 @@ -9,7 +9,8 @@ local function load_main_host(module) 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 + if roles == false then return; end + if not roles or not roles["prosody:restricted"] then -- Bypass isolation for all unrestricted users session.no_host_isolation = true; end From e19b0a32afb33df956a1f4ec34d9091a4a48ab8c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 11 Nov 2021 14:40:09 +0000 Subject: [PATCH 12/23] prosody: Tune GC to be more aggressive by default It appears that, in some environments at least, large file uploads can still cause a significant increase in RAM. This reduces that effect. It is expected that a future release will switch to Lua 5.4, which has shown to have far better GC behaviour. --- ansible/files/prosody.cfg.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 83fed8f..480dfd7 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -29,6 +29,11 @@ data_path = "/snikket/prosody" pidfile = "/var/run/prosody/prosody.pid" +-- Aggressive GC to reduce resource consumption. These values are not +-- incredibly scientific, but should be good for a small private server. +-- They should be reviewed on the upgrade to Lua 5.4. +gc = { threshold = 100, speed = 750 } + modules_enabled = { -- Generally required From 08080f03b991b6f3a0c8f107dd21139a40e5e2f8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 12 Nov 2021 13:41:32 +0000 Subject: [PATCH 13/23] prosody: Show Snikket domain in admin shell prompt --- ansible/files/prosody.cfg.lua | 2 ++ ansible/snikket.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 480dfd7..c014470 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -29,6 +29,8 @@ data_path = "/snikket/prosody" pidfile = "/var/run/prosody/prosody.pid" +admin_shell_prompt = ("prosody [%s]> "):format(DOMAIN) + -- Aggressive GC to reduce resource consumption. These values are not -- incredibly scientific, but should be good for a small private server. -- They should be reviewed on the upgrade to Lua 5.4. diff --git a/ansible/snikket.yml b/ansible/snikket.yml index d9c45cc..5b1fad2 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -7,7 +7,7 @@ vars: prosody: package: "prosody-trunk" - build: "1535" + build: "1537" prosody_modules: revision: "8bd36bba2292" tasks: From ce14c8153b6a76e595be2c418ff745d993ef8566 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 12 Nov 2021 15:56:52 +0000 Subject: [PATCH 14/23] prosody: Load mod_snikket_restricted_users on main host --- 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 480dfd7..0ade43b 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -83,6 +83,7 @@ modules_enabled = { "isolate_host"; "snikket_client_id"; "snikket_ios_preserve_push"; + "snikket_restricted_users"; -- Spam/abuse management "spam_reporting"; -- Allow users to report spam/abuse From a2714fc178d9a97d8e1f83f978d246c79337536c Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 12 Nov 2021 15:58:34 +0000 Subject: [PATCH 15/23] prosody: Bump to build 1540 for role improvements This change will disconnect user sessions when their role changes, ensuring appropriate policies are always enforced. --- ansible/snikket.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/snikket.yml b/ansible/snikket.yml index d9c45cc..21f53f7 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -7,7 +7,7 @@ vars: prosody: package: "prosody-trunk" - build: "1535" + build: "1540" prosody_modules: revision: "8bd36bba2292" tasks: From a24eddab8bc3d986580c0d7160d9b7fa97f8cc01 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 15 Nov 2021 14:15:56 +0000 Subject: [PATCH 16/23] prosody: Add symlink for mod_muc_offline_delivery --- ansible/tasks/prosody.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index ee3c406..bab6dc7 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -117,6 +117,7 @@ - mod_groups_muc_bookmarks - mod_muc_defaults - mod_muc_local_only + - mod_muc_offline_delivery - mod_http_host_status_check - mod_measure_process - mod_prometheus From 17444cc3bd1d01f8df3fc941b54f5206d0fac1d0 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 16 Nov 2021 16:08:16 +0000 Subject: [PATCH 17/23] prosody: Enable push notifications for offline group members by default This avoids the app needing to gain logic to opt-in to push notifications. Such logic may be fragile, and introduce additional traffic and round-trips that would hurt performance. Note that this will trigger pushes even to users who only use Android or non-mobile devices. That should cause no issues, and the impact would be minor. Also considering that non-iOS devices usually remain online most of the time anyway. Not accounted for in this commit is the MUC notification filtering side of things. By default the MUC will push all messages, and mod_cloud_notify(_filters) will allow all of them through to the device unless the user explicitly configures otherwise within the app. If the server can detect whether a MUC is public or private, it can make the default behaviour more sensible (maybe when adding bookmarks or something?). In any case, public channels are not a primary use-case for Snikket and can easily be configured manually in the app for now. --- ansible/files/prosody.cfg.lua | 5 +++++ ansible/snikket.yml | 4 ++-- ansible/tasks/prosody.yml | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index de9aeeb..8b6ac45 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -250,6 +250,7 @@ Component ("groups."..DOMAIN) "muc" "muc_defaults"; "muc_offline_delivery"; "snikket_restricted_users"; + "muc_auto_reserve_nicks"; } restrict_room_creation = "local" muc_local_only = { "general@groups."..DOMAIN } @@ -259,6 +260,10 @@ Component ("groups."..DOMAIN) "muc" muc_room_default_persistent = true muc_room_default_public = false + -- Enable push notifications for offline group members by default + -- (this also requires mod_muc_auto_reserve_nicks in practice) + muc_offline_delivery_default = true + default_mucs = { { jid_node = "general"; diff --git a/ansible/snikket.yml b/ansible/snikket.yml index 21f53f7..38fd604 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -7,9 +7,9 @@ vars: prosody: package: "prosody-trunk" - build: "1540" + build: "1544" prosody_modules: - revision: "8bd36bba2292" + revision: "eb63890ae8fc" tasks: - import_tasks: tasks/prosody.yml - import_tasks: tasks/supervisor.yml diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index bab6dc7..c404e85 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -124,6 +124,7 @@ - mod_spam_reporting - mod_watch_spam_reports - mod_isolate_host + - mod_muc_auto_reserve_nicks - name: Enable wanted modules (snikket-modules) file: From cd462a28a7d966defce786e9d77aebfd39eecc08 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Tue, 16 Nov 2021 17:11:36 +0000 Subject: [PATCH 18/23] docs: Add page about user roles --- docs/features/user_roles.md | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/features/user_roles.md diff --git a/docs/features/user_roles.md b/docs/features/user_roles.md new file mode 100644 index 0000000..f6ec1e9 --- /dev/null +++ b/docs/features/user_roles.md @@ -0,0 +1,53 @@ +--- +title: User roles +--- + +# User roles + +Snikket allows you to select a role for users, each role granting different +permissions. + +Each user may have one of three roles: + +## Administrator + +This is the default role of the first user (if you're reading this, that's +probably you!). + +Administrators have full control over the server, settings, users and circles. +These features can be accessed primarily through the admin panel in the +Snikket web interface. + +## Normal + +This is the default role for most users. It gives access to all +non-administrative server functionality. + +## Limited + +Limited users have various restrictions. The purpose of this role is to +allow granting someone an account on the server, only for the purposes of +communicating with other people on that server. This can be useful to provide +a guest or child account, for example. + +In particular, limited users are not allowed to: + +- Communicate with users on other servers +- Join group chats on other servers +- Create public channels (including on the current server) +- Invite new users to the server (regardless of whether this is enabled for + normal users). + +### Caveats + +The current support for limited users has some known issues. It is designed to +prevent casual misuse of the server, but it is not intended to be a foolproof +security measure. For example, limited users are still able to *receive* +messages and contact requests from other servers, even though they cannot send +them to other servers. It is expected that we will restrict incoming traffic +for limited users in a future release, after further testing. + +Also note that limited accounts may have issues using non-Snikket mobile apps +that use push notifications, depending on the design of the app. This is +because the restrictions may prevent the app communicating with its' +developer's push notification services over XMPP. From 569fce239cbd4492687101622a49faed430b2c18 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 17 Nov 2021 13:47:42 +0000 Subject: [PATCH 19/23] prosody: Switch to and enable mod_lastlog2 This records a timestamp of various account events - account registration time, last connection and last disconnection. In the future I would like to keep a time-limited record of account activity so we can also present it to the user for security purposes (e.g. detecting account compromise and access by third-parties). That will need additional design work to figure out how to do it in a privacy-preserving way. --- ansible/files/prosody.cfg.lua | 1 + ansible/tasks/prosody.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 8b6ac45..34a8bd5 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -86,6 +86,7 @@ modules_enabled = { "snikket_client_id"; "snikket_ios_preserve_push"; "snikket_restricted_users"; + "lastlog2"; -- Spam/abuse management "spam_reporting"; -- Allow users to report spam/abuse diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index c404e85..325a107 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -87,7 +87,7 @@ - mod_compact_resource - mod_conversejs - mod_migrate_http_upload - - mod_lastlog + - mod_lastlog2 - mod_limit_auth - mod_password_policy - mod_roster_allinall From ad694d643622ea6e725e359ac9276b5f9079e938 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 17 Nov 2021 13:51:05 +0000 Subject: [PATCH 20/23] prosody: Enable mod_measure_active_users This allows an operator (via Prometheus, or eventually the web portal) to keep tabs on how many people are using the server, e.g. to assist with capacity planning. This will become more important once we allow user-to-user account invitations. --- ansible/files/prosody.cfg.lua | 1 + ansible/snikket.yml | 2 +- ansible/tasks/prosody.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ansible/files/prosody.cfg.lua b/ansible/files/prosody.cfg.lua index 34a8bd5..0080bf9 100644 --- a/ansible/files/prosody.cfg.lua +++ b/ansible/files/prosody.cfg.lua @@ -127,6 +127,7 @@ modules_enabled = { -- Monitoring & maintenance "measure_process"; + "measure_active_users"; } registration_watchers = {} -- Disable by default diff --git a/ansible/snikket.yml b/ansible/snikket.yml index 38fd604..53b35f4 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -9,7 +9,7 @@ package: "prosody-trunk" build: "1544" prosody_modules: - revision: "eb63890ae8fc" + revision: "1132f2888cd2" tasks: - import_tasks: tasks/prosody.yml - import_tasks: tasks/supervisor.yml diff --git a/ansible/tasks/prosody.yml b/ansible/tasks/prosody.yml index 325a107..26e9a79 100644 --- a/ansible/tasks/prosody.yml +++ b/ansible/tasks/prosody.yml @@ -125,6 +125,7 @@ - mod_watch_spam_reports - mod_isolate_host - mod_muc_auto_reserve_nicks + - mod_measure_active_users - name: Enable wanted modules (snikket-modules) file: From fbc5a46c4349900cc92964b543a6b3c1be7a5ab8 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 18 Nov 2021 09:09:05 +0000 Subject: [PATCH 21/23] prosody: Bump prosody-modules for bugfix in fd90925dc239 --- ansible/snikket.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/snikket.yml b/ansible/snikket.yml index 53b35f4..80b9cba 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -9,7 +9,7 @@ package: "prosody-trunk" build: "1544" prosody_modules: - revision: "1132f2888cd2" + revision: "fd90925dc239" tasks: - import_tasks: tasks/prosody.yml - import_tasks: tasks/supervisor.yml From e5d493483e3fc5dcc88bc19431c7df79fd0e5825 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Fri, 19 Nov 2021 17:02:09 +0000 Subject: [PATCH 22/23] prosody: Bump prosody-modules for bugfix in 4abb33a15897 --- ansible/snikket.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/snikket.yml b/ansible/snikket.yml index 80b9cba..e5aa26d 100644 --- a/ansible/snikket.yml +++ b/ansible/snikket.yml @@ -9,7 +9,7 @@ package: "prosody-trunk" build: "1544" prosody_modules: - revision: "fd90925dc239" + revision: "4abb33a15897" tasks: - import_tasks: tasks/prosody.yml - import_tasks: tasks/supervisor.yml From d1cdca0c2ca1a2af3375a0d33ee9f5463b48d3c2 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 25 Nov 2021 15:00:41 +0000 Subject: [PATCH 23/23] docs: Update certificate troubleshooting docs with more info --- docs/setup/troubleshooting.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/setup/troubleshooting.md b/docs/setup/troubleshooting.md index 6ae7eb3..14c0697 100644 --- a/docs/setup/troubleshooting.md +++ b/docs/setup/troubleshooting.md @@ -110,16 +110,38 @@ for more information on correctly configuring reverse proxies. ### Certificate debugging commands -If everything looks okay and you're not sure what the problem could be, -you can get the error message from the debug log: +#### Checking for errors + +If you think you have everything set up correctly and you're not sure what the +problem could be, check the error log: + +``` +docker-compose exec snikket_certs cat /var/log/letsencrypt/errors.log +``` + +If you get a "No such file or directory" error when running the above command, +inspect the debug log instead: ``` docker-compose exec snikket_certs cat /var/log/letsencrypt/letsencrypt.log | grep detail ``` +#### Trying again + Once you have fixed any problems, you can force a new attempt with the following command: +``` +docker-compose exec snikket_certs /etc/cron.daily/certbot +``` + +If that command says that no certificates are due for renewal, but you need to +trigger a renewal anyway, run: + ``` docker-compose exec snikket_certs su letsencrypt -- -c "certbot renew --config-dir /snikket/letsencrypt --cert-path /etc/ssl/certbot --force-renew" ``` + +Note that Let's Encrypt has strict [rate limits](https://letsencrypt.org/docs/rate-limits/) - +do not run these commands more often than necessary, or you may find yourself +unable to get new certificates for a while.