&"\'';
$escaped = htmlspecialchars($maliciousLog);
expect($escaped)->toBe('<>&"'');
});
it('preserves legitimate text content', function () {
$legitimateLog = 'INFO: Application started successfully';
$escaped = htmlspecialchars($legitimateLog);
expect($escaped)->toBe($legitimateLog);
});
it('handles ANSI color codes after escaping', function () {
$logWithAnsi = "\e[31mERROR:\e[0m Something went wrong";
$escaped = htmlspecialchars($logWithAnsi);
// ANSI codes should be preserved in escaped form
expect($escaped)->toContain('ERROR');
expect($escaped)->toContain('Something went wrong');
});
it('escapes complex nested HTML structures', function () {
$maliciousLog = '
';
$escaped = htmlspecialchars($maliciousLog);
expect($escaped)->toContain('<div');
expect($escaped)->toContain('<img');
expect($escaped)->toContain('<script>');
expect($escaped)->not->toContain('
not->toContain('
![]()
not->toContain('';
$escaped = htmlspecialchars($contentWithHtml);
// When stored in data attribute and rendered with x-text:
// 1. Server escapes to: <script>alert("XSS")</script>
// 2. Browser decodes the attribute value to:
// 3. x-text renders it as textContent (plain text), NOT innerHTML
// 4. Result: User sees "" as text, script never executes
expect($escaped)->toContain('<script>');
expect($escaped)->not->toContain('';
// Step 1: Server-side escaping (PHP)
$escaped = htmlspecialchars($rawLog);
expect($escaped)->toBe('<script>alert("XSS")</script>');
// Step 2: Stored in data-log-content attribute
//
// Step 3: Client-side getDisplayText() decodes HTML entities
// const decoded = doc.documentElement.textContent;
// Result: '' (as text string)
// Step 4: x-text renders as textContent (NOT innerHTML)
// Alpine.js sets element.textContent = decoded
// Result: Browser displays '' as visible text
// The script tag is never parsed or executed - it's just text
// Step 5: Highlighting via CSS class
// If search query matches, 'log-highlight' class is added
// Visual feedback is provided through CSS, not HTML injection
});
it('documents search highlighting with CSS classes', function () {
$legitimateLog = '2024-01-01T12:00:00.000Z ERROR: Database connection failed';
// Server-side: Escape and store
$escaped = htmlspecialchars($legitimateLog);
expect($escaped)->toBe($legitimateLog); // No special chars
// Client-side: If user searches for "ERROR"
// 1. splitTextForHighlight() divides the text into parts:
// - Part 1: "2024-01-01T12:00:00.000Z " (highlight: false)
// - Part 2: "ERROR" (highlight: true) <- This part gets highlighted
// - Part 3: ": Database connection failed" (highlight: false)
// 2. Each part is rendered as a
with x-text (safe)
// 3. Only Part 2 gets the 'log-highlight' class via :class binding
// 4. CSS provides yellow/warning background color on "ERROR" only
// 5. No HTML injection occurs - just multiple safe text spans
expect($legitimateLog)->toContain('ERROR');
});
it('verifies no HTML injection occurs during search', function () {
$logWithHtml = 'User input:
';
$escaped = htmlspecialchars($logWithHtml);
// Even if log contains malicious HTML:
// 1. Server escapes it
// 2. x-text renders as plain text
// 3. Search highlighting uses CSS class, not HTML tags
// 4. User sees the literal text with highlight background
// 5. No script execution possible
expect($escaped)->toContain('<img');
expect($escaped)->toContain('onerror');
expect($escaped)->not->toContain('
alert("XSS")';
// The search query is used in matchesSearch() which does:
// line.toLowerCase().includes(this.searchQuery.toLowerCase())
// This is safe string comparison, no HTML parsing
expect($userSearchQuery)->toContain('