first commit
This commit is contained in:
239
tests/Shared/HtmlSanitizerTest.php
Normal file
239
tests/Shared/HtmlSanitizerTest.php
Normal file
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Shared;
|
||||
|
||||
use App\Shared\Html\HtmlPurifierFactory;
|
||||
use App\Shared\Html\HtmlSanitizer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests unitaires pour HtmlSanitizer.
|
||||
*
|
||||
* Vérifie que HTMLPurifier supprime bien les contenus dangereux
|
||||
* (XSS, balises non autorisées, schémas URI interdits) et conserve
|
||||
* les balises légitimes produites par l'éditeur Trumbowyg.
|
||||
*
|
||||
* Ces tests utilisent une vraie instance HTMLPurifier (pas de mock)
|
||||
* car c'est le comportement de purification lui-même qui est testé.
|
||||
*/
|
||||
final class HtmlSanitizerTest extends TestCase
|
||||
{
|
||||
private HtmlSanitizer $sanitizer;
|
||||
|
||||
/**
|
||||
* Crée une instance réelle de HtmlSanitizer avant chaque test.
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
$purifier = HtmlPurifierFactory::create(sys_get_temp_dir() . '/htmlpurifier_tests');
|
||||
$this->sanitizer = new HtmlSanitizer($purifier);
|
||||
}
|
||||
|
||||
|
||||
// ── Balises autorisées ─────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Les balises de texte courantes doivent être conservées.
|
||||
*/
|
||||
public function testTextTagsPreserved(): void
|
||||
{
|
||||
$html = '<p>Un <strong>texte</strong> avec <em>emphase</em> et <u>soulignement</u>.</p>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('<strong>texte</strong>', $result);
|
||||
$this->assertStringContainsString('<em>emphase</em>', $result);
|
||||
$this->assertStringContainsString('<u>soulignement</u>', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les titres h1 à h6 doivent être conservés.
|
||||
*/
|
||||
public function testHeadingsPreserved(): void
|
||||
{
|
||||
$html = '<h1>Titre 1</h1><h2>Titre 2</h2><h3>Titre 3</h3>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('<h1>', $result);
|
||||
$this->assertStringContainsString('<h2>', $result);
|
||||
$this->assertStringContainsString('<h3>', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les listes ordonnées et non ordonnées doivent être conservées.
|
||||
*/
|
||||
public function testListsPreserved(): void
|
||||
{
|
||||
$html = '<ul><li>Item 1</li><li>Item 2</li></ul><ol><li>A</li></ol>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('<ul>', $result);
|
||||
$this->assertStringContainsString('<ol>', $result);
|
||||
$this->assertStringContainsString('<li>', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les liens avec href http/https doivent être conservés.
|
||||
*/
|
||||
public function testHttpLinksPreserved(): void
|
||||
{
|
||||
$html = '<a href="https://example.com">Lien</a>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('href="https://example.com"', $result);
|
||||
$this->assertStringContainsString('Lien', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les images avec src doivent être conservées.
|
||||
*/
|
||||
public function testImagesPreserved(): void
|
||||
{
|
||||
$html = '<img src="https://example.com/image.jpg" alt="Description">';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('<img', $result);
|
||||
$this->assertStringContainsString('src="https://example.com/image.jpg"', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les blocs de code doivent être conservés.
|
||||
*/
|
||||
public function testPreTagPreserved(): void
|
||||
{
|
||||
$html = '<pre>code ici</pre>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('<pre>', $result);
|
||||
}
|
||||
|
||||
|
||||
// ── Balises et attributs dangereux — suppression XSS ───────────
|
||||
|
||||
/**
|
||||
* Les balises <script> doivent être supprimées.
|
||||
*/
|
||||
public function testScriptTagRemoved(): void
|
||||
{
|
||||
$html = '<p>Texte</p><script>alert("xss")</script>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('<script>', $result);
|
||||
$this->assertStringNotContainsString('alert(', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les attributs onclick et autres handlers JavaScript doivent être supprimés.
|
||||
*/
|
||||
public function testJavascriptAttributesRemoved(): void
|
||||
{
|
||||
$html = '<p onclick="alert(1)" onmouseover="evil()">Texte</p>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('onclick', $result);
|
||||
$this->assertStringNotContainsString('onmouseover', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les liens javascript: doivent être supprimés.
|
||||
*/
|
||||
public function testJavascriptLinkRemoved(): void
|
||||
{
|
||||
$html = '<a href="javascript:alert(1)">Cliquez</a>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('javascript:', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les liens data: doivent être supprimés.
|
||||
*/
|
||||
public function testDataLinkRemoved(): void
|
||||
{
|
||||
$html = '<a href="data:text/html,<script>alert(1)</script>">XSS</a>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('data:', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* La balise <iframe> doit être supprimée.
|
||||
*/
|
||||
public function testIframeTagRemoved(): void
|
||||
{
|
||||
$html = '<iframe src="https://evil.com"></iframe>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('<iframe', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* La balise <object> doit être supprimée.
|
||||
*/
|
||||
public function testObjectTagRemoved(): void
|
||||
{
|
||||
$html = '<object data="malware.swf"></object>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('<object', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* La balise <form> doit être supprimée.
|
||||
*/
|
||||
public function testFormTagRemoved(): void
|
||||
{
|
||||
$html = '<form action="/steal"><input type="password"></form>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('<form', $result);
|
||||
$this->assertStringNotContainsString('<input', $result);
|
||||
}
|
||||
|
||||
|
||||
// ── Cas limites ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Une chaîne vide doit retourner une chaîne vide (ou quasi-vide).
|
||||
*/
|
||||
public function testEmptyStringReturnsEmptyOrBlank(): void
|
||||
{
|
||||
$result = $this->sanitizer->sanitize('');
|
||||
|
||||
$this->assertSame('', trim($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Du texte brut sans balises doit être conservé.
|
||||
*/
|
||||
public function testPlainTextWithoutTags(): void
|
||||
{
|
||||
$html = 'Bonjour le monde';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('Bonjour le monde', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les attributs CSS text-align doivent être conservés.
|
||||
*/
|
||||
public function testStyleTextAlignAttributePreserved(): void
|
||||
{
|
||||
$html = '<p style="text-align: center;">Centré</p>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringContainsString('text-align', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Les propriétés CSS autres que text-align doivent être supprimées.
|
||||
*/
|
||||
public function testOtherCssPropertiesRemoved(): void
|
||||
{
|
||||
$html = '<p style="color: red; background: url(evil.php);">Texte</p>';
|
||||
$result = $this->sanitizer->sanitize($html);
|
||||
|
||||
$this->assertStringNotContainsString('color', $result);
|
||||
$this->assertStringNotContainsString('background', $result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user