Skip to content

Commit 6657ec6

Browse files
authored
avoid regex for tag content footgun (#89)
using regex to try to select the content fo the table was leading to runaway catastprohic backtracking. the simple solution is to just do string substring selection and insertion on the start and end tag
1 parent 7186fa0 commit 6657ec6

File tree

2 files changed

+23
-2
lines changed

2 files changed

+23
-2
lines changed

Diff for: src/paste-markdown-table.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ function generateText(transfer: DataTransfer): string | undefined {
9191
const html = transfer.getData('text/html')
9292
if (!/<table/i.test(html)) return
9393

94+
// eslint-disable-next-line github/unescaped-html-literal
95+
const start = html.substring(0, html.indexOf('<table'))
96+
const tableCloseIndex = html.lastIndexOf('</table>')
97+
if (!start || !tableCloseIndex) return
98+
const end = html.substring(tableCloseIndex + 8)
99+
94100
const parser = new DOMParser()
95101
const parsedDocument = parser.parseFromString(html, 'text/html')
96102

@@ -100,5 +106,7 @@ function generateText(transfer: DataTransfer): string | undefined {
100106

101107
const formattedTable = tableMarkdown(table)
102108

103-
return html.replace(/<meta.*?>/, '').replace(/<table[.\S\s]*<\/table>/, `\n${formattedTable}`)
109+
if (!formattedTable) return
110+
111+
return [start, formattedTable, end].join('').replace(/<meta.*?>/, '')
104112
}

Diff for: test/test.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ describe('paste-markdown', function () {
202202
assert.equal(
203203
textarea.value.trim(),
204204
// eslint-disable-next-line github/unescaped-html-literal
205-
`<p>Here is a cool table</p>\n \n \n\n${tableMarkdown}\n\n\n\n <p>Very cool</p>`
205+
`<p>Here is a cool table</p>\n \n \n${tableMarkdown}\n\n\n\n <p>Very cool</p>`
206206
)
207207
})
208208

@@ -225,6 +225,19 @@ describe('paste-markdown', function () {
225225
assertUnformattedPaste(textarea)
226226
})
227227

228+
it('rejects malformed tables', function () {
229+
// eslint-disable-next-line github/unescaped-html-literal, prefer-template
230+
const html = '<table'.repeat(999) + '<div><table></div>'
231+
const data = {
232+
'text/html': html
233+
}
234+
paste(textarea, data)
235+
236+
// Synthetic paste events don't manipulate the DOM. A empty textarea
237+
// means that the event handler didn't fire and normal paste happened.
238+
assertUnformattedPaste(textarea)
239+
})
240+
228241
it('accepts x-gfm', function () {
229242
paste(textarea, {'text/plain': 'hello', 'text/x-gfm': '# hello'})
230243
assert.include(textarea.value, '# hello')

0 commit comments

Comments
 (0)