From 1ab7340949b90d655bf7a33402caa93d3ec74a00 Mon Sep 17 00:00:00 2001 From: f Date: Sat, 11 Jan 2025 12:03:50 -0300 Subject: [PATCH] feat: upgrade to stable --- compose.yml | 6 +- prosody.cfg.lua.tmpl | 213 +++++++++++++++++++++++++++++++------------ 2 files changed, 160 insertions(+), 59 deletions(-) diff --git a/compose.yml b/compose.yml index f8a89e7..fdb45f5 100644 --- a/compose.yml +++ b/compose.yml @@ -17,7 +17,7 @@ x-environment: &default-env services: app: - image: snikket/snikket-web-proxy:beta.20220119.1 + image: snikket/snikket-web-proxy:stable.20240926 networks: - proxy - backend @@ -42,13 +42,13 @@ services: - "coop-cloud.${STACK_NAME}.version=0.1.0+beta.20220119.1" portal: - image: snikket/snikket-web-portal:beta.20220119.1 + image: snikket/snikket-web-portal:stable.20240926 environment: *default-env networks: - backend server: - image: snikket/snikket-server:beta.20220119.1 + image: snikket/snikket-server:stable.20240926 secrets: - coturn_secret configs: diff --git a/prosody.cfg.lua.tmpl b/prosody.cfg.lua.tmpl index 21d3a08..9113594 100644 --- a/prosody.cfg.lua.tmpl +++ b/prosody.cfg.lua.tmpl @@ -1,27 +1,34 @@ --- fork of https://github.com/snikket-im/snikket-server/blob/master/ansible/files/prosody.cfg.lua +-- fork of https://github.com/snikket-im/snikket-server/blob/stable.20240926/ansible/files/prosody.cfg.lua -- added changes from https://github.com/3-w-c/snikket-server/blob/d8577e0e57a79afd48695aadc60f7873b56897bc/ansible/files/prosody.cfg.lua -- until https://github.com/snikket-im/snikket-server/issues/88 is resolved +local function split(s) + local v = {}; + for p in (s or ""):gmatch("[^%s,]+") do + v[#v+1] = p; + end + return v; +end + +local DOMAIN = Lua.assert(ENV_SNIKKET_DOMAIN, "Please set the SNIKKET_DOMAIN environment variable") + local CERT_PATH = ENV_SNIKKET_CERTFILE or "/etc/prosody/certs/"..DOMAIN..".crt"; local KEY_PATH = ENV_SNIKKET_KEYFILE or "/etc/prosody/certs/"..DOMAIN..".key"; -local DOMAIN = assert(ENV_SNIKKET_DOMAIN, "Please set the SNIKKET_DOMAIN environment variable") +local RETENTION_DAYS = Lua.tonumber(ENV_SNIKKET_RETENTION_DAYS) or 7; +local UPLOAD_STORAGE_GB = Lua.tonumber(ENV_SNIKKET_UPLOAD_STORAGE_GB); -local RETENTION_DAYS = tonumber(ENV_SNIKKET_RETENTION_DAYS) or 7; -local UPLOAD_STORAGE_GB = tonumber(ENV_SNIKKET_UPLOAD_STORAGE_GB); - -if prosody.process_type == "prosody" and not prosody.config_loaded then +if Lua.prosody.process_type == "prosody" and not Lua.prosody.config_loaded then -- Wait at startup for certificates local lfs, socket = require "lfs", require "socket"; - local cert_path = "/etc/prosody/certs/"..DOMAIN..".crt"; local counter = 0; while not lfs.attributes(CERT_PATH, "mode") do counter = counter + 1; if counter == 1 or counter%6 == 0 then - print("Waiting for certificates..."); + Lua.print("Waiting for certificates..."); elseif counter > 60 then - print("No certificates found... exiting"); - os.exit(1); + Lua.print("No certificates found... exiting"); + Lua.os.exit(1); end socket.sleep(5); end @@ -38,11 +45,6 @@ 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 = { -- Generally required @@ -57,6 +59,7 @@ modules_enabled = { "blocklist"; -- Allow users to block communications with other users "vcard4"; -- User profiles (stored in PEP) "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard + "password_policy"; -- Nice to have "version"; -- Replies to server version requests @@ -67,6 +70,19 @@ modules_enabled = { "mam"; -- Store messages in an archive and allow users to access it "csi_simple"; -- Simple Mobile optimizations + -- SASL2/FAST + "sasl2"; + "sasl2_bind2"; + "sasl2_sm"; + "sasl2_fast"; + "client_management"; + + -- Event auditing + "audit"; + "audit_auth"; -- Audit authentication attempts and new clients + "audit_status"; -- Audit status changes of the server (start, stop, crash) + "audit_user_accounts"; -- Audit status changes of user accounts (created, deleted, etc.) + -- Push notifications "cloud_notify"; "cloud_notify_extensions"; @@ -87,26 +103,25 @@ modules_enabled = { "bookmarks"; "update_check"; "update_notify"; - "turncredentials"; + "turn_external"; "admin_shell"; - "isolate_host"; "snikket_client_id"; "snikket_ios_preserve_push"; "snikket_restricted_users"; "lastlog2"; + "admin_blocklist"; + "snikket_server_vcard"; -- Spam/abuse management "spam_reporting"; -- Allow users to report spam/abuse "watch_spam_reports"; -- Alert admins of spam/abuse reports by users + "server_contact_info"; -- Publish contact information for this service -- TODO... --"groups"; -- Shared roster support - --"server_contact_info"; -- Publish contact information for this service --"announce"; -- Send announcement to all online users --"motd"; -- Send a message to users when they log in - "welcome"; -- Welcome users who register accounts "http_files"; -- Serve static files from a directory over HTTP - "reload_modules"; -- Invites "invites"; @@ -137,23 +152,41 @@ modules_enabled = { "measure_active_users"; "measure_lua"; "measure_malloc"; + "portcheck"; } registration_watchers = {} -- Disable by default registration_notification = "New user registered: $username" -reload_global_modules = { "http" } +contact_info = { + abuse = ENV_SNIKKET_ABUSE_EMAIL and {"mailto:"..ENV_SNIKKET_ABUSE_EMAIL} or nil; + security = ENV_SNIKKET_SECURITY_EMAIL and {"mailto:"..ENV_SNIKKET_SECURITY_EMAIL} or nil; +} http_ports = { ENV_SNIKKET_TWEAK_INTERNAL_HTTP_PORT or 5280 } http_interfaces = { ENV_SNIKKET_TWEAK_INTERNAL_HTTP_INTERFACE or "127.0.0.1" } +http_max_content_size = 1024 * 1024 -- non-streaming uploads limited to 1MB (improves RAM usage) https_ports = {}; c2s_direct_tls_ports = { 5223 } +proxy65_ports = { ENV_SNIKKET_PROXY65_PORT or 5000 } + allow_registration = true registration_invite_only = true +password_policy = { + length = 10; +} + +-- In the future we want to switch to SASL2 for better security, +-- as client ids are not supported in SASL1 (identification is via +-- the resource string, which is semi-public and not authenticated) +-- This tweak is for developers to test with the future configuration, +-- or people who want to opt into the new security sooner. +enforce_client_ids = ENV_SNIKKET_TWEAK_REQUIRE_SASL2 == "1" + -- This disables in-app invites for non-admins -- TODO: The plan is to enable it once we can -- give the admin more fine-grained control @@ -163,24 +196,46 @@ allow_contact_invites = false -- Disallow restricted users to create invitations to the server deny_user_invites_by_roles = { "prosody:restricted" } +-- This role was renamed 'guest' in Prosody. +custom_roles = { { name = "prosody:restricted"; priority = 15 } } + invites_page = ENV_SNIKKET_INVITE_URL or ("https://"..DOMAIN.."/invite/{invite.token}/"); invites_page_external = true -invites_bootstrap_index = tonumber(ENV_TWEAK_SNIKKET_BOOTSTRAP_INDEX) +invites_bootstrap_index = Lua.tonumber(ENV_TWEAK_SNIKKET_BOOTSTRAP_INDEX) invites_bootstrap_secret = ENV_TWEAK_SNIKKET_BOOTSTRAP_SECRET +invites_bootstrap_ttl = Lua.tonumber(ENV_TWEAK_SNIKKET_BOOTSTRAP_TTL or (28 * 86400)) -- default 28 days + +-- The Resource Owner Credentials grant used internally between the web portal +-- and Prosody, so ensure this is enabled. Other unused flows can be disabled. +allowed_oauth2_grant_types = { "password" } +allowed_oauth2_response_types = {} + +-- Longer access token lifetime than the default +-- TODO: Use the already longer-lived refresh tokens +oauth2_access_token_ttl = 86400 c2s_require_encryption = true s2s_require_encryption = true s2s_secure_auth = true +-- Grant federation privileges to regular users but not restricted users. +-- This is enforced by mod_isolate_host. +add_permissions = { + ["prosody:registered"] = { + "xmpp:federate"; + }; +} + archive_expires_after = ("%dd"):format(RETENTION_DAYS) -- Remove archived messages after N days --- Disable IPv6 by default because Docker does not --- have it enabled by default, and s2s to domains --- with A+AAAA records breaks (as opposed to just AAAA) --- TODO: implement happy eyeballs in net.connect --- https://issues.prosody.im/1246 -use_ipv6 = (ENV_SNIKKET_TWEAK_IPV6 == "1") +-- Delay full account deletion via IBR for RETENTION_DAYS, to allow restoration +-- in case of accidental or malicious deletion of an account +registration_delete_grace_period = ("%d days"):format(RETENTION_DAYS) + +-- Allow disabling IPv6 because Docker does not have it enabled by default, but +-- we don't use Docker networking so it should not matter. +use_ipv6 = (ENV_SNIKKET_TWEAK_IPV6 ~= "0") log = { [ENV_SNIKKET_LOGLEVEL or "info"] = "*stdout" @@ -188,7 +243,18 @@ log = { authentication = "internal_hashed" authorization = "internal" -storage = "internal" +disable_sasl_mechanisms = { "PLAIN", "OAUTHBEARER" } + +if ENV_SNIKKET_TWEAK_STORAGE == "sqlite" then + storage = "sql" + sql = { + driver = "SQLite3"; + database = "/snikket/prosody/prosody.sqlite"; + } +else + storage = "internal" +end + statistics = "internal" if ENV_SNIKKET_TWEAK_PROMETHEUS == "1" then @@ -203,10 +269,24 @@ else statistics_interval = 60 end --- certificates = "certs" +if ENV_SNIKKET_TWEAK_DNSSEC == "1" then + local trustfile = "/usr/share/dns/root.ds"; -- Requires apt:dns-root-data + -- Bail out if it doesn't work + Lua.assert(Lua.require"lunbound".new{ resolvconf = true; trustfile = trustfile }:resolve ".".secure, + "Upstream DNS resolver is not DNSSEC-capable. Fix this or disable SNIKKET_TWEAK_DNSSEC"); + unbound = { trustfile = trustfile } + + -- Since we have DNSSEC, we can also do DANE + use_dane = true +end + +certificates = "certs" group_default_name = ENV_SNIKKET_SITE_NAME or DOMAIN +site_name = ENV_SNIKKET_SITE_NAME or DOMAIN +site_logo = "/usr/local/share/snikket/logo.png" + -- Update check configuration software_name = "Snikket" update_notify_version_url = "https://snikket.org/updates/{branch}/{version}" @@ -223,8 +303,10 @@ http_host = DOMAIN http_external_url = "https://"..DOMAIN.."/" if ENV_SNIKKET_TWEAK_TURNSERVER ~= "0" or ENV_SNIKKET_TWEAK_TURNSERVER_DOMAIN then - turncredentials_host = ENV_SNIKKET_TWEAK_TURNSERVER_DOMAIN or DOMAIN - turncredentials_secret = ENV_SNIKKET_TWEAK_TURNSERVER_SECRET or assert(io.open("/snikket/prosody/turn-auth-secret-v2")):read("*l"); + turn_external_host = ENV_SNIKKET_TWEAK_TURNSERVER_DOMAIN or DOMAIN + turn_external_port = ENV_SNIKKET_TWEAK_TURNSERVER_PORT + turn_external_secret = ENV_SNIKKET_TWEAK_TURNSERVER_SECRET or Lua.assert(Lua.io.open("/snikket/prosody/turn-auth-secret-v2")):read("*l"); + turn_external_tcp = true end -- Allow restricted users access to push notification servers @@ -239,6 +321,9 @@ VirtualHost (DOMAIN) key = KEY_PATH; }; + modules_enabled = {} + firewall_scripts = {} + http_files_dir = "/var/www" http_paths = { files = "/"; @@ -248,29 +333,57 @@ VirtualHost (DOMAIN) } if ENV_SNIKKET_TWEAK_PROMETHEUS == "1" then - modules_enabled = { + modules_enabled: append { "http_openmetrics"; } end - welcome_message = [[Hi, welcome to Snikket on $host! Thanks for joining us.]] - .."\n\n" - ..[[For help and enquiries related to this service you may contact the admin via email: ]] - ..ENV_SNIKKET_ADMIN_EMAIL - .."\n\n" - ..[[Happy chatting!]] + if ENV_SNIKKET_TWEAK_S2S_STATUS == "1" then + modules_enabled: append { + "s2s_status"; + } + end + + if ENV_SNIKKET_TWEAK_PUSH2 == "1" then + modules_enabled: append { + "push2"; + } + end + + if ENV_SNIKKET_TWEAK_RESTRICTED_USERS_V2 == "1" then + firewall_scripts: append { + "/etc/prosody/firewall/restricted_users.pfw"; + } + else + modules_enabled: append { + "isolate_host"; + } + end + Component ("groups."..DOMAIN) "muc" modules_enabled = { "muc_mam"; + "muc_moderation"; "muc_local_only"; "vcard_muc"; "muc_defaults"; "muc_offline_delivery"; "snikket_restricted_users"; + "snikket_deprecate_general_muc"; "muc_auto_reserve_nicks"; } + + if ENV_SNIKKET_TWEAK_S2S_STATUS == "1" then + modules_enabled: append { + "s2s_status"; + } + end + restrict_room_creation = "local" + + -- Some older deployments may have the general@ MUC, so we still need + -- to protect it: muc_local_only = { "general@groups."..DOMAIN } -- Default configuration for rooms (typically overwritten by the client) @@ -285,22 +398,6 @@ Component ("groups."..DOMAIN) "muc" -- to detect whether push notifications are enabled) muc_registration_include_form = true - default_mucs = { - { - jid_node = "general"; - config = { - name = "General Chat"; - description = "Welcome to "..DOMAIN.." general chat!"; - change_subject = false; - history_length = 30; - members_only = false; - moderated = false; - persistent = true; - public = true; - public_jids = true; - }; - } - } Component ("share."..DOMAIN) "http_file_share" -- For backwards compat, allow HTTP upload on the base domain @@ -313,7 +410,7 @@ Component ("share."..DOMAIN) "http_file_share" -- 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_expires_after = 60 * 60 * 24 * RETENTION_DAYS -- N days if UPLOAD_STORAGE_GB then http_file_share_global_quota = 1024 * 1024 * 1024 * UPLOAD_STORAGE_GB @@ -322,4 +419,8 @@ Component ("share."..DOMAIN) "http_file_share" file_share = "/upload" } + modules_disabled = { + "s2s"; + } + Include (ENV_SNIKKET_TWEAK_EXTRA_CONFIG or "/snikket/prosody/*.cfg.lua") -- 2.49.0