Disk 26.1250.0–26.1375.0: запрет скачивания при праве на чтение теперь проверяет сервер
Обновление безопасности
Закрыта уязвимость или ослабленная проверка прав. Ставить в первую очередь.
Диск обновился с 26.1200.0 (разбор) сразу на четыре версии: 26.1250.0, 26.1300.0, 26.1350.0 и 26.1375.0. В 26.1300.0 сервер начал проверять запрет скачивания при праве на чтение, который раньше почти ничего не ограничивал, и отказ придёт по прямой ссылке, в архиве, в REST и в редакторе. В 26.1350.0 закрыли SQL-инъекцию и SSRF. Коробкам с OnlyOffice за обратным прокси после него нужна новая опция, иначе правки пользователей пропадут.
Новое
Проверяйте право на скачивание отдельно от чтения (26.1300.0)
С правом на изменение файл можно скачать всегда, с правом на чтение только при включённой у объекта опции «Разрешить скачивание с правом на просмотр». Это правило проверяют BaseObject::canDownload(SecurityContext), AttachedObject::canDownload($userId), SecurityContext::canDownload($objectId) и DocumentSession::canDownload(SecurityContext). Код, который строит ссылку на скачивание после canRead(), переводите на новую проверку, иначе сервер откажет по выданной ссылке.
<?php declare(strict_types=1);
use Bitrix\Disk\Driver;
use Bitrix\Disk\File;
use Bitrix\Main\Loader;
Loader::requireModule('disk');
function diskDownloadUrl(int $fileId, int $userId): ?string
{
$file = File::loadById($fileId);
$securityContext = $file?->getStorage()?->getSecurityContext($userId);
if ($securityContext === null || !$file->canDownload($securityContext)) {
return null; // файл можно только смотреть
}
return Driver::getInstance()->getUrlManager()->getUrlForDownloadFile($file);
}
Синхронизируйте Диск через REST v3 (26.1300.0)
Шесть методов disk.sync.* (capabilities.get, session.create, snapshot.list, changes.list, state.check и content.get) строят синхронизацию по журналу изменений. Клиент создаёт сессию, выкачивает начальный снимок и дальше читает только изменения по подписанному курсору. Файл отдаётся по подписанной ссылке, которая живёт час. Контур выключен, пока опция disk_enable_sync_rest не равна Y.
<?php declare(strict_types=1);
use Bitrix\Disk\Configuration;
use Bitrix\Main\Config\Option;
use Bitrix\Main\Loader;
Loader::requireModule('disk');
Option::set('disk', 'disk_enable_sync_rest', 'Y');
var_dump(Configuration::isSyncRestEnabled()); // bool(true)
Включите комментарии на досках (26.1300.0)
Доски получили HTTP API комментариев и аннотаций (/api/disk/flipchart/comments/v1/*, /api/disk/flipchart/annotations/v1/*) с тредами, реакциями, упоминаниями, вложениями и отметками о прочтении. Упомянутым приходит уведомление в мессенджер, ссылку на элемент доски даёт UrlManager::getUrlForViewBoardElement(). В редакторе доски комментарии, аннотации и теги включают опции модуля boards.comments_enabled, boards.annotations_enabled и boards.tags_enabled, по умолчанию N. С 26.1375.0 маршруты отвечают и с завершающим слэшем, потому что облачный веб-сервер сам отдаёт 404 на путь без расширения и слэша.
Выбирайте файлы из дисков чатов (26.1250.0)
Окно выбора файлов показывает источник «Диск чатов» и грузит список источников постранично (FilePicker::getInitialStageAction() принимает page, в ответе есть хеш каталога sourceRevision). На коробке новое окно включает опция disk_enable_universal_file_picker, по умолчанию N. В 26.1300.0 там заработал предпросмотр, в 26.1350.0 кнопка выбора стала называться «Прикрепить».
Следите за статусами сохранения OnlyOffice (26.1350.0)
Если версию записать не удалось, портал отвечает серверу документов {"error": 1}, раньше там всегда был ноль. Отклонённое финальное сохранение оставляет ключ документа (статус SAVE_REJECTED) и сессии, и следующее открытие получает тот же документ. Когда пользователь возвращается в него, портал сам шлёт forcesave, до трёх попыток, потому что сервер документов хранит документ только сутки.
Сессии, по которым сервер молчит дольше 900 секунд, закрывает агент, а участники получают уведомление «Редактирование документа #NAME# прервано...». Порог задаёт опция disk_onlyoffice_interrupt_threshold, агент отключается опцией disk_onlyoffice_interrupt_agent_enabled = N. Редактор показывает новые статусы «Не сохранено на Диске», «Сохранение не подтверждено», «Редактирование прервано» и «Ошибка редактора». Отказы пишутся в канал логгера disk.onlyoffice.save, а если его нет, в журнал событий с типом DISK_ONLYOFFICE_SAVE_FAILED.
Что сломается
Запрет скачивания проверяет сервер (26.1300.0)
До 26.1300.0 настройки запрета скачивание почти не ограничивали. Опция объекта «Разрешить скачивание с правом на просмотр» только сохранялась, а флаг публичной ссылки CAN_DOWNLOAD_WITH_READ_ACCESS с 26.1250.0 прятал лишь кнопку в OnlyOffice. Теперь сервер отказывает при скачивании файла и версии, в «Сохранить себе», во вложениях пользовательских полей и в архивах. Архив папки не отдаётся совсем, если в нём есть хоть один запрещённый файл. Публичная ссылка без права на изменение и с выключенным флагом больше не скачивает, OnlyOffice без права отключает скачивание и печать. По умолчанию разрешено всё, отказы начнутся там, где запрет включили явно.
REST скачивает файл или версию по DOWNLOAD_URL через Rest\Service\Base::assertCanDownload() и при отказе бросает AccessException. Вебхук с правом на чтение, который выкачивал такие файлы, начнёт получать ошибку.
Сверьте копии шаблонов (26.1250.0, 26.1300.0)
С 26.1300.0 в disk.uf.file у файла из FILES бывают DOWNLOAD_URL и COPY_TO_ME_URL, равные null, рядом лежит новый CAN_DOWNLOAD, а DOWNLOAD_ARCHIVE_URL проверяйте по CAN_DOWNLOAD_ARCHIVE. В disk.file.view есть $arResult['CAN_DOWNLOAD'], в disk.external.link LINK_TO_DOWNLOAD задаётся только при CAN_DOWNLOAD. Копия шаблона без этих проверок покажет пустую ссылку.
<?php foreach ($arResult['FILES'] as $file): ?>
<?php if ($file['CAN_DOWNLOAD']): ?>
<a href="<?= htmlspecialcharsbx($file['DOWNLOAD_URL']) ?>"><?= htmlspecialcharsbx($file['NAME']) ?></a>
<?php else: ?>
<span><?= htmlspecialcharsbx($file['NAME']) ?></span>
<?php endif ?>
<?php endforeach ?>
disk.file.viewer-html в 26.1250.0 перестал читать DOWNLOAD_URL, COPY_LINK_URL, SHARING_OBJECT_ID и SHARING_UNIQUE_CODE. Шапку теперь описывает HEADER_COMPOSITION, без него шапки нет. Копия шаблона или вызов со старыми параметрами останется без кнопок «Скачать», «Доступ» и «Скопировать ссылку».
Пропишите хост OnlyOffice за прокси (26.1350.0)
Сохранённый документ портал теперь скачивает только по http или https, без редиректов, с хоста сервера документов из настроек или с хостов из новой опции disk_onlyoffice_save_extra_hosts. Об этом предупреждает PHPDoc readExtraHosts(): если OnlyOffice отдаёт адрес другого хоста или обратный прокси переписывает Host, без опции сохранение отклоняется и правки пользователя теряются. Любой публичный хост принимается только при облачной регистрации сервера документов.
<?php declare(strict_types=1);
use Bitrix\Main\Config\Option;
// Хосты через запятую или пробел, можно с портом
Option::set('disk', 'disk_onlyoffice_save_extra_hosts', 'office.example.local, 10.0.0.15:8443');
Передайте коды прав в setAfterMove() (26.1300.0)
RightsManager::setAfterMove() получил обязательный второй параметр array $codesBeforeMove. Коды снимают до переноса новым captureCodesBeforeMove(), после переноса это уже коды нового места. PHPDoc объясняет, что параметр сделали обязательным нарочно, и пусть лучше забытый вызов упадёт, чем права молча уйдут не той аудитории. BaseObject::moveTo() делает всё сам, править нужно только собственный перенос.
<?php declare(strict_types=1);
use Bitrix\Disk\Driver;
$rightsManager = Driver::getInstance()->getRightsManager();
$codesBeforeMove = $rightsManager->captureCodesBeforeMove($object); // строго до переноса
// ...ваш перенос объекта...
$rightsManager->setAfterMove($object, $codesBeforeMove);
Поправьте вызовы, наследников и свои реализации
- Вызовы
FileDownloader(26.1350.0). Удалены__construct(string $downloadUrl)иdownload(), адрес теперь передаётся вdownloadToTempFile(string $url, float $processingStartedAt): Result, аnew FileDownloader($url)даст TypeError. CommandServiceClientInterface(26.1350.0) требует методforceSave(string $documentKey): Result.SecurityContext::preloadOperationsForChildren()иpreloadOperationsForSpecifiedObjects()(26.1300.0) получили необязательныйbool $shouldPreloadDownloadAccess. Наследник со старой сигнатурой упадёт.- Наследники
CDiskFileEditorOnlyOfficeComponentиCDiskFileEditorVibeofficeComponent(26.1250.0).buildHeaderComposition(DocumentSession)(у обоих) иbuildPresenceConfig(DocumentSession)(у OnlyOffice) переехали в трейтDocumentHeaderPageс сигнатурамиbuildHeaderComposition(?OpeningContext)иbuildPresenceConfig(DocumentSession, ?OpeningContext), переопределение по-старому даст фатал. Volume\QueryHelper::prepareOrder()(26.1350.0) молча выкидывает направления кроме ASC и DESC и поля без алиаса, если имя не похоже наFIELDилиT.FIELD. Сортировка выражением илиDESC NULLS LASTпропадёт без ошибки.
Обновитесь ради закрытых уязвимостей
- 26.1350.0. «Очистка Диска» передавала порядок сортировки из настроек грида в сырой SQL. Теперь поля и направления проходят через белый список.
- 26.1350.0. Скачивание сохранённого документа по адресу из callback OnlyOffice закрыли от SSRF: белый список хостов, без редиректов, приватные адреса только для своего сервера, лимит размера и общий дедлайн.
- 26.1375.0. Администратор портала или соцсети через выбор файлов получал файлы чатов, в которых не состоит. Для хранилищ чатов снова работает обычная проверка прав, которой не было в 26.1300.0 и 26.1350.0.
- 26.1300.0. Кроме серверного запрета скачивания, диалоги
disk.dialog-markupпропускают в ссылку только относительный путь или адрес своего origin. Раньшеinformation_popups.jsвставлялdata.linkв HTML строкой.
Deprecated
BX.Disk.InformationPopups.getContentWarningLockedDocument() устарел в 26.1300.0, замена BX.Disk.DialogMarkup.renderLockedDocumentWarning(). Новый метод возвращает HTMLElement, старый по-прежнему отдаёт строку. Без расширения disk.dialog-markup методы BX.Disk.InformationPopups бросают Error, ядровое расширение disk подключает его само.
БД
26.1300.0 добавил таблицы b_disk_flipchart_* и b_disk_sync_* и четыре индекса на b_disk_object. На большом портале построение этих индексов может затянуть обновление. В 26.1350.0 у b_disk_document_info.CONTENT_STATUS новые значения 7 (SAVE_REJECTED) и 8 (INTERRUPTED), DocumentInfo::isFinished() считает их завершёнными. Если ваши запросы выбирают открытые документы по статусу, учтите оба.
Мелочи и находки
- 26.1250.0.
disk.document-headerбольше не тянетpull.clientиui.vue3.components.avatar. Если они приходили к вам вместе с шапкой, подключайте их сами. - 26.1375.0. Исправлен Error «Undefined constant» в предпросмотре выбора файлов, появившийся в 26.1300.0.
Устаревшие и удалённые API в этой версии
| Символ | Статус | Чем заменять |
|---|---|---|
BX.Disk.InformationPopups.getContentWarningLockedDocument()
|
Deprecated |
BX.Disk.DialogMarkup.renderLockedDocumentWarning()
|
Bitrix\Disk\Document\OnlyOffice\FileDownloader::download()
|
Удалено |
Bitrix\Disk\Document\OnlyOffice\FileDownloader::downloadToTempFile()
|