Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package prosody for openSUSE:Factory checked 
in at 2026-09-28 10:40:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/prosody (Old)
 and      /work/SRC/openSUSE:Factory/.prosody.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "prosody"

Mon Sep 28 10:40:10 2026 rev:45 rq:1380331 version:13.0.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/prosody/prosody.changes  2026-06-03 
20:28:29.872330629 +0200
+++ /work/SRC/openSUSE:Factory/.prosody.new.383539/prosody.changes      
2026-09-28 10:40:38.590349160 +0200
@@ -1,0 +2,20 @@
+Fri Sep 25 05:54:36 UTC 2026 - Michael Vetter <[email protected]>
+
+- Update to 13.0.7:
+  * rostermanager, mod_roster: Include ‘approved’ attribute in roster items
+  * util.startup: Always apply umask
+  * Update TLS profile data from Mozilla/TLSRef
+  * net.server_epoll: Disable read timeouts on server sockets
+  * net.unbound: Reset and apply new config on reload
+  * net.unbound: Simplify by removing cancel()
+  * util.poll: Reject file descriptors outside of FD_SETSIZE in all methods
+  * net.websocket: Release connection and input state on disconnect
+  * net.server_select: Release queued strings on forced close
+  * net.unbound: Let in-flight queries complete after re-initialization
+  * net.server_epoll: Release pending write buffers on destruction
+  * net.server_event: Release retained state on destruction
+  * net.server_event: Fix incorrect flag logic for watchfd handles
+  * prosodyctl check: Validate tls_profile and tls_profile_version
+  * See https://blog.prosody.im/prosody-13.0.7-released
+
+-------------------------------------------------------------------

Old:
----
  prosody-13.0.6.tar.gz
  prosody-13.0.6.tar.gz.asc

New:
----
  prosody-13.0.7.tar.gz
  prosody-13.0.7.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ prosody.spec ++++++
--- /var/tmp/diff_new_pack.aZ6X0h/_old  2026-09-28 10:40:39.753397930 +0200
+++ /var/tmp/diff_new_pack.aZ6X0h/_new  2026-09-28 10:40:39.754397972 +0200
@@ -18,7 +18,7 @@
 
 %define _piddir /run
 Name:           prosody
-Version:        13.0.6
+Version:        13.0.7
 Release:        0
 Summary:        Communications server for Jabber/XMPP
 License:        MIT

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.aZ6X0h/_old  2026-09-28 10:40:39.841401620 +0200
+++ /var/tmp/diff_new_pack.aZ6X0h/_new  2026-09-28 10:40:39.851402040 +0200
@@ -1,6 +1,6 @@
-mtime: 1780466263
-commit: 96f6b9288d6a2f05d732feffc5e482b5a105dd1b0fc8d7ebfafa5b60f9420f9a
+mtime: 1790315810
+commit: 93a19189edd04f65298e2d7b74e7d7ec56b50a4e7104a02c40935d3f28511683
 url: https://src.opensuse.org/lua/prosody
-revision: 96f6b9288d6a2f05d732feffc5e482b5a105dd1b0fc8d7ebfafa5b60f9420f9a
+revision: 93a19189edd04f65298e2d7b74e7d7ec56b50a4e7104a02c40935d3f28511683
 projectscmsync: https://src.opensuse.org/lua/_ObsPrj.git
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-09-25 07:56:50.000000000 +0200
@@ -0,0 +1 @@
+.osc

++++++ prosody-13.0.6.tar.gz -> prosody-13.0.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/.hg_archival.txt 
new/prosody-13.0.7/.hg_archival.txt
--- old/prosody-13.0.6/.hg_archival.txt 2026-05-27 15:57:49.731381928 +0200
+++ new/prosody-13.0.7/.hg_archival.txt 2026-09-23 18:44:22.389430863 +0200
@@ -1,4 +1,4 @@
 repo: 3e3171b59028ee70122cfec6ecf98f518f946b59
-node: 8eac8de97bca1ed5debe7a1366ab4414e4ea4dfe
+node: dab08c582cf273dfdc72a524f621ccbb496a34d9
 branch: 13.0
-tag: 13.0.6
+tag: 13.0.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/core/certmanager.lua 
new/prosody-13.0.7/core/certmanager.lua
--- old/prosody-13.0.6/core/certmanager.lua     2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/core/certmanager.lua     2026-09-23 18:44:22.389430863 
+0200
@@ -12,6 +12,8 @@
 local tls = require "prosody.net.tls_luasec";
 local stat = require "lfs".attributes;
 
+local tlsref = require "prosody.util.tlsref";
+
 local x509 = require "prosody.util.x509";
 local lfs = require "lfs";
 
@@ -216,84 +218,6 @@
        dane = tls.features.capabilities.dane and configmanager.get("*", 
"use_dane") and { "no_ee_namechecks" };
 }
 
--- https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.1
-local ffdhe2048 = [[
------BEGIN DH PARAMETERS-----
-MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
-+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
-87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
-YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
-7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
-ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
------END DH PARAMETERS-----
-]]
-
-local mozilla_ssl_configs = {
-       -- https://wiki.mozilla.org/Security/Server_Side_TLS
-       -- Version 5.7 as of 2023-07-09
-       modern = {
-               protocol = "tlsv1_3";
-               options = { cipher_server_preference = false };
-               ciphers = "DEFAULT"; -- TLS 1.3 uses 'ciphersuites' rather than 
these
-               curveslist = { "X25519"; "prime256v1"; "secp384r1" };
-               ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
-       };
-       intermediate = {
-               protocol = "tlsv1_2+";
-               dhparam = ffdhe2048;
-               options = { cipher_server_preference = false };
-               ciphers = {
-                       "ECDHE-ECDSA-AES128-GCM-SHA256";
-                       "ECDHE-RSA-AES128-GCM-SHA256";
-                       "ECDHE-ECDSA-AES256-GCM-SHA384";
-                       "ECDHE-RSA-AES256-GCM-SHA384";
-                       "ECDHE-ECDSA-CHACHA20-POLY1305";
-                       "ECDHE-RSA-CHACHA20-POLY1305";
-                       "DHE-RSA-AES128-GCM-SHA256";
-                       "DHE-RSA-AES256-GCM-SHA384";
-                       "DHE-RSA-CHACHA20-POLY1305";
-               };
-               curveslist = { "X25519"; "prime256v1"; "secp384r1" };
-               ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
-       };
-       old = {
-               protocol = "tlsv1+";
-               dhparam = nil; -- openssl dhparam 1024
-               options = { cipher_server_preference = true };
-               ciphers = {
-                       "ECDHE-ECDSA-AES128-GCM-SHA256";
-                       "ECDHE-RSA-AES128-GCM-SHA256";
-                       "ECDHE-ECDSA-AES256-GCM-SHA384";
-                       "ECDHE-RSA-AES256-GCM-SHA384";
-                       "ECDHE-ECDSA-CHACHA20-POLY1305";
-                       "ECDHE-RSA-CHACHA20-POLY1305";
-                       "DHE-RSA-AES128-GCM-SHA256";
-                       "DHE-RSA-AES256-GCM-SHA384";
-                       "DHE-RSA-CHACHA20-POLY1305";
-                       "ECDHE-ECDSA-AES128-SHA256";
-                       "ECDHE-RSA-AES128-SHA256";
-                       "ECDHE-ECDSA-AES128-SHA";
-                       "ECDHE-RSA-AES128-SHA";
-                       "ECDHE-ECDSA-AES256-SHA384";
-                       "ECDHE-RSA-AES256-SHA384";
-                       "ECDHE-ECDSA-AES256-SHA";
-                       "ECDHE-RSA-AES256-SHA";
-                       "DHE-RSA-AES128-SHA256";
-                       "DHE-RSA-AES256-SHA256";
-                       "AES128-GCM-SHA256";
-                       "AES256-GCM-SHA384";
-                       "AES128-SHA256";
-                       "AES256-SHA256";
-                       "AES128-SHA";
-                       "AES256-SHA";
-                       "DES-CBC3-SHA";
-               };
-               curveslist = { "X25519"; "prime256v1"; "secp384r1" };
-               ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
-       };
-};
-
-
 if tls.features.curves then
        for i = #core_defaults.curveslist, 1, -1 do
                if not tls.features.curves[ core_defaults.curveslist[i] ] then
@@ -321,12 +245,33 @@
                -- We can't read the password interactively when daemonized
                password = function() log("error", "Encrypted certificate for 
%s requires 'ssl' 'password' to be set in config", host); end;
        });
-       local profile = configmanager.get("*", "tls_profile") or "intermediate";
-       if mozilla_ssl_configs[profile] then
-               cfg:apply(mozilla_ssl_configs[profile]);
-       elseif profile ~= "legacy" then
-               log("error", "Invalid value for 'tls_profile': expected one of 
\"modern\", \"intermediate\" (default), \"old\" or \"legacy\" but got %q", 
profile);
-               return nil, "Invalid configuration, 'tls_profile' had an 
unknown value.";
+       local profile_version = configmanager.get("*", "tls_profile_version");
+       local profile_name = configmanager.get("*", "tls_profile");
+
+       if profile_name ~= "legacy" then
+               local tls_profile, tls_profile_err = 
tlsref.get_profile(profile_version, profile_name);
+               if not tls_profile then
+                       if tls_profile_err == "unknown-version" then
+                               log(
+                                       "error",
+                                       "Invalid value %q for 
'tls_profile_version': expected one of: \"%s\" or \"latest\"",
+                                       profile_version,
+                                       tlsref.get_valid_versions():concat("\", 
\"")
+                               );
+                               return nil, "Invalid configuration, 
'tls_profile_version' had an unknown value.";
+                       elseif tls_profile_err == "unknown-profile" then
+                               log(
+                                       "error",
+                                       "Invalid value %q for 'tls_profile': 
expected one of \"%s\" or \"legacy\" (default: %q)",
+                                       profile_name,
+                                       
tlsref.get_valid_profile_names(profile_version):concat("\", \""),
+                                       
tlsref.get_default_profile_name(profile_version)
+                               );
+                               return nil, "Invalid configuration, 
'tls_profile' had an unknown value.";
+                       end
+               else
+                       cfg:apply(tls_profile);
+               end
        end
        cfg:apply(global_ssl_config);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/core/features.lua 
new/prosody-13.0.7/core/features.lua
--- old/prosody-13.0.6/core/features.lua        2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/core/features.lua        2026-09-23 18:44:22.389430863 
+0200
@@ -37,5 +37,8 @@
 
                -- SIGUSR1 and 2 events
                "signal-events";
+
+               -- util.human.io.simple_version_compare
+               "simple-version-compare";
        };
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/core/rostermanager.lua 
new/prosody-13.0.7/core/rostermanager.lua
--- old/prosody-13.0.6/core/rostermanager.lua   2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/core/rostermanager.lua   2026-09-23 18:44:22.389430863 
+0200
@@ -67,7 +67,13 @@
                local stanza = st.iq({type="set", id=new_id()});
                stanza:tag("query", {xmlns = "jabber:iq:roster", ver = 
tostring(roster[false].version or "1")  });
                if item then
-                       stanza:tag("item", {jid = jid, subscription = 
item.subscription, name = item.name, ask = item.ask});
+                       stanza:tag("item", {
+                               jid = jid;
+                               subscription = item.subscription;
+                               name = item.name;
+                               ask = item.ask;
+                               approved = item.approved;
+                       });
                        for group in pairs(item.groups) do
                                stanza:tag("group"):text(group):up();
                        end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/net/server_epoll.lua 
new/prosody-13.0.7/net/server_epoll.lua
--- old/prosody-13.0.6/net/server_epoll.lua     2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/net/server_epoll.lua     2026-09-23 18:44:22.389430863 
+0200
@@ -541,6 +541,10 @@
        self:onconnect();
        if not self.conn then return nil, "no-conn"; end -- could have been 
closed in onconnect
        self:on("predrain");
+       if not self.conn then -- The predrain handler may have destroyed the 
connection.
+               self._writing = nil;
+               return nil, "no-conn";
+       end
        local buffer = self.writebuffer or "";
        -- Naming things ... s/data/slice/ ?
        local data = buffer:sub(1, cfg.max_send_chunk);
@@ -593,6 +597,7 @@
 
 -- Add data to write buffer and set flag for wanting to write
 function interface:write(data)
+       if not self.conn then return nil, "closed"; end
        local buffer = self.writebuffer;
        -- (nil)    -> save string
        -- (string) -> convert to buffer (3 tables!)
@@ -709,6 +714,7 @@
        self.on = noop;
        self.conn:close();
        self.conn = nil;
+       self.writebuffer = nil;
 end
 
 function interface:ssl()
@@ -1024,6 +1030,7 @@
                listeners = listeners;
                read_size = config and config.read_size;
                onreadable = interface.onacceptable;
+               setreadtimeout = noop;
                tls_ctx = config and config.tls_ctx;
                tls_direct = config and config.tls_direct;
                hosts = config and config.sni_hosts;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/net/server_event.lua 
new/prosody-13.0.7/net/server_event.lua
--- old/prosody-13.0.6/net/server_event.lua     2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/net/server_event.lua     2026-09-23 18:44:22.389430863 
+0200
@@ -229,6 +229,8 @@
        return true
 end
 function interface_mt:_destroy()  -- close this interface + events and call 
last listener
+       if self._destroyed then return true; end
+       self._destroyed = true;
        debug( "closing client with id:", self.id, self.fatalerror )
        self:_lock( true, true, true )  -- first of all, lock the interface to 
avoid further actions
        local _
@@ -248,11 +250,16 @@
                self.eventread, self.eventwrite = nil, nil
                self.eventstarthandshake, self.eventhandshake, self.eventclose 
= nil, nil, nil
                self.readcallback, self.writecallback = nil, nil
+               self.eventconnect, self.eventsession = nil, nil
+               self.eventwritetimeout, self.eventreadtimeout = nil, nil
+               self.startsslcallback = nil
        else
                self.conn:close( )
                self.eventread, self.eventclose = nil, nil
                self.interface, self.readcallback = nil, nil
        end
+       self.conn = nil
+       self.writebuffer, self.writebufferlen = nil, 0
        interfacelist[ self ] = nil
        return true
 end
@@ -583,6 +590,7 @@
                                end
                        end
                        interface:onpredrain();
+                       if interface._destroyed then return -1; end
                        interface.writebuffer = { 
t_concat(interface.writebuffer) }
                        local succ, err, byte = interface.conn:send( 
interface.writebuffer[1], 1, interface.writebufferlen )
                        --vdebug( "write data:", interface.writebuffer, 
"error:", err, "part:", byte )
@@ -590,6 +598,7 @@
                                interface.writebuffer[1] = nil
                                interface.writebufferlen = 0
                                interface:ondrain();
+                               if interface._destroyed then return -1; end
                                if interface.fatalerror then
                                        debug "closing client after writing"
                                        interface:_close()  -- close interface 
if needed
@@ -654,6 +663,7 @@
                                interface.eventreadtimeout = nil
                        end
                end
+               if interface._destroyed then return -1; end
                local buffer, err, part = interface.conn:receive( 
interface._pattern )  -- receive buffer with "pattern"
                --vdebug( "read data:", tostring(buffer), "error:", 
tostring(err), "part:", tostring(part) )
                buffer = buffer or part
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/net/server_select.lua 
new/prosody-13.0.7/net/server_select.lua
--- old/prosody-13.0.6/net/server_select.lua    2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/net/server_select.lua    2026-09-23 18:44:22.389430863 
+0200
@@ -392,8 +392,12 @@
        handler.force_close = function ( self, err )
                if bufferqueuelen ~= 0 then
                        out_put("server.lua: discarding unwritten data for ", 
tostring(ip), ":", tostring(clientport))
+                       for i = 1, bufferqueuelen do
+                               bufferqueue[i] = nil;
+                       end
                        bufferqueuelen = 0;
                end
+               bufferlen = 0;
                return self:close(err);
        end
        handler.close = function( self, err )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/net/unbound.lua 
new/prosody-13.0.7/net/unbound.lua
--- old/prosody-13.0.6/net/unbound.lua  2026-05-27 15:57:49.731381928 +0200
+++ new/prosody-13.0.7/net/unbound.lua  2026-09-23 18:44:22.389430863 +0200
@@ -19,6 +19,7 @@
 local libunbound = require"lunbound";
 local promise = require"prosody.util.promise";
 local new_id = require "prosody.util.id".short;
+local timer = require "prosody.util.timer";
 
 local dns_utils = require"prosody.util.dns";
 local classes, types, errors = dns_utils.classes, dns_utils.types, 
dns_utils.errors;
@@ -42,13 +43,6 @@
 end
 
 local unbound_config;
-if prosody then
-       local config = require"prosody.core.configmanager";
-       unbound_config = add_defaults(config.get("*", "unbound"));
-       prosody.events.add_handler("config-reloaded", function()
-               unbound_config = add_defaults(config.get("*", "unbound"));
-       end);
-end
 -- Note: libunbound will default to using root hints if resolvconf is unset
 
 local function connect_server(unbound, server)
@@ -65,9 +59,6 @@
        unbound = libunbound.new(unbound_config);
        server_conn = connect_server(unbound, net_server);
 end
-if prosody then
-       prosody.events.add_handler("server-started", initialize);
-end
 
 local answer_mt = {
        __tostring = function(self)
@@ -92,8 +83,6 @@
        end;
 };
 
-local waiting_queries = {};
-
 local function prep_answer(a)
        if not a then return end
        local status = errors[a.rcode];
@@ -126,11 +115,9 @@
        local ntype, nclass = types[qtype], classes[qclass];
 
        local m;
-       local ret;
        local log_query = logger.init("unbound.query"..new_id());
        local function callback_wrapper(a, err)
                m();
-               waiting_queries[ret] = nil;
                if a then
                        prep_answer(a);
                        log_query("debug", "Results for %s %s %s: %s (%s)", 
qname, qclass, qtype, a.rcode == 0 and (#a .. " items") or a.status,
@@ -143,11 +130,8 @@
        end
        log_query("debug", "Resolve %s %s %s", qname, qclass, qtype);
        m = measure(qclass, qtype);
-       local err;
-       ret, err = unbound:resolve_async(callback_wrapper, qname, ntype, 
nclass);
-       if ret then
-               waiting_queries[ret] = callback;
-       else
+       local ret, err = unbound:resolve_async(callback_wrapper, qname, ntype, 
nclass);
+       if not ret then
                log_query("error", "Resolver error: %s", err);
        end
        return ret, err;
@@ -163,35 +147,42 @@
        return prep_answer(a);
 end
 
-local function cancel(id)
-       local cb = waiting_queries[id];
-       unbound:cancel(id);
-       if cb then
-               cb(nil, "canceled");
-               waiting_queries[id] = nil;
-       end
-       return true;
-end
-
 -- Reinitiate libunbound context, drops cache
 local function purge()
-       for id in pairs(waiting_queries) do cancel(id); end
-       if server_conn then server_conn:close(); end
+       if server_conn then
+               local old_unbound, old_server_conn = unbound, server_conn;
+               timer.add_task(30, function()
+                       old_server_conn:close();
+                       if old_unbound.cancelall then
+                               old_unbound:cancelall();
+                       end
+               end)
+       end
        initialize();
        return true;
 end
 
+if prosody then
+       local config = require"prosody.core.configmanager";
+       unbound_config = add_defaults(config.get("*", "unbound"));
+       prosody.events.add_handler("config-reloaded", function()
+               unbound_config = add_defaults(config.get("*", "unbound"));
+               purge();
+       end);
+       prosody.events.add_handler("server-started", initialize);
+end
+
 local function not_implemented()
        error "not implemented";
 end
 -- Public API
 local _M = {
        lookup = lookup;
-       cancel = cancel;
+       cancel = not_implemented;
        new_async_socket = not_implemented;
        dns = {
                lookup = lookup_sync;
-               cancel = cancel;
+               cancel = not_implemented;
                cache = noop;
                socket_wrapper_set = noop;
                settimeout = noop;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/net/websocket.lua 
new/prosody-13.0.7/net/websocket.lua
--- old/prosody-13.0.6/net/websocket.lua        2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/net/websocket.lua        2026-09-23 18:44:22.389430863 
+0200
@@ -30,6 +30,8 @@
                s.close_timer = nil;
        end
        s.readyState = 3;
+       s.conn = nil;
+       s.readbuffer, s.databuffer = "", nil;
        if s.close_code == nil and s.onerror then s:onerror(err); end
        if s.onclose then s:onclose(s.close_code, s.close_message or err); end
 end
@@ -40,8 +42,9 @@
 
 local function fail(s, code, reason)
        log("warn", "WebSocket connection failed, closing. %d %s", code, 
reason);
+       local conn = s.conn;
        s:close(code, reason);
-       s.conn:close();
+       conn:close();
        return false
 end
 
@@ -136,6 +139,7 @@
                self.readyState = 2;
                local conn = self.conn;
                conn:write(frames.build_close(code, reason, true));
+               if self.readyState == 3 then return; end
                -- Do not close socket straight away, wait for acknowledgement 
from server.
                self.close_timer = timer.add_task(close_timeout, 
close_timeout_cb, self);
        elseif self.readyState == 2 then
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/plugins/mod_roster.lua 
new/prosody-13.0.7/plugins/mod_roster.lua
--- old/prosody-13.0.6/plugins/mod_roster.lua   2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/plugins/mod_roster.lua   2026-09-23 18:44:22.389430863 
+0200
@@ -48,6 +48,7 @@
                                        roster:tag("item", {
                                                jid = jid,
                                                subscription = 
item.subscription,
+                                               approved = item.approved,
                                                ask = item.ask,
                                                name = item.name,
                                        });
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/prosody.release 
new/prosody-13.0.7/prosody.release
--- old/prosody-13.0.6/prosody.release  2026-05-27 15:57:49.731381928 +0200
+++ new/prosody-13.0.7/prosody.release  2026-09-23 18:44:22.389430863 +0200
@@ -1 +1 @@
-13.0.6
+13.0.7
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/spec/util_human_io_spec.lua 
new/prosody-13.0.7/spec/util_human_io_spec.lua
--- old/prosody-13.0.6/spec/util_human_io_spec.lua      2026-05-27 
15:57:49.731381928 +0200
+++ new/prosody-13.0.7/spec/util_human_io_spec.lua      2026-09-23 
18:44:22.389430863 +0200
@@ -100,6 +100,79 @@
                        return assert.is_nil(human_io.parse_duration_lax("two 
weeks"), "\"2 weeks\" -> nil");
                end);
        end);
+
+       describe("simple_version_compare", function ()
+               local version_compare = human_io.simple_version_compare;
+
+               local function cmp_version(a, b, exp)
+                       assert.equal(exp, version_compare(a, b), ("%q < 
%q"):format(a, b));
+               end
+
+               it("orders versions with differing major numbers", function ()
+                       cmp_version("1.0", "2.0", true);
+                       cmp_version("2.0", "1.0", false);
+               end);
+
+               it("orders versions with differing minor numbers", function ()
+                       cmp_version("1.0", "1.1", true);
+                       cmp_version("1.1", "1.0", false);
+               end);
+
+               it("treats a shorter version as less than a longer one sharing 
the same prefix", function ()
+                       cmp_version("1.0", "1.0.1", true);
+                       cmp_version("1.0.1", "1.0", false);
+
+                       cmp_version("1", "1.0", true);
+                       cmp_version("1", "1.1", true);
+
+                       cmp_version("1.0.0", "1.0.0.1", true);
+               end);
+
+               it("compares components left-to-right regardless of how many 
components there are", function ()
+                       cmp_version("1.0.1", "1.1", true);
+                       cmp_version("1.1", "1.0.1", false);
+
+                       cmp_version("1.0.1", "1.1.0", true);
+                       cmp_version("1.1.0", "1.0.1", false);
+
+                       cmp_version("1.0.0.1", "1.0.1", true);
+               end);
+
+               it("never considers a version less than itself", function ()
+                       cmp_version("0", "0", false);
+                       cmp_version("1.0", "1.0", false);
+                       cmp_version("1.2.3", "1.2.3", false);
+                       cmp_version("foo", "foo", false);
+               end);
+
+               it("compares components numerically", function ()
+                       cmp_version("1.9", "1.10", true);
+                       cmp_version("1.10", "1.9", false);
+
+                       cmp_version("1.9.9", "1.10.0", true);
+
+                       cmp_version("2.0", "10.0", true);
+                       cmp_version("10.0", "2.0", false);
+
+                       cmp_version("1.2", "1.10", true);
+
+                       cmp_version("1.99", "1.100", true);
+                       cmp_version("1.100", "1.99", false);
+               end);
+
+               it("handles leading zeros in numeric components", function ()
+                       cmp_version("1.02", "1.10", true);
+                       cmp_version("1.10", "1.02", false);
+               end);
+
+               it("treats an empty or non-numeric string as a version with no 
components", function ()
+                       cmp_version("", "1.0", true);
+                       cmp_version("1.0", "", false);
+                       cmp_version("foo", "1.0", true);
+                       cmp_version("1.0", "foo", false);
+                       cmp_version("", "", false);
+               end);
+       end);
 end);
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/spec/util_tlsref_spec.lua 
new/prosody-13.0.7/spec/util_tlsref_spec.lua
--- old/prosody-13.0.6/spec/util_tlsref_spec.lua        1970-01-01 
01:00:00.000000000 +0100
+++ new/prosody-13.0.7/spec/util_tlsref_spec.lua        2026-09-23 
18:44:22.389430863 +0200
@@ -0,0 +1,168 @@
+local tlsref = require "prosody.util.tlsref";
+
+describe("util.tlsref", function()
+       local version_compare = require 
"prosody.util.human.io".simple_version_compare;
+
+       describe("default version", function()
+               it("is not greater than latest version", function ()
+                       local default_version = tlsref.get_default_version();
+                       local latest_version = tlsref.get_latest_version();
+                       assert.equal(false, version_compare(latest_version, 
default_version));
+               end);
+
+               it("is a known version", function ()
+                       
assert.is_table(tlsref.get_profile(tlsref.get_default_version()));
+               end);
+       end);
+
+       describe("latest version", function ()
+               it("is a known version", function ()
+                       assert.is_table(tlsref.get_profile("latest"));
+               end);
+
+               it("is the first entry of get_valid_versions()", function ()
+                       local versions = tlsref.get_valid_versions();
+                       assert.equal(tlsref.get_latest_version(), versions[1]);
+               end);
+       end);
+
+       describe("get_valid_versions()", function ()
+               it("returns versions in descending order", function ()
+                       local versions = tlsref.get_valid_versions();
+                       assert.is_true(#versions >= 1);
+                       for i = 1, #versions-1 do
+                               -- versions[i] must sort before versions[i+1]
+                               assert.equal(false, 
version_compare(versions[i], versions[i+1]));
+                       end
+               end);
+
+               it("contains the default version", function ()
+                       local found = false;
+                       for _, v in ipairs(tlsref.get_valid_versions()) do
+                               if v == tlsref.get_default_version() then found 
= true; end
+                       end
+                       assert.is_true(found);
+               end);
+       end);
+
+       describe("get_valid_profile_names()", function ()
+               it("returns an error for unknown versions", function ()
+                       local names, err = 
tlsref.get_valid_profile_names("0.0");
+                       assert.is_nil(names);
+                       assert.equal("unknown-version", err);
+               end);
+
+               it("uses the default version when none is given", function ()
+                       assert.same(
+                               
tlsref.get_valid_profile_names(tlsref.get_default_version()),
+                               tlsref.get_valid_profile_names()
+                       );
+               end);
+
+               it("accepts 'latest' as a version", function ()
+                       assert.same(
+                               
tlsref.get_valid_profile_names(tlsref.get_latest_version()),
+                               tlsref.get_valid_profile_names("latest")
+                       );
+               end);
+
+               it("lists the most-preferred profile first", function ()
+                       for _, version in ipairs(tlsref.get_valid_versions()) do
+                               local names = 
tlsref.get_valid_profile_names(version);
+                               assert.equal("modern", names[1],
+                                       ("most-preferred profile should be 
first for version %s"):format(version));
+                       end
+               end);
+       end);
+
+       describe("get_profile()", function ()
+               it("returns the default profile of the default version when 
called with no arguments", function ()
+                       assert.equal(
+                               
tlsref.get_profile(tlsref.get_default_version(), 
tlsref.get_default_profile_name()),
+                               tlsref.get_profile()
+                       );
+               end);
+
+               it("resolves 'latest' to the latest version", function ()
+                       assert.equal(
+                               tlsref.get_profile(tlsref.get_latest_version()),
+                               tlsref.get_profile("latest")
+                       );
+               end);
+
+               it("returns an error for unknown versions", function ()
+                       local profile, err = tlsref.get_profile("0.0");
+                       assert.is_nil(profile);
+                       assert.equal("unknown-version", err);
+               end);
+
+               it("returns an error for unknown profile names", function ()
+                       local profile, err = tlsref.get_profile(nil, 
"no-such-profile");
+                       assert.is_nil(profile);
+                       assert.equal("unknown-profile", err);
+               end);
+
+               it("returns an error for profiles absent from a given version", 
function ()
+                       -- 'old' was dropped from the 6.0 guidelines
+                       local profile, err = tlsref.get_profile("6.0", "old");
+                       assert.is_nil(profile);
+                       assert.equal("unknown-profile", err);
+               end);
+
+               it("resolves every advertised version/profile combination", 
function ()
+                       for _, version in ipairs(tlsref.get_valid_versions()) do
+                               for _, name in 
ipairs(tlsref.get_valid_profile_names(version)) do
+                                       local profile, err = 
tlsref.get_profile(version, name);
+                                       assert.is_table(profile,
+                                               ("get_profile(%q, %q) failed: 
%s"):format(version, name, err));
+                               end
+                       end
+               end);
+       end);
+
+       describe("get_default_profile_name()", function ()
+               it("returns an error for unknown versions", function ()
+                       local name, err = 
tlsref.get_default_profile_name("0.0");
+                       assert.is_nil(name);
+                       assert.equal("unknown-version", err);
+               end);
+
+               it("accepts 'latest' as a version", function ()
+                       
assert.is_string(tlsref.get_default_profile_name("latest"));
+               end);
+
+               it("returns a profile name valid for every version", function ()
+                       for _, version in ipairs(tlsref.get_valid_versions()) do
+                               local name = 
tlsref.get_default_profile_name(version);
+                               assert.is_string(name);
+                               assert.is_table(tlsref.get_profile(version, 
name),
+                                       ("default profile %q missing from 
version %s"):format(name, version));
+                       end
+               end);
+       end);
+
+       describe("profile contents", function ()
+               it("every profile specifies a TLS protocol version", function ()
+                       for _, version in ipairs(tlsref.get_valid_versions()) do
+                               for _, name in 
ipairs(tlsref.get_valid_profile_names(version)) do
+                                       local profile = 
tlsref.get_profile(version, name);
+                                       assert.is_string(profile.protocol);
+                                       
assert.truthy(profile.protocol:match("^tlsv1"),
+                                               ("unexpected protocol %q in 
%s/%s"):format(profile.protocol, version, name));
+                               end
+                       end
+               end);
+
+               it("every profile specifies TLS 1.3 ciphersuites and curves", 
function ()
+                       for _, version in ipairs(tlsref.get_valid_versions()) do
+                               for _, name in 
ipairs(tlsref.get_valid_profile_names(version)) do
+                                       local profile = 
tlsref.get_profile(version, name);
+                                       assert.is_table(profile.ciphersuites);
+                                       assert.is_true(#profile.ciphersuites > 
0);
+                                       assert.is_table(profile.curveslist);
+                                       assert.is_true(#profile.curveslist > 0);
+                               end
+                       end
+               end);
+       end);
+end);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/util/human/io.lua 
new/prosody-13.0.7/util/human/io.lua
--- old/prosody-13.0.6/util/human/io.lua        2026-05-27 15:57:49.731381928 
+0200
+++ new/prosody-13.0.7/util/human/io.lua        2026-09-23 18:44:22.389430863 
+0200
@@ -222,6 +222,29 @@
        return tonumber(n) * ( multipliers_lax[m] or 1 );
 end
 
+-- Compares simple version strings (numeric only, not semver compatible)
+-- (can be passed to table.sort)
+local function simple_version_compare(a, b)
+       local a_f, a_s, a_part = a:gmatch("%d+");
+       local b_f, b_s, b_part = b:gmatch("%d+");
+
+       a_part = a_f(a_s, a_part);
+       b_part = b_f(b_s, b_part);
+
+       while a_part and b_part do
+               local an, bn = tonumber(a_part), tonumber(b_part);
+               if an ~= bn then
+                       return an < bn;
+               end
+               a_part = a_f(a_s, a_part);
+               b_part = b_f(b_s, b_part);
+       end
+
+       -- return true (a is lower) if b is exhausted
+       -- otherwise, they are equal or b is longer/greater (-> return false)
+       return b_part ~= nil;
+end
+
 return {
        getchar = getchar;
        getline = getline;
@@ -237,4 +260,5 @@
        table = new_table;
        parse_duration = parse_duration;
        parse_duration_lax = parse_duration_lax;
+       simple_version_compare = simple_version_compare;
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/util/prosodyctl/check.lua 
new/prosody-13.0.7/util/prosodyctl/check.lua
--- old/prosody-13.0.6/util/prosodyctl/check.lua        2026-05-27 
15:57:49.731381928 +0200
+++ new/prosody-13.0.7/util/prosodyctl/check.lua        2026-09-23 
18:44:22.389430863 +0200
@@ -464,6 +464,7 @@
                        "statistics_interval",
                        "tcp_keepalives",
                        "tls_profile",
+                       "tls_profile_version",
                        "trusted_proxies",
                        "umask",
                        "use_dane",
@@ -726,6 +727,26 @@
                end
 
                do
+                       local tlsref = require "prosody.util.tlsref";
+                       local tls_profile_name = configmanager.get("*", 
"tls_profile");
+                       local tls_profile_version = configmanager.get("*", 
"tls_profile_version");
+                       local profile, err = 
tlsref.get_profile(tls_profile_version, tls_profile_name);
+                       if not profile then
+                               print("");
+                               print("    TLS profile selection:");
+                               if err == "unknown-version" then
+                                       print(("        tls_profile_version is 
set to an unknown value (%q)"):format(tls_profile_version));
+                                       print(("        Valid values: 
\"%s\""):format(tlsref.get_valid_versions():concat("\", \"")));
+                               elseif err == "unknown-profile" then
+                                       print(("        tls_profile is set to 
an unknown value (%q)"):format(tls_profile_name));
+                                       print(("        Valid values: 
\"%s\""):format(tlsref.get_valid_profile_names():concat("\", \"")));
+                               else
+                                       print(("        Unknown error loading 
the configured profile: %s"):format(err));
+                               end
+                       end
+               end
+
+               do
                        local registration_enabled_hosts = {};
                        for host in enabled_hosts() do
                                local host_modules, component = 
modulemanager.get_modules_for_host(host);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/util/startup.lua 
new/prosody-13.0.7/util/startup.lua
--- old/prosody-13.0.6/util/startup.lua 2026-05-27 15:57:49.731381928 +0200
+++ new/prosody-13.0.7/util/startup.lua 2026-09-23 18:44:22.389430863 +0200
@@ -634,8 +634,6 @@
                        end
                end
 
-               -- Set our umask to protect data files
-               pposix.umask(config.get("*", "umask") or "027");
                pposix.setenv("HOME", prosody.paths.data);
                pposix.setenv("PROSODY_CONFIG", prosody.config_file);
        else
@@ -725,9 +723,9 @@
        end
 end
 
-function startup.posix_umask()
+function startup.set_umask()
        if prosody.platform ~= "posix" then return end
-       local pposix = require "prosody.util.pposix";
+       local pposix = check_posix();
        local umask = config.get("*", "umask") or "027";
        pposix.umask(umask);
 end
@@ -936,6 +934,7 @@
        startup.chdir();
        startup.read_version();
        startup.switch_user();
+       startup.set_umask();
        startup.check_dependencies();
        startup.log_startup_warnings();
        startup.check_unwriteable();
@@ -964,6 +963,7 @@
        startup.setup_plugin_install_path();
        startup.setup_datadir();
        startup.chdir();
+       startup.set_umask();
        startup.add_global_prosody_functions();
        startup.read_version();
        startup.log_greeting();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/util/tlsref.lua 
new/prosody-13.0.7/util/tlsref.lua
--- old/prosody-13.0.6/util/tlsref.lua  1970-01-01 01:00:00.000000000 +0100
+++ new/prosody-13.0.7/util/tlsref.lua  2026-09-23 18:44:22.389430863 +0200
@@ -0,0 +1,232 @@
+local array = require "prosody.util.array";
+local it = require "prosody.util.iterators";
+local version_compare = require "prosody.util.human.io".simple_version_compare;
+
+local latest_version = "6.0"
+local default_version = "5.7";
+local default_profile = "intermediate"; -- should exist in all profiles
+
+-- https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.1
+local ffdhe2048 = [[
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz
++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a
+87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7
+YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi
+7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD
+ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==
+-----END DH PARAMETERS-----
+]];
+
+local profiles = {
+       -- https://wiki.mozilla.org/Security/Server_Side_TLS
+       ["6.0"] = {
+               -- Version 6.0 as of 2026-04-08
+               modern = {
+                       protocol = "tlsv1_3";
+                       options = { cipher_server_preference = false };
+                       ciphers = "DEFAULT"; -- TLS 1.3 uses 'ciphersuites' 
rather than these
+                       curveslist = { "X25519MLKEM768"; "X25519"; 
"prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+               intermediate = {
+                       protocol = "tlsv1_2+";
+                       dhparam = ffdhe2048;
+                       options = { cipher_server_preference = false };
+                       ciphers = {
+                               "ECDHE-ECDSA-AES128-GCM-SHA256";
+                               "ECDHE-RSA-AES128-GCM-SHA256";
+                               "ECDHE-ECDSA-AES256-GCM-SHA384";
+                               "ECDHE-RSA-AES256-GCM-SHA384";
+                               "ECDHE-ECDSA-CHACHA20-POLY1305";
+                               "ECDHE-RSA-CHACHA20-POLY1305";
+                       };
+                       curveslist = { "X25519MLKEM768"; "X25519"; 
"prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+       };
+
+       ["5.8"] = {
+               -- Version 5.8 as of 2026-04-08
+               modern = {
+                       protocol = "tlsv1_3";
+                       options = { cipher_server_preference = false };
+                       ciphers = "DEFAULT"; -- TLS 1.3 uses 'ciphersuites' 
rather than these
+                       curveslist = { "X25519MLKEM768"; "X25519"; 
"prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+               intermediate = {
+                       protocol = "tlsv1_2+";
+                       dhparam = ffdhe2048;
+                       options = { cipher_server_preference = false };
+                       ciphers = {
+                               "ECDHE-ECDSA-AES128-GCM-SHA256";
+                               "ECDHE-RSA-AES128-GCM-SHA256";
+                               "ECDHE-ECDSA-AES256-GCM-SHA384";
+                               "ECDHE-RSA-AES256-GCM-SHA384";
+                               "ECDHE-ECDSA-CHACHA20-POLY1305";
+                               "ECDHE-RSA-CHACHA20-POLY1305";
+                       };
+                       curveslist = { "X25519MLKEM768"; "X25519"; 
"prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+               old = {
+                       protocol = "tlsv1+";
+                       dhparam = ffdhe2048;
+                       options = { cipher_server_preference = true };
+                       ciphers = {
+                               "ECDHE-ECDSA-AES128-GCM-SHA256";
+                               "ECDHE-RSA-AES128-GCM-SHA256";
+                               "ECDHE-ECDSA-AES256-GCM-SHA384";
+                               "ECDHE-RSA-AES256-GCM-SHA384";
+                               "ECDHE-ECDSA-CHACHA20-POLY1305";
+                               "ECDHE-RSA-CHACHA20-POLY1305";
+                               "ECDHE-ECDSA-AES128-SHA256";
+                               "ECDHE-RSA-AES128-SHA256";
+                               "ECDHE-ECDSA-AES128-SHA";
+                               "ECDHE-RSA-AES128-SHA";
+                               "ECDHE-ECDSA-AES256-SHA384";
+                               "ECDHE-RSA-AES256-SHA384";
+                               "ECDHE-ECDSA-AES256-SHA";
+                               "ECDHE-RSA-AES256-SHA";
+                               "AES128-GCM-SHA256";
+                               "AES256-GCM-SHA384";
+                               "AES128-SHA256";
+                               "AES256-SHA256";
+                               "AES128-SHA";
+                               "AES256-SHA";
+                               "DES-CBC3-SHA";
+                       };
+                       curveslist = { "X25519MLKEM768"; "X25519"; 
"prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+       };
+
+       ["5.7"] = {
+               -- Version 5.7 as of 2023-07-09
+               modern = {
+                       protocol = "tlsv1_3";
+                       options = { cipher_server_preference = false };
+                       ciphers = "DEFAULT"; -- TLS 1.3 uses 'ciphersuites' 
rather than these
+                       curveslist = { "X25519"; "prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+               intermediate = {
+                       protocol = "tlsv1_2+";
+                       dhparam = ffdhe2048;
+                       options = { cipher_server_preference = false };
+                       ciphers = {
+                               "ECDHE-ECDSA-AES128-GCM-SHA256";
+                               "ECDHE-RSA-AES128-GCM-SHA256";
+                               "ECDHE-ECDSA-AES256-GCM-SHA384";
+                               "ECDHE-RSA-AES256-GCM-SHA384";
+                               "ECDHE-ECDSA-CHACHA20-POLY1305";
+                               "ECDHE-RSA-CHACHA20-POLY1305";
+                               "DHE-RSA-AES128-GCM-SHA256";
+                               "DHE-RSA-AES256-GCM-SHA384";
+                               "DHE-RSA-CHACHA20-POLY1305";
+                       };
+                       curveslist = { "X25519"; "prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+               old = {
+                       protocol = "tlsv1+";
+                       dhparam = nil; -- openssl dhparam 1024
+                       options = { cipher_server_preference = true };
+                       ciphers = {
+                               "ECDHE-ECDSA-AES128-GCM-SHA256";
+                               "ECDHE-RSA-AES128-GCM-SHA256";
+                               "ECDHE-ECDSA-AES256-GCM-SHA384";
+                               "ECDHE-RSA-AES256-GCM-SHA384";
+                               "ECDHE-ECDSA-CHACHA20-POLY1305";
+                               "ECDHE-RSA-CHACHA20-POLY1305";
+                               "DHE-RSA-AES128-GCM-SHA256";
+                               "DHE-RSA-AES256-GCM-SHA384";
+                               "DHE-RSA-CHACHA20-POLY1305";
+                               "ECDHE-ECDSA-AES128-SHA256";
+                               "ECDHE-RSA-AES128-SHA256";
+                               "ECDHE-ECDSA-AES128-SHA";
+                               "ECDHE-RSA-AES128-SHA";
+                               "ECDHE-ECDSA-AES256-SHA384";
+                               "ECDHE-RSA-AES256-SHA384";
+                               "ECDHE-ECDSA-AES256-SHA";
+                               "ECDHE-RSA-AES256-SHA";
+                               "DHE-RSA-AES128-SHA256";
+                               "DHE-RSA-AES256-SHA256";
+                               "AES128-GCM-SHA256";
+                               "AES256-GCM-SHA384";
+                               "AES128-SHA256";
+                               "AES256-SHA256";
+                               "AES128-SHA";
+                               "AES256-SHA";
+                               "DES-CBC3-SHA";
+                       };
+                       curveslist = { "X25519"; "prime256v1"; "secp384r1" };
+                       ciphersuites = { "TLS_AES_128_GCM_SHA256"; 
"TLS_AES_256_GCM_SHA384"; "TLS_CHACHA20_POLY1305_SHA256" };
+               };
+       };
+};
+
+local function get_valid_versions()
+       return array.collect(it.keys(profiles)):sort(version_compare):reverse();
+end
+
+local pref_order = { modern = 100, intermediate = 50, old = 0 };
+
+local function sort_profile_by_pref(a, b)
+       local pref_a, pref_b = pref_order[a] or 0, pref_order[b] or 0;
+       return pref_a > pref_b; -- Best first
+end
+
+local function get_valid_profile_names(version)
+       if version == "latest" then
+               version = latest_version;
+       end
+       local version_profiles = profiles[version or default_version];
+       if not version_profiles then
+               return nil, "unknown-version";
+       end
+       return 
array.collect(it.keys(version_profiles)):sort(sort_profile_by_pref);
+end
+
+local function get_profile(version, profile_name)
+       if version == "latest" then
+               version = latest_version;
+       end
+       local version_profiles = profiles[version or default_version];
+       if not version_profiles then
+               return nil, "unknown-version";
+       end
+       local profile = version_profiles[profile_name or default_profile];
+       if not profile then
+               return nil, "unknown-profile";
+       end
+       return profile;
+end
+
+local function get_default_version()
+       return default_version;
+end
+
+local function get_latest_version()
+       return latest_version;
+end
+
+local function get_default_profile_name(version)
+       -- Default profile name is currently the same across all versions,
+       -- but can't guarantee this in the future - ensure valid version
+       if version ~= "latest" and not profiles[version or default_version] then
+               return nil, "unknown-version";
+       end
+       return default_profile;
+end
+
+return {
+       profiles = profiles;
+       get_default_version = get_default_version;
+       get_latest_version = get_latest_version;
+       get_default_profile_name = get_default_profile_name;
+       get_valid_versions = get_valid_versions;
+       get_valid_profile_names = get_valid_profile_names;
+       get_profile = get_profile;
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/prosody-13.0.6/util-src/poll.c 
new/prosody-13.0.7/util-src/poll.c
--- old/prosody-13.0.6/util-src/poll.c  2026-05-27 15:57:49.731381928 +0200
+++ new/prosody-13.0.7/util-src/poll.c  2026-09-23 18:44:22.389430863 +0200
@@ -234,6 +234,13 @@
 #endif
 #ifdef USE_SELECT
 
+       if(fd >= FD_SETSIZE) {
+               luaL_pushfail(L);
+               lua_pushstring(L, strerror(EBADF));
+               lua_pushinteger(L, EBADF);
+               return 3;
+       }
+
        if(!FD_ISSET(fd, &state->all)) {
                luaL_pushfail(L);
                lua_pushstring(L, strerror(ENOENT));
@@ -327,6 +334,13 @@
 #endif
 #ifdef USE_SELECT
 
+       if(fd >= FD_SETSIZE) {
+               luaL_pushfail(L);
+               lua_pushstring(L, strerror(EBADF));
+               lua_pushinteger(L, EBADF);
+               return 3;
+       }
+
        if(!FD_ISSET(fd, &state->all)) {
                luaL_pushfail(L);
                lua_pushstring(L, strerror(ENOENT));

Reply via email to