im 26.700.0: гостевой доступ переписан с нуля — REST-метод joinByCode удалён
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
Вход гостя в чат по ссылке перестал быть «REST-методом плюс правилом в urlrewrite» и стал полноценной областью авторизации на уровне ядра. Заодно у гостевых ссылок появился срок жизни, а у неактивных гостей — агент очистки. Если вы что-то строили поверх гостевых чатов, этот релиз ломающий.
Что было и что стало
Раньше схема выглядела так: установщик модуля прописывал в urlrewrite правило /guest/{code} → /guest/index.php, ставил шаблон im_guest и права на каталог, а вход выполнялся REST-методом im.v2.Guest.joinByCode.
Теперь:
- REST-метод
joinByCodeудалён, вместо негоim.v2.Guest.checkSession—checkSessionAction(string $code, ?Token $token = null). Разница принципиальная: раньше вызов по коду создавал гостя, теперь проверяется существующая сессия. - Появилась страница
Guest\Controller\Page::viewAction(string $code)со своим шаблоном. - Установщик больше не трогает
urlrewrite, шаблонim_guestи права на/guest/. В коде оставлен комментарий: при установленномintranetмаршрут/guest/здесь больше не описывается. Изim.router/class.phpснята обработкаGUEST_PATH.
GuestApplication: гостя заперли в собственной области
Ключевое — новый Guest\Auth\GuestApplication (приложение авторизации main, ID im_guest), подписанный на onApplicationsBuildList и onApplicationScopeError. Он ограничивает сессию гостя списком физических скриптов: /guest/, /bitrix/routing_index.php, /rest/, /bitrix/services/main/ajax.php и ещё несколько служебных. Всё, что вне списка, приводит к main:onApplicationScopeError, а пролог отвечает 403.
Зачем понадобилось отдельное приложение, объясняет комментарий в самом классе: архитектурно это копия Intranet\PublicApplication, но со своей областью — чтобы более широкий public-список (лайвчат, видеоконференции, платёжные коллбэки) не протекал на гостей. То есть до этого гость, вошедший по ссылке в чат, жил в общей публичной области с доступом к сценариям, к которым его не звали.
Там же — поучительная деталь про сопровождение таких списков. В allowlist явно внесены /bitrix/tools/conversion/ и /bitrix/tools/public_session.php, потому что шаблон Битрикс24 сам дёргает их сразу после загрузки гостевой страницы (счётчик и продление сессии). Без этого проверка области падала на хите счётчика, срабатывал Logout() с regenerateId(), гостевая сессия умирала посреди пачки AJAX-запросов, и наружу это выглядело как плавающие 401/500 и «Could not start session by PHP».
Ссылки с истечением и уборка гостей
SharingLink\Dto\CreateDto::initForGuestChat*иGuestInviteService::inviteByEmail()/inviteByPhone()получили опциональный?DateTime $dateExpire = null. Гостевая ссылка теперь может протухать.CleanupService::cleanInactiveGuestsAgent()— агент с интервалом 60 секунд, чистит неактивных гостей пачками и сам подстраивает период по тому, был ли батч полным.AuthorizationServiceнаучилсяinvalidateGuestUser(),terminate(),setInviteCode(); появился pull-событиеGuest\Pull\UserLogout.
Общая мысль релиза: гостевая учётка перестала быть вечной.
Что сломается
im.v2.Guest.joinByCode— метода нет. Внешние интеграции, которые им пользовались, встанут.CopilotTitle::sendPush()→sendPush(Chat $chat), аргумент обязательный.GuestLinkService::getOrCreateLink(Chat $chat, int $authorId, bool $withMessage = true)— параметр$withMessageудалён.Features::__construct— в конец добавленbool $isCopilotDraftChatAvailable. Позиционная сборкаFeaturesломается.- Установка модуля больше не создаёт правило urlrewrite для
/guest/. Если вы полагались на него в своих маршрутах — проверьте.
Совместимо: Features::isChatWithGuestsAvailable(?int $inviterId = null), CopilotChat::sendBanner() (?bool $isUpdate → bool $isUpdate = false), новые поля manageMessagesAutoDelete и manageGuestInvites в ChatCreateFields.
Черновик чата с Копилотом
Отдельная небольшая история: Chat\Copilot\DraftChatService, экшен Controller\Copilot\DraftChat::getAction и методы CopilotChat::isDraftChat(), activateDraftChat(), activateDraftIfNeeded().
Логика — чат заводится как черновик и активируется только при первом реальном сообщении. Пользователь открыл Копилота, передумал и закрыл — в списке чатов ничего не осталось. Без этого каждое открытие плодило бы пустой чат.
Что делать
- Найдите в интеграциях
im.v2.Guest.joinByCode— переезжать наcheckSession. - Проверьте позиционные вызовы
Features,sendPush,getOrCreateLink. - Если у вас свой шаблон или права на
/guest/— они больше не ставятся установщиком. - Учтите срок жизни гостевых ссылок при выдаче: теперь их можно (и стоит) ограничивать.