1
0
mirror of https://github.com/weechat/weechat.git synced 2026-06-12 14:14:48 +02:00
Commit Graph

13817 Commits

Author SHA1 Message Date
Sébastien Helleu 91223591e9 exec: contribute "light" theme overrides
Add exec-theme.{c,h} with the exec plugin contribution to the built-in
"light" theme: 2 entries (exec.color.flag_finished=red,
exec.color.flag_running=green) tuned for a light-background terminal.

Same 2D-array pattern as the other plugin contributions.

Default option values are NOT changed.
2026-06-08 09:39:22 +02:00
Sébastien Helleu f50b91a6d9 xfer: contribute "light" theme overrides
Add xfer-theme.{c,h} with the xfer plugin contribution to the built-in
"light" theme: 7 overrides on xfer.color.* (status_aborted,
status_active, status_connecting, status_done, status_failed,
status_waiting, text_selected) tuned for a light-background terminal.

Same NULL-terminated 2D-array pattern as the irc, fset and buflist
contributions; xfer_theme_init() is called once from
weechat_plugin_init after xfer_config_init / xfer_config_read.

Default option values are NOT changed.
2026-06-08 09:39:22 +02:00
Sébastien Helleu d2d490146c buflist: contribute "light" theme overrides
Add buflist-theme.{c,h} with the buflist plugin contribution to the
built-in "light" theme: 5 overrides on buflist.format.* options
(buffer_current, hotlist_low, hotlist_message, lag, number) tuned for
a light-background terminal. Each target is a "string|themable" option
holding an evaluated format expression with embedded ${color:...}
references.

Follows the same pattern as the irc and fset contributions: a
NULL-terminated 2D string table consumed by a tiny local register
helper that builds a hashtable and calls weechat_theme_register;
buflist_theme_init() is called once from weechat_plugin_init after
buflist_config_init / buflist_config_read.

Default option values are NOT changed.
2026-06-08 09:39:22 +02:00
Sébastien Helleu f587a9dcaf fset: contribute "light" theme overrides
Add fset-theme.{c,h} with the fset plugin contribution to the built-in
"light" theme: 47 overrides on fset.color.* options (line backgrounds,
selected-row tuning, title and value colors) tuned for a
light-background terminal.

The table is a NULL-terminated 2-column array of strings (no struct
wrapper, matching the pattern adopted for the irc contribution).
fset_theme_register builds a hashtable from the table and calls
weechat_theme_register; fset_theme_init() is called once from
weechat_plugin_init after fset_config_init / fset_config_read.

Default option values are NOT changed.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 54b0753aab irc: contribute "light" theme overrides
Add irc-theme.{c,h} with the IRC plugin contribution to the built-in
"light" theme: 9 overrides on irc.color.* options tuned for a
light-background terminal (input_nick, item_lag_finished,
item_tls_version_deprecated, list_buffer_line_selected,
message_chghost, message_setname, nick_prefixes, topic_new, topic_old).

The registration is a small wrapper around weechat_theme_register that
builds a hashtable from a static (option, value) table and frees it
after the call. irc_theme_init() is called from weechat_plugin_init
after irc_config_init/read so the option names are already created
when the theme registry references them.

Default option values are NOT changed.
2026-06-08 09:39:22 +02:00
Sébastien Helleu d189ca7f19 core: register built-in "light" theme
Add a small core-theme-builtin.c module containing the core
contribution to the "light" theme: 33 overrides for
"weechat.bar.{status,title}.color_*" and "weechat.color.*" tuned for
light-background terminals.

theme_builtin_init() builds a hashtable from the static entry table and
calls theme_register("light", overrides), then frees the temporary
hashtable. It is called once from weechat_init right after theme_init.
Calling it twice is a no-op (the registry merges identical keys).

Default option values are NOT changed. Existing configs render exactly
as before; users opt in with "/theme apply light".

