Disk 26.1200.0: единые ссылки на папки, капча на паролях публичных ссылок, версиями управляет право правки
Ломающее обновление
Удалены или изменены публичные API — прикладной код может перестать работать.
Диск обновился с 26.1175.0 (разбор) до 26.1200.0 и пришёл в одном пакете с intranet 26.1475.0, который разобран отдельно. Единые ссылки теперь работают для папок, форма пароля публичной ссылки после трёх ошибок просит капчу, а восстанавливать и удалять версии может любой, у кого есть право на редактирование.
Свой код проверьте, если читаете File::SECONDS_TO_JOIN_VERSION, вызываете команду проверки пароля публичной ссылки, держите копию шаблона disk.external.link или передаёте права в REST-методы загрузки файлов и создания папок.
Новое
Единые ссылки открывают папки
До этого релиза единая ссылка вела только на файл. Теперь supportsUnifiedLink() и loadByUniqueCode() живут в BaseObject, а UrlManager::getUnifiedLink() и getUnifiedEditLink() принимают любой объект. Компонент disk.folder.list показывает папку, открытую по такой ссылке. Внутри с файлами работают как в своём хранилище, все операции для этого есть у контроллера UnifiedLinkActions, начиная с getChildren. Мобильное приложение ходит в те же действия, это мы разбирали в diskmobile 26.500.0.
Ссылку на папку можно собрать у себя:
<?php declare(strict_types=1);
use Bitrix\Disk\Driver;
use Bitrix\Disk\Folder;
use Bitrix\Main\Loader;
Loader::requireModule('disk');
$folder = Folder::loadById(42);
if ($folder instanceof Folder && $folder->supportsUnifiedLink()) {
echo Driver::getInstance()->getUrlManager()->getUnifiedLink($folder, ['absolute' => true]);
}
Содержимое папки по коду ссылки отдаёт AJAX-действие:
const { data } = await BX.ajax.runAction('disk.api.UnifiedLinkActions.getChildren', {
data: { uniqueCode: folderCode, search: 'договор' },
});
// data.items, data.total, data.currentFolderRights
Уровень доступа папки по единой ссылке по умолчанию Denied (опция unified_link.folder_default_access_level). Пока папке не задан свой уровень, без собственных прав на неё по ссылке ничего не открыть. Уровень Edit даёт чтение, добавление, правку, удаление и запуск бизнес-процессов. Учесть эти права в своём коде помогут Storage::getCurrentUserSecurityContext(true) и третий параметр RightsManager::getUserOperationsByObject($objectId, $userId, true).
Пароль публичной ссылки защищён капчей
Форма пароля на странице публичной ссылки считает неверные попытки по паре «ссылка + IP». После трёх ошибок за час она показывает капчу, и без верной капчи пароль не проверяется. Та же защита стоит на AJAX-проверке пароля в компоненте и на проверке пароля единой ссылки. Запрос, у которого не удалось определить IP, отклоняется. Форма теперь передаёт sessid, а компонент его проверяет.
Служебные ссылки на вложения писем
Для файлов и папок внутри папки почтовых вложений появился свой сценарий публичной ссылки, mail_attachments. Создаёт такие ссылки одна команда, CreateMailAttachmentLinkCommand, её уже ждал шлюз mail 26.1100.0 (разбор). Команда возвращает действующую служебную ссылку или создаёт новую, а обычные ручные ссылки объекта при этом заменяет. Права вызывающего на файл она не проверяет. Поэтому userId должен совпадать с текущим пользователем, а агент, очередь или CLI-скрипт передают bySystem: true. На тарифе нужна опция disk_manual_external_link. Служебная ссылка открывается, даже если ручные публичные ссылки на портале выключены, а настройки любых ссылок в дереве папки вложений заблокированы.
<?php declare(strict_types=1);
use Bitrix\Disk\Public\Command\ExternalLink\CreateMailAttachmentLink\CreateMailAttachmentLinkCommand;
use Bitrix\Main\Loader;
Loader::requireModule('disk');
$result = (new CreateMailAttachmentLinkCommand(userId: $userId, objectId: $attachmentId))->run();
$url = $result->isSuccess() ? $result->getData()['url'] : null;
Общая шапка у редакторов и досок
OnlyOffice, Vibeoffice и доски получили шапку из расширения disk.document-header: переименование, кто сейчас смотрит, копирование ссылки и статус сохранения. Данные отдаёт контроллер DocumentHeader (getComposition, getPresence, rename).
Поддерево через EXISTS
Folder::getDescendants() принимает параметр subtree_check. В режиме SUBTREE_CHECK_EXISTS принадлежность поддереву проверяется через EXISTS по таблице путей, а выборку Диск заранее сужает по STORAGE_ID контейнера:
<?php declare(strict_types=1);
use Bitrix\Disk\Internals\ObjectTable;
$files = $folder->getDescendants($securityContext, [
'filter' => ['=TYPE' => ObjectTable::TYPE_FILE],
'subtree_check' => ObjectTable::SUBTREE_CHECK_EXISTS,
]);
Поля таблицы путей в select, filter и order в этом режиме недоступны, сортировки по глубине нет, а фильтр с LOGIC => OR на верхнем уровне вызовет ArgumentException. Вернуть весь портал на JOIN без деплоя можно опцией disk_enable_subtree_check_by_exists = N.
Что сломается
Замените File::SECONDS_TO_JOIN_VERSION
Константу удалили без депрекейта, код с ней упадёт с Error: Undefined constant. Интервал склейки версий теперь задаёт опция disk_seconds_to_join_version, по умолчанию 300 секунд, а 0 выключает склейку. В настройках модуля поле называется «Интервал объединения версий, мин.», введённые минуты сохраняются в секундах.
<?php declare(strict_types=1);
// было: \Bitrix\Disk\File::SECONDS_TO_JOIN_VERSION
$seconds = \Bitrix\Disk\Configuration::getSecondsToJoinVersion(); // 0 — версии не склеиваются
Версии восстанавливает и удаляет право на редактирование
Восстановление из версии и удаление версии проверяют File::canManageVersions(), а он равен canUpdate(). Раньше требовалась операция disk_restore, а она есть только в полном доступе. После обновления кнопки в истории файла, AJAX и REST disk.file.restoreFromVersion доступны всем с правом «Редактирование».
Если ваш интерфейс решал это через canRestore(), перейдите на canManageVersions(), иначе он разойдётся со штатным.
Обновите вызовы ExternalLinkValidatePasswordCommand
В публичной команде параметр fileId переименован в objectId, третьим обязательным стал sourceIp, добавились необязательные captchaSid и captchaWord. Вызов с именованным fileId: или с двумя аргументами упадёт. Команда теперь возвращает ошибки CAPTCHA_REQUIRED, CAPTCHA_INVALID и FORBIDDEN, данные капчи лежат в customData ошибки.
<?php declare(strict_types=1);
use Bitrix\Disk\Public\Command\ExternalLink\ValidatePassword\ExternalLinkValidatePasswordCommand;
use Bitrix\Main\Context;
$result = (new ExternalLinkValidatePasswordCommand(
objectId: $fileId,
password: $password,
sourceIp: Context::getCurrent()->getRequest()->getRemoteAddress(),
))->run();
Добавьте sessid и капчу в копию формы пароля
Компонент disk.external.link проверяет check_bitrix_sessid() при отправке PASSWORD, а после трёх ошибок ждёт CAPTCHA_SID и CAPTCHA_WORD. Копия protected_by_password.php без bitrix_sessid_post() будет всегда получать ошибку запроса. Состояние капчи шаблон берёт из $arResult['PASSWORD_PROTECTION']: ключи CAPTCHA_REQUIRED, CAPTCHA_SID и ERROR. AJAX checkPasswordAction компонента вместо wrong теперь отвечает wrong_password, captcha_required или captcha_invalid и добавляет поля captchaRequired и captchaSid.
REST строже проверяет права
disk.folder.addsubfolder, disk.folder.uploadfile, disk.storage.addfolder и disk.storage.uploadfile отклоняют rights, если ACCESS_CODE пустой или длиннее 50 символов, TASK_ID не целое число или такой задачи нет, или NEGATIVE не булево значение. DOMAIN отбрасывается молча. Методы папки раньше передавали права дальше без проверки, так что интеграция, у которой такие права проходили, теперь получит ошибку.
Ещё disk.folder.sharetouser на тарифе без disk_folder_sharing теперь отвечает отказом в доступе.
Уберите disk.sharing-legacy-popup
JS-расширение disk.sharing-legacy-popup с классом BX.Disk.Sharing.LegacyPopup удалено, вместо него disk.sharing-members-popup (BX.Disk.SharingMembersPopup) на Vue 3, а хелперы кодов доступа переехали в disk.rights-access-codes (BX.Disk.Rights).
БД
В b_disk_external_link появилась колонка SCENARIO (varchar(50), одноимённое поле ORM). У обычной ссылки там пусто, у служебной mail_attachments. Сценарий задаётся только при создании, ExternalLink::update() поле отбрасывает.
Мелочи и находки
- HTML-просмотрщик разрешил внешние ресурсы. В CSP теперь
script-src 'unsafe-inline' 'unsafe-eval' https:,connect-src https:, а стили, шрифты, картинки и медиа грузятся с любого https-адреса. ДокблокHtmlViewerServiceговорит, что изоляцию держит sandbox безallow-same-origin. Опцияdisk_html_viewer_csp_hostsпосле этого ничего не добавляет. Ещё в просмотрщике появился режим презентации. - Перенос с переименованием больше не падает, если новое имя занято в исходной папке.
Internals\Model::update()теперь сам ловитDuplicateEntryExceptionи возвращает ошибку, для объектов Диска этоERROR_NON_UNIQUE_NAME. Вашcatchвокруг переименования больше не сработает, смотритеgetErrors().
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
Bitrix\Disk\File::SECONDS_TO_JOIN_VERSION
|
Удалено |
Bitrix\Disk\Configuration::getSecondsToJoinVersion()
|
Bitrix\Disk\Document\Vibeoffice\Configuration::isEnabledOnPortal()
|
Удалено |
Bitrix\Disk\Document\Vibeoffice\Feature::isEnabledOnPortal()
|
Bitrix\Disk\Document\Vibeoffice\Service\PresenceService
|
Удалено |
Bitrix\Disk\Internal\Service\DocumentPresence\PresenceService
|
Bitrix\Disk\Document\Vibeoffice\Service\PresenceAccessService
|
Удалено |
Bitrix\Disk\Internal\Service\DocumentPresence\PresenceAccessService
|
BX.Disk.Sharing.LegacyPopup
|
Удалено |
BX.Disk.SharingMembersPopup
|