Call 26.800.0 + callmobile 26.800.0: гость больше не попадёт в чужой чат через конференцию, у CallAIError новые константы
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
call 26.800.0 и callmobile 26.800.0 пришли одним пакетом с im 26.1100.0, immobile 26.1200.0 и intranet 26.1500.0, у них свои разборы. В call закрыли несколько дыр в гостевом доступе. Через открытую конференцию гость попадал в чат чужой, запароленной: пароль проверялся по videoconf_id, а в чат добавляли по ALIAS. По кодам ошибок регистрации можно было перебрать, какие конференции существуют и какие под паролем. Журнал звонков отвечал гостю через ajax.php в обход гостевых ограничений REST. Разработчикам придётся переименовать константы CallAIError, а подписчикам событий завершения звонка — учесть, что часть работы ушла в фоновые задачи. Мобильный звонок получил «Завершить для всех», переключатель вида и автоподстройку качества, все три выключены по умолчанию.
Новое
Включите новинки опциями модуля
Bitrix\Call\Settings читает три новых флага:
finish_for_all_enabled— пункт «Завершить для всех» в мобильном звонке, на портал или на пользователя черезCUserOptions;view_toggle_enabled— ручное переключение «сетка / спикер» в мобильном звонке, только на портал;call_auto_balance_enabled— автоподстройка качества входящего видео в вебе и в приложении, на портал или на пользователя.
<?php declare(strict_types=1);
use Bitrix\Main\Config\Option;
Option::set('call', 'view_toggle_enabled', '1');
// пилот на одном сотруднике
\CUserOptions::SetOption('call', 'finish_for_all_enabled', true, false, $userId);
\CUserOptions::SetOption('call', 'call_auto_balance_enabled', true, false, $userId);
Значение приводится к bool, поэтому строка 'N' функцию тоже включит. Выключайте удалением: Option::delete('call', ['name' => 'view_toggle_enabled']).
Пороги автоподстройки тоже настраиваются опциями nqe_*: окна понижения и повышения (5 и 15 секунд), разогрев (30 секунд), пороги потерь пакетов, RTT и джиттера на каждый шаг качества. Докблоки Settings::getNqe*RttMs() уверяют, что клиент RTT не использует, но оценщик в вебе и в приложении сравнивает его с порогами наравне с потерями и джиттером.
Мобильный звонок (callmobile 26.800.0)
«Завершить для всех» есть только в групповом звонке и открывается долгим нажатием на кнопку завершения. Пункт вызывает call.CallManager.finish, и у всех участников, включая того, кто нажал, звонок закрывается по Pull-событию Call::finish. Кнопка переключения вида появляется, когда кто-то показывает экран или закреплён участник. Если на экране двое, кнопки нет. Демонстрация экрана важнее закрепления, её плитка подписана «Экран #NAME#». Автоподстройка следит за потерями пакетов, RTT и джиттером и меняет качество входящего видео с задержкой, чтобы картинка не прыгала на каждом всплеске. Гость видит журнал звонков в приложении без действия «позвонить».
Веб-звонок
Если открыть идущий звонок один на один из другой вкладки, вкладка со звонком мигает заголовком и иконкой и показывает системное уведомление «Идёт звонок с ...». Окно звонка получило ARIA-метки и объявления для скринридеров вроде «Запись началась», а после закрытия возвращает фокус на кнопку, с которой его открыли. На порталах с пресетом Синка каждому пользователю один раз показывается промо «Теперь все звонки в Битрикс24 Синк».
Проверяйте доступ к звонку без загрузки участников
Call::checkAccessClosedForm(int $userId) отвечает так же, как checkAccess() (участник звонка или пользователь с доступом к связанной сущности, например к чату), но читает из b_call_user только строку этого пользователя. getUserClosedForm() возвращает CallUser одного участника или null.
<?php declare(strict_types=1);
use Bitrix\Call\Call\Registry;
function callUserState(int $callId, int $userId): ?string
{
$call = Registry::getCallWithId($callId);
if ($call === null || !$call->checkAccessClosedForm($userId)) {
return null;
}
return $call->getUserClosedForm($userId)?->getState();
}
Что сломается
Замените константы CallAIError
| Было | Стало |
|---|---|
AI_UNSUPPORTED_TRACK_ERROR |
UNSUPPORTED_TRACK_ERROR |
AI_EMPTY_PAYLOAD_ERROR |
EMPTY_PAYLOAD_ERROR |
AI_RECORD_TOO_SHORT |
RECORD_TOO_SHORT |
AI_RECORDING_DISABLED |
RECORDING_DISABLED |
AI_TRACKPACK_NOT_RECEIVED |
TRACK_PACK_NOT_FOUND_ERROR или TRACK_PACK_NOT_FOUND_TIMEOUT |
Алиасов на старые имена нет, обращение к ним падает с Error: Undefined constant. Строковые значения кодов тоже сменились. Бывший 'AI_TRACKPACK_NOT_FOUND' разделился на два кода: TRACK_PACK_NOT_FOUND_ERROR означает, что трек-пак не пришёл при явном повторе анализа, TRACK_PACK_NOT_FOUND_TIMEOUT — что истекло ожидание. Если вы сравниваете коды ошибок AI-итогов со строками, сравнения молча перестанут срабатывать. Вариант, который работает на обеих версиях модуля:
<?php declare(strict_types=1);
use Bitrix\Call\Integration\AI\CallAIError;
function isRecordTooShort(\Bitrix\Main\Error $error): bool
{
$code = defined(CallAIError::class . '::RECORD_TOO_SHORT')
? CallAIError::RECORD_TOO_SHORT // call 26.800.0+
: 'AI_RECORD_TOO_SHORT';
return $error->getCode() === $code;
}
События и статистика завершения звонка ушли в фон
При завершении звонка переходы CALLING→IDLE (участник не ответил) и UNAVAILABLE→UNAVAILABLE (до него не дозвонились) уходят в im:OnCallUserStateChange из фоновой задачи. Код, который ждёт эти события сразу после finish(), получит их только после ответа клиенту. Событие отправляется только по участникам, которых завершение действительно перевело, и не отправляется, если их состояние за это время сменилось. Обработчик call:onCallFinished статистику звонка больше не увидит: раньше saveStat() выполнялся до события, теперь — фоновой задачей после него.
Гостевые клиенты конференций получат один код ошибки
call.user.register и im.call.user.register на любой отказ до регистрации гостя отвечают CALL_AUTH_ACCESS_DENIED. Раньше отказы различались кодами (CALL_AUTH_VIDEOCONF_NOT_ACTIVE, CALL_AUTH_DIFF_USER, WRONG_ALIAS и другие), и перебором videoconf_id по ним выяснялось, какие конференции существуют и какие закрыты паролем. batch с регистрацией внутри теперь отклоняется целиком, потому что batch проверял авторизацию только у внешней команды и вложенная регистрация проходила без проверки пароля. Ещё одна новая проверка сравнивает чат конференции из videoconf_id с чатом из ALIAS. До неё гость проходил проверку по videoconf_id открытой конференции, а по ALIAS попадал в чат чужой, запароленной. Методы приватные, их вызывает публичная страница конференции. Самописный гостевой клиент больше не различит причину отказа и не получит additional.hash из бывшего CALL_AUTH_DIFF_USER.
Гость видит в журнале звонков только свои чаты
Гость по ссылке на чат видит в журнале звонки только тех чатов, где он ещё состоит. По тому же правилу считаются счётчик пропущенных и бейдж в приложении. До обновления исключённому гостю журнал продолжал показывать актуальные название и аватар чата. Удалить запись, отметить отдельный звонок просмотренным или открыть чат из журнала гость больше не может. Сбросить весь бейдж гость по-прежнему может, но только POST-запросом и не с чужого сайта. Гостевой список разрешённых методов в im срабатывал только на /rest/, а те же действия через /bitrix/services/main/ajax.php гостя пускали. Если ваши контроллеры полагаются на этот список, проверяйте гостя в фильтре самого действия.
Deprecated
Языковые фразы call и callmobile с вшитыми «BitrixGPT» и «CoPilot» помечены @deprecated. На их место пришли ключи с суффиксом _MSGVER_1 и плейсхолдером #COPILOT_NAME#. Имя по региону лицензии возвращает CallAISettings::getCopilotName(). Так выглядит замена в копии шаблона call.ai:
<?php declare(strict_types=1);
use Bitrix\Call\Integration\AI\CallAISettings;
use Bitrix\Main\Localization\Loc;
?>
<h2><?= Loc::getMessage('CALL_COMPONENT_COPILOT_DETAIL_TITLE_MSGVER_1', [
'#COPILOT_NAME#' => CallAISettings::getCopilotName(),
]) ?></h2>
БД
В b_call_track добавлен индекс по EXTERNAL_TRACK_ID, у b_call_session в PostgreSQL — по uuid (в MySQL он уже был). Агент очистки журнала звонков удаляет записи пачками и берёт настройки из опций: call_userlog_cleanup_period_days (90 дней, раньше срок был зашит как три месяца), call_userlog_cleanup_batch_size (1000) и call_userlog_cleanup_time_limit_sec (25 секунд на запуск).
Мелочи и находки
- Push-приглашение в звонок живёт два периода вызова, по умолчанию 60 секунд. Раньше срок не ограничивался, и приглашение могло всплыть после конца звонка.
- Повторное приглашение через
call.CallManager.inviteне звонит тем, кто уже отклонил звонок или был занят. - Звонок один на один на JWT-схеме не закрывал комнату на контроллере, и повторный вызов тому же собеседнику попадал в мёртвую комнату. Теперь комнату закрывает тот, кто завершил звонок.
call.CallController.pingTracksобъявляетBX_CRONTABпрямо в веб-запросе, чтобы на портале с агентами на кроне в конце запроса отработали разовые агенты скачивания записей. Вместе с ними отрабатывают просроченные разовые агенты всех модулей.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
Bitrix\Call\Integration\AI\CallAIError::AI_UNSUPPORTED_TRACK_ERROR
|
Удалено |
Bitrix\Call\Integration\AI\CallAIError::UNSUPPORTED_TRACK_ERROR
|
Bitrix\Call\Integration\AI\CallAIError::AI_EMPTY_PAYLOAD_ERROR
|
Удалено |
Bitrix\Call\Integration\AI\CallAIError::EMPTY_PAYLOAD_ERROR
|
Bitrix\Call\Integration\AI\CallAIError::AI_RECORD_TOO_SHORT
|
Удалено |
Bitrix\Call\Integration\AI\CallAIError::RECORD_TOO_SHORT
|
Bitrix\Call\Integration\AI\CallAIError::AI_RECORDING_DISABLED
|
Удалено |
Bitrix\Call\Integration\AI\CallAIError::RECORDING_DISABLED
|
Bitrix\Call\Integration\AI\CallAIError::AI_TRACKPACK_NOT_RECEIVED
|
Удалено |
Bitrix\Call\Integration\AI\CallAIError::TRACK_PACK_NOT_FOUND_ERROR / Bitrix\Call\Integration\AI\CallAIError::TRACK_PACK_NOT_FOUND_TIMEOUT
|