RichEditor у Filament 5 побудований на TipTap. За замовчуванням він зберігає HTML, а з json() - структурований JSON у форматі TipTap (модель потребує касту array).
use Filament\Forms\Components\RichEditor;
RichEditor::make('content')
->json()
->fileAttachmentsDisk('s3')
->fileAttachmentsDirectory('posts')
->fileAttachmentsVisibility('private');
Головна загроза - XSS. Редактор надсилає на сервер сирий HTML, і зловмисник може перехопити запит і підставити будь-яку розмітку з <script> чи onerror. Тобто вміст редактора - недовірені дані, навіть якщо його вводять лише адміністратори.
Як виводити:
- у компонентах Filament (
TextColumn::make('content')->html(),TextEntryзhtml()/markdown()) вміст санітизується автоматично; - у власному Blade - це ваша відповідальність:
{!! str($post->content)->sanitizeHtml() !!}
- для JSON-вмісту, приватних зображень чи власних блоків -
RichContentRenderer, що теж санітизує:
use Filament\Forms\Components\RichEditor\RichContentRenderer;
RichContentRenderer::make($post->content)
->fileAttachmentsDisk('s3')
->fileAttachmentsVisibility('private')
->toHtml();
Нюанс санітайзера: він пропускає атрибути style (потрібні для кольору тексту, підсвітки, розміру зображень). Тож CSS на кшталт position: fixed чи background: url(...) переживе очищення. Для вмісту від сторонніх користувачів (коментарі, профілі) варто налаштувати суворіший санітайзер.
Зображення в редакторі:
- за замовчуванням зберігаються публічно - так вміст можна вивести будь-де простим посиланням;
- з
privateу HTML зберігається не URL, а ідентифікатор файлу в атрибутіdata-id, і тимчасові підписані URL генеруються під час рендеру. Тому приватні зображення обов'язково виводити черезRichContentRendererз тими самими налаштуваннями диска; data-idтеж приходить від клієнта: якщо на тому самому диску лежать чужі приватні файли, підмінений ідентифікатор може «підтягнути» чужий файл. Окремий диск чи каталог під вкладення редактора зменшує ризик.
HTML чи JSON: HTML простіше виводити й шукати; JSON зручніший, коли вміст треба програмно обробляти (власні блоки, теги злиття, рендер в інші формати).