mirror of
https://github.com/weechat/weechat.git
synced 2026-07-05 09:13:14 +02:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0645731b9b | |||
| 9d43e2eed7 | |||
| acaf528628 | |||
| cfa59405cf | |||
| 9388c01074 | |||
| 0cd736af22 | |||
| 703120bbfb | |||
| 12c4170fbf | |||
| e9138c5d55 | |||
| eb8c8641ea | |||
| bd6455d07f | |||
| 8d3180fa78 | |||
| 519ab4e7bb | |||
| 3c36fd7412 | |||
| b62c97dbe3 | |||
| f91f92b48f | |||
| 30529057c8 | |||
| a69f356182 | |||
| 1438255a87 | |||
| d15ce789a0 | |||
| 377b6da43d | |||
| 8b1b06a407 | |||
| c09c1bf2fc | |||
| c83afb9a06 | |||
| ed9535a43f |
@@ -131,7 +131,7 @@ jobs:
|
|||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
sudo apt-get --yes --no-install-recommends install ${{ env.CHECK_DEPS_UBUNTU }}
|
sudo apt-get --yes --no-install-recommends install ${{ env.CHECK_DEPS_UBUNTU }}
|
||||||
pipx install msgcheck ruff
|
pipx install msgcheck ruff
|
||||||
cargo install --version 0.0.10 poexam
|
cargo install --version 0.0.12 poexam
|
||||||
|
|
||||||
- name: Check gettext files (msgcheck)
|
- name: Check gettext files (msgcheck)
|
||||||
run: msgcheck po/*.po
|
run: msgcheck po/*.po
|
||||||
@@ -280,8 +280,10 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
dnf install -y epel-release
|
dnf install -y epel-release dnf-plugins-core
|
||||||
dnf config-manager --set-enabled crb
|
dnf config-manager --set-enabled crb
|
||||||
|
# pin a working ruby stream (ruby:4.0 has broken module metadata on Rocky 9.8)
|
||||||
|
dnf module enable -y ruby:3.3
|
||||||
dnf install -y ${{ env.WEECHAT_DEPS_ROCKYLINUX }}
|
dnf install -y ${{ env.WEECHAT_DEPS_ROCKYLINUX }}
|
||||||
|
|
||||||
- name: Build and run tests
|
- name: Build and run tests
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ select = [
|
|||||||
"checks",
|
"checks",
|
||||||
]
|
]
|
||||||
ignore = [
|
ignore = [
|
||||||
|
"acronyms",
|
||||||
"brackets",
|
"brackets",
|
||||||
"double-quotes",
|
"double-quotes",
|
||||||
"double-words",
|
"double-words",
|
||||||
|
"functions",
|
||||||
"header",
|
"header",
|
||||||
"html-tags",
|
"html-tags",
|
||||||
"paths",
|
"paths",
|
||||||
|
|||||||
+25
-3
@@ -6,15 +6,37 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
|
|
||||||
# WeeChat ChangeLog
|
# WeeChat ChangeLog
|
||||||
|
|
||||||
|
## Version 4.9.3 (under dev)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- core: fix buffer overflow in connection to SOCKS5 proxy ([#2325](https://github.com/weechat/weechat/issues/2325))
|
||||||
|
- relay/api: fix memory leak in resources "handshake", "input" and "completion"
|
||||||
|
- relay: fix read of uncompressed websocket frame ([#2331](https://github.com/weechat/weechat/issues/2331))
|
||||||
|
- xfer: fix out-of-bounds write in xfer file transfer resume ([#2326](https://github.com/weechat/weechat/issues/2326))
|
||||||
|
|
||||||
|
## Version 4.9.2 (2026-06-07)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- api: fix infinite loop in function string_replace when the search string is empty
|
||||||
|
- irc: limit size of data received from the server to prevent memory exhaustion
|
||||||
|
- irc: fix out-of-bounds read on incoming DCC command with a quoted filename ending the message ([#2322](https://github.com/weechat/weechat/issues/2322))
|
||||||
|
- relay: limit size of received websocket frame and HTTP body to prevent memory exhaustion
|
||||||
|
- relay: limit size of partial message received while reading an HTTP request to prevent memory exhaustion
|
||||||
|
- relay: fix out-of-bounds read in dump of data ([#2324](https://github.com/weechat/weechat/issues/2324))
|
||||||
|
- xfer: replace directory separator in remote nick by underscore in download filename to prevent writing the file outside the download directory ([#2321](https://github.com/weechat/weechat/issues/2321))
|
||||||
|
- xfer: fix out-of-bounds read when receiving empty line in DCC chat ([#2323](https://github.com/weechat/weechat/issues/2323))
|
||||||
|
|
||||||
## Version 4.9.1 (2026-05-31)
|
## Version 4.9.1 (2026-05-31)
|
||||||
|
|
||||||
### Fixed
|
### 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))
|
- 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
|
- 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: 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), [CVE-2026-53524](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53524))
|
||||||
- relay: fix timing attack on password authentication ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc))
|
- relay: fix timing attack on password authentication ([GHSA-vhv8-g2r9-cwcc](https://github.com/weechat/weechat/security/advisories/GHSA-vhv8-g2r9-cwcc), [CVE-2026-53525](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53525))
|
||||||
- api, relay: fix timing attack on TOTP validation ([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), [CVE-2026-53525](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-53525))
|
||||||
|
|
||||||
## Version 4.9.0 (2026-03-29)
|
## Version 4.9.0 (2026-03-29)
|
||||||
|
|
||||||
|
|||||||
@@ -1028,6 +1028,13 @@ Path parameters:
|
|||||||
confused with the buffer number, which is different)
|
confused with the buffer number, which is different)
|
||||||
* `buffer_name` (string, **required**): buffer name
|
* `buffer_name` (string, **required**): buffer name
|
||||||
|
|
||||||
|
Query parameters:
|
||||||
|
|
||||||
|
* `colors` (string, optional, default: `ansi`): how to return strings with color codes:
|
||||||
|
** `ansi`: return ANSI color codes
|
||||||
|
** `weechat`: return WeeChat internal color codes
|
||||||
|
** `strip`: strip colors
|
||||||
|
|
||||||
Request example: get nicks of a buffer:
|
Request example: get nicks of a buffer:
|
||||||
|
|
||||||
[source,shell]
|
[source,shell]
|
||||||
|
|||||||
@@ -1040,6 +1040,14 @@ Paramètres de chemin :
|
|||||||
confondre avec le numéro du tampon, qui est différent)
|
confondre avec le numéro du tampon, qui est différent)
|
||||||
* `buffer_name` (chaîne, **obligatoire**) : nom du tampon
|
* `buffer_name` (chaîne, **obligatoire**) : nom du tampon
|
||||||
|
|
||||||
|
Paramètres de requête :
|
||||||
|
|
||||||
|
* `colors` (chaîne, facultatif, par défaut : `ansi`) : comment les chaînes avec
|
||||||
|
des couleurs sont retournées :
|
||||||
|
** `ansi` : retourner les codes couleur ANSI
|
||||||
|
** `weechat` : retourner les codes couleur internes WeeChat
|
||||||
|
** `strip` : supprimer les couleurs
|
||||||
|
|
||||||
Exemple de requête : obtenir les pseudos d'un tampon :
|
Exemple de requête : obtenir les pseudos d'un tampon :
|
||||||
|
|
||||||
[source,shell]
|
[source,shell]
|
||||||
|
|||||||
@@ -1024,12 +1024,19 @@ GET /api/buffers/{id_бафера}/nicks
|
|||||||
GET /api/buffers/{име_бафера}/nicks
|
GET /api/buffers/{име_бафера}/nicks
|
||||||
----
|
----
|
||||||
|
|
||||||
Параметри упита:
|
Параметри путање:
|
||||||
|
|
||||||
* `id_бафера` (цео број, **обавезно**): јединствени идентификатор бафера (не треба
|
* `id_бафера` (цео број, **обавезно**): јединствени идентификатор бафера (не треба
|
||||||
да се помеша са бројем бафера, то је нешто друго)
|
да се помеша са бројем бафера, то је нешто друго)
|
||||||
* `име_бафера` (стринг, **обавезно**): име бафера
|
* `име_бафера` (стринг, **обавезно**): име бафера
|
||||||
|
|
||||||
|
Параметри упита:
|
||||||
|
|
||||||
|
* `colors` (стринг, није обавезно, подразумевано: `ansi`): како се враћају стрингови са кодовима боје:
|
||||||
|
** `ansi`: враћају се ANSI кодови боје
|
||||||
|
** `weechat`: враћају се WeeChat интерни кодови боје
|
||||||
|
** `strip`: уклањају се боје
|
||||||
|
|
||||||
Пример захтева: врати надимке бафера:
|
Пример захтева: врати надимке бафера:
|
||||||
|
|
||||||
[source,shell]
|
[source,shell]
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: WeeChat\n"
|
"Project-Id-Version: WeeChat\n"
|
||||||
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
|
"Report-Msgid-Bugs-To: flashcode@flashtux.org\n"
|
||||||
"POT-Creation-Date: 2026-03-21 17:24+0100\n"
|
"POT-Creation-Date: 2026-03-21 17:24+0100\n"
|
||||||
"PO-Revision-Date: 2026-03-21 17:24+0100\n"
|
"PO-Revision-Date: 2026-07-03 08:28+0200\n"
|
||||||
"Last-Translator: Nils Görs <weechatter@arcor.de>\n"
|
"Last-Translator: Nils Görs <weechatter@arcor.de>\n"
|
||||||
"Language-Team: German <kde-i18n-de@kde.org>\n"
|
"Language-Team: German <kde-i18n-de@kde.org>\n"
|
||||||
"Language: de_DE\n"
|
"Language: de_DE\n"
|
||||||
@@ -17330,7 +17330,7 @@ msgstr ""
|
|||||||
"Um Tastenkurzbefehle im Skript-Buffer direkt nutzen zu können (zum Beispiel: "
|
"Um Tastenkurzbefehle im Skript-Buffer direkt nutzen zu können (zum Beispiel: "
|
||||||
"alt+i = installieren, alt+r = entfernen, ...), muss diese Einstellung "
|
"alt+i = installieren, alt+r = entfernen, ...), muss diese Einstellung "
|
||||||
"aktiviert werden. Andernfalls können Aktionen nur über die Eingabezeile "
|
"aktiviert werden. Andernfalls können Aktionen nur über die Eingabezeile "
|
||||||
"durchgeführt werden: i,r..."
|
"durchgeführt werden: i,r, ..."
|
||||||
|
|
||||||
msgid "color for status \"autoloaded\" (\"a\")"
|
msgid "color for status \"autoloaded\" (\"a\")"
|
||||||
msgstr "Farbe in der der Status \"autoloaded\" (\"a\") dargestellt werden soll"
|
msgstr "Farbe in der der Status \"autoloaded\" (\"a\") dargestellt werden soll"
|
||||||
|
|||||||
+19
-1
@@ -581,7 +581,13 @@ network_pass_socks5proxy (struct t_proxy *proxy, int sock, const char *address,
|
|||||||
int port)
|
int port)
|
||||||
{
|
{
|
||||||
struct t_network_socks5 socks5;
|
struct t_network_socks5 socks5;
|
||||||
unsigned char buffer[288];
|
/*
|
||||||
|
* buffer must be large enough for the username/password authentication
|
||||||
|
* request, which is the longest message sent/received here; according to
|
||||||
|
* RFC 1929 it is: version (1) + username length (1) + username (max 255)
|
||||||
|
* + password length (1) + password (max 255)
|
||||||
|
*/
|
||||||
|
unsigned char buffer[2 + 255 + 1 + 255];
|
||||||
int username_len, password_len, addr_len, addr_buffer_len;
|
int username_len, password_len, addr_len, addr_buffer_len;
|
||||||
unsigned char *addr_buffer;
|
unsigned char *addr_buffer;
|
||||||
char *username, *password;
|
char *username, *password;
|
||||||
@@ -630,6 +636,18 @@ network_pass_socks5proxy (struct t_proxy *proxy, int sock, const char *address,
|
|||||||
username_len = strlen (username);
|
username_len = strlen (username);
|
||||||
password_len = strlen (password);
|
password_len = strlen (password);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* username and password length are each stored on a single byte
|
||||||
|
* (RFC 1929), so they cannot exceed 255 bytes: reject longer values,
|
||||||
|
* otherwise the memcpy calls below would overflow the buffer
|
||||||
|
*/
|
||||||
|
if ((username_len > 255) || (password_len > 255))
|
||||||
|
{
|
||||||
|
free (username);
|
||||||
|
free (password);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* make username/password buffer */
|
/* make username/password buffer */
|
||||||
buffer[0] = 1;
|
buffer[0] = 1;
|
||||||
buffer[1] = (unsigned char) username_len;
|
buffer[1] = (unsigned char) username_len;
|
||||||
|
|||||||
@@ -1965,6 +1965,9 @@ string_replace (const char *string, const char *search, const char *replace)
|
|||||||
if (!string || !search || !replace)
|
if (!string || !search || !replace)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!search[0])
|
||||||
|
return strdup (string);
|
||||||
|
|
||||||
length1 = strlen (search);
|
length1 = strlen (search);
|
||||||
length2 = strlen (replace);
|
length2 = strlen (replace);
|
||||||
|
|
||||||
|
|||||||
@@ -3804,6 +3804,7 @@ gui_buffer_close (struct t_gui_buffer *buffer)
|
|||||||
|
|
||||||
gui_hotlist_remove_buffer (buffer, 1);
|
gui_hotlist_remove_buffer (buffer, 1);
|
||||||
free (buffer->hotlist_removed);
|
free (buffer->hotlist_removed);
|
||||||
|
buffer->hotlist_removed = NULL;
|
||||||
if (gui_hotlist_initial_buffer == buffer)
|
if (gui_hotlist_initial_buffer == buffer)
|
||||||
gui_hotlist_initial_buffer = NULL;
|
gui_hotlist_initial_buffer = NULL;
|
||||||
|
|
||||||
@@ -3822,55 +3823,85 @@ gui_buffer_close (struct t_gui_buffer *buffer)
|
|||||||
/* free all lines */
|
/* free all lines */
|
||||||
gui_line_free_all (buffer);
|
gui_line_free_all (buffer);
|
||||||
free (buffer->own_lines);
|
free (buffer->own_lines);
|
||||||
|
buffer->own_lines = NULL;
|
||||||
free (buffer->mixed_lines);
|
free (buffer->mixed_lines);
|
||||||
|
buffer->mixed_lines = NULL;
|
||||||
|
|
||||||
/* free some data */
|
/* free some data */
|
||||||
gui_buffer_undo_free_all (buffer);
|
gui_buffer_undo_free_all (buffer);
|
||||||
gui_history_buffer_free (buffer);
|
gui_history_buffer_free (buffer);
|
||||||
gui_completion_free (buffer->completion);
|
gui_completion_free (buffer->completion);
|
||||||
|
buffer->completion = NULL;
|
||||||
gui_nicklist_remove_all (buffer);
|
gui_nicklist_remove_all (buffer);
|
||||||
gui_nicklist_remove_group (buffer, buffer->nicklist_root);
|
gui_nicklist_remove_group (buffer, buffer->nicklist_root);
|
||||||
|
buffer->nicklist_root = NULL;
|
||||||
hashtable_free (buffer->hotlist_max_level_nicks);
|
hashtable_free (buffer->hotlist_max_level_nicks);
|
||||||
|
buffer->hotlist_max_level_nicks = NULL;
|
||||||
gui_key_free_all (-1, &buffer->keys, &buffer->last_key,
|
gui_key_free_all (-1, &buffer->keys, &buffer->last_key,
|
||||||
&buffer->keys_count, 0);
|
&buffer->keys_count, 0);
|
||||||
gui_buffer_local_var_remove_all (buffer);
|
gui_buffer_local_var_remove_all (buffer);
|
||||||
hashtable_free (buffer->local_variables);
|
hashtable_free (buffer->local_variables);
|
||||||
|
buffer->local_variables = NULL;
|
||||||
free (buffer->plugin_name_for_upgrade);
|
free (buffer->plugin_name_for_upgrade);
|
||||||
|
buffer->plugin_name_for_upgrade = NULL;
|
||||||
free (buffer->name);
|
free (buffer->name);
|
||||||
|
buffer->name = NULL;
|
||||||
free (buffer->full_name);
|
free (buffer->full_name);
|
||||||
|
buffer->full_name = NULL;
|
||||||
free (buffer->old_full_name);
|
free (buffer->old_full_name);
|
||||||
|
buffer->old_full_name = NULL;
|
||||||
free (buffer->short_name);
|
free (buffer->short_name);
|
||||||
|
buffer->short_name = NULL;
|
||||||
free (buffer->title);
|
free (buffer->title);
|
||||||
|
buffer->title = NULL;
|
||||||
free (buffer->modes);
|
free (buffer->modes);
|
||||||
|
buffer->modes = NULL;
|
||||||
free (buffer->input_prompt);
|
free (buffer->input_prompt);
|
||||||
|
buffer->input_prompt = NULL;
|
||||||
free (buffer->input_buffer);
|
free (buffer->input_buffer);
|
||||||
|
buffer->input_buffer = NULL;
|
||||||
free (buffer->input_undo_snap);
|
free (buffer->input_undo_snap);
|
||||||
|
buffer->input_undo_snap = NULL;
|
||||||
free (buffer->text_search_input);
|
free (buffer->text_search_input);
|
||||||
|
buffer->text_search_input = NULL;
|
||||||
if (buffer->text_search_regex_compiled)
|
if (buffer->text_search_regex_compiled)
|
||||||
{
|
{
|
||||||
regfree (buffer->text_search_regex_compiled);
|
regfree (buffer->text_search_regex_compiled);
|
||||||
free (buffer->text_search_regex_compiled);
|
free (buffer->text_search_regex_compiled);
|
||||||
|
buffer->text_search_regex_compiled = NULL;
|
||||||
}
|
}
|
||||||
free (buffer->highlight_words);
|
free (buffer->highlight_words);
|
||||||
|
buffer->highlight_words = NULL;
|
||||||
free (buffer->highlight_disable_regex);
|
free (buffer->highlight_disable_regex);
|
||||||
|
buffer->highlight_disable_regex = NULL;
|
||||||
if (buffer->highlight_disable_regex_compiled)
|
if (buffer->highlight_disable_regex_compiled)
|
||||||
{
|
{
|
||||||
regfree (buffer->highlight_disable_regex_compiled);
|
regfree (buffer->highlight_disable_regex_compiled);
|
||||||
free (buffer->highlight_disable_regex_compiled);
|
free (buffer->highlight_disable_regex_compiled);
|
||||||
|
buffer->highlight_disable_regex_compiled = NULL;
|
||||||
}
|
}
|
||||||
free (buffer->highlight_regex);
|
free (buffer->highlight_regex);
|
||||||
|
buffer->highlight_regex = NULL;
|
||||||
if (buffer->highlight_regex_compiled)
|
if (buffer->highlight_regex_compiled)
|
||||||
{
|
{
|
||||||
regfree (buffer->highlight_regex_compiled);
|
regfree (buffer->highlight_regex_compiled);
|
||||||
free (buffer->highlight_regex_compiled);
|
free (buffer->highlight_regex_compiled);
|
||||||
|
buffer->highlight_regex_compiled = NULL;
|
||||||
}
|
}
|
||||||
free (buffer->highlight_tags_restrict);
|
free (buffer->highlight_tags_restrict);
|
||||||
|
buffer->highlight_tags_restrict = NULL;
|
||||||
string_free_split_tags (buffer->highlight_tags_restrict_array);
|
string_free_split_tags (buffer->highlight_tags_restrict_array);
|
||||||
|
buffer->highlight_tags_restrict_array = NULL;
|
||||||
free (buffer->highlight_tags);
|
free (buffer->highlight_tags);
|
||||||
|
buffer->highlight_tags = NULL;
|
||||||
string_free_split_tags (buffer->highlight_tags_array);
|
string_free_split_tags (buffer->highlight_tags_array);
|
||||||
|
buffer->highlight_tags_array = NULL;
|
||||||
free (buffer->input_callback_data);
|
free (buffer->input_callback_data);
|
||||||
|
buffer->input_callback_data = NULL;
|
||||||
free (buffer->close_callback_data);
|
free (buffer->close_callback_data);
|
||||||
|
buffer->close_callback_data = NULL;
|
||||||
free (buffer->nickcmp_callback_data);
|
free (buffer->nickcmp_callback_data);
|
||||||
|
buffer->nickcmp_callback_data = NULL;
|
||||||
|
|
||||||
/* remove buffer from buffers list */
|
/* remove buffer from buffers list */
|
||||||
if (buffer->prev_buffer)
|
if (buffer->prev_buffer)
|
||||||
|
|||||||
@@ -857,7 +857,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
|
|||||||
* double-quote
|
* double-quote
|
||||||
*/
|
*/
|
||||||
pos = strrchr (pos_file, '"');
|
pos = strrchr (pos_file, '"');
|
||||||
if (!pos || (pos == pos_file))
|
if (!pos || (pos == pos_file) || !pos[1])
|
||||||
{
|
{
|
||||||
weechat_printf (
|
weechat_printf (
|
||||||
ctxt->server->buffer,
|
ctxt->server->buffer,
|
||||||
@@ -1032,7 +1032,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
|
|||||||
* double-quote
|
* double-quote
|
||||||
*/
|
*/
|
||||||
pos = strrchr (pos_file, '"');
|
pos = strrchr (pos_file, '"');
|
||||||
if (!pos || (pos == pos_file))
|
if (!pos || (pos == pos_file) || !pos[1])
|
||||||
{
|
{
|
||||||
weechat_printf (
|
weechat_printf (
|
||||||
ctxt->server->buffer,
|
ctxt->server->buffer,
|
||||||
@@ -1176,7 +1176,7 @@ irc_ctcp_recv_dcc (struct t_irc_protocol_ctxt *ctxt, const char *arguments)
|
|||||||
* double-quote
|
* double-quote
|
||||||
*/
|
*/
|
||||||
pos = strrchr (pos_file, '"');
|
pos = strrchr (pos_file, '"');
|
||||||
if (!pos || (pos == pos_file))
|
if (!pos || (pos == pos_file) || !pos[1])
|
||||||
{
|
{
|
||||||
weechat_printf (
|
weechat_printf (
|
||||||
ctxt->server->buffer,
|
ctxt->server->buffer,
|
||||||
|
|||||||
@@ -4164,16 +4164,25 @@ IRC_PROTOCOL_CALLBACK(005)
|
|||||||
if (ctxt->server->isupport)
|
if (ctxt->server->isupport)
|
||||||
{
|
{
|
||||||
length_isupport = strlen (ctxt->server->isupport);
|
length_isupport = strlen (ctxt->server->isupport);
|
||||||
isupport2 = realloc (ctxt->server->isupport,
|
/*
|
||||||
length_isupport + /* existing */
|
* limit the size of the accumulated ISUPPORT data: once the
|
||||||
1 + /* space */
|
* maximum is reached, ignore the extra data (protection against a
|
||||||
length + /* new */
|
* server flooding "005" messages, which would consume all the
|
||||||
1);
|
* memory)
|
||||||
if (isupport2)
|
*/
|
||||||
|
if (length_isupport + 1 + length < IRC_SERVER_ISUPPORT_MAX_LENGTH)
|
||||||
{
|
{
|
||||||
ctxt->server->isupport = isupport2;
|
isupport2 = realloc (ctxt->server->isupport,
|
||||||
strcat (ctxt->server->isupport, " ");
|
length_isupport + /* existing */
|
||||||
strcat (ctxt->server->isupport, str_info);
|
1 + /* space */
|
||||||
|
length + /* new */
|
||||||
|
1);
|
||||||
|
if (isupport2)
|
||||||
|
{
|
||||||
|
ctxt->server->isupport = isupport2;
|
||||||
|
strcat (ctxt->server->isupport, " ");
|
||||||
|
strcat (ctxt->server->isupport, str_info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -3409,6 +3409,14 @@ irc_server_msgq_add_unterminated (struct t_irc_server *server,
|
|||||||
|
|
||||||
if (server->unterminated_message)
|
if (server->unterminated_message)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* limit the size of the unterminated message: once the maximum is
|
||||||
|
* reached, ignore the extra data (protection against a server sending
|
||||||
|
* a very long line without end-of-line, which would consume all the
|
||||||
|
* memory)
|
||||||
|
*/
|
||||||
|
if (strlen (server->unterminated_message) >= IRC_SERVER_RECV_MSG_MAX_LENGTH)
|
||||||
|
return;
|
||||||
unterminated_message2 =
|
unterminated_message2 =
|
||||||
realloc (server->unterminated_message,
|
realloc (server->unterminated_message,
|
||||||
(strlen (server->unterminated_message) +
|
(strlen (server->unterminated_message) +
|
||||||
|
|||||||
@@ -144,6 +144,15 @@ enum t_irc_server_option
|
|||||||
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_BYTES 4096
|
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_BYTES 4096
|
||||||
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_LINES 24
|
#define IRC_SERVER_MULTILINE_DEFAULT_MAX_LINES 24
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maximum length of an unterminated message (a received line without
|
||||||
|
* end-of-line) and of the accumulated "005" (ISUPPORT) data; these limits
|
||||||
|
* protect against a server sending a huge amount of data without end-of-line
|
||||||
|
* (or a flood of "005" messages), which would consume all the memory
|
||||||
|
*/
|
||||||
|
#define IRC_SERVER_RECV_MSG_MAX_LENGTH (64 * 1024)
|
||||||
|
#define IRC_SERVER_ISUPPORT_MAX_LENGTH (64 * 1024)
|
||||||
|
|
||||||
/* casemapping (string comparisons for nicks/channels) */
|
/* casemapping (string comparisons for nicks/channels) */
|
||||||
enum t_irc_server_casemapping
|
enum t_irc_server_casemapping
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -402,7 +402,10 @@ RELAY_API_PROTOCOL_CALLBACK(handshake)
|
|||||||
if (json_body)
|
if (json_body)
|
||||||
{
|
{
|
||||||
if (!cJSON_IsObject (json_body))
|
if (!cJSON_IsObject (json_body))
|
||||||
|
{
|
||||||
|
cJSON_Delete (json_body);
|
||||||
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
||||||
|
}
|
||||||
json_algos = cJSON_GetObjectItem (json_body, "password_hash_algo");
|
json_algos = cJSON_GetObjectItem (json_body, "password_hash_algo");
|
||||||
if (json_algos)
|
if (json_algos)
|
||||||
{
|
{
|
||||||
@@ -781,8 +784,13 @@ RELAY_API_PROTOCOL_CALLBACK(input)
|
|||||||
char str_delay[32];
|
char str_delay[32];
|
||||||
|
|
||||||
json_body = cJSON_Parse (client->http_req->body);
|
json_body = cJSON_Parse (client->http_req->body);
|
||||||
if (!json_body || !cJSON_IsObject (json_body))
|
if (!json_body)
|
||||||
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
||||||
|
if (!cJSON_IsObject (json_body))
|
||||||
|
{
|
||||||
|
cJSON_Delete (json_body);
|
||||||
|
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
/* get buffer either by name or by id */
|
/* get buffer either by name or by id */
|
||||||
ptr_buffer = NULL;
|
ptr_buffer = NULL;
|
||||||
@@ -908,8 +916,13 @@ RELAY_API_PROTOCOL_CALLBACK(completion)
|
|||||||
struct t_gui_buffer *ptr_buffer;
|
struct t_gui_buffer *ptr_buffer;
|
||||||
|
|
||||||
json_body = cJSON_Parse (client->http_req->body);
|
json_body = cJSON_Parse (client->http_req->body);
|
||||||
if (!json_body || !cJSON_IsObject(json_body))
|
if (!json_body)
|
||||||
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
||||||
|
if (!cJSON_IsObject(json_body))
|
||||||
|
{
|
||||||
|
cJSON_Delete (json_body);
|
||||||
|
return RELAY_API_PROTOCOL_RC_BAD_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
/* get buffer either by name or by id */
|
/* get buffer either by name or by id */
|
||||||
ptr_buffer = NULL;
|
ptr_buffer = NULL;
|
||||||
|
|||||||
@@ -513,6 +513,19 @@ relay_http_add_to_body (struct t_relay_http_request *request,
|
|||||||
if (!partial_message || !*partial_message)
|
if (!partial_message || !*partial_message)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reject the body if its announced length is too big: this prevents a
|
||||||
|
* client from forcing an unbounded allocation by announcing a huge
|
||||||
|
* "Content-Length"
|
||||||
|
*/
|
||||||
|
if (request->content_length > RELAY_HTTP_BODY_MAX_LENGTH)
|
||||||
|
{
|
||||||
|
free (*partial_message);
|
||||||
|
*partial_message = NULL;
|
||||||
|
request->status = RELAY_HTTP_END;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
num_bytes_missing = request->content_length
|
num_bytes_missing = request->content_length
|
||||||
- request->body_size;
|
- request->body_size;
|
||||||
if (num_bytes_missing <= 0)
|
if (num_bytes_missing <= 0)
|
||||||
@@ -993,6 +1006,14 @@ relay_http_recv (struct t_relay_client *client, const char *data, int size)
|
|||||||
|
|
||||||
if (client->partial_message)
|
if (client->partial_message)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* limit the size of the partial message: once the maximum is reached,
|
||||||
|
* ignore the extra data (protection against a client sending a huge
|
||||||
|
* amount of data without any end-of-line and dribbling it, which would
|
||||||
|
* consume all the memory)
|
||||||
|
*/
|
||||||
|
if (strlen (client->partial_message) >= RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH)
|
||||||
|
return;
|
||||||
new_partial = realloc (client->partial_message,
|
new_partial = realloc (client->partial_message,
|
||||||
strlen (client->partial_message) +
|
strlen (client->partial_message) +
|
||||||
strlen (data) + 1);
|
strlen (data) + 1);
|
||||||
@@ -1695,7 +1716,7 @@ relay_http_print_log_request (struct t_relay_http_request *request)
|
|||||||
weechat_log_printf (" path_items. . . . . . . : %p", request->path_items);
|
weechat_log_printf (" path_items. . . . . . . : %p", request->path_items);
|
||||||
if (request->path_items)
|
if (request->path_items)
|
||||||
{
|
{
|
||||||
for (i = 0; request->path_items[0]; i++)
|
for (i = 0; request->path_items[i]; i++)
|
||||||
{
|
{
|
||||||
weechat_log_printf (" '%s'", request->path_items[i]);
|
weechat_log_printf (" '%s'", request->path_items[i]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,22 @@ enum t_relay_client_http_status
|
|||||||
#define RELAY_HTTP_ERROR_METHOD_NOT_ALLOWED "Method Not Allowed"
|
#define RELAY_HTTP_ERROR_METHOD_NOT_ALLOWED "Method Not Allowed"
|
||||||
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
|
#define RELAY_HTTP_ERROR_OUT_OF_MEMORY "Out of memory"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maximum length of an HTTP request body: used as an upper bound on the
|
||||||
|
* "Content-Length" accepted from a client, to prevent a client from forcing
|
||||||
|
* an unbounded allocation by announcing a huge body
|
||||||
|
*/
|
||||||
|
#define RELAY_HTTP_BODY_MAX_LENGTH (8 * 1024 * 1024)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maximum length of the partial message accumulated while reading an HTTP
|
||||||
|
* request: once this limit is reached, the extra data is ignored; this
|
||||||
|
* protects against a client sending a huge amount of data without any
|
||||||
|
* end-of-line (an unterminated method or header line), which would consume
|
||||||
|
* all the memory
|
||||||
|
*/
|
||||||
|
#define RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH (8 * 1024 * 1024)
|
||||||
|
|
||||||
struct t_relay_http_request
|
struct t_relay_http_request
|
||||||
{
|
{
|
||||||
enum t_relay_client_http_status status; /* HTTP status */
|
enum t_relay_client_http_status status; /* HTTP status */
|
||||||
|
|||||||
@@ -653,7 +653,7 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
|||||||
size_t size_decompressed;
|
size_t size_decompressed;
|
||||||
char *payload_decompressed;
|
char *payload_decompressed;
|
||||||
struct t_relay_websocket_frame *frames2, *ptr_frame;
|
struct t_relay_websocket_frame *frames2, *ptr_frame;
|
||||||
int size, masked_frame, mask[4];
|
int size, compressed, masked_frame, mask[4];
|
||||||
|
|
||||||
if (!buffer || !frames || !num_frames)
|
if (!buffer || !frames || !num_frames)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -674,6 +674,9 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
|||||||
|
|
||||||
opcode = buffer[index_buffer] & 15;
|
opcode = buffer[index_buffer] & 15;
|
||||||
|
|
||||||
|
/* RSV1 indicates whether this message is compressed */
|
||||||
|
compressed = (buffer[index_buffer] & 64) ? 1 : 0;
|
||||||
|
|
||||||
/* check if frame is masked */
|
/* check if frame is masked */
|
||||||
masked_frame = (buffer[index_buffer + 1] & 128) ? 1 : 0;
|
masked_frame = (buffer[index_buffer + 1] & 128) ? 1 : 0;
|
||||||
|
|
||||||
@@ -703,6 +706,14 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
|||||||
index_buffer += length_frame_size;
|
index_buffer += length_frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reject the frame if its announced length is too big: this prevents
|
||||||
|
* a client from forcing an unbounded allocation (and unbounded
|
||||||
|
* accumulation of partial frames) by announcing a huge frame
|
||||||
|
*/
|
||||||
|
if (length_frame > WEBSOCKET_FRAME_MAX_LENGTH)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (masked_frame)
|
if (masked_frame)
|
||||||
{
|
{
|
||||||
/* read mask (4 bytes) */
|
/* read mask (4 bytes) */
|
||||||
@@ -772,9 +783,9 @@ relay_websocket_decode_frame (const unsigned char *buffer,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* decompress data if frame is not empty and if "permessage-deflate"
|
* decompress data if frame is not empty and if "permessage-deflate"
|
||||||
* is enabled
|
* is enabled and the message is compressed
|
||||||
*/
|
*/
|
||||||
if ((length_frame > 0) && ws_deflate && ws_deflate->enabled)
|
if ((length_frame > 0) && ws_deflate && ws_deflate->enabled && compressed)
|
||||||
{
|
{
|
||||||
if (!ws_deflate->strm_inflate)
|
if (!ws_deflate->strm_inflate)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,6 +41,14 @@
|
|||||||
|
|
||||||
#define WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "api.weechat"
|
#define WEBSOCKET_SUB_PROTOCOL_API_WEECHAT "api.weechat"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* maximum length of a websocket frame received from a client (or a remote
|
||||||
|
* WeeChat): used as an upper bound on the announced frame payload length, to
|
||||||
|
* prevent a client from forcing an unbounded allocation by announcing a huge
|
||||||
|
* frame and dribbling its payload
|
||||||
|
*/
|
||||||
|
#define WEBSOCKET_FRAME_MAX_LENGTH (8 * 1024 * 1024)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* maximum size of a decompressed websocket frame (with "permessage-deflate"):
|
* maximum size of a decompressed websocket frame (with "permessage-deflate"):
|
||||||
* used as an upper bound when inflating, to prevent a small compressed frame
|
* used as an upper bound when inflating, to prevent a small compressed frame
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ xfer_chat_recv_cb (const void *pointer, void *data, int fd)
|
|||||||
{
|
{
|
||||||
ctcp_action = 0;
|
ctcp_action = 0;
|
||||||
length = strlen (ptr_buf);
|
length = strlen (ptr_buf);
|
||||||
if (ptr_buf[length - 1] == '\r')
|
if ((length > 0) && (ptr_buf[length - 1] == '\r'))
|
||||||
{
|
{
|
||||||
ptr_buf[length - 1] = '\0';
|
ptr_buf[length - 1] = '\0';
|
||||||
length--;
|
length--;
|
||||||
|
|||||||
@@ -242,8 +242,8 @@ int
|
|||||||
xfer_dcc_resume_hash (struct t_xfer *xfer)
|
xfer_dcc_resume_hash (struct t_xfer *xfer)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
unsigned long long total_read;
|
unsigned long long total_read, length_buf, to_read;
|
||||||
ssize_t length_buf, to_read, num_read;
|
ssize_t num_read;
|
||||||
int ret, fd;
|
int ret, fd;
|
||||||
|
|
||||||
total_read = 0;
|
total_read = 0;
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ xfer_file_find_suffix (struct t_xfer *xfer)
|
|||||||
void
|
void
|
||||||
xfer_file_find_filename (struct t_xfer *xfer)
|
xfer_file_find_filename (struct t_xfer *xfer)
|
||||||
{
|
{
|
||||||
char *dir_separator, *path;
|
char *dir_separator, *path, *nick;
|
||||||
struct t_hashtable *options;
|
struct t_hashtable *options;
|
||||||
|
|
||||||
if (!XFER_IS_FILE(xfer->type))
|
if (!XFER_IS_FILE(xfer->type))
|
||||||
@@ -287,12 +287,20 @@ xfer_file_find_filename (struct t_xfer *xfer)
|
|||||||
{
|
{
|
||||||
strcat (xfer->local_filename, dir_separator);
|
strcat (xfer->local_filename, dir_separator);
|
||||||
}
|
}
|
||||||
free (dir_separator);
|
|
||||||
if (weechat_config_boolean (xfer_config_file_use_nick_in_filename))
|
if (weechat_config_boolean (xfer_config_file_use_nick_in_filename))
|
||||||
{
|
{
|
||||||
strcat (xfer->local_filename, xfer->remote_nick);
|
/*
|
||||||
|
* the remote nick comes from the server and can contain a directory
|
||||||
|
* separator: replace it so the nick cannot make the file be written
|
||||||
|
* outside the download directory
|
||||||
|
*/
|
||||||
|
nick = (dir_separator) ?
|
||||||
|
weechat_string_replace (xfer->remote_nick, dir_separator, "_") : NULL;
|
||||||
|
strcat (xfer->local_filename, (nick) ? nick : xfer->remote_nick);
|
||||||
|
free (nick);
|
||||||
strcat (xfer->local_filename, ".");
|
strcat (xfer->local_filename, ".");
|
||||||
}
|
}
|
||||||
|
free (dir_separator);
|
||||||
strcat (xfer->local_filename, xfer->filename);
|
strcat (xfer->local_filename, xfer->filename);
|
||||||
|
|
||||||
free (path);
|
free (path);
|
||||||
|
|||||||
@@ -1454,6 +1454,8 @@ TEST(CoreString, Replace)
|
|||||||
WEE_TEST_STR(NULL, string_replace ("string", NULL, "replace"));
|
WEE_TEST_STR(NULL, string_replace ("string", NULL, "replace"));
|
||||||
WEE_TEST_STR(NULL, string_replace (NULL, "search", "replace"));
|
WEE_TEST_STR(NULL, string_replace (NULL, "search", "replace"));
|
||||||
|
|
||||||
|
WEE_TEST_STR("test abc def", string_replace("test abc def", "", "xxx"));
|
||||||
|
|
||||||
WEE_TEST_STR("test abc def", string_replace("test abc def", "xyz", "xxx"));
|
WEE_TEST_STR("test abc def", string_replace("test abc def", "xyz", "xxx"));
|
||||||
WEE_TEST_STR("test xxx def", string_replace("test abc def", "abc", "xxx"));
|
WEE_TEST_STR("test xxx def", string_replace("test abc def", "abc", "xxx"));
|
||||||
WEE_TEST_STR("xxx test xxx def xxx",
|
WEE_TEST_STR("xxx test xxx def xxx",
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ TEST_GROUP(IrcProtocolWithServer)
|
|||||||
|
|
||||||
void server_recv (const char *command)
|
void server_recv (const char *command)
|
||||||
{
|
{
|
||||||
char str_command[4096];
|
char str_command[8192];
|
||||||
|
|
||||||
record_start ();
|
record_start ();
|
||||||
arraylist_clear (sent_messages);
|
arraylist_clear (sent_messages);
|
||||||
@@ -3866,6 +3866,44 @@ TEST(IrcProtocolWithServer, 005_full)
|
|||||||
STRCMP_EQUAL(IRC_MSG_005 " " IRC_MSG_005, ptr_server->isupport);
|
STRCMP_EQUAL(IRC_MSG_005 " " IRC_MSG_005, ptr_server->isupport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* irc_protocol_cb_005 (accumulated ISUPPORT is bounded)
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(IrcProtocolWithServer, 005_limit)
|
||||||
|
{
|
||||||
|
char str_msg[4096], str_value[3500];
|
||||||
|
size_t length1, length2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SRV_INIT;
|
||||||
|
|
||||||
|
memset (str_value, 'X', sizeof (str_value) - 1);
|
||||||
|
str_value[sizeof (str_value) - 1] = '\0';
|
||||||
|
snprintf (str_msg, sizeof (str_msg),
|
||||||
|
":server 005 alice TEST=%s :are supported", str_value);
|
||||||
|
|
||||||
|
/* flood the server with "005" messages */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
server_recv (str_msg);
|
||||||
|
}
|
||||||
|
CHECK(ptr_server->isupport);
|
||||||
|
length1 = strlen (ptr_server->isupport);
|
||||||
|
|
||||||
|
/* the accumulated ISUPPORT data must be bounded */
|
||||||
|
CHECK(length1 <= IRC_SERVER_ISUPPORT_MAX_LENGTH + sizeof (str_value));
|
||||||
|
|
||||||
|
/* receiving more "005" messages must not grow it any further */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
server_recv (str_msg);
|
||||||
|
}
|
||||||
|
length2 = strlen (ptr_server->isupport);
|
||||||
|
LONGS_EQUAL(length1, length2);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* irc_protocol_cb_005 (infos from server, multiple messages)
|
* irc_protocol_cb_005 (infos from server, multiple messages)
|
||||||
|
|||||||
@@ -65,6 +65,49 @@ TEST(IrcServer, Valid)
|
|||||||
irc_server_free (server);
|
irc_server_free (server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* irc_server_msgq_add_unterminated (via irc_server_msgq_add_buffer)
|
||||||
|
*
|
||||||
|
* Check that data received without any end-of-line does not grow the
|
||||||
|
* unterminated message buffer without limit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(IrcServer, MsgqAddBufferLimit)
|
||||||
|
{
|
||||||
|
struct t_irc_server *server;
|
||||||
|
char chunk[4097];
|
||||||
|
int i;
|
||||||
|
size_t length1, length2;
|
||||||
|
|
||||||
|
server = irc_server_alloc ("server_msgq");
|
||||||
|
CHECK(server);
|
||||||
|
|
||||||
|
memset (chunk, 'a', sizeof (chunk) - 1);
|
||||||
|
chunk[sizeof (chunk) - 1] = '\0';
|
||||||
|
|
||||||
|
/* feed a lot of data with no end-of-line */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
irc_server_msgq_add_buffer (server, chunk);
|
||||||
|
}
|
||||||
|
CHECK(server->unterminated_message);
|
||||||
|
length1 = strlen (server->unterminated_message);
|
||||||
|
|
||||||
|
/* the buffer must be bounded (not ~400 KB) */
|
||||||
|
CHECK(length1 <= IRC_SERVER_RECV_MSG_MAX_LENGTH + sizeof (chunk));
|
||||||
|
|
||||||
|
/* feeding more data must not grow the buffer any further */
|
||||||
|
for (i = 0; i < 100; i++)
|
||||||
|
{
|
||||||
|
irc_server_msgq_add_buffer (server, chunk);
|
||||||
|
}
|
||||||
|
length2 = strlen (server->unterminated_message);
|
||||||
|
LONGS_EQUAL(length1, length2);
|
||||||
|
|
||||||
|
irc_server_free (server);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* irc_server_search
|
* irc_server_search
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ extern "C"
|
|||||||
#include "src/plugins/relay/relay-client.h"
|
#include "src/plugins/relay/relay-client.h"
|
||||||
#include "src/plugins/relay/relay-config.h"
|
#include "src/plugins/relay/relay-config.h"
|
||||||
#include "src/plugins/relay/relay-http.h"
|
#include "src/plugins/relay/relay-http.h"
|
||||||
|
#include "src/plugins/relay/relay-server.h"
|
||||||
#include "src/plugins/relay/relay-websocket.h"
|
#include "src/plugins/relay/relay-websocket.h"
|
||||||
#include "src/plugins/weechat-plugin.h"
|
#include "src/plugins/weechat-plugin.h"
|
||||||
|
|
||||||
@@ -161,6 +162,35 @@ TEST(RelayHttp, RequestAllocReinitFree)
|
|||||||
relay_http_request_free (request);
|
relay_http_request_free (request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* relay_http_add_to_body (body too large is rejected)
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(RelayHttp, AddToBodyLimit)
|
||||||
|
{
|
||||||
|
struct t_relay_http_request *request;
|
||||||
|
char *partial;
|
||||||
|
|
||||||
|
request = relay_http_request_alloc ();
|
||||||
|
CHECK(request);
|
||||||
|
|
||||||
|
/* announce a body larger than the maximum allowed */
|
||||||
|
request->status = RELAY_HTTP_BODY;
|
||||||
|
request->content_length = RELAY_HTTP_BODY_MAX_LENGTH + 1;
|
||||||
|
partial = strdup ("some body data");
|
||||||
|
|
||||||
|
relay_http_add_to_body (request, &partial);
|
||||||
|
|
||||||
|
/* the body must be rejected: nothing allocated, request ended */
|
||||||
|
POINTERS_EQUAL(NULL, request->body);
|
||||||
|
LONGS_EQUAL(0, request->body_size);
|
||||||
|
POINTERS_EQUAL(NULL, partial);
|
||||||
|
LONGS_EQUAL(RELAY_HTTP_END, request->status);
|
||||||
|
|
||||||
|
relay_http_request_free (request);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* relay_http_url_decode
|
* relay_http_url_decode
|
||||||
@@ -992,6 +1022,69 @@ TEST(RelayHttp, Recv)
|
|||||||
/* TODO: write tests */
|
/* TODO: write tests */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test functions:
|
||||||
|
* relay_http_recv (partial message accumulated is bounded)
|
||||||
|
*
|
||||||
|
* Check that data received without any end-of-line does not grow the partial
|
||||||
|
* message buffer without limit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
TEST(RelayHttp, RecvLimit)
|
||||||
|
{
|
||||||
|
struct t_relay_server *server;
|
||||||
|
struct t_relay_client *client;
|
||||||
|
char *chunk;
|
||||||
|
int chunk_size, i;
|
||||||
|
size_t length1, length2;
|
||||||
|
|
||||||
|
/* disable auto-open of relay buffer (it would pollute other tests) */
|
||||||
|
config_file_option_set (relay_config_look_auto_open_buffer, "off", 1);
|
||||||
|
|
||||||
|
server = relay_server_new ("weechat", RELAY_PROTOCOL_WEECHAT, NULL,
|
||||||
|
9000,
|
||||||
|
NULL, /* path */
|
||||||
|
1, /* ipv4 */
|
||||||
|
0, /* ipv6 */
|
||||||
|
0, /* tls */
|
||||||
|
0); /* unix_socket */
|
||||||
|
CHECK(server);
|
||||||
|
client = relay_client_new (-1, "test", server);
|
||||||
|
CHECK(client);
|
||||||
|
|
||||||
|
chunk_size = 1024 * 1024;
|
||||||
|
chunk = (char *)malloc (chunk_size + 1);
|
||||||
|
CHECK(chunk);
|
||||||
|
memset (chunk, 'a', chunk_size);
|
||||||
|
chunk[chunk_size] = '\0';
|
||||||
|
|
||||||
|
/* feed more than the maximum, with no end-of-line (16 MB) */
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
relay_http_recv (client, chunk, chunk_size);
|
||||||
|
}
|
||||||
|
CHECK(client->partial_message);
|
||||||
|
length1 = strlen (client->partial_message);
|
||||||
|
|
||||||
|
/* the partial message must be bounded (not ~16 MB) */
|
||||||
|
CHECK(length1 <= RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH + (size_t)chunk_size);
|
||||||
|
|
||||||
|
/* feeding more data must not grow it any further */
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
relay_http_recv (client, chunk, chunk_size);
|
||||||
|
}
|
||||||
|
length2 = strlen (client->partial_message);
|
||||||
|
LONGS_EQUAL(length1, length2);
|
||||||
|
|
||||||
|
free (chunk);
|
||||||
|
relay_client_free (client);
|
||||||
|
relay_server_free (server);
|
||||||
|
|
||||||
|
/* restore auto-open of relay buffer */
|
||||||
|
config_file_option_reset (relay_config_look_auto_open_buffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* relay_http_compress
|
* relay_http_compress
|
||||||
|
|||||||
@@ -510,7 +510,44 @@ TEST(RelayWebsocket, Inflate)
|
|||||||
|
|
||||||
TEST(RelayWebsocket, DecodeFrame)
|
TEST(RelayWebsocket, DecodeFrame)
|
||||||
{
|
{
|
||||||
/* TODO: write tests */
|
struct t_relay_websocket_frame *frames;
|
||||||
|
char *partial_ws_frame;
|
||||||
|
int num_frames, partial_ws_frame_size;
|
||||||
|
/* small unmasked binary frame with payload "hello" */
|
||||||
|
unsigned char frame_ok[7] = { 0x82, 0x05, 'h', 'e', 'l', 'l', 'o' };
|
||||||
|
/* masked frame announcing a 1 GB payload (64-bit length field) */
|
||||||
|
unsigned char frame_too_big[10] = {
|
||||||
|
0x82, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* a valid small frame is decoded */
|
||||||
|
frames = NULL;
|
||||||
|
num_frames = 0;
|
||||||
|
partial_ws_frame = NULL;
|
||||||
|
partial_ws_frame_size = 0;
|
||||||
|
LONGS_EQUAL(1, relay_websocket_decode_frame (
|
||||||
|
frame_ok, sizeof (frame_ok), 0, NULL,
|
||||||
|
&frames, &num_frames, &partial_ws_frame,
|
||||||
|
&partial_ws_frame_size));
|
||||||
|
LONGS_EQUAL(1, num_frames);
|
||||||
|
CHECK(frames);
|
||||||
|
LONGS_EQUAL(5, frames[0].payload_size);
|
||||||
|
MEMCMP_EQUAL("hello", frames[0].payload, 5);
|
||||||
|
free (frames[0].payload);
|
||||||
|
free (frames);
|
||||||
|
free (partial_ws_frame);
|
||||||
|
|
||||||
|
/* a frame announcing an oversized payload is rejected (return 0) */
|
||||||
|
frames = NULL;
|
||||||
|
num_frames = 0;
|
||||||
|
partial_ws_frame = NULL;
|
||||||
|
partial_ws_frame_size = 0;
|
||||||
|
LONGS_EQUAL(0, relay_websocket_decode_frame (
|
||||||
|
frame_too_big, sizeof (frame_too_big), 1, NULL,
|
||||||
|
&frames, &num_frames, &partial_ws_frame,
|
||||||
|
&partial_ws_frame_size));
|
||||||
|
free (frames);
|
||||||
|
free (partial_ws_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -25,6 +25,11 @@
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "src/core/core-config-file.h"
|
||||||
|
#include "src/plugins/xfer/xfer.h"
|
||||||
|
#include "src/plugins/xfer/xfer-config.h"
|
||||||
#include "src/plugins/xfer/xfer-file.h"
|
#include "src/plugins/xfer/xfer-file.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +37,42 @@ TEST_GROUP(XferFile)
|
|||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build a "file recv" xfer with the given remote nick (and a fixed filename),
|
||||||
|
* call xfer_file_find_filename and return a copy of the basename of the local
|
||||||
|
* filename (the part after the last directory separator).
|
||||||
|
*
|
||||||
|
* Note: result must be freed after use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char *
|
||||||
|
test_find_filename_basename (const char *remote_nick)
|
||||||
|
{
|
||||||
|
struct t_xfer xfer;
|
||||||
|
char *pos, *result;
|
||||||
|
|
||||||
|
memset (&xfer, 0, sizeof (xfer));
|
||||||
|
xfer.type = XFER_TYPE_FILE_RECV_ACTIVE;
|
||||||
|
xfer.remote_nick = strdup (remote_nick);
|
||||||
|
xfer.filename = strdup ("test.txt");
|
||||||
|
|
||||||
|
xfer_file_find_filename (&xfer);
|
||||||
|
|
||||||
|
result = NULL;
|
||||||
|
if (xfer.local_filename)
|
||||||
|
{
|
||||||
|
pos = strrchr (xfer.local_filename, DIR_SEPARATOR_CHAR);
|
||||||
|
result = strdup ((pos) ? pos + 1 : xfer.local_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
free (xfer.remote_nick);
|
||||||
|
free (xfer.filename);
|
||||||
|
free (xfer.local_filename);
|
||||||
|
free (xfer.temp_local_filename);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test functions:
|
* Test functions:
|
||||||
* xfer_file_search_crc32
|
* xfer_file_search_crc32
|
||||||
@@ -91,7 +132,30 @@ TEST(XferFile, FindSuffix)
|
|||||||
|
|
||||||
TEST(XferFile, FindFilename)
|
TEST(XferFile, FindFilename)
|
||||||
{
|
{
|
||||||
/* TODO: write tests */
|
char *basename;
|
||||||
|
|
||||||
|
config_file_option_set (xfer_config_file_download_path, "/tmp/weechat_test_xfer", 1);
|
||||||
|
|
||||||
|
/* remote nick without directory separator: used as-is */
|
||||||
|
basename = test_find_filename_basename ("alice");
|
||||||
|
STRCMP_EQUAL("alice.test.txt", basename);
|
||||||
|
free (basename);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remote nick with a directory separator: the separator is replaced by
|
||||||
|
* "_" so the nick cannot make the file be written outside the download
|
||||||
|
* directory
|
||||||
|
*/
|
||||||
|
basename = test_find_filename_basename ("../foo");
|
||||||
|
STRCMP_EQUAL(".._foo.test.txt", basename);
|
||||||
|
free (basename);
|
||||||
|
|
||||||
|
/* all directory separators in the nick are replaced */
|
||||||
|
basename = test_find_filename_basename ("a/b/c");
|
||||||
|
STRCMP_EQUAL("a_b_c.test.txt", basename);
|
||||||
|
free (basename);
|
||||||
|
|
||||||
|
config_file_option_unset (xfer_config_file_download_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+2
-2
@@ -41,8 +41,8 @@
|
|||||||
# devel-number the devel version as hex number ("0x04010000" for "4.1.0-dev")
|
# devel-number the devel version as hex number ("0x04010000" for "4.1.0-dev")
|
||||||
#
|
#
|
||||||
|
|
||||||
weechat_stable="4.9.1"
|
weechat_stable="4.9.2"
|
||||||
weechat_devel="4.9.1"
|
weechat_devel="4.9.3-dev"
|
||||||
|
|
||||||
stable_major=$(echo "${weechat_stable}" | cut -d"." -f1)
|
stable_major=$(echo "${weechat_stable}" | cut -d"." -f1)
|
||||||
stable_minor=$(echo "${weechat_stable}" | cut -d"." -f2)
|
stable_minor=$(echo "${weechat_stable}" | cut -d"." -f2)
|
||||||
|
|||||||
Reference in New Issue
Block a user