Sanitize browse categories HTML output

This commit is contained in:
2026-04-25 08:12:46 +02:00
parent a0b903f09d
commit 157c6d49e8
2 changed files with 35 additions and 3 deletions

View File

@@ -7,6 +7,10 @@
@extends('layouts.nova') @extends('layouts.nova')
@section('content') @section('content')
@php
$sanitizeHtml = fn (?string $value) => \App\Services\ContentSanitizer::sanitizeRenderedHtml($value ?? '');
@endphp
<div class="effect2"> <div class="effect2">
<div class="page-heading"> <div class="page-heading">
<h1 class="page-header">Browse Categories</h1> <h1 class="page-header">Browse Categories</h1>
@@ -24,7 +28,7 @@
<h2 class="panel-title">{{ $ct->name }}</h2> <h2 class="panel-title">{{ $ct->name }}</h2>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p>{!! $ct->description ?? '' !!}</p> <p>{!! $sanitizeHtml($ct->description) !!}</p>
@php @php
$roots = $categoriesByType[$ct->slug] ?? $ct->rootCategories ?? collect(); $roots = $categoriesByType[$ct->slug] ?? $ct->rootCategories ?? collect();
@@ -37,7 +41,7 @@
@foreach ($roots as $category) @foreach ($roots as $category)
<li style="display:block;margin-bottom:8px;"> <li style="display:block;margin-bottom:8px;">
<h4>{{ $category->name }}</h4> <h4>{{ $category->name }}</h4>
<p>{!! $category->description !!}</p> <p>{!! $sanitizeHtml($category->description) !!}</p>
<ul style="list-style:none;padding:0;margin:0;"> <ul style="list-style:none;padding:0;margin:0;">
@foreach ($category->subcategories as $subcategory) @foreach ($category->subcategories as $subcategory)
@php @php
@@ -47,7 +51,7 @@
@endphp @endphp
<li style="width:19%;display:inline-block;vertical-align:top;"> <li style="width:19%;display:inline-block;vertical-align:top;">
<img src="/gfx/icons/{{ $picture }}" width="15" height="15" alt="{{ $subcategoryName }}" /> <img src="/gfx/icons/{{ $picture }}" width="15" height="15" alt="{{ $subcategoryName }}" />
<a href="{{ $subcategoryUrl }}" title="{{ $subcategoryName }}">{!! $subcategoryName !!}</a> <a href="{{ $subcategoryUrl }}" title="{{ $subcategoryName }}">{{ $subcategoryName }}</a>
</li> </li>
@endforeach @endforeach
</ul> </ul>

View File

@@ -77,6 +77,34 @@ test('render adds rel=noopener to external links', function () {
expect($html)->toContain('rel="noopener noreferrer nofollow"'); expect($html)->toContain('rel="noopener noreferrer nofollow"');
}); });
test('sanitizeRenderedHtml keeps allowed formatting tags', function () {
$html = ContentSanitizer::sanitizeRenderedHtml('<p><strong>Bold</strong> and <em>italic</em> with <a href="/categories">link</a></p>');
expect($html)
->toContain('<p>')
->toContain('<strong>Bold</strong>')
->toContain('<em>italic</em>')
->toContain('<a href="/categories"')
->toContain('rel="noopener noreferrer nofollow"');
});
test('sanitizeRenderedHtml strips script tags and event handlers', function () {
$html = ContentSanitizer::sanitizeRenderedHtml('<p onclick="evil()">Hello<script>alert(1)</script></p>');
expect($html)
->not()->toContain('<script')
->not()->toContain('onclick')
->toContain('Hello');
});
test('sanitizeRenderedHtml strips javascript links', function () {
$html = ContentSanitizer::sanitizeRenderedHtml('<a href="javascript:alert(1)">click</a>');
expect($html)
->not()->toContain('javascript:')
->toContain('click');
});
// ── Legacy HTML conversion ──────────────────────────────────────────────────── // ── Legacy HTML conversion ────────────────────────────────────────────────────
test('render converts legacy bold HTML to markdown output', function () { test('render converts legacy bold HTML to markdown output', function () {