mirror of
https://github.com/FreeTubeApp/FreeTube
synced 2024-12-13 04:59:33 +01:00
Escape HTML in local API text runs to prevent XSS (#3675)
This commit is contained in:
parent
e97e1a1459
commit
3c6e1d1a8e
@ -9,6 +9,7 @@ import { MAIN_PROFILE_ID } from '../../../constants'
|
||||
import { calculateColorLuminance, getRandomColor } from '../../helpers/colors'
|
||||
import {
|
||||
copyToClipboard,
|
||||
escapeHTML,
|
||||
getTodayDateStrLocalTimezone,
|
||||
readFileFromDialog,
|
||||
showOpenDialog,
|
||||
@ -587,12 +588,7 @@ export default defineComponent({
|
||||
let opmlData = '<opml version="1.1"><body><outline text="YouTube Subscriptions" title="YouTube Subscriptions">'
|
||||
|
||||
this.profileList[0].subscriptions.forEach((channel) => {
|
||||
const escapedName = channel.name
|
||||
.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll('\'', ''')
|
||||
const escapedName = escapeHTML(channel.name)
|
||||
|
||||
const channelOpmlString = `<outline text="${escapedName}" title="${escapedName}" type="rss" xmlUrl="https://www.youtube.com/feeds/videos.xml?channel_id=${channel.id}"/>`
|
||||
opmlData += channelOpmlString
|
||||
|
@ -5,6 +5,7 @@ import { join } from 'path'
|
||||
import { PlayerCache } from './PlayerCache'
|
||||
import {
|
||||
CHANNEL_HANDLE_REGEX,
|
||||
escapeHTML,
|
||||
extractNumberFromString,
|
||||
getUserDataPath,
|
||||
toLocalePublicationString
|
||||
@ -551,8 +552,12 @@ export function parseLocalTextRuns(runs, emojiSize = 16, options = { looseChanne
|
||||
const parsedRuns = []
|
||||
|
||||
for (const run of runs) {
|
||||
// may contain HTML, so we need to escape it, as we don't render unwanted HTML
|
||||
// example: https://youtu.be/Hh_se2Zqsdk (see pinned comment)
|
||||
const text = escapeHTML(run.text)
|
||||
|
||||
if (run instanceof Misc.EmojiRun) {
|
||||
const { emoji, text } = run
|
||||
const { emoji } = run
|
||||
|
||||
// empty array if video creator removes a channel emoji so we ignore.
|
||||
// eg: pinned comment here https://youtu.be/v3wm83zoSSY
|
||||
@ -577,7 +582,7 @@ export function parseLocalTextRuns(runs, emojiSize = 16, options = { looseChanne
|
||||
parsedRuns.push(`<img src="${emoji.image[0].url}" alt="${altText}" width="${emojiSize}" height="${emojiSize}" loading="lazy" style="vertical-align: middle">`)
|
||||
}
|
||||
} else {
|
||||
const { text, bold, italics, strikethrough, endpoint } = run
|
||||
const { bold, italics, strikethrough, endpoint } = run
|
||||
|
||||
if (endpoint) {
|
||||
switch (endpoint.metadata.page_type) {
|
||||
|
@ -646,3 +646,16 @@ export function getTodayDateStrLocalTimezone() {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
|
||||
return timeNowStr.split('T')[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes HTML tags to avoid XSS
|
||||
* @param {string} untrusted
|
||||
* @returns {string}
|
||||
*/
|
||||
export function escapeHTML(untrusted) {
|
||||
return untrusted.replaceAll('&', '&')
|
||||
.replaceAll('<', '<')
|
||||
.replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll('\'', ''')
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user