Add TEST(CoreTheme, BuiltinInit) covering:
  - the "light" theme is absent before theme_builtin_init();
  - it is present after, with >= 30 overrides;
  - three spot-checked values match the source table;
  - calling theme_builtin_init() a second time does not change the
    override count.

Plugins contribute their own "light" overrides via weechat_theme_register
in subsequent commits.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 86d8bec433 script: expose theme_register to python, perl, ruby, lua, tcl, javascript, php, guile
Add weechat.theme_register (name, overrides) to all eight script
languages. Each binding is a mechanical translation of the same
signature:

  - name:      string
  - overrides: language-native dict / hash / associative array of
               full_option_name -> value strings
  - returns:   pointer-as-string of the registered t_theme (empty
               string on failure)

Each binding converts the dict to a struct t_hashtable using the
existing per-language helper (weechat_python_dict_to_hashtable,
weechat_perl_hash_to_hashtable, weechat_ruby_hash_to_hashtable,
weechat_lua_tohashtable, weechat_tcl_dict_to_hashtable,
weechat_js_object_to_hashtable, weechat_php_array_to_hashtable,
weechat_guile_alist_to_hashtable), calls weechat_theme_register,
frees the temporary hashtable, and returns the result. The new
function is registered right after the config_* functions so the API
listing stays grouped by topic.

PHP also receives a new arginfo entry (string, array -> string) in
both weechat-php_arginfo.h and weechat-php_legacy_arginfo.h.

This is plumbing only - the underlying theme_register function is
already covered by tests/unit/core/test-core-theme.cpp
(TEST(CoreTheme, Register)). No script-side tests are added here.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 53db79aa5f api: expose theme_register to plugins
Add a single new entry point to the plugin API:

  struct t_theme *weechat_theme_register (const char *name,
                                          struct t_hashtable *overrides);

Plugins call this at init time to contribute their per-theme color (or
other themable) overrides for a built-in theme like "dark". The
overrides hashtable maps full option names ("irc.color.input_nick") to
their string values; the caller retains ownership and may free it
right after the call. Repeated calls with the same theme name merge
into the existing registry entry, so each plugin can declare its own
contributions independently of core and of other plugins.

Wiring:

- struct t_theme forward-declared in weechat-plugin.h alongside the
  other opaque types.
- theme_register function pointer added to t_weechat_plugin.
- weechat_theme_register convenience macro added.
- plugin.c initializes the pointer to core's theme_register.
- WEECHAT_PLUGIN_API_VERSION bumped to 20260526-01.

This commit is plumbing only: the underlying theme_register function
already has unit-test coverage in tests/unit/core/test-core-theme.cpp
(TEST(CoreTheme, Register)), so no new tests are added here.
2026-06-08 09:39:22 +02:00
Sébastien Helleu b994a645e3 core: add theme name completion
Add two completion items hooked alongside "layouts_names":

- "theme_themes_all": all theme names (built-ins from the registry
  plus every *.theme file in <weechat_config_dir>/themes/, including
  backup-*.theme). Used by tab-complete on /theme apply and
  /theme info.
- "theme_themes_user": user theme files only (excludes built-ins
  and backup-*.theme). Used by tab-complete on /theme save and
  /theme delete, so users cannot accidentally try to overwrite a
  built-in name or save a name colliding with the reserved backup
  prefix.

Both callbacks share a small dir_exec_on_files-based helper to filter
the themes directory. The /theme command's completion template in
core-command.c is updated to reference these new items.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 64f17761f1 core: implement /theme save and /theme delete
Add two complementary subcommands:

  /theme save <name> [-full]: writes a user theme file at
    ${weechat_config_dir}/themes/<name>.theme containing the current
    themable options. By default only options whose value differs from
    their default (config_file_option_has_changed) are written, which
    keeps the file small and focused. Pass "-full" to write every
    themable option (matches the format used by automatic backups).

    Name validation: refuses any name matching a built-in theme (those
    are reserved for in-memory registrations) and any name starting
    with "backup-" (reserved for /theme apply backups). Both checks
    print an error and abort without writing.

  /theme delete <name>: removes ${weechat_config_dir}/themes/<name>.theme
    via unlink. Refuses to delete a name registered as a built-in
    theme (a built-in has no file on disk to delete, even if the user
    has a shadowing file of the same name they cannot remove it this
    way; they can rename or delete it manually).

