4.95v 1. Notable changes since 4.94v - Security hardening (primary focus of this release): outbound bot REST API requests now resolve the destination host once and pin the IP via `CURLOPT_RESOLVE` to defeat DNS rebinding, reject loopback/private/reserved ranges and redirects, and honour a new `rest_api_limit` configuration (`deny_local`, `allow_host` accepting a bare host or `host:port` entries; `deny_local` defaults to `true` on fresh installs). The external image zoom view now requires an authenticated operator session and rejects non http/https and private/reserved destinations, and file downloads were hardened against SSRF. REST API session tokens gained a bounded lifetime (`session_token_expire`, default 30 days) with an `isExpired()` helper, tokens are stamped with `expires_on` on issue, expired tokens are revoked on use, and `loginbytoken` / `notifications` reject missing, non-string, blank, revoked and expired tokens. Sessions and "remember me" cookies are now bound to the password hash via `hash_equals()`, so changing a password invalidates every other session and all previously issued remember-me tokens. `cron.php` is restricted to CLI and cronjob/extension options are validated against a whitelist regex with a realpath confinement check. User import field mapping is restricted to a whitelisted attribute set, theme import only accepts whitelisted model attributes and rejects non-image uploads, and proactive invitation image uploads are validated as real images. Template and module compilation now uses `var_export()` for inlined translations/config and skips inlining values that could form a `` header or as a `?token=` parameter (a generated token uses `random_bytes` and comparisons use `hash_equals`), and allowed CORS origins plus an optional host allowlist for the SDK DNS rebinding protection can be configured through the `ai_mcp_options` chat configuration. - MCP tools and helpers: fourteen read-only tools are exposed - `get_user_id_by_email`, `get_user_id_by_username`, `get_user_permissions`, `get_url_permissions`, `check_user_object_access`, `explain_chat_access`, `get_department_auto_assign_settings`, `explain_chat_auto_assign`, `count_chats`, `get_chat_statistics`, `get_chat_activity`, `get_chat_performance`, `get_last_chats` and `get_chat_filter_fields`; `LiveHelperChat\Mcp\Access` resolves a back office URL into module/view and the permissions it requires with the same logic as the permission explorer (absolute URL, plain path, with/without `index.php`, with/without siteaccess) and evaluates permissions grouped so that checks in the same group are OR-ed and different groups are AND-ed; `LiveHelperChat\Mcp\Rules` diagnoses object level access for departments, users, chats and canned message replace variables, reporting only identifiers, booleans and generic placeholders (no names, e-mail addresses, chat nicks or message bodies) and can be extended by extensions with the new `ai_mcp.object_access_rules` event; `LiveHelperChat\Mcp\AutoAssign` is a read-only port of `erLhcoreClassChatWorkflow::autoAssign()` which replays the candidate and gate checks without any write or lock, so it can be run safely against a live installation to answer "would chat X be auto assigned?" or "why was operator Y not auto assigned to chat X?"; the chat statistics tools answer quantitative questions - `count_chats` counts chats for the raw filter map and groups them by department, operator, status, bot, device type, country, channel, theme, product, subject or a time dimension, `get_chat_statistics` reports the chat volume and the visitor/operator/system/bot message counters of a window (with optional live per department counters), `get_chat_activity` returns a time series per hour/day/week/month/weekday from a single grouped query, `get_chat_performance` reports the average chat duration, first response and agent response times plus the wait time distribution and the hourly workload, `get_last_chats` returns at most five chats for a filter as a chat id and a creation date (the follow up to a counting question, "give me the last chat ids of this visitor"), ordered by chat id with a `sort` parameter for newest (default) or oldest first and also carries a `list_url` which opens the back office chat list with the same filters and ordering so the returned chats can be verified by hand, and `get_chat_filter_fields` lists the accepted operators, `lh_chat` fields, `group_by` values, intervals and period shorthands; all four data tools also accept a dedicated `nick` parameter (a case insensitive `filterlike` match on `nick`, the same semantic the back office chat search uses) so a visitor nick never has to be assembled by hand; `LiveHelperChat\Mcp\ChatStats` is the shared engine behind them - it validates the raw filter map against an operator allowlist (exactly the operators understood by both `erLhcoreClassModelChat::getCount()` and `erLhcoreClassChat::getCount()`) and against the `lh_chat` column list, accepts no raw SQL, joins, sorting or limits from the client, qualifies every field to remove the `lh_chat`/`lh_msg` ambiguity of the joined message counters, resolves the `1h`/`24h`/`7d`/`30d`/`today`/`this_week`/`this_month`/`all` style time windows, applies the statistic module session timezone and timeout guards, and builds all aggregate expressions server side so every tool answers from the same numbers; the statistics tools are read only and installation wide, they apply no per operator department limitation. - MCP sessions and dependencies: handshake sessions are stored in the new `lh_mcp_session` table instead of per-request or per-node state, so the endpoint also works on load balanced installations; sessions expire one hour after the last write (the SDK default), a failing query is reported as a missing session instead of turning the endpoint into a PHP error page, and expired sessions are purged by the regular chat cleanup cron so the table stays small; `composer.json` gained the `mcp/sdk` and `symfony/finder` dependencies, `erLhcoreClassSystem::$QueryString` is now a declared property, `ezcUrl::parsePathElement()` no longer warns when a path element is `null`, and the new table is created by the regular database update. - Audit log size protection: audit records larger than the MySQL `max_allowed_packet` no longer break the operation being logged - oversized audit messages are truncated to a safe size (16 MB minus a 1 MB reserve for the rest of the query) with UTF-8 safe truncation and a marker showing the original size, and a failing log write is reported through `error_log()` instead of propagating up, unless `debug_output` is enabled so developers still see the error. - Chat transfer to human: `chat/transfertohuman` now runs inside a database transaction, loads the chat with `fetchAndLock()` and locks the department before changing the state, re-validates the chat hash and status after the lock was acquired, and returns a JSON error instead of failing when the chat does not exist or was closed/transferred in the meantime; a missing chat is also handled safely when grouping canned message items, and incomplete canned message replace conditions (missing field, comparator or value) are skipped instead of raising warnings. - Assignment and SQL mode fixes: editing a department operator assignment returns "Assignment record was not found" instead of failing when the assignment record is missing; aggregate queries in the department operator lists (operators, operators group) and in collected survey results set `sql_mode=''` so installations with `ONLY_FULL_GROUP_BY` enabled can still list operators and survey results; the operator assignment priority field gained an explanation that it is only taken into account when the department enables assignment by operator priority, otherwise auto-assignment sorts by lowest workload / least recently accepted first. - Bot: the "Update message" bot command can now update the `del_st` (deleted status) field of a message, and the bot workflow translation/replace helper guards against a non-object chat. - Widget and operator profile: relative URIs in chat responses are treated as same site links, so they open inside the embedded chat instead of a new browser window; send button and in-progress icons received small padding and alignment fixes; new `--lhc-message-spacing` and `--lhc-message-group-spacing` CSS variables let a theme control the spacing between message bubbles and between message groups without overriding the whole stylesheet; the "job title in new row" theme option is now implemented with CSS classes (`op-job-title-sep`, `operator-profile-content`, `op-photo`) instead of duplicated template markup; the widget React app version was bumped. - Miscellaneous: updated install scripts, `structure.json` and `db.dbml` for the new `lh_mcp_session` table; bumped version to 4.92v. 2. Summary - This release focuses on AI tooling for administrators, plus reliability and compatibility fixes. - A Model Context Protocol endpoint lets AI clients read permission, access, auto-assignment and chat statistics information from an installation through fourteen read-only tools, protected by an access token and a dedicated `lhaimcp`/`use` permission. - MCP sessions live in the new `lh_mcp_session` table, making the endpoint safe for load balanced setups, with automatic expiry and cleanup. - Oversized audit records are truncated instead of breaking the logged operation, and a failing log write no longer interrupts the request flow. - Chat transfer to human, department assignments and SQL mode sensitive queries are hardened, and incomplete canned message replace conditions are handled safely. - Widget links, message spacing and operator profile job titles were polished. execute doc/update_db/update_358.sql for update 4.91v 1. Notable changes since 4.90v - Chat widget CAPTCHA providers: added Google reCAPTCHA v3 and Cloudflare Turnstile support for verifying chat widget visitors through provider-based CAPTCHA validation; CAPTCHA settings gained a chat-specific enable flag and a configurable reCAPTCHA v3 score threshold; a dedicated widget CAPTCHA helper loads the provider script and resolves the token, which is now sent and verified as part of the widget online chat submission; the CAPTCHA settings screen gained a provider toggle and CAPTCHA settings are exposed through the widget online settings endpoint. - Canned message replaceable variables: added a `configuration` field to `lh_canned_msg_replace` storing per-variable JSON options to hide the variable value from the replaceable variables list ("Hide value in list") and to restrict management of the variable to operators holding the new `use_replace_sensitive` permission of the `lhcannedmsg` module ("Restricted access"); restricted variables show a "Restricted" badge, their value and clone/edit/delete actions are hidden from operators without the permission, and access control is enforced in the clone, edit and delete handlers. - Exact counts for chat and mail searches: the chat and mail conversation search panels gained an "Exact count" toggle; by default the result total is capped by counting only the first 1,000 matching rows through new `limit_count` support in `getCount()`, avoiding slow full-table scans on large result sets, and the paginator shows an approximate total ("~") whenever the count was capped; enabling "Exact count" performs a precise count of every matching row. - Bot REST API actions: authentication credentials used for NTLM, Bearer token and API key (header and query parameter) requests now resolve through replaceable variables; authorization headers are masked in debug logs by shortening them from both sides so secrets are not exposed; new user language dynamic variables (`{{user_locale}}`, `{{user_site_access}}`, `{{user_content_language}}`, `{{user_content_language_name}}`) were added for REST API bot actions, backed by a new `user_language` magic property on the chat model; streaming requests gained a configurable row start pattern so response streams that do not use the SSE `data: {` prefix are parsed correctly. - Bot trigger arguments: invisible message arguments (`{message_invisible_N}`) passed from the widget are now consistently forwarded to every trigger execution path, including theme-based bot trigger execution and the default trigger, by centralizing trigger argument processing early in the widget online submission flow. - Offline reasons for operators: the offline reasons feature now supports operator access control through a new `offlinereasons_operator` permission that can be granted with limitations restricting operators to specific reasons; the status (online/offline) modal shows a reason selector when an operator goes offline and stores the selection as `offline_reason_id`, and only the reasons an operator is allowed to use are exposed in the dashboard and status modal; the permission editor and "who grants" summary show the offline-reason limitation, specific function limitations are now respected over wildcard grants, and offline reasons can be deleted. - Statistics averages: agent statistics averages now include the full result set instead of trimming the highest and lowest ten percent, and preserve fractional values when computing the averages. - Security hardening: file downloads in incoming webhooks and online-user avatar fetching were hardened against SSRF - only HTTP/HTTPS URLs are accepted, `localhost` and private/reserved IP addresses are rejected, the resolved hostname is pinned to a validated IP to prevent DNS rebinding, and redirect following is disabled; message validation and the message preview modal were fixed. - Reliability: the bot "Close chat" command now runs inside a database transaction with row locking to prevent race conditions and partial state updates during chat closure; the mail conversation fetch API returns an error instead of failing fatally when the conversation cannot be found; mailbox syncing now limits SQL statement execution and lock-wait time and sets IMAP open/read/write/close timeouts so a slow mail server cannot stall the sync process. - Message masking test tool: added a chat-context simulation mode where a chat and a test message are supplied and the tool reproduces the real widget masking flow with step-by-step diagnostics (chat found, guardrails enabled, chat assigned to operator, matching masking rule, operator permission, masking result) using the chat's department, assigned operator and permissions, along with clearer explanations. - Miscellaneous: added RAR and other MIME type detection for downloaded webhook attachments; added Latvian (`lv_LV`) and Estonian (`et_EE`) translations and updated the translation update script; widened the widget theme custom CSS fields from `text` to `mediumtext` to prevent CSS truncation; updated install scripts and database structure definitions; bumped version to 4.91v. 2. Summary - This release focuses on safeguarding sensitive data, richer chat widget CAPTCHA options, and performance tuning for large searches. - Chat widget visitors can now be verified with Google reCAPTCHA v3 or Cloudflare Turnstile, controlled by a chat-specific CAPTCHA switch and a configurable score threshold. - Canned message replaceable variables can hide their values from lists and be locked down to operators with a dedicated permission. - Chat and mail searches gain an "Exact count" option while default counts are capped and marked approximate for large result sets. - Bot REST API actions support variable-based authentication with masked secrets, user language variables, and flexible streaming row parsing, and invisible message arguments now reach all trigger workflows. - Offline reasons become permission-controlled, file downloads are hardened against SSRF, and mail fetching, chat closing, statistics averaging and translation coverage were improved. execute doc/update_db/update_357.sql for update 4.91v 1. Notable changes since 4.90v - Chat widget CAPTCHA providers: added Google reCAPTCHA v3 and Cloudflare Turnstile support for verifying chat widget visitors through provider-based CAPTCHA validation; CAPTCHA settings gained a chat-specific enable flag and a configurable reCAPTCHA v3 score threshold; a dedicated widget CAPTCHA helper loads the provider script and resolves the token, which is now sent and verified as part of the widget online chat submission; the CAPTCHA settings screen gained a provider toggle and CAPTCHA settings are exposed through the widget online settings endpoint. - Canned message replaceable variables: added a `configuration` field to `lh_canned_msg_replace` storing per-variable JSON options to hide the variable value from the replaceable variables list ("Hide value in list") and to restrict management of the variable to operators holding the new `use_replace_sensitive` permission of the `lhcannedmsg` module ("Restricted access"); restricted variables show a "Restricted" badge, their value and clone/edit/delete actions are hidden from operators without the permission, and access control is enforced in the clone, edit and delete handlers. - Exact counts for chat and mail searches: the chat and mail conversation search panels gained an "Exact count" toggle; by default the result total is capped by counting only the first 1,000 matching rows through new `limit_count` support in `getCount()`, avoiding slow full-table scans on large result sets, and the paginator shows an approximate total ("~") whenever the count was capped; enabling "Exact count" performs a precise count of every matching row. - Bot REST API actions: authentication credentials used for NTLM, Bearer token and API key (header and query parameter) requests now resolve through replaceable variables; authorization headers are masked in debug logs by shortening them from both sides so secrets are not exposed; new user language dynamic variables (`{{user_locale}}`, `{{user_site_access}}`, `{{user_content_language}}`, `{{user_content_language_name}}`) were added for REST API bot actions, backed by a new `user_language` magic property on the chat model; streaming requests gained a configurable row start pattern so response streams that do not use the SSE `data: {` prefix are parsed correctly. - Bot trigger arguments: invisible message arguments (`{message_invisible_N}`) passed from the widget are now consistently forwarded to every trigger execution path, including theme-based bot trigger execution and the default trigger, by centralizing trigger argument processing early in the widget online submission flow. - Offline reasons for operators: the offline reasons feature now supports operator access control through a new `offlinereasons_operator` permission that can be granted with limitations restricting operators to specific reasons; the status (online/offline) modal shows a reason selector when an operator goes offline and stores the selection as `offline_reason_id`, and only the reasons an operator is allowed to use are exposed in the dashboard and status modal; the permission editor and "who grants" summary show the offline-reason limitation, specific function limitations are now respected over wildcard grants, and offline reasons can be deleted. - Statistics averages: agent statistics averages now include the full result set instead of trimming the highest and lowest ten percent, and preserve fractional values when computing the averages. - Security hardening: file downloads in incoming webhooks and online-user avatar fetching were hardened against SSRF - only HTTP/HTTPS URLs are accepted, `localhost` and private/reserved IP addresses are rejected, the resolved hostname is pinned to a validated IP to prevent DNS rebinding, and redirect following is disabled; message validation and the message preview modal were fixed. - Reliability: the bot "Close chat" command now runs inside a database transaction with row locking to prevent race conditions and partial state updates during chat closure; the mail conversation fetch API returns an error instead of failing fatally when the conversation cannot be found; mailbox syncing now limits SQL statement execution and lock-wait time and sets IMAP open/read/write/close timeouts so a slow mail server cannot stall the sync process. - Message masking test tool: added a chat-context simulation mode where a chat and a test message are supplied and the tool reproduces the real widget masking flow with step-by-step diagnostics (chat found, guardrails enabled, chat assigned to operator, matching masking rule, operator permission, masking result) using the chat's department, assigned operator and permissions, along with clearer explanations. - Miscellaneous: added RAR and other MIME type detection for downloaded webhook attachments; added Latvian (`lv_LV`) and Estonian (`et_EE`) translations and updated the translation update script; widened the widget theme custom CSS fields from `text` to `mediumtext` to prevent CSS truncation; updated install scripts and database structure definitions; bumped version to 4.91v. 2. Summary - This release focuses on safeguarding sensitive data, richer chat widget CAPTCHA options, and performance tuning for large searches. - Chat widget visitors can now be verified with Google reCAPTCHA v3 or Cloudflare Turnstile, controlled by a chat-specific CAPTCHA switch and a configurable score threshold. - Canned message replaceable variables can hide their values from lists and be locked down to operators with a dedicated permission. - Chat and mail searches gain an "Exact count" option while default counts are capped and marked approximate for large result sets. - Bot REST API actions support variable-based authentication with masked secrets, user language variables, and flexible streaming row parsing, and invisible message arguments now reach all trigger workflows. - Offline reasons become permission-controlled, file downloads are hardened against SSRF, and mail fetching, chat closing, statistics averaging and translation coverage were improved. execute doc/update_db/update_357.sql for update 4.90v 1. Notable changes since 4.88v - Track who set a user online: added `online_by_user_id` column to `lh_users_online_session` recording which operator set a user online; online-hours statistics gained a "Set online by" column showing that operator. execute doc/update_db/update_356.sql for update