Skip to content

Commit 25ec074

Browse files
authored
fix: Escape HTML in error content (#83)
1 parent e8d6dfb commit 25ec074

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

src/templates/error_info/main.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import { BaseComponent } from '../../component.js'
1111
import { publicDirURL } from '../../public_dir.js'
12-
import { wordWrap, colors } from '../../helpers.js'
12+
import { wordWrap, colors, htmlEscape } from '../../helpers.js'
1313
import type { ErrorInfoProps } from '../../types.js'
1414

1515
const ERROR_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="24" height="24" fill="none"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 7v6m0 4.01.01-.011M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10Z"/></svg>`
@@ -41,15 +41,15 @@ export class ErrorInfo extends BaseComponent<ErrorInfoProps> {
4141
*/
4242
async toHTML(props: ErrorInfoProps): Promise<string> {
4343
return `<section>
44-
<h4 id="error-name">${props.error.name}</h4>
45-
<h1 id="error-title">${props.title}</h1>
44+
<h4 id="error-name">${htmlEscape(props.error.name)}</h4>
45+
<h1 id="error-title">${htmlEscape(props.title)}</h1>
4646
</section>
4747
<section>
4848
<div class="card">
4949
<div class="card-body">
5050
<h2 id="error-message">
5151
<span>${ERROR_ICON_SVG}</span>
52-
<span>${props.error.message}</span>
52+
<span>${htmlEscape(props.error.message)}</span>
5353
<button
5454
id="copy-error-btn"
5555
data-error-text="${htmlAttributeEscape(`${props.error.name}: ${props.error.message}`)}"

src/templates/error_metadata/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { dump, themes } from '@poppinss/dumper/html'
1111

1212
import { BaseComponent } from '../../component.js'
1313
import { publicDirURL } from '../../public_dir.js'
14+
import { htmlEscape } from '../../helpers.js'
1415
import type { ErrorMetadataProps, ErrorMetadataRow } from '../../types.js'
1516

1617
/**
@@ -29,7 +30,7 @@ export class ErrorMetadata extends BaseComponent<ErrorMetadataProps> {
2930
}
3031

3132
if (this.#primitives.includes(typeof value) || value === null) {
32-
return value
33+
return typeof value === 'string' ? htmlEscape(value) : value
3334
}
3435

3536
return dump(value, { styles: themes.cssVariables, cspNonce })

tests/templates.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,39 @@ test.group('Templates', () => {
256256
'Something went wrong'
257257
)
258258
})
259+
260+
test('renders error fields with inline HTML as literal text', async ({ expect }) => {
261+
const error = new Error('<b>Error message with HTML</b>', { cause: '<i>Cause with HTML</i>' })
262+
263+
error.name = '<ul>Name with HTML</ul>'
264+
265+
const metadata = new Metadata()
266+
267+
metadata.group('Request', { url: { key: 'url', value: '<span>URL with HTML</span>' } })
268+
269+
const templates = new Templates(true)
270+
const html = await templates.toHTML({
271+
title: '<ul>Error with HTML</ul>',
272+
metadata,
273+
error: await new ErrorParser().parse(error),
274+
})
275+
276+
const { window } = new JSDOM(html)
277+
278+
expect(window.document.querySelector('#error-message')?.textContent?.trim()).toBe(
279+
'<b>Error message with HTML</b>'
280+
)
281+
expect(window.document.querySelector('#error-name')?.textContent?.trim()).toBe(
282+
'<ul>Name with HTML</ul>'
283+
)
284+
expect(window.document.querySelector('#error-title')?.textContent?.trim()).toBe(
285+
'<ul>Error with HTML</ul>'
286+
)
287+
expect(window.document.querySelector('#error-cause')?.textContent?.trim()).toContain(
288+
'<i>Cause with HTML</i>'
289+
)
290+
expect(
291+
window.document.querySelector('.metadata-group .card-subtitle + span')?.textContent?.trim()
292+
).toBe('<span>URL with HTML</span>')
293+
})
259294
})

0 commit comments

Comments
 (0)