The full-snapshot writer used by /theme apply backups is refactored
into theme_write_file (name, description, diff_only). It is reused
by theme_make_backup (diff_only=0) and theme_save (diff_only inverted
from the user's -full flag).

Bug fix while at it: the writer was previously calling
config_file_option_value_to_string (ptr_option, 0, 1, 0); the third
and fourth arguments are "use_colors" and "use_delimiters", so the
call inserted GUI color escape codes into the file output and skipped
quoting strings. Corrected to (ptr_option, 0, 0, 1) so plain text
with proper string quoting is written; the change also fixes the
content of files produced by theme_make_backup in the previous commit.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 3bdb31bbf6 core: implement theme file parsing and transient file reads in /theme apply
Add a small INI-style parser for *.theme files and wire it into the
/theme command so user themes living in directory "themes" inside the
WeeChat configuration directory can be applied (and inspected) without
ever being cached.

Parser (theme_file_parse in core-theme.c) accepts two sections:

  [info]
  name = "..."          \ shown by /theme info; ignored for apply
  description = "..."   |
  date = "..."          |
  weechat = "..."       /
  (unknown keys are ignored with a warning)

  [options]
  full.option.name = "value"

Surrounding single or double quotes around a value are stripped (same
rule used by the regular config file reader). The parsed result is a
heap-allocated t_theme; the caller frees with theme_free.

Resolution rule in theme_apply: if the path
"${weechat_config_dir}/themes/<name>.theme" is readable it is parsed
and used (file shadows any built-in of the same name); otherwise the
built-in registry is consulted. The transient t_theme is freed before
the final refresh, so user themes have no steady-state memory
footprint regardless of how many .theme files have accumulated.

/theme list now also scans the themes directory and appends user
files to the listing (each marked "(file)"). backup-*.theme are
hidden by default; pass "-backups" to include them.

/theme info <name> works for both sources: file path is shown when the
information comes from disk; "built-in (in-memory)" otherwise.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 7f1f9462f4 core: implement /theme apply with themable enforcement and auto-backup
Implement /theme apply <name> for themes currently in the in-memory
registry. The file-shadowing branch (read a .theme file from
${weechat_config_dir}/themes/ when no built-in matches) is added in
the next commit together with the parser.

Apply algorithm (theme_apply in core-theme.c):

- Look up the theme in the registry; abort with an error if unknown.
- If weechat.look.theme_backup is on and the target name does not
  begin with "backup-", write a full snapshot of every themable
  option to ${weechat_config_dir}/themes/backup-<timestamp>.theme
  via theme_make_backup; abort the apply if the backup cannot be
  written, so the user can always undo.
- Iterate the theme's overrides with theme_applying=1 so the
  per-option config_change_color skips its gui refresh; for each
  entry look up the option, refuse it if missing or non-themable
  (warning to core buffer), otherwise call config_file_option_set.
- Perform a single gui_color_init_weechat + gui_window_ask_refresh
  at the end.
- Persist the active label in weechat.look.theme and send signal
  "theme_applied" with the name as data.

Add the new option weechat.look.theme_backup (boolean, default on)
which controls the backup-or-abort behaviour described above.

Wire the new /theme apply subcommand into core-command.c with the
existing /theme registration; update help text accordingly.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 9fbc81dc54 core: add /theme command with list and info subcommands
Add the /theme command with two read-only subcommands for now:

- /theme  (or  /theme list): list registered themes; the active theme
  (matching weechat.look.theme) is marked with "->".
- /theme info <name>: show name, description, creation date, WeeChat
  version and override count of a theme.

Both subcommands only consider themes present in the in-memory
registry (registered via core/plugins/scripts). User theme files on
disk are not yet handled: the file parser and transient file reads
land in a later commit together with /theme apply.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 4550c3e33a core: add weechat.look.theme option and theme_applying guard
Add a new string option "weechat.look.theme" holding the name of the
last theme applied via the upcoming /theme command. It is set
automatically by /theme apply and persisted on disk for /theme info to
display after restart; it is NOT re-applied at startup (the user's
saved color values win to avoid clobbering manual post-apply tweaks).

Amend config_change_color so it skips the gui_color_init_weechat ()
and gui_window_ask_refresh (1) calls when theme_applying is set.
/theme apply will set this flag while iterating overrides so the N
individual option changes do not trigger N redundant screen refreshes;
the apply path then performs a single refresh at the end.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 7e2b9ffa9a core: add core-theme skeleton and theme registry
Introduce a new module (core-theme.{c,h}) holding the in-memory registry
of built-in themes used by the upcoming /theme command:

- struct t_theme stores name, description, date and weechat version
  captured at registration time, plus a hashtable of overrides keyed by
  full option name (file.section.option) -> value string.
- theme_register (name, overrides) creates a new theme or merges the
  given overrides into an existing one (later calls override duplicate
  keys); this is the API plugins and scripts will use to contribute
  per-theme color values.
- theme_search and theme_list provide lookup and ordered enumeration.
- theme_init / theme_end are called from weechat_init / weechat_end.

The theme_applying flag is declared here but not yet consumed (it will
gate config_change_color in the next commit to avoid N redundant
window refreshes during /theme apply).

User theme files are not handled by this module: they are read
transiently inside /theme apply (a later commit) and never cached.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 04f817814f fset: add "t:themable" filter
Extend the "t:" filter so the special value "themable" matches every
option whose new themable flag is set, regardless of type (color,
string, integer, boolean, enum). This makes the flag interactively
discoverable in the fset buffer and is the natural way to inspect the
surface area that an upcoming /theme command will be allowed to touch.

The themable flag of an option is now mirrored on struct t_fset_option,
exposed via hdata ("themable", integer) and infolist ("themable",
integer), and printed in the log.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 0315c53a9e core: add themable flag to configuration options
Add an "int themable" field on struct t_config_option. The flag is set
automatically for every CONFIG_OPTION_TYPE_COLOR option, and may be set
explicitly on any other type by suffixing the type argument with
"|themable" in the call to config_file_new_option (e.g. "string|themable"
for a string option whose value contains "${color:...}" references).

Opt in the relevant string options in core (buffer_time_format,
day_change_message_*, item_time_format, nick_color_force, prefix_*,
chat_nick_colors, eval_syntax_colors, color palette aliases) and in the
buflist, fset, irc, relay plugins.

The flag is exposed via hdata, infolist, and print_log so scripts and
/debug can read it. This is the foundation for an upcoming /theme
command that will only be allowed to modify themable options.
2026-06-08 09:39:22 +02:00
Sébastien Helleu 3aeaa70e64 ci: bump poexam to version 0.0.11 2026-06-07 21:56:22 +02:00
Sébastien Helleu 66e633e27e core: add version 4.9.2 2026-06-07 11:51:55 +02:00
Sébastien Helleu 436bbeceff tests: increase buffer size for injection of fake IRC message 2026-06-07 08:47:36 +02:00
Sébastien Helleu c307087e2d core: update ChangeLog (#2324) 2026-06-06 11:19:14 +02:00
aizu-m 51a1149852 relay: fix out-of-bounds read in relay_http_print_log_request (#2324) 2026-06-06 11:18:06 +02:00
Sébastien Helleu d74993a42c relay: limit size of partial message received while reading an HTTP request to prevent memory exhaustion
A relay client could send data with no end-of-line (an unterminated method
or header line) and dribble its payload, making WeeChat accumulate it in the
partial message buffer that grew without limit, until all memory was
exhausted. This path is reachable before authentication during websocket
initialization with the "weechat" and "irc" protocols.

The accumulated partial message is now bounded by
RELAY_HTTP_PARTIAL_MESSAGE_MAX_LENGTH: once the limit is reached, the extra
data is ignored.
2026-06-06 09:36:22 +02:00
Sébastien Helleu 51464e400f core: add links to issues in ChangeLog (#2321, #2322) 2026-06-06 07:20:41 +02:00
Sébastien Helleu 1c5e6c3fc2 core: update ChangeLog (#2323) 2026-06-06 07:20:38 +02:00
Sébastien Helleu e563dfc903 doc: add build of Serbian API Relay doc 2026-06-06 07:09:04 +02:00
Sébastien Helleu befbcceb7f relay/api: add field "last_read_line_id" in GET /api/buffers 2026-06-06 07:04:46 +02:00
aizu-m 56f9ad68fb xfer: fix out-of-bounds read in xfer_chat_recv_cb on empty line (#2323) 2026-06-06 07:01:18 +02:00
aizu-m 328f86affc irc: fix out-of-bounds read in DCC command with quoted filename 2026-06-04 23:17:58 +02:00
Sébastien Helleu f4dc30ec58 tests: add tests on function xfer_file_find_filename 2026-06-04 23:17:58 +02:00
aizu-m 23291acb7b xfer: replace directory separator in remote nick by underscore in download filename 2026-06-04 22:38:08 +02:00
Sébastien Helleu b802681230 api: fix infinite loop in function string_replace when the search string is empty 2026-06-03 21:15:16 +02:00
Sébastien Helleu 3687ce0f0f relay: limit size of received websocket frame and HTTP body to prevent memory exhaustion
A relay client could announce a huge websocket frame (or HTTP body via
"Content-Length") and dribble its payload, making WeeChat accumulate it
in a buffer that grew without limit, until all memory was exhausted. The
websocket frame path is reachable before authentication with the
"weechat" and "irc" protocols.

The announced websocket frame length and HTTP "Content-Length" are now
bounded by WEBSOCKET_FRAME_MAX_LENGTH and RELAY_HTTP_BODY_MAX_LENGTH: an
oversized websocket frame closes the connection, and an oversized body is
rejected.
2026-06-01 21:56:34 +02:00
Sébastien Helleu 1211510ded irc: limit size of data received from the server to prevent memory exhaustion
A malicious or compromised IRC server could send data with no end-of-line
(or a flood of "005" messages), making WeeChat accumulate it in a buffer
that grew without limit, until all memory was exhausted.

The unterminated received message and the accumulated "005" (ISUPPORT)
data are now bounded by IRC_SERVER_RECV_MSG_MAX_LENGTH and
IRC_SERVER_ISUPPORT_MAX_LENGTH: extra data is ignored once the limit is
reached.
2026-06-01 21:53:03 +02:00
aizu-m 07871f123f core: fix possible integer truncation in function eval_string_split (#2320) 2026-06-01 10:25:35 +02:00
Sébastien Helleu a0cf82d4a6 core: replace Bash/Ubuntu with WSL in README 2026-05-31 17:24:41 +02:00
Sébastien Helleu 13291b6b9a core: add missing trailing slash to Ruby scripts URL in README 2026-05-31 17:24:24 +02:00
Sébastien Helleu 76d652a513 core: fix multi-protocol feature wording in README 2026-05-31 17:24:13 +02:00
Sébastien Helleu ff9b698665 core: improve wording of semantic versioning section in README 2026-05-31 17:24:01 +02:00
Sébastien Helleu d5c985eb11 core: add security policy in SECURITY.md 2026-05-31 16:04:33 +02:00
Sébastien Helleu b29f464322 ci: enable ruby 3.3 module on Rocky Linux 9 2026-05-31 15:13:43 +02:00
Sébastien Helleu 171a9a9fc4 ci: install dnf-plugins-core on Rocky Linux 9 for dnf config-manager 2026-05-31 15:13:43 +02:00
Sébastien Helleu d7bc041098 core: add version 4.9.1 2026-05-31 15:09:01 +02:00
Sébastien Helleu 43a118ac47 core: fix timing attack on TOTP validation (GHSA-vhv8-g2r9-cwcc)
weecrypto_totp_validate compared the generated and client-supplied OTPs
with strcmp and broke out of the time-window loop on the first match.
Both choices leaked information via response timing: strcmp leaked the
expected OTP digit-by-digit (shrinking the brute-force search from
~10^digits to a handful of guesses within the 30-second window), and
the early break leaked which window offset matched.

Compare in constant time with string_memcmp_constant_time and always
iterate the full window, OR-ing the result into otp_ok without an
early exit.

This affects both relay protocols (which call totp_validate via the
public info hook) and any other caller of the info hook.
2026-05-31 09:16:46 +02:00
Sébastien Helleu e540d7a2cf relay/irc: fix timing attack on PASS command (GHSA-vhv8-g2r9-cwcc)
The IRC relay protocol's PASS handler compared the server password with
the client-supplied value using strcmp, leaking the password byte-by-byte
via response timing. This is the same class of bug fixed for the api and
weechat protocols, on a separate code path that did not go through
relay_auth_check_password_plain.

Extract the HMAC-then-constant-time-compare logic from
relay_auth_check_password_plain into relay_auth_password_equals, then
use it in both the plain-auth wrapper and the IRC PASS handler.
2026-05-31 09:16:36 +02:00
Sébastien Helleu 6948aea626 relay: fix timing attack on password authentication (GHSA-vhv8-g2r9-cwcc)
The relay authentication used non-constant-time comparisons (strcasecmp,
strcmp) to verify password hashes and plaintext passwords, allowing an
attacker to derive the expected hash byte-by-byte from response timing
and then authenticate without knowing the password.

- SHA/PBKDF2 hex hash comparisons: normalize the client-supplied hash to
  uppercase and compare in constant time over the fixed expected length.
- Plaintext password comparison: HMAC-SHA256 both passwords with a fresh
  per-call random key and compare the fixed-size MACs in constant time,
  hiding both per-byte timing and the password length.

Add string_memcmp_constant_time helper in core, exposed via the plugin
API. Bump WEECHAT_PLUGIN_API_VERSION accordingly.
2026-05-31 09:16:15 +02:00
Sébastien Helleu 5dbb96b66a relay: limit size of decompressed websocket frame to prevent memory exhaustion (GHSA-v2v4-45wm-5cr3)
An authenticated relay client using the permessage-deflate websocket
extension could send a small compressed frame that decompresses to an
unbounded amount of data, exhausting all memory and crashing WeeChat.

The output buffer in relay_websocket_inflate is now capped to
WEBSOCKET_INFLATE_MAX_SIZE: frames decompressing beyond this limit are
rejected and the connection is closed.
2026-05-31 09:16:06 +02:00
Sébastien Helleu 4fdcbf8f93 irc: fix description of info "irc_nick_from_host"
This fixes the following warning from xgettext:

src/plugins/irc/irc-info.c:1361: warning: Message contains an embedded email address.  Better move it out of the translatable string, see https://www.gnu.org/software/gettext/manual/html_node/No-embedded-URLs.html
2026-05-30 15:36:26 +02:00
Sébastien Helleu e4b70ad252 core: update translations 2026-05-30 14:00:43 +02:00
Sébastien Helleu d7fd2b7b0b core: define author name/email as constants
This fixes the following compiler warning:

src/core/core-args.c:180: warning: Message contains an embedded email address.  Better move it out of the translatable string, see https://www.gnu.org/software/gettext/manual/html_node/No-embedded-URLs.html
2026-05-30 13:39:45 +02:00