Skip to content

Commit

Permalink
feat: Improve iframe parameter handling (#1299)
Browse files Browse the repository at this point in the history
* fix(utils): Fix TypeScript issues in `parse.ts`

* feat: Improve iframe parameter handling (modrinth/knossos#362)
- Remove not whitelisted parameters instead of not rendering whole iframe
- Allowed `start` and `end` parameters in YouTube embeds
  • Loading branch information
Norbiros authored Jul 20, 2024
1 parent 797e1f1 commit 3a73994
Showing 1 changed file with 33 additions and 25 deletions.
58 changes: 33 additions & 25 deletions packages/utils/parse.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import MarkdownIt from 'markdown-it'
import xss from 'xss'
import { escapeAttrValue, FilterXSS, safeAttrValue, whiteList } from 'xss'

export const configuredXss = new xss.FilterXSS({
export const configuredXss = new FilterXSS({
whiteList: {
...xss.whiteList,
...whiteList,
summary: [],
h1: ['id'],
h2: ['id'],
Expand All @@ -14,12 +14,12 @@ export const configuredXss = new xss.FilterXSS({
kbd: ['id'],
input: ['checked', 'disabled', 'type'],
iframe: ['width', 'height', 'allowfullscreen', 'frameborder', 'start', 'end'],
img: [...xss.whiteList.img, 'usemap', 'style'],
img: [...(whiteList.img || []), 'usemap', 'style'],
map: ['name'],
area: [...xss.whiteList.a, 'coords'],
a: [...xss.whiteList.a, 'rel'],
td: [...xss.whiteList.td, 'style'],
th: [...xss.whiteList.th, 'style'],
area: [...(whiteList.a || []), 'coords'],
a: [...(whiteList.a || []), 'rel'],
td: [...(whiteList.td || []), 'style'],
th: [...(whiteList.th || []), 'style'],
picture: [],
source: ['media', 'sizes', 'src', 'srcset', 'type'],
},
Expand All @@ -35,35 +35,43 @@ export const configuredXss = new xss.FilterXSS({
if (tag === 'iframe' && name === 'src') {
const allowedSources = [
{
regex:
/^https?:\/\/(www\.)?youtube(-nocookie)?\.com\/embed\/[a-zA-Z0-9_-]{11}(\?&autoplay=[0-1]{1})?$/,
remove: ['&autoplay=1'], // Prevents autoplay
url: /^https?:\/\/(www\.)?youtube(-nocookie)?\.com\/embed\/[a-zA-Z0-9_-]{11}/,
allowedParameters: [/start=\d+/, /end=\d+/],
},
{
regex: /^https?:\/\/(www\.)?discord\.com\/widget\?id=\d{18,19}(&theme=\w+)?$/,
remove: [/&theme=\w+/],
url: /^https?:\/\/(www\.)?discord\.com\/widget/,
allowedParameters: [/id=\d{18,19}/],
},
]

const url = new URL(value)

for (const source of allowedSources) {
if (source.regex.test(value)) {
for (const remove of source.remove) {
value = value.replace(remove, '')
}
return `${name}="${xss.escapeAttrValue(value)}"`
if (!source.url.test(url.href)) {
continue
}

const newSearchParams = new URLSearchParams()
url.searchParams.forEach((value, key) => {
if (!source.allowedParameters.some((param) => param.test(`${key}=${value}`))) {
newSearchParams.delete(key)
}
})

url.search = newSearchParams.toString()
return `${name}="${escapeAttrValue(url.toString())}"`
}
}

// For Highlight.JS
if (name === 'class' && ['pre', 'code', 'span'].includes(tag)) {
const allowedClasses = []
const allowedClasses: string[] = []
for (const className of value.split(/\s/g)) {
if (className.startsWith('hljs-') || className.startsWith('language-')) {
allowedClasses.push(className)
}
}
return `${name}="${xss.escapeAttrValue(allowedClasses.join(' '))}"`
return `${name}="${escapeAttrValue(allowedClasses.join(' '))}"`
}
},
safeAttrValue(tag, name, value, cssFilter) {
Expand Down Expand Up @@ -92,7 +100,7 @@ export const configuredXss = new xss.FilterXSS({
]

if (!allowedHostnames.includes(url.hostname)) {
return xss.safeAttrValue(
return safeAttrValue(
tag,
name,
`https://wsrv.nl/?url=${encodeURIComponent(
Expand All @@ -101,13 +109,13 @@ export const configuredXss = new xss.FilterXSS({
cssFilter,
)
}
return xss.safeAttrValue(tag, name, url.toString(), cssFilter)
return safeAttrValue(tag, name, url.toString(), cssFilter)
} catch (err) {
/* empty */
}
}

return xss.safeAttrValue(tag, name, value, cssFilter)
return safeAttrValue(tag, name, value, cssFilter)
},
})

Expand All @@ -129,7 +137,7 @@ export const md = (options = {}) => {
const token = tokens[idx]
const index = token.attrIndex('href')

if (index !== -1) {
if (token.attrs && index !== -1) {
const href = token.attrs[index][1]

try {
Expand All @@ -152,4 +160,4 @@ export const md = (options = {}) => {
return md
}

export const renderString = (string) => configuredXss.process(md().render(string))
export const renderString = (string: string) => configuredXss.process(md().render(string))

0 comments on commit 3a73994

Please sign in to comment.