Skip to content

Commit 9353936

Browse files
author
Codex Security Bot
committed
security: harden highlight directive against html injection
1 parent f8ab88f commit 9353936

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed
Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
import './highlight.less'
22

3+
const escapeRegExp = (value) => {
4+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
5+
}
6+
7+
const escapeHtml = (value) => {
8+
return value
9+
.replace(/&/g, '&')
10+
.replace(/</g, '&lt;')
11+
.replace(/>/g, '&gt;')
12+
.replace(/"/g, '&quot;')
13+
.replace(/'/g, '&#39;')
14+
}
15+
16+
const sanitizeClassName = (value) => {
17+
const className = value ? `${value}` : 'ops-text-highlight'
18+
return /^[A-Za-z0-9_-]+$/.test(className) ? className : 'ops-text-highlight'
19+
}
20+
321
const highlight = (el, binding) => {
4-
if (binding.value.value) {
5-
let testValue = `${binding.value.value}`
6-
if (['(', ')', '$'].includes(testValue)) {
7-
testValue = `\\${testValue}`
8-
}
9-
const regex = new RegExp(`(${testValue})`, 'gi')
10-
el.innerHTML = el.innerText.replace(regex, `<span class='${binding.value.class ?? 'ops-text-highlight'}'>$1</span>`)
11-
}
22+
const options = (binding && binding.value) || {}
23+
if (options.value === undefined || options.value === null || `${options.value}` === '') {
24+
return
25+
}
26+
27+
const text = escapeHtml(el.innerText || '')
28+
const keyword = escapeRegExp(`${options.value}`)
29+
const className = sanitizeClassName(options.class)
30+
const regex = new RegExp(`(${keyword})`, 'gi')
31+
el.innerHTML = text.replace(regex, `<span class='${className}'>$1</span>`)
1232
}
1333

1434
export default highlight

0 commit comments

Comments
 (0)