Merge branch 'master' into ccchaos
This commit is contained in:
commit
6dd5a3b0fc
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,5 +1,21 @@
|
||||||
# Snikket Server changelog
|
# 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
|
## beta.20210519
|
||||||
|
|
||||||
- Allow custom HTTP bind interface
|
- Allow custom HTTP bind interface
|
||||||
|
|
|
@ -31,6 +31,13 @@ data_path = "/snikket/prosody"
|
||||||
|
|
||||||
pidfile = "/var/run/prosody/prosody.pid"
|
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.
|
||||||
|
gc = { threshold = 100, speed = 750 }
|
||||||
|
|
||||||
modules_enabled = {
|
modules_enabled = {
|
||||||
|
|
||||||
-- Generally required
|
-- Generally required
|
||||||
|
@ -77,8 +84,11 @@ modules_enabled = {
|
||||||
"update_notify";
|
"update_notify";
|
||||||
"turncredentials";
|
"turncredentials";
|
||||||
"admin_shell";
|
"admin_shell";
|
||||||
|
"isolate_host";
|
||||||
"snikket_client_id";
|
"snikket_client_id";
|
||||||
"snikket_ios_preserve_push";
|
"snikket_ios_preserve_push";
|
||||||
|
"snikket_restricted_users";
|
||||||
|
"lastlog2";
|
||||||
|
|
||||||
-- Spam/abuse management
|
-- Spam/abuse management
|
||||||
"spam_reporting"; -- Allow users to report spam/abuse
|
"spam_reporting"; -- Allow users to report spam/abuse
|
||||||
|
@ -119,6 +129,7 @@ modules_enabled = {
|
||||||
|
|
||||||
-- Monitoring & maintenance
|
-- Monitoring & maintenance
|
||||||
"measure_process";
|
"measure_process";
|
||||||
|
"measure_active_users";
|
||||||
}
|
}
|
||||||
|
|
||||||
registration_watchers = {} -- Disable by default
|
registration_watchers = {} -- Disable by default
|
||||||
|
@ -142,6 +153,9 @@ registration_invite_only = true
|
||||||
-- over what happens when a user invites someone.
|
-- over what happens when a user invites someone.
|
||||||
allow_contact_invites = false
|
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 = ENV_SNIKKET_INVITE_URL or ("https://"..DOMAIN.."/invite/{invite.token}/");
|
||||||
invites_page_external = true
|
invites_page_external = true
|
||||||
|
|
||||||
|
@ -205,6 +219,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");
|
turncredentials_secret = ENV_SNIKKET_TWEAK_TURNSERVER_SECRET or assert(io.open("/snikket/prosody/turn-auth-secret-v2")):read("*l");
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Allow restricted users access to push notification servers
|
||||||
|
isolate_except_domains = { "push.snikket.net", "push-ios.snikket.net" }
|
||||||
|
|
||||||
VirtualHost (DOMAIN)
|
VirtualHost (DOMAIN)
|
||||||
authentication = "internal_hashed"
|
authentication = "internal_hashed"
|
||||||
|
|
||||||
|
@ -243,11 +260,20 @@ Component ("groups."..DOMAIN) "muc"
|
||||||
"vcard_muc";
|
"vcard_muc";
|
||||||
"muc_defaults";
|
"muc_defaults";
|
||||||
"muc_offline_delivery";
|
"muc_offline_delivery";
|
||||||
|
"snikket_restricted_users";
|
||||||
|
"muc_auto_reserve_nicks";
|
||||||
}
|
}
|
||||||
restrict_room_creation = "local"
|
restrict_room_creation = "local"
|
||||||
muc_local_only = { "general@groups."..DOMAIN }
|
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_allow_member_invites = true
|
||||||
|
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 = {
|
default_mucs = {
|
||||||
{
|
{
|
||||||
|
@ -272,8 +298,13 @@ Component ("share."..DOMAIN) "http_file_share"
|
||||||
http_host = "share."..DOMAIN
|
http_host = "share."..DOMAIN
|
||||||
http_external_url = "https://share."..DOMAIN.."/"
|
http_external_url = "https://share."..DOMAIN.."/"
|
||||||
end
|
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
|
http_file_share_expire_after = 60 * 60 * 24 * RETENTION_DAYS -- N days
|
||||||
|
|
||||||
if UPLOAD_STORAGE_GB then
|
if UPLOAD_STORAGE_GB then
|
||||||
http_file_share_global_quota = 1024 * 1024 * 1024 * UPLOAD_STORAGE_GB
|
http_file_share_global_quota = 1024 * 1024 * 1024 * UPLOAD_STORAGE_GB
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
vars:
|
vars:
|
||||||
prosody:
|
prosody:
|
||||||
package: "prosody-trunk"
|
package: "prosody-trunk"
|
||||||
build: "1521"
|
build: "1544"
|
||||||
prosody_modules:
|
prosody_modules:
|
||||||
revision: "8b3e91249cff"
|
revision: "4abb33a15897"
|
||||||
tasks:
|
tasks:
|
||||||
- import_tasks: tasks/prosody.yml
|
- import_tasks: tasks/prosody.yml
|
||||||
- import_tasks: tasks/supervisor.yml
|
- import_tasks: tasks/supervisor.yml
|
||||||
|
|
|
@ -79,6 +79,7 @@
|
||||||
loop:
|
loop:
|
||||||
- mod_smacks
|
- mod_smacks
|
||||||
- mod_cloud_notify
|
- mod_cloud_notify
|
||||||
|
- mod_cloud_notify_extensions
|
||||||
- mod_cloud_notify_encrypted
|
- mod_cloud_notify_encrypted
|
||||||
- mod_cloud_notify_priority_tag
|
- mod_cloud_notify_priority_tag
|
||||||
- mod_cloud_notify_filters
|
- mod_cloud_notify_filters
|
||||||
|
@ -86,7 +87,7 @@
|
||||||
- mod_compact_resource
|
- mod_compact_resource
|
||||||
- mod_conversejs
|
- mod_conversejs
|
||||||
- mod_migrate_http_upload
|
- mod_migrate_http_upload
|
||||||
- mod_lastlog
|
- mod_lastlog2
|
||||||
- mod_limit_auth
|
- mod_limit_auth
|
||||||
- mod_password_policy
|
- mod_password_policy
|
||||||
- mod_roster_allinall
|
- mod_roster_allinall
|
||||||
|
@ -116,11 +117,15 @@
|
||||||
- mod_groups_muc_bookmarks
|
- mod_groups_muc_bookmarks
|
||||||
- mod_muc_defaults
|
- mod_muc_defaults
|
||||||
- mod_muc_local_only
|
- mod_muc_local_only
|
||||||
|
- mod_muc_offline_delivery
|
||||||
- mod_http_host_status_check
|
- mod_http_host_status_check
|
||||||
- mod_measure_process
|
- mod_measure_process
|
||||||
- mod_prometheus
|
- mod_prometheus
|
||||||
- mod_spam_reporting
|
- mod_spam_reporting
|
||||||
- mod_watch_spam_reports
|
- mod_watch_spam_reports
|
||||||
|
- mod_isolate_host
|
||||||
|
- mod_muc_auto_reserve_nicks
|
||||||
|
- mod_measure_active_users
|
||||||
|
|
||||||
- name: Enable wanted modules (snikket-modules)
|
- name: Enable wanted modules (snikket-modules)
|
||||||
file:
|
file:
|
||||||
|
@ -134,6 +139,7 @@
|
||||||
- mod_invites_bootstrap
|
- mod_invites_bootstrap
|
||||||
- mod_snikket_client_id
|
- mod_snikket_client_id
|
||||||
- mod_snikket_ios_preserve_push
|
- mod_snikket_ios_preserve_push
|
||||||
|
- mod_snikket_restricted_users
|
||||||
|
|
||||||
- name: "Install lua-ossl for encrypted push notifications"
|
- name: "Install lua-ossl for encrypted push notifications"
|
||||||
apt:
|
apt:
|
||||||
|
|
|
@ -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.
|
|
@ -110,16 +110,38 @@ for more information on correctly configuring reverse proxies.
|
||||||
|
|
||||||
### Certificate debugging commands
|
### Certificate debugging commands
|
||||||
|
|
||||||
If everything looks okay and you're not sure what the problem could be,
|
#### Checking for errors
|
||||||
you can get the error message from the debug log:
|
|
||||||
|
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
|
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
|
Once you have fixed any problems, you can force a new attempt with the
|
||||||
following command:
|
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"
|
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.
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
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
|
||||||
|
local bare_jid = jid_bare(session.full_jid);
|
||||||
|
local roles = um_get_roles(bare_jid, module.host);
|
||||||
|
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
|
||||||
|
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
|
||||||
|
|
||||||
|
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.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.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
|
||||||
|
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
|
Loading…
Reference in New Issue