import * as xss from 'xss'
let xssOptions: any = {
enableAttrs: true,
enableHtml: true,
enableUrl: true,
html: {
whiteList: {
a: ['class', 'style', 'contenteditable', 'data-id', 'data-title', 'data-size', 'href', 'data-last-modified'],
address: ['class', 'style'],
area: ['class', 'style'],
article: ['class', 'style'],
aside: ['class', 'style'],
audio: ['class', 'style'],
b: ['class', 'style'],
bdi: ['class', 'style'],
bdo: ['class', 'style'],
big: ['class', 'style'],
blockquote: ['class', 'style'],
br: ['class', 'style'],
caption: ['class', 'style'],
center: ['class', 'style'],
cite: ['class', 'style'],
code: ['class', 'style'],
col: ['class', 'style'],
colgroup: ['class', 'style'],
dd: ['class', 'style'],
del: ['class', 'style'],
details: ['class', 'style'],
div: [
'class',
'style',
'spellcheck',
'data-gramm',
'spellcheck',
'data-mode',
'data-position',
'data-row',
'data-cell',
'data-rowspan',
'data-colspan',
'data-cell-bg',
'data-parent-bg'
],
dl: ['class', 'style'],
dt: ['class', 'style'],
em: ['class', 'style'],
figcaption: ['class', 'style'],
figure: ['class', 'style'],
font: ['class', 'style'],
footer: ['class', 'style'],
h1: ['class', 'style'],
h2: ['class', 'style'],
h3: ['class', 'style'],
h4: ['class', 'style'],
h5: ['class', 'style'],
h6: ['class', 'style'],
header: ['class', 'style'],
hr: ['class', 'style'],
i: ['class', 'style', 'data-image-id', 'data-image'],
img: ['class', 'style', 'data-image-id', 'src'],
input: ['class', 'style', 'data-formula', 'data-link', 'data-video'],
ins: ['class', 'style'],
li: ['class', 'style'],
mark: ['class', 'style'],
nav: ['class', 'style'],
ol: ['class', 'style'],
p: ['class', 'style'],
pre: ['class', 'style'],
s: ['class', 'style'],
section: ['class', 'style'],
small: ['class', 'style'],
span: ['class', 'style', 'contenteditable', 'color', 'style'],
sub: ['class', 'style'],
summary: ['class', 'style'],
sup: ['class', 'style'],
strong: ['class', 'style'],
strike: ['class', 'style'],
svg: ['class', 'style', 't', 'viewBox', 'viewbox', 'version', 'xmlns', 'p-id', 'xmlns:xlink'],
path: ['d', 'p-id'],
table: ['class', 'style'],
tbody: ['class', 'style'],
td: ['class', 'style', 'data-row', 'data-cell', 'data-cell-bg', 'data-parent-bg'],
tfoot: ['class', 'style'],
th: ['class', 'style'],
thead: ['class', 'style'],
tr: ['class', 'style', 'data-row'],
tt: ['class', 'style'],
u: ['class', 'style'],
ul: ['class', 'style'],
video: ['class', 'style']
}
}
}
const defaultWhiteList = (xss.getDefaultWhiteList && xss.getDefaultWhiteList()) || {}
xssOptions.html.whiteList = Object.assign(defaultWhiteList, xssOptions.html.whiteList)
let xssFilterHtml = new xss.FilterXSS(xssOptions.html)
export const getXssOption = (): object => {
return xssOptions
}
export const setXssOption = (option: any): void => {
let whiteList
if (option?.html?.whiteList) {
whiteList = Object.assign(xssOptions.html.whiteList, option.html.whiteList)
}
xssOptions = Object.assign(xssOptions, option)
if (whiteList) {
xssOptions.html.whiteList = whiteList
}
xssFilterHtml = new xss.FilterXSS(xssOptions.html)
}
let filterHtml = (content: string): string => {
if (!xssOptions.enableHtml || typeof content !== 'string') {
return content
}
return xssFilterHtml.process(content)
}
export const setFilterHtml = (filter: (content: string) => string): void => {
filterHtml = filter
}
let filterAttrs = (content: string) => {
if (!xssOptions.enableAttrs || typeof content !== 'string') {
return content
}
return content.replace(/<.*?>/gi, '').replace(/on[a-z]+=/gi, '')
}
export const setFilterAttrs = (filter: (content: string) => string) => {
filterAttrs = filter
}
let filterUrl = (content: string) => {
if (!xssOptions.enableUrl || typeof content !== 'string') {
return content
}
const filteredUrl = content
.replace(/&#(\w+)(^\w|;)?/g, (match, dec) => String.fromCharCode(dec))
.replace(/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim, '')
.trim()
if (!filteredUrl) {
return ''
}
if (['.', '/'].includes(filteredUrl[0])) {
return filteredUrl
}
const urlParse = filteredUrl.match(/^([^:]+):/gm)
if (!urlParse) {
return filteredUrl
}
if (/^([^\w]*)(javascript|data|vbscript)/im.test(urlParse[0])) {
return ''
}
return filteredUrl
}
export const setFilterUrl = (filter: (content: any) => any) => {
filterUrl = filter
}
export default {
getXssOption,
setXssOption,
filterHtml,
setFilterHtml,
filterAttrs,
setFilterAttrs,
filterUrl,
setFilterUrl
}