Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package weechat for openSUSE:Factory checked 
in at 2026-06-01 18:08:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/weechat (Old)
 and      /work/SRC/openSUSE:Factory/.weechat.new.1937 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "weechat"

Mon Jun  1 18:08:28 2026 rev:93 rq:1356360 version:4.9.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/weechat/weechat.changes  2026-03-30 
18:37:10.821810607 +0200
+++ /work/SRC/openSUSE:Factory/.weechat.new.1937/weechat.changes        
2026-06-01 18:09:14.935351525 +0200
@@ -1,0 +2,12 @@
+Mon Jun  1 13:01:54 UTC 2026 - Hunter Wardlaw <[email protected]>
+
+-  Update to 4.9.1:
+  * core: fix option weechat.look.color_real_white not applied when 
+    color is "white" on 16+ colors terminals (#1742)
+  * irc: fix tag in message with list of names when joining a channel
+  * relay: limit size of decompressed websocket frame with 
+    permessage-deflate to prevent memory exhaustion (GHSA-v2v4-45wm-5cr3)
+  * relay: fix timing attack on password authentication (GHSA-vhv8-g2r9-cwcc)
+  * api, relay: fix timing attack on TOTP validation (GHSA-vhv8-g2r9-cwcc)
+
+-------------------------------------------------------------------

Old:
----
  weechat-4.9.0.tar.xz
  weechat-4.9.0.tar.xz.asc

New:
----
  weechat-4.9.1.tar.xz
  weechat-4.9.1.tar.xz.asc

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

Other differences:
------------------
++++++ weechat.spec ++++++
--- /var/tmp/diff_new_pack.qIo2tk/_old  2026-06-01 18:09:15.855389680 +0200
+++ /var/tmp/diff_new_pack.qIo2tk/_new  2026-06-01 18:09:15.855389680 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           weechat
-Version:        4.9.0
+Version:        4.9.1
 Release:        0
 Summary:        Multi-protocol extensible Chat Client
 License:        GPL-3.0-or-later

++++++ weechat-4.9.0.tar.xz -> weechat-4.9.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/.poexam/poexam.toml 
new/weechat-4.9.1/.poexam/poexam.toml
--- old/weechat-4.9.0/.poexam/poexam.toml       2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/.poexam/poexam.toml       2026-05-31 13:46:04.000000000 
+0200
@@ -9,7 +9,14 @@
 ignore = [
     "brackets",
     "double-quotes",
+    "double-words",
+    "header",
+    "html-tags",
+    "paths",
+    "punc-space-str",
     "unchanged",
+    "unicode-ctrl",
+    "urls",
 ]
 path_words = "."
 langs = [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/CHANGELOG.md 
new/weechat-4.9.1/CHANGELOG.md
--- old/weechat-4.9.0/CHANGELOG.md      2026-03-29 10:20:23.000000000 +0200
+++ new/weechat-4.9.1/CHANGELOG.md      2026-05-31 13:46:04.000000000 +0200
@@ -6,6 +6,16 @@
 
 # WeeChat ChangeLog
 
+## Version 4.9.1 (2026-05-31)
+
+### Fixed
+
+- core: fix option weechat.look.color_real_white not applied when color is 
"white" on 16+ colors terminals 
([#1742](https://github.com/weechat/weechat/issues/1742))
+- irc: fix tag in message with list of names when joining a channel
+- relay: limit size of decompressed websocket frame with permessage-deflate to 
prevent memory exhaustion 
([GHSA-v2v4-45wm-5cr3](https://github.com/weechat/weechat/security/advisories/GHSA-v2v4-45wm-5cr3))
+- relay: fix timing attack on password authentication 
([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
+- api, relay: fix timing attack on TOTP validation 
([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
+
 ## Version 4.9.0 (2026-03-29)
 
 ### Changed
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/CMakeLists.txt 
new/weechat-4.9.1/CMakeLists.txt
--- old/weechat-4.9.0/CMakeLists.txt    2026-03-29 10:20:23.000000000 +0200
+++ new/weechat-4.9.1/CMakeLists.txt    2026-05-31 13:46:04.000000000 +0200
@@ -28,6 +28,7 @@
 # CMake options
 set(CMAKE_VERBOSE_MAKEFILE OFF)
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}")
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
 set(CMAKE_SKIP_RPATH ON)
 
 # compiler options
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/core/core-crypto.c 
new/weechat-4.9.1/src/core/core-crypto.c
--- old/weechat-4.9.0/src/core/core-crypto.c    2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/src/core/core-crypto.c    2026-05-31 13:46:04.000000000 
+0200
@@ -46,6 +46,9 @@
 #include <netinet/in.h>
 #include <inttypes.h>
 #define BE_INT64 htonll
+#elif defined(__HAIKU__)
+#include <ByteOrder.h>
+#define BE_INT64 B_HOST_TO_BENDIAN_INT64
 #else
 #define BE_INT64 htobe64
 #endif
@@ -657,15 +660,18 @@
 
     otp_ok = 0;
 
+    /*
+     * Compare in constant time and never break early: a non-constant
+     * compare and an early exit on match would let an observer measure
+     * how many digits of the expected OTP they got right and which
+     * time-window offset matched.
+     */
     for (i = moving_factor - window; i <= moving_factor + window; i++)
     {
         rc = weecrypto_totp_generate_internal (secret, length_secret,
                                                i, digits, str_otp);
-        if (rc && (strcmp (str_otp, otp) == 0))
-        {
+        if (rc && (string_memcmp_constant_time (str_otp, otp, digits) == 0))
             otp_ok = 1;
-            break;
-        }
     }
 
     free (secret);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/core/core-string.c 
new/weechat-4.9.1/src/core/core-string.c
--- old/weechat-4.9.0/src/core/core-string.c    2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/src/core/core-string.c    2026-05-31 13:46:04.000000000 
+0200
@@ -923,6 +923,43 @@
 }
 
 /*
+ * Compare two memory areas of the same size in constant time.
+ *
+ * Use to compare secrets (e.g. password hashes, MACs) without leaking
+ * information through the comparison's running time. The loop always
+ * walks the full "size" bytes and uses only bitwise operations on the
+ * data, so the execution time depends on "size" alone, not on the
+ * position of the first differing byte.
+ *
+ * If either pointer is NULL, the areas are considered different (the
+ * NULL check itself is not constant time but does not look at any
+ * secret content).
+ *
+ * Return:
+ *   0: areas are equal
+ *   1: areas differ
+ */
+
+int
+string_memcmp_constant_time (const void *area1, const void *area2, size_t size)
+{
+    const unsigned char *p1, *p2;
+    unsigned char diff;
+    size_t i;
+
+    if (!area1 || !area2)
+        return (area1 == area2) ? 0 : 1;
+
+    p1 = (const unsigned char *)area1;
+    p2 = (const unsigned char *)area2;
+    diff = 0;
+    for (i = 0; i < size; i++)
+        diff |= p1[i] ^ p2[i];
+
+    return (diff == 0) ? 0 : 1;
+}
+
+/*
  * Search for a string in another string (locale and case independent).
  *
  * Return pointer to string found, or NULL if not found.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/core/core-string.h 
new/weechat-4.9.1/src/core/core-string.h
--- old/weechat-4.9.0/src/core/core-string.h    2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/src/core/core-string.h    2026-05-31 13:46:04.000000000 
+0200
@@ -69,6 +69,8 @@
                                        const char *string2,
                                        const char *chars_ignored,
                                        int case_sensitive);
+extern int string_memcmp_constant_time (const void *area1, const void *area2,
+                                        size_t size);
 extern const char *string_strcasestr (const char *string, const char *search);
 extern int string_match (const char *string, const char *mask,
                          int case_sensitive);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/core/core-url.c 
new/weechat-4.9.1/src/core/core-url.c
--- old/weechat-4.9.0/src/core/core-url.c       2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/src/core/core-url.c       2026-05-31 13:46:04.000000000 
+0200
@@ -125,7 +125,9 @@
     URL_DEF_CONST(AUTH, NTLM),
     URL_DEF_CONST(AUTH, ANY),
     URL_DEF_CONST(AUTH, ANYSAFE),
+#if LIBCURL_VERSION_NUM < 0x081500 /* < 8.21.0 */
     URL_DEF_CONST(AUTH, DIGEST_IE),
+#endif
     URL_DEF_CONST(AUTH, ONLY),
 #if LIBCURL_VERSION_NUM < 0x080800 /* < 8.8.0 */
     URL_DEF_CONST(AUTH, NTLM_WB),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/gui/curses/gui-curses-window.c 
new/weechat-4.9.1/src/gui/curses/gui-curses-window.c
--- old/weechat-4.9.0/src/gui/curses/gui-curses-window.c        2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/gui/curses/gui-curses-window.c        2026-05-31 
13:46:04.000000000 +0200
@@ -372,7 +372,8 @@
          * if not real white, we use default terminal foreground instead of
          * white if bold attribute is set
          */
-        if ((fg == COLOR_WHITE) && (gui_color[num_color]->attributes & A_BOLD)
+        if (((fg == COLOR_WHITE + 8)
+             || ((fg == COLOR_WHITE) && (gui_color[num_color]->attributes & 
A_BOLD)))
             && !CONFIG_BOOLEAN(config_look_color_real_white))
         {
             fg = -1;
@@ -442,7 +443,8 @@
              * if not real white, we use default terminal foreground instead of
              * white if bold attribute is set
              */
-            if ((fg == COLOR_WHITE) && (attributes & A_BOLD)
+            if (((fg == COLOR_WHITE + 8)
+                 || ((fg == COLOR_WHITE) && (attributes & A_BOLD)))
                 && !CONFIG_BOOLEAN(config_look_color_real_white))
             {
                 fg = -1;
@@ -535,7 +537,8 @@
              * if not real white, we use default terminal foreground instead of
              * white if bold attribute is set
              */
-            if ((fg == COLOR_WHITE) && (attributes & A_BOLD)
+            if (((fg == COLOR_WHITE + 8)
+                 || ((fg == COLOR_WHITE) && (attributes & A_BOLD)))
                 && !CONFIG_BOOLEAN(config_look_color_real_white))
             {
                 fg = -1;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/irc/irc-protocol.c 
new/weechat-4.9.1/src/plugins/irc/irc-protocol.c
--- old/weechat-4.9.0/src/plugins/irc/irc-protocol.c    2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/irc/irc-protocol.c    2026-05-31 
13:46:04.000000000 +0200
@@ -208,7 +208,8 @@
  */
 
 const char *
-irc_protocol_tags (struct t_irc_protocol_ctxt *ctxt, const char *extra_tags)
+irc_protocol_tags_cmd (struct t_irc_protocol_ctxt *ctxt, const char *command,
+                       const char *extra_tags)
 {
     static char string[4096];
     const char *ptr_tag_batch, *ptr_nick, *ptr_address;
@@ -222,7 +223,7 @@
     ptr_nick = NULL;
     ptr_address = NULL;
 
-    is_numeric = irc_protocol_is_numeric_command (ctxt->command);
+    is_numeric = irc_protocol_is_numeric_command (command);
     has_irc_tags = (ctxt->tags
                     && weechat_hashtable_get_integer (ctxt->tags,
                                                       "items_count") > 0);
@@ -287,9 +288,9 @@
         }
     }
 
-    if (ctxt->command && ctxt->command[0])
+    if (command && command[0])
     {
-        log_level = irc_protocol_log_level_for_command (ctxt->command);
+        log_level = irc_protocol_log_level_for_command (command);
         if (log_level > 0)
         {
             snprintf (str_log_level, sizeof (str_log_level),
@@ -299,8 +300,8 @@
 
     snprintf (string, sizeof (string),
               "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
-              (ctxt->command && ctxt->command[0]) ? "irc_" : "",
-              (ctxt->command && ctxt->command[0]) ? ctxt->command : "",
+              (command && command[0]) ? "irc_" : "",
+              (command && command[0]) ? command : "",
               (is_numeric) ? "," : "",
               (is_numeric) ? "irc_numeric" : "",
               (str_irc_tags && (*str_irc_tags)[0]) ? "," : "",
@@ -323,6 +324,16 @@
 }
 
 /*
+ * Build tags list with IRC command and optional tags and nick.
+ */
+
+const char *
+irc_protocol_tags (struct t_irc_protocol_ctxt *ctxt, const char *extra_tags)
+{
+    return irc_protocol_tags_cmd (ctxt, ctxt->command, extra_tags);
+}
+
+/*
  * Build a string with nick and optional address.
  *
  * If server_message is 1, color nick according to option
@@ -6659,7 +6670,7 @@
                         ctxt->server, NULL, ctxt->command, "names", 
ptr_channel->buffer),
                     ctxt->date,
                     ctxt->date_usec,
-                    irc_protocol_tags (ctxt, NULL),
+                    irc_protocol_tags_cmd (ctxt, "353", NULL),
                     _("%sNicks %s%s%s%s: %s[%s%s]"),
                     weechat_prefix ("network"),
                     IRC_COLOR_CHAT_CHANNEL,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/plugin.c 
new/weechat-4.9.1/src/plugins/plugin.c
--- old/weechat-4.9.0/src/plugins/plugin.c      2026-03-29 10:20:23.000000000 
+0200
+++ new/weechat-4.9.1/src/plugins/plugin.c      2026-05-31 13:46:04.000000000 
+0200
@@ -624,6 +624,7 @@
         new_plugin->strncasecmp = &string_strncasecmp;
         new_plugin->strncasecmp_range = &string_strncasecmp_range;
         new_plugin->strcmp_ignore_chars = &string_strcmp_ignore_chars;
+        new_plugin->string_memcmp_constant_time = &string_memcmp_constant_time;
         new_plugin->strcasestr = &string_strcasestr;
         new_plugin->strlen_screen = &gui_chat_strlen_screen;
         new_plugin->string_match = &string_match;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/relay/irc/relay-irc.c 
new/weechat-4.9.1/src/plugins/relay/irc/relay-irc.c
--- old/weechat-4.9.0/src/plugins/relay/irc/relay-irc.c 2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/relay/irc/relay-irc.c 2026-05-31 
13:46:04.000000000 +0200
@@ -33,6 +33,7 @@
 #include "../../weechat-plugin.h"
 #include "../relay.h"
 #include "relay-irc.h"
+#include "../relay-auth.h"
 #include "../relay-buffer.h"
 #include "../relay-client.h"
 #include "../relay-config.h"
@@ -1701,7 +1702,7 @@
                         NULL, NULL, NULL);
                     if (password)
                     {
-                        if (strcmp (password, pos_password) == 0)
+                        if (relay_auth_password_equals (password, 
pos_password))
                         {
                             RELAY_IRC_DATA(client, password_ok) = 1;
                             weechat_hook_signal_send ("relay_client_auth_ok",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/relay/relay-auth.c 
new/weechat-4.9.1/src/plugins/relay/relay-auth.c
--- old/weechat-4.9.0/src/plugins/relay/relay-auth.c    2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/relay/relay-auth.c    2026-05-31 
13:46:04.000000000 +0200
@@ -103,6 +103,66 @@
 }
 
 /*
+ * Compare two passwords for equality in constant time.
+ *
+ * HMAC both sides with a fresh random key, then compare the fixed-size
+ * MACs. This hides both the per-byte comparison and the password length
+ * from a timing-side-channel observer.
+ *
+ * Both messages are prefixed with a zero byte so empty passwords still
+ * produce a valid HMAC (the underlying crypto API rejects zero-length
+ * messages); the prefix is identical on both sides so equal inputs
+ * still yield equal MACs.
+ *
+ * Return:
+ *   1: passwords are equal
+ *   0: passwords are not equal (or an error occurred)
+ */
+
+int
+relay_auth_password_equals (const char *password1, const char *password2)
+{
+    unsigned char key[32];
+    char hmac1[64], hmac2[64];
+    char *buf1, *buf2;
+    int buf1_size, buf2_size, hmac1_size, hmac2_size, rc;
+
+    if (!password1 || !password2)
+        return 0;
+
+    rc = 0;
+    buf1_size = strlen (password1) + 1;
+    buf2_size = strlen (password2) + 1;
+    buf1 = malloc (buf1_size);
+    buf2 = malloc (buf2_size);
+    if (buf1 && buf2)
+    {
+        buf1[0] = 0;
+        memcpy (buf1 + 1, password1, buf1_size - 1);
+        buf2[0] = 0;
+        memcpy (buf2 + 1, password2, buf2_size - 1);
+        gcry_create_nonce (key, sizeof (key));
+        if (weechat_crypto_hmac (key, sizeof (key),
+                                 buf1, buf1_size,
+                                 "sha256",
+                                 hmac1, &hmac1_size)
+            && weechat_crypto_hmac (key, sizeof (key),
+                                    buf2, buf2_size,
+                                    "sha256",
+                                    hmac2, &hmac2_size)
+            && (hmac1_size == hmac2_size)
+            && (weechat_string_memcmp_constant_time (
+                    hmac1, hmac2, hmac1_size) == 0))
+        {
+            rc = 1;
+        }
+    }
+    free (buf1);
+    free (buf2);
+    return rc;
+}
+
+/*
  * Check if password received as plain text is valid.
  *
  * Return:
@@ -127,7 +187,7 @@
         return -1;
     }
 
-    return (strcmp (password, relay_password) == 0) ? 0 : -2;
+    return relay_auth_password_equals (password, relay_password) ? 0 : -2;
 }
 
 /*
@@ -347,8 +407,9 @@
                            const char *hash_sha,
                            const char *relay_password)
 {
-    char *salt_password, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
-    int rc, length, hash_size;
+    char *salt_password, *hash_sha_upper, hash[512 / 8];
+    char hash_hexa[((512 / 8) * 2) + 1];
+    int rc, length, hash_size, hash_hexa_len;
 
     rc = 0;
 
@@ -366,10 +427,23 @@
                                  hash_algo,
                                  hash, &hash_size))
         {
-            weechat_string_base_encode ("16", hash, hash_size,
-                                        hash_hexa);
-            if (weechat_strcasecmp (hash_hexa, hash_sha) == 0)
+            hash_hexa_len = weechat_string_base_encode ("16", hash, hash_size,
+                                                        hash_hexa);
+            /*
+             * Compare in constant time to defeat timing attacks: the
+             * client-supplied hash is normalized to uppercase to match
+             * the output of base16 encoding, then compared byte-for-byte
+             * with no early exit.
+             */
+            hash_sha_upper = weechat_string_toupper (hash_sha);
+            if (hash_sha_upper
+                && ((int)strlen (hash_sha_upper) == hash_hexa_len)
+                && (weechat_string_memcmp_constant_time (
+                        hash_hexa, hash_sha_upper, hash_hexa_len) == 0))
+            {
                 rc = 1;
+            }
+            free (hash_sha_upper);
         }
         free (salt_password);
     }
@@ -393,8 +467,8 @@
                               const char *hash_pbkdf2,
                               const char *relay_password)
 {
-    char hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
-    int rc, hash_size;
+    char *hash_pbkdf2_upper, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
+    int rc, hash_size, hash_hexa_len;
 
     rc = 0;
 
@@ -407,9 +481,18 @@
                                         iterations,
                                         hash, &hash_size))
         {
-            weechat_string_base_encode ("16", hash, hash_size, hash_hexa);
-            if (weechat_strcasecmp (hash_hexa, hash_pbkdf2) == 0)
+            hash_hexa_len = weechat_string_base_encode ("16", hash, hash_size,
+                                                        hash_hexa);
+            /* see relay_auth_check_hash_sha for rationale */
+            hash_pbkdf2_upper = weechat_string_toupper (hash_pbkdf2);
+            if (hash_pbkdf2_upper
+                && ((int)strlen (hash_pbkdf2_upper) == hash_hexa_len)
+                && (weechat_string_memcmp_constant_time (
+                        hash_hexa, hash_pbkdf2_upper, hash_hexa_len) == 0))
+            {
                 rc = 1;
+            }
+            free (hash_pbkdf2_upper);
         }
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/relay/relay-auth.h 
new/weechat-4.9.1/src/plugins/relay/relay-auth.h
--- old/weechat-4.9.0/src/plugins/relay/relay-auth.h    2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/relay/relay-auth.h    2026-05-31 
13:46:04.000000000 +0200
@@ -39,6 +39,8 @@
 
 extern int relay_auth_password_hash_algo_search (const char *name);
 extern char *relay_auth_generate_nonce (int size);
+extern int relay_auth_password_equals (const char *password1,
+                                       const char *password2);
 extern int relay_auth_check_password_plain (struct t_relay_client *client,
                                             const char *password,
                                             const char *relay_password);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/relay/relay-websocket.c 
new/weechat-4.9.1/src/plugins/relay/relay-websocket.c
--- old/weechat-4.9.0/src/plugins/relay/relay-websocket.c       2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/relay/relay-websocket.c       2026-05-31 
13:46:04.000000000 +0200
@@ -532,7 +532,7 @@
     int rc;
     unsigned char append_bytes[4] = { 0x00, 0x00, 0xFF, 0xFF };
     Bytef *data2, *dest, *dest2;
-    uLongf size2, dest_size;
+    uLongf size2, dest_size, new_size;
 
     if (!data || (size == 0) || !strm || !size_decompressed)
         return NULL;
@@ -549,8 +549,13 @@
     memcpy (data2, data, size);
     memcpy (data2 + size, append_bytes, sizeof (append_bytes));
 
-    /* estimate the decompressed size, by default 10 * size */
-    dest_size = 10 * size2;
+    /*
+     * estimate the decompressed size, by default 10 * size, capped to the
+     * maximum allowed size (also prevents an integer overflow on the
+     * multiplication)
+     */
+    dest_size = (size2 > WEBSOCKET_INFLATE_MAX_SIZE / 10) ?
+        WEBSOCKET_INFLATE_MAX_SIZE : 10 * size2;
     dest = malloc (dest_size);
     if (!dest)
         goto error;
@@ -579,8 +584,19 @@
                 && (strm->avail_in > 0)))
         {
             /* output buffer is not large enough */
-            strm->avail_out += dest_size;
-            dest_size *= 2;
+            if (dest_size >= WEBSOCKET_INFLATE_MAX_SIZE)
+            {
+                /*
+                 * decompressed data is too large: reject the frame
+                 * (protection against a "deflate bomb")
+                 */
+                goto error;
+            }
+            /* double the buffer, capped to the maximum allowed size */
+            new_size = (dest_size > WEBSOCKET_INFLATE_MAX_SIZE / 2) ?
+                WEBSOCKET_INFLATE_MAX_SIZE : dest_size * 2;
+            strm->avail_out += (uInt)(new_size - dest_size);
+            dest_size = new_size;
             dest2 = realloc (dest, dest_size);
             if (!dest2)
                 goto error;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/relay/relay-websocket.h 
new/weechat-4.9.1/src/plugins/relay/relay-websocket.h
--- old/weechat-4.9.0/src/plugins/relay/relay-websocket.h       2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/relay/relay-websocket.h       2026-05-31 
13:46:04.000000000 +0200
@@ -41,6 +41,13 @@
 
 #define WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "api.weechat"
 
+/*
+ * maximum size of a decompressed websocket frame (with "permessage-deflate"):
+ * used as an upper bound when inflating, to prevent a small compressed frame
+ * from decompressing to an unbounded amount of data ("deflate bomb")
+ */
+#define WEBSOCKET_INFLATE_MAX_SIZE (8 * 1024 * 1024)
+
 struct t_relay_client;
 struct t_relay_http_request;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/src/plugins/weechat-plugin.h 
new/weechat-4.9.1/src/plugins/weechat-plugin.h
--- old/weechat-4.9.0/src/plugins/weechat-plugin.h      2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/src/plugins/weechat-plugin.h      2026-05-31 
13:46:04.000000000 +0200
@@ -76,7 +76,7 @@
  * please change the date with current one; for a second change at same
  * date, increment the 01, otherwise please keep 01.
  */
-#define WEECHAT_PLUGIN_API_VERSION "20251112-01"
+#define WEECHAT_PLUGIN_API_VERSION "20260530-01"
 
 /* macros for defining plugin infos */
 #define WEECHAT_PLUGIN_NAME(__name)                                     \
@@ -348,6 +348,8 @@
                               int max, int range);
     int (*strcmp_ignore_chars) (const char *string1, const char *string2,
                                 const char *chars_ignored, int case_sensitive);
+    int (*string_memcmp_constant_time) (const void *area1, const void *area2,
+                                        size_t size);
     const char *(*strcasestr) (const char *string, const char *search);
     int (*strlen_screen) (const char *string);
     int (*string_match) (const char *string, const char *mask,
@@ -1348,6 +1350,9 @@
     (weechat_plugin->strcmp_ignore_chars)(__string1, __string2,         \
                                           __chars_ignored,              \
                                           __case_sensitive)
+#define weechat_string_memcmp_constant_time(__area1, __area2, __size)   \
+    (weechat_plugin->string_memcmp_constant_time)(__area1, __area2,     \
+                                                  __size)
 #define weechat_strcasestr(__string, __search)                          \
     (weechat_plugin->strcasestr)(__string, __search)
 #define weechat_strlen_screen(__string)                                 \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/tests/unit/core/test-core-string.cpp 
new/weechat-4.9.1/tests/unit/core/test-core-string.cpp
--- old/weechat-4.9.0/tests/unit/core/test-core-string.cpp      2026-03-29 
10:20:23.000000000 +0200
+++ new/weechat-4.9.1/tests/unit/core/test-core-string.cpp      2026-05-31 
13:46:04.000000000 +0200
@@ -802,6 +802,38 @@
 
 /*
  * Test functions:
+ *   string_memcmp_constant_time
+ */
+
+TEST(CoreString, MemcmpConstantTime)
+{
+    /* NULL handling */
+    LONGS_EQUAL(0, string_memcmp_constant_time (NULL, NULL, 0));
+    LONGS_EQUAL(0, string_memcmp_constant_time (NULL, NULL, 4));
+    LONGS_EQUAL(1, string_memcmp_constant_time (NULL, "abcd", 4));
+    LONGS_EQUAL(1, string_memcmp_constant_time ("abcd", NULL, 4));
+
+    /* zero-size compare always equal */
+    LONGS_EQUAL(0, string_memcmp_constant_time ("", "", 0));
+    LONGS_EQUAL(0, string_memcmp_constant_time ("abc", "xyz", 0));
+
+    /* equal areas */
+    LONGS_EQUAL(0, string_memcmp_constant_time ("abcd", "abcd", 4));
+    LONGS_EQUAL(0, string_memcmp_constant_time ("\x00\x01\x02\xff",
+                                                "\x00\x01\x02\xff", 4));
+
+    /* differing areas (first / middle / last byte) */
+    LONGS_EQUAL(1, string_memcmp_constant_time ("Xbcd", "abcd", 4));
+    LONGS_EQUAL(1, string_memcmp_constant_time ("aXcd", "abcd", 4));
+    LONGS_EQUAL(1, string_memcmp_constant_time ("abcX", "abcd", 4));
+    LONGS_EQUAL(1, string_memcmp_constant_time ("abcd", "abce", 4));
+
+    /* only compares "size" bytes, ignores trailing content */
+    LONGS_EQUAL(0, string_memcmp_constant_time ("abcd", "abcz", 3));
+}
+
+/*
+ * Test functions:
  *   string_strcasestr
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/weechat-4.9.0/tests/unit/plugins/relay/test-relay-auth.cpp 
new/weechat-4.9.1/tests/unit/plugins/relay/test-relay-auth.cpp
--- old/weechat-4.9.0/tests/unit/plugins/relay/test-relay-auth.cpp      
2026-03-29 10:20:23.000000000 +0200
+++ new/weechat-4.9.1/tests/unit/plugins/relay/test-relay-auth.cpp      
2026-05-31 13:46:04.000000000 +0200
@@ -111,6 +111,31 @@
 
 /*
  * Test functions:
+ *   relay_auth_password_equals
+ */
+
+TEST(RelayAuth, PasswordEquals)
+{
+    /* invalid arguments */
+    LONGS_EQUAL(0, relay_auth_password_equals (NULL, NULL));
+    LONGS_EQUAL(0, relay_auth_password_equals ("abcd", NULL));
+    LONGS_EQUAL(0, relay_auth_password_equals (NULL, "abcd"));
+
+    /* different passwords */
+    LONGS_EQUAL(0, relay_auth_password_equals ("test", "password"));
+    LONGS_EQUAL(0, relay_auth_password_equals ("Password", "password"));
+    LONGS_EQUAL(0, relay_auth_password_equals ("", "password"));
+    LONGS_EQUAL(0, relay_auth_password_equals ("password", ""));
+
+    /* equal passwords */
+    LONGS_EQUAL(1, relay_auth_password_equals ("", ""));
+    LONGS_EQUAL(1, relay_auth_password_equals ("password", "password"));
+    LONGS_EQUAL(1, relay_auth_password_equals ("a really long password with 
spaces",
+                                               "a really long password with 
spaces"));
+}
+
+/*
+ * Test functions:
  *   relay_auth_check_password_plain
  */
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/weechat-4.9.0/tests/unit/plugins/relay/test-relay-websocket.cpp 
new/weechat-4.9.1/tests/unit/plugins/relay/test-relay-websocket.cpp
--- old/weechat-4.9.0/tests/unit/plugins/relay/test-relay-websocket.cpp 
2026-03-29 10:20:23.000000000 +0200
+++ new/weechat-4.9.1/tests/unit/plugins/relay/test-relay-websocket.cpp 
2026-05-31 13:46:04.000000000 +0200
@@ -466,6 +466,41 @@
     free (payload_comp);
 
     relay_websocket_deflate_free (ws_deflate);
+
+    /*
+     * protection against "deflate bomb": a small compressed frame that
+     * decompresses to more than WEBSOCKET_INFLATE_MAX_SIZE must be rejected
+     * (relay_websocket_inflate returns NULL)
+     */
+    ws_deflate = relay_websocket_deflate_alloc ();
+    CHECK(ws_deflate);
+    ws_deflate->window_bits_deflate = 15;
+    ws_deflate->window_bits_inflate = 15;
+    ws_deflate->strm_deflate = (z_stream *)calloc (1, sizeof 
(*ws_deflate->strm_deflate));
+    CHECK(ws_deflate->strm_deflate);
+    LONGS_EQUAL(1, relay_websocket_deflate_init_stream_deflate (ws_deflate));
+    ws_deflate->strm_inflate = (z_stream *)calloc (1, sizeof 
(*ws_deflate->strm_inflate));
+    CHECK(ws_deflate->strm_inflate);
+    LONGS_EQUAL(1, relay_websocket_deflate_init_stream_inflate (ws_deflate));
+
+    /* highly compressible payload that decompresses past the maximum size */
+    size_t bomb_size = WEBSOCKET_INFLATE_MAX_SIZE + (1024 * 1024);
+    char *bomb = (char *)calloc (1, bomb_size);
+    CHECK(bomb);
+
+    payload_comp = (char *)relay_websocket_deflate (bomb, bomb_size,
+                                                    ws_deflate->strm_deflate, 
&size_comp);
+    CHECK(payload_comp);
+    CHECK(size_comp < bomb_size);
+
+    payload_decomp = (char *)relay_websocket_inflate (payload_comp, size_comp,
+                                                      
ws_deflate->strm_inflate, &size_decomp);
+    POINTERS_EQUAL(NULL, payload_decomp);
+
+    free (payload_comp);
+    free (bomb);
+
+    relay_websocket_deflate_free (ws_deflate);
 }
 
 /*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/weechat-4.9.0/version.sh new/weechat-4.9.1/version.sh
--- old/weechat-4.9.0/version.sh        2026-03-29 10:20:23.000000000 +0200
+++ new/weechat-4.9.1/version.sh        2026-05-31 13:46:04.000000000 +0200
@@ -41,8 +41,8 @@
 #     devel-number   the devel version as hex number ("0x04010000" for 
"4.1.0-dev")
 #
 
-weechat_stable="4.9.0"
-weechat_devel="4.9.0"
+weechat_stable="4.9.1"
+weechat_devel="4.9.1"
 
 stable_major=$(echo "${weechat_stable}" | cut -d"." -f1)
 stable_minor=$(echo "${weechat_stable}" | cut -d"." -f2)

Reply via email to