From 59adbc348a37bccc8f9a277378e863efbe95497a Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Sun, 30 Jan 2022 00:27:26 +0300 Subject: [PATCH] Escape HTML --- package-lock.json | 9 +++- package.json | 2 + src/components/actionSheet/actionSheet.js | 11 +++-- src/components/activitylog.js | 5 +- src/components/cardbuilder/cardBuilder.js | 27 ++++++----- .../cardbuilder/chaptercardbuilder.js | 3 +- src/components/channelMapper/channelMapper.js | 7 +-- .../collectionEditor/collectionEditor.js | 3 +- .../dashboard/users/SelectElement.tsx | 3 +- .../users/SelectMaxParentalRating.tsx | 3 +- src/components/dialog/dialog.js | 5 +- .../directorybrowser/directorybrowser.js | 9 ++-- .../displaySettings/displaySettings.js | 5 +- src/components/filtermenu/filtermenu.js | 3 +- src/components/guide/guide.js | 9 ++-- .../homeScreenSettings/homeScreenSettings.js | 9 ++-- src/components/homesections/homesections.js | 7 +-- src/components/itemMediaInfo/itemMediaInfo.js | 5 +- .../itemidentifier/itemidentifier.js | 11 +++-- .../libraryoptionseditor.js | 25 +++++----- src/components/listview/listview.js | 3 +- .../mediaLibraryCreator.js | 5 +- .../mediaLibraryEditor/mediaLibraryEditor.js | 7 +-- src/components/mediainfo/mediainfo.js | 7 +-- .../metadataEditor/metadataEditor.js | 11 +++-- src/components/playback/nowplayinghelper.js | 6 ++- .../playlisteditor/playlisteditor.js | 3 +- src/components/prompt/prompt.js | 6 +-- .../recordingcreator/recordingcreator.js | 8 ++-- .../recordingcreator/seriesrecordingeditor.js | 2 +- src/components/remotecontrol/remotecontrol.js | 25 +++++----- src/components/search/SearchSuggestions.tsx | 3 +- .../subtitleeditor/subtitleeditor.js | 11 +++-- src/components/upnextdialog/upnextdialog.js | 2 +- src/controllers/dashboard/dashboard.js | 37 ++++++++------- src/controllers/dashboard/devices/device.js | 2 +- src/controllers/dashboard/devices/devices.js | 7 +-- src/controllers/dashboard/dlna/profile.js | 11 +++-- src/controllers/dashboard/dlna/profiles.js | 3 +- src/controllers/dashboard/dlna/settings.js | 3 +- src/controllers/dashboard/library.js | 5 +- src/controllers/dashboard/metadatanfo.js | 3 +- .../notifications/notification/index.js | 5 +- .../dashboard/users/userpasswordpage.js | 2 +- src/controllers/itemDetails/index.js | 47 ++++++++++--------- src/controllers/movies/moviegenres.js | 3 +- src/controllers/movies/moviesrecommended.js | 4 +- src/controllers/playback/video/index.js | 3 +- src/controllers/session/selectServer/index.js | 3 +- src/controllers/shows/tvgenres.js | 3 +- src/controllers/user/menu/index.js | 2 +- src/controllers/user/profile/index.js | 2 +- src/elements/emby-input/emby-input.js | 4 +- .../emby-playstatebutton.js | 2 +- .../emby-ratingbutton/emby-ratingbutton.js | 2 +- src/elements/emby-select/emby-select.js | 4 +- src/elements/emby-slider/emby-slider.js | 2 +- src/elements/emby-textarea/emby-textarea.js | 4 +- src/scripts/editorsidebar.js | 3 +- src/scripts/libraryMenu.js | 11 +++-- 60 files changed, 245 insertions(+), 192 deletions(-) diff --git a/package-lock.json b/package-lock.json index 92f5392cae..25ff48f5a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2568,6 +2568,12 @@ "@types/node": "*" } }, + "@types/escape-html": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.1.tgz", + "integrity": "sha512-4mI1FuUUZiuT95fSVqvZxp/ssQK9zsa86S43h9x3zPOSU9BBJ+BfDkXwuaU7BfsD+e7U0/cUUfJFk3iW2M4okA==", + "dev": true + }, "@types/eslint": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", @@ -5299,8 +5305,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, "escape-string-regexp": { "version": "1.0.5", diff --git a/package.json b/package.json index 27a498c947..8069a55dc4 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@babel/preset-react": "7.16.7", "@babel/preset-typescript": "7.16.7", "@thornbill/jellyfin-sdk": "0.4.1", + "@types/escape-html": "1.0.1", "@types/lodash-es": "4.17.6", "@types/react": "17.0.39", "@types/react-dom": "17.0.12", @@ -75,6 +76,7 @@ "date-fns": "2.28.0", "dompurify": "2.3.4", "epubjs": "0.3.90", + "escape-html": "1.0.3", "fast-text-encoding": "1.0.3", "flv.js": "1.6.2", "headroom.js": "0.12.0", diff --git a/src/components/actionSheet/actionSheet.js b/src/components/actionSheet/actionSheet.js index 0b040861b0..12d080e3b9 100644 --- a/src/components/actionSheet/actionSheet.js +++ b/src/components/actionSheet/actionSheet.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dialogHelper from '../dialogHelper/dialogHelper'; import layoutManager from '../layoutManager'; import globalize from '../../scripts/globalize'; @@ -156,10 +157,10 @@ export function show(options) { } if (options.title) { - html += '

' + options.title + '

'; + html += '

' + escapeHtml(options.title) + '

'; } if (options.text) { - html += '

' + options.text + '

'; + html += '

' + escapeHtml(options.text) + '

'; } let scrollerClassName = 'actionSheetScroller'; @@ -212,17 +213,17 @@ export function show(options) { html += '
'; html += '
'; - html += (item.name || item.textContent || item.innerText); + html += escapeHtml(item.name || item.textContent || item.innerText); html += '
'; if (item.secondaryText) { - html += `
${item.secondaryText}
`; + html += `
${escapeHtml(item.secondaryText)}
`; } html += '
'; if (item.asideText) { - html += `
${item.asideText}
`; + html += `
${escapeHtml(item.asideText)}
`; } html += ''; diff --git a/src/components/activitylog.js b/src/components/activitylog.js index dab5633f7d..b48b364fc7 100644 --- a/src/components/activitylog.js +++ b/src/components/activitylog.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import { Events } from 'jellyfin-apiclient'; import globalize from '../scripts/globalize'; import dom from '../scripts/dom'; @@ -33,13 +34,13 @@ import alert from './alert'; html += '
'; html += '
'; - html += entry.Name; + html += escapeHtml(entry.Name); html += '
'; html += '
'; html += datefns.formatRelative(Date.parse(entry.Date), Date.parse(new Date()), { locale: dfnshelper.getLocale() }); html += '
'; html += '
'; - html += entry.ShortOverview || ''; + html += escapeHtml(entry.ShortOverview || ''); html += '
'; html += '
'; diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index c2300fb2d8..7826cf2f81 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -5,6 +5,7 @@ * @module components/cardBuilder/cardBuilder */ +import escapeHtml from 'escape-html'; import datetime from '../../scripts/datetime'; import imageLoader from '../images/imageLoader'; import itemHelper from '../itemHelper'; @@ -813,11 +814,11 @@ import ServerConnections from '../ServerConnections'; IsFolder: true })); } else { - lines.push(item.SeriesName); + lines.push(escapeHtml(item.SeriesName)); } } else { if (isUsingLiveTvNaming(item)) { - lines.push(item.Name); + lines.push(escapeHtml(item.Name)); if (!item.EpisodeTitle) { titleAdded = true; @@ -826,7 +827,7 @@ import ServerConnections from '../ServerConnections'; const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || ''; if (parentTitle || showTitle) { - lines.push(parentTitle); + lines.push(escapeHtml(parentTitle)); } } } @@ -860,7 +861,7 @@ import ServerConnections from '../ServerConnections'; item.AlbumArtists[0].IsFolder = true; lines.push(getTextActionButton(item.AlbumArtists[0], null, serverId)); } else { - lines.push(isUsingLiveTvNaming(item) ? item.Name : (item.SeriesName || item.Series || item.Album || item.AlbumArtist || '')); + lines.push(escapeHtml(isUsingLiveTvNaming(item) ? item.Name : (item.SeriesName || item.Series || item.Album || item.AlbumArtist || ''))); } } @@ -948,13 +949,13 @@ import ServerConnections from '../ServerConnections'; }, item.ChannelName)); } else { - lines.push(item.ChannelName || ' '); + lines.push(escapeHtml(item.ChannelName) || ' '); } } if (options.showCurrentProgram && item.Type === 'TvChannel') { if (item.CurrentProgram) { - lines.push(item.CurrentProgram.Name); + lines.push(escapeHtml(item.CurrentProgram.Name)); } else { lines.push(''); } @@ -980,13 +981,13 @@ import ServerConnections from '../ServerConnections'; if (item.RecordAnyChannel) { lines.push(globalize.translate('AllChannels')); } else { - lines.push(item.ChannelName || globalize.translate('OneChannel')); + lines.push(escapeHtml(item.ChannelName) || globalize.translate('OneChannel')); } } if (options.showPersonRoleOrType) { if (item.Role) { - lines.push(globalize.translate('PersonRole', item.Role)); + lines.push(globalize.translate('PersonRole', escapeHtml(item.Role))); } } } @@ -996,7 +997,7 @@ import ServerConnections from '../ServerConnections'; } if (overlayText && showTitle) { - lines = [item.Name]; + lines = [escapeHtml(item.Name)]; } const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; @@ -1031,6 +1032,8 @@ import ServerConnections from '../ServerConnections'; text = itemHelper.getDisplayName(item); } + text = escapeHtml(text); + if (layoutManager.tv) { return text; } @@ -1442,7 +1445,7 @@ import ServerConnections from '../ServerConnections'; const mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : ''; const collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : ''; const channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : ''; - const pathData = item.Path ? (' data-path="' + item.Path + '"') : ''; + const pathData = item.Path ? (' data-path="' + escapeHtml(item.Path) + '"') : ''; const contextData = options.context ? (' data-context="' + options.context + '"') : ''; const parentIdData = options.parentId ? (' data-parentid="' + options.parentId + '"') : ''; const startDate = item.StartDate ? (' data-startdate="' + item.StartDate.toString() + '"') : ''; @@ -1454,7 +1457,7 @@ import ServerConnections from '../ServerConnections'; additionalCardContent += getHoverMenuHtml(item, action); } - return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + pathData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + startDate + endDate + ' data-prefix="' + prefix + '" class="' + className + '"' + ariaLabelAttribute + '>' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + ''; + return '<' + tagName + ' data-index="' + index + '"' + timerAttributes + actionAttribute + ' data-isfolder="' + (item.IsFolder || false) + '" data-serverid="' + (item.ServerId || options.serverId) + '" data-id="' + (item.Id || item.ItemId) + '" data-type="' + item.Type + '"' + mediaTypeData + collectionTypeData + channelIdData + pathData + positionTicksData + collectionIdData + playlistIdData + contextData + parentIdData + startDate + endDate + ' data-prefix="' + escapeHtml(prefix) + '" class="' + className + '"' + ariaLabelAttribute + '>' + cardImageContainerOpen + innerCardFooter + cardImageContainerClose + overlayButtons + additionalCardContent + cardScalableClose + outerCardFooter + cardBoxClose + ''; } /** @@ -1544,7 +1547,7 @@ import ServerConnections from '../ServerConnections'; } const defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item); - return '
' + defaultName + '
'; + return '
' + escapeHtml(defaultName) + '
'; } /** diff --git a/src/components/cardbuilder/chaptercardbuilder.js b/src/components/cardbuilder/chaptercardbuilder.js index 9f48017936..da8de34f9a 100644 --- a/src/components/cardbuilder/chaptercardbuilder.js +++ b/src/components/cardbuilder/chaptercardbuilder.js @@ -5,6 +5,7 @@ * @module components/cardBuilder/chaptercardbuilder */ +import escapeHtml from 'escape-html'; import datetime from '../../scripts/datetime'; import imageLoader from '../images/imageLoader'; import layoutManager from '../layoutManager'; @@ -98,7 +99,7 @@ import ServerConnections from '../ServerConnections'; } let nameHtml = ''; - nameHtml += `
${chapter.Name}
`; + nameHtml += `
${escapeHtml(chapter.Name)}
`; nameHtml += `
${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}
`; const cardBoxCssClass = 'cardBox'; diff --git a/src/components/channelMapper/channelMapper.js b/src/components/channelMapper/channelMapper.js index d1338f182e..be9ff841ce 100644 --- a/src/components/channelMapper/channelMapper.js +++ b/src/components/channelMapper/channelMapper.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dom from '../../scripts/dom'; import dialogHelper from '../dialogHelper/dialogHelper'; import loading from '../loading/loading'; @@ -29,7 +30,7 @@ export default class channelMapper { }).then(mapping => { const listItem = dom.parentWithClass(button, 'listItem'); button.setAttribute('data-providerid', mapping.ProviderChannelId); - listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName); + listItem.querySelector('.secondary').innerText = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName); loading.hide(); }); } @@ -75,12 +76,12 @@ export default class channelMapper { html += ''; html += '
'; html += '

'; - html += channel.Name; + html += escapeHtml(channel.Name); html += '

'; html += '
'; if (channel.ProviderChannelName) { - html += getMappingSecondaryName(channel, providerName); + html += escapeHtml(getMappingSecondaryName(channel, providerName)); } html += '
'; diff --git a/src/components/collectionEditor/collectionEditor.js b/src/components/collectionEditor/collectionEditor.js index f78573af3d..946ddfebbb 100644 --- a/src/components/collectionEditor/collectionEditor.js +++ b/src/components/collectionEditor/collectionEditor.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dom from '../../scripts/dom'; import dialogHelper from '../dialogHelper/dialogHelper'; import loading from '../loading/loading'; @@ -112,7 +113,7 @@ import toast from '../toast/toast'; html += ``; html += result.Items.map(i => { - return ``; + return ``; }); select.innerHTML = html; diff --git a/src/components/dashboard/users/SelectElement.tsx b/src/components/dashboard/users/SelectElement.tsx index a8d88b81c8..329dd9b575 100644 --- a/src/components/dashboard/users/SelectElement.tsx +++ b/src/components/dashboard/users/SelectElement.tsx @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import React, { FunctionComponent } from 'react'; import globalize from '../../../scripts/globalize'; @@ -26,7 +27,7 @@ type IProps = { const SelectElement: FunctionComponent = ({ className, label, currentProviderId, providers }: IProps) => { const renderOption = providers.map((provider) => { const selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : ''; - return ''; + return ''; }); return ( diff --git a/src/components/dashboard/users/SelectMaxParentalRating.tsx b/src/components/dashboard/users/SelectMaxParentalRating.tsx index 24afe7b277..d1865b29e7 100644 --- a/src/components/dashboard/users/SelectMaxParentalRating.tsx +++ b/src/components/dashboard/users/SelectMaxParentalRating.tsx @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import React, { FunctionComponent } from 'react'; import globalize from '../../../scripts/globalize'; @@ -27,7 +28,7 @@ const SelectMaxParentalRating: FunctionComponent = ({ className, label, const renderOption = () => { let content = ''; for (const rating of parentalRatings) { - content += ``; + content += ``; } return content; }; diff --git a/src/components/dialog/dialog.js b/src/components/dialog/dialog.js index e95b8a42e0..68b8c0a4ba 100644 --- a/src/components/dialog/dialog.js +++ b/src/components/dialog/dialog.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dialogHelper from '../dialogHelper/dialogHelper'; import dom from '../../scripts/dom'; import layoutManager from '../layoutManager'; @@ -47,7 +48,7 @@ import template from './dialog.template.html'; } if (options.title) { - dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || ''; + dlg.querySelector('.formDialogHeaderTitle').innerText = options.title || ''; } else { dlg.querySelector('.formDialogHeaderTitle').classList.add('hide'); } @@ -82,7 +83,7 @@ import template from './dialog.template.html'; buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom'; } - html += ``; + html += ``; if (item.description) { html += `
${item.description}
`; diff --git a/src/components/directorybrowser/directorybrowser.js b/src/components/directorybrowser/directorybrowser.js index cc11736d99..ceb47b4438 100644 --- a/src/components/directorybrowser/directorybrowser.js +++ b/src/components/directorybrowser/directorybrowser.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import loading from '../loading/loading'; import dialogHelper from '../dialogHelper/dialogHelper'; import dom from '../../scripts/dom'; @@ -71,10 +72,10 @@ function refreshDirectoryBrowser(page, path, fileOptions, updatePathOnError) { function getItem(cssClass, type, path, name) { let html = ''; - html += `
`; + html += `
`; html += '
'; html += '
'; - html += name; + html += escapeHtml(name); html += '
'; html += '
'; html += ''; @@ -87,7 +88,7 @@ function getEditorHtml(options, systemInfo) { html += '
'; html += '
'; if (!options.pathReadOnly) { - const instruction = options.instruction ? `${options.instruction}

` : ''; + const instruction = options.instruction ? `${escapeHtml(options.instruction)}

` : ''; html += '
'; html += instruction; if (systemInfo.OperatingSystem.toLowerCase() === 'bsd') { @@ -266,7 +267,7 @@ class DirectoryBrowser { html += '
'; html += ``; html += '

'; - html += options.header || globalize.translate('HeaderSelectPath'); + html += escapeHtml(options.header) || globalize.translate('HeaderSelectPath'); html += '

'; html += '
'; html += getEditorHtml(options, systemInfo); diff --git a/src/components/displaySettings/displaySettings.js b/src/components/displaySettings/displaySettings.js index bf93e7a005..9b9df94131 100644 --- a/src/components/displaySettings/displaySettings.js +++ b/src/components/displaySettings/displaySettings.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import browser from '../../scripts/browser'; import layoutManager from '../layoutManager'; import { pluginManager } from '../pluginManager'; @@ -21,7 +22,7 @@ import template from './displaySettings.template.html'; function fillThemes(select, selectedTheme) { skinManager.getThemes().then(themes => { select.innerHTML = themes.map(t => { - return ``; + return ``; }).join(''); // get default theme @@ -47,7 +48,7 @@ import template from './displaySettings.template.html'; }); selectScreensaver.innerHTML = options.map(o => { - return ``; + return ``; }).join(''); selectScreensaver.value = userSettings.screensaver(); diff --git a/src/components/filtermenu/filtermenu.js b/src/components/filtermenu/filtermenu.js index 8c71782968..6f2378eca3 100644 --- a/src/components/filtermenu/filtermenu.js +++ b/src/components/filtermenu/filtermenu.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dom from '../../scripts/dom'; import focusManager from '../focusManager'; import dialogHelper from '../dialogHelper/dialogHelper'; @@ -37,7 +38,7 @@ function renderOptions(context, selector, cssClass, items, isCheckedFn) { const checkedHtml = isCheckedFn(filter) ? ' checked' : ''; itemHtml += ''; return itemHtml; diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index 017bfdb415..c9b5b108e0 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import inputManager from '../../scripts/inputManager'; import browser from '../../scripts/browser'; import globalize from '../../scripts/globalize'; @@ -538,7 +539,7 @@ function Guide(options) { html += '
'; - html += '
' + program.Name; + html += '
' + escapeHtml(program.Name); let indicatorHtml = null; if (program.IsLive && options.showLiveIndicator) { @@ -556,7 +557,7 @@ function Guide(options) { html += '
'; if (program.EpisodeTitle && options.showEpisodeTitle) { - html += '' + program.EpisodeTitle + ''; + html += '' + escapeHtml(program.EpisodeTitle) + ''; } html += '
'; } @@ -604,7 +605,7 @@ function Guide(options) { title.push(channel.Name); } - html += ''; diff --git a/src/components/homeScreenSettings/homeScreenSettings.js b/src/components/homeScreenSettings/homeScreenSettings.js index 7561a40791..2adba2f6b8 100644 --- a/src/components/homeScreenSettings/homeScreenSettings.js +++ b/src/components/homeScreenSettings/homeScreenSettings.js @@ -1,4 +1,5 @@ +import escapeHtml from 'escape-html'; import layoutManager from '../layoutManager'; import focusManager from '../focusManager'; import globalize from '../../scripts/globalize'; @@ -32,7 +33,7 @@ import template from './homeScreenSettings.template.html'; currentHtml += ''; return currentHtml; @@ -165,7 +166,7 @@ import template from './homeScreenSettings.template.html'; const selectedHtml = selected ? ' selected' : ''; const optionValue = o.isDefault ? '' : o.value; - return ``; + return ``; }).join(''); } @@ -182,7 +183,7 @@ import template from './homeScreenSettings.template.html'; currentHtml += '
'; currentHtml += '
'; - currentHtml += view.Name; + currentHtml += escapeHtml(view.Name); currentHtml += '
'; currentHtml += '
'; @@ -265,7 +266,7 @@ import template from './homeScreenSettings.template.html'; prefix += '
'; prefix += '

'; - prefix += item.Name; + prefix += escapeHtml(item.Name); prefix += '

'; html = prefix + html; diff --git a/src/components/homesections/homesections.js b/src/components/homesections/homesections.js index 25c231d560..320dc94471 100644 --- a/src/components/homesections/homesections.js +++ b/src/components/homesections/homesections.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import cardBuilder from '../cardbuilder/cardBuilder'; import dom from '../../scripts/dom'; import layoutManager from '../layoutManager'; @@ -192,7 +193,7 @@ import ServerConnections from '../ServerConnections'; for (let i = 0, length = items.length; i < length; i++) { const item = items[i]; const icon = imageHelper.getLibraryIcon(item.CollectionType); - html += '' + item.Name + ''; + html += '' + escapeHtml(item.Name) + ''; } html += '
'; @@ -281,12 +282,12 @@ import ServerConnections from '../ServerConnections'; section: 'latest' }) + '" class="more button-flat button-flat-mini sectionTitleTextButton">'; html += '

'; - html += globalize.translate('LatestFromLibrary', parent.Name); + html += globalize.translate('LatestFromLibrary', escapeHtml(parent.Name)); html += '

'; html += ''; html += ''; } else { - html += '

' + globalize.translate('LatestFromLibrary', parent.Name) + '

'; + html += '

' + globalize.translate('LatestFromLibrary', escapeHtml(parent.Name)) + '

'; } html += '
'; diff --git a/src/components/itemMediaInfo/itemMediaInfo.js b/src/components/itemMediaInfo/itemMediaInfo.js index a61dd165de..08c290379c 100644 --- a/src/components/itemMediaInfo/itemMediaInfo.js +++ b/src/components/itemMediaInfo/itemMediaInfo.js @@ -5,6 +5,7 @@ * @module components/itemMediaInfo/itemMediaInfo */ +import escapeHtml from 'escape-html'; import dialogHelper from '../dialogHelper/dialogHelper'; import layoutManager from '../layoutManager'; import toast from '../toast/toast'; @@ -55,7 +56,7 @@ const attributeDelimiterHtml = layoutManager.tv ? '' : ':

${version.Name}${copyButtonHtml}

\n`; + html += `

${escapeHtml(version.Name)}${copyButtonHtml}

\n`; } if (version.Container) { html += `${createAttribute(globalize.translate('MediaInfoContainer'), version.Container)}
`; @@ -181,7 +182,7 @@ const attributeDelimiterHtml = layoutManager.tv ? '' : ': ${label}${attributeDelimiterHtml}${value}\n`; + return `${label}${attributeDelimiterHtml}${escapeHtml(value)}\n`; } function loadMediaInfo(itemId, serverId) { diff --git a/src/components/itemidentifier/itemidentifier.js b/src/components/itemidentifier/itemidentifier.js index 885f21a2f3..eae3257513 100644 --- a/src/components/itemidentifier/itemidentifier.js +++ b/src/components/itemidentifier/itemidentifier.js @@ -5,6 +5,7 @@ * @module components/itemidentifier/itemidentifier */ +import escapeHtml from 'escape-html'; import dialogHelper from '../dialogHelper/dialogHelper'; import loading from '../loading/loading'; import globalize from '../../scripts/globalize'; @@ -162,7 +163,7 @@ import template from './itemidentifier.template.html'; currentSearchResult = identifyResult; const lines = []; - lines.push(identifyResult.Name); + lines.push(escapeHtml(identifyResult.Name)); if (identifyResult.ProductionYear) { lines.push(identifyResult.ProductionYear); @@ -218,7 +219,7 @@ import template from './itemidentifier.template.html'; if (result.ImageUrl) { html += `
`; } else { - html += `
${result.Name}
`; + html += `
${escapeHtml(result.Name)}
`; } html += '
'; html += '
'; @@ -245,7 +246,7 @@ import template from './itemidentifier.template.html'; } else { html += '
'; } - html += lines[i] || ' '; + html += escapeHtml(lines[i]) || ' '; html += '
'; } @@ -299,7 +300,7 @@ import template from './itemidentifier.template.html'; fullName = `${idInfo.Name} ${globalize.translate(idInfo.Type)}`; } - const idLabel = globalize.translate('LabelDynamicExternalId', fullName); + const idLabel = globalize.translate('LabelDynamicExternalId', escapeHtml(fullName)); html += ``; @@ -364,7 +365,7 @@ import template from './itemidentifier.template.html'; dlg.querySelector('.fldPath').classList.add('hide'); } - dlg.querySelector('.txtPath').innerHTML = item.Path || ''; + dlg.querySelector('.txtPath').innerText = item.Path || ''; dialogHelper.open(dlg); diff --git a/src/components/libraryoptionseditor/libraryoptionseditor.js b/src/components/libraryoptionseditor/libraryoptionseditor.js index f57e6e1b65..59478280a9 100644 --- a/src/components/libraryoptionseditor/libraryoptionseditor.js +++ b/src/components/libraryoptionseditor/libraryoptionseditor.js @@ -5,6 +5,7 @@ * @module components/libraryoptionseditor/libraryoptionseditor */ +import escapeHtml from 'escape-html'; import globalize from '../../scripts/globalize'; import dom from '../../scripts/dom'; import '../../elements/emby-checkbox/emby-checkbox'; @@ -68,11 +69,11 @@ import template from './libraryoptionseditor.template.html'; html += '
'; for (let i = 0; i < plugins.length; i++) { const plugin = plugins[i]; - html += `
`; + html += `
`; html += ''; html += '
'; html += '

'; - html += plugin.Name; + html += escapeHtml(plugin.Name); html += '

'; html += '
'; if (i > 0) { @@ -101,7 +102,7 @@ import template from './libraryoptionseditor.template.html'; html += '
'; for (let i = 0; i < metadataSavers.length; i++) { const plugin = metadataSavers[i]; - html += ``; + html += ``; } html += '
'; html += `
${globalize.translate('LabelMetadataSaversHelp')}
`; @@ -122,13 +123,13 @@ import template from './libraryoptionseditor.template.html'; html += '
'; plugins.forEach((plugin, index) => { - html += '
'; + html += '
'; const isChecked = libraryOptionsForType.MetadataFetchers ? libraryOptionsForType.MetadataFetchers.includes(plugin.Name) : plugin.DefaultEnabled; const checkedHtml = isChecked ? ' checked="checked"' : ''; - html += ''; + html += ''; html += '
'; html += '

'; - html += plugin.Name; + html += escapeHtml(plugin.Name); html += '

'; html += '
'; if (index > 0) { @@ -188,13 +189,13 @@ import template from './libraryoptionseditor.template.html'; html += '
'; for (let i = 0; i < plugins.length; i++) { const plugin = plugins[i]; - html += `
`; + html += `
`; const isChecked = libraryOptions.DisabledSubtitleFetchers ? !libraryOptions.DisabledSubtitleFetchers.includes(plugin.Name) : plugin.DefaultEnabled; const checkedHtml = isChecked ? ' checked="checked"' : ''; - html += ``; + html += ``; html += '
'; html += '

'; - html += plugin.Name; + html += escapeHtml(plugin.Name); html += '

'; html += '
'; if (i > 0) { @@ -227,13 +228,13 @@ import template from './libraryoptionseditor.template.html'; html += '
'; for (let i = 0; i < plugins.length; i++) { const plugin = plugins[i]; - html += '
'; + html += '
'; const isChecked = libraryOptionsForType.ImageFetchers ? libraryOptionsForType.ImageFetchers.includes(plugin.Name) : plugin.DefaultEnabled; const checkedHtml = isChecked ? ' checked="checked"' : ''; - html += ''; + html += ''; html += '
'; html += '

'; - html += plugin.Name; + html += escapeHtml(plugin.Name); html += '

'; html += '
'; if (i > 0) { diff --git a/src/components/listview/listview.js b/src/components/listview/listview.js index d75580f824..ee75656367 100644 --- a/src/components/listview/listview.js +++ b/src/components/listview/listview.js @@ -5,6 +5,7 @@ * @module components/listview/listview */ +import escapeHtml from 'escape-html'; import itemHelper from '../itemHelper'; import mediaInfo from '../mediainfo/mediainfo'; import indicators from '../indicators/indicators'; @@ -203,7 +204,7 @@ import ServerConnections from '../ServerConnections'; } else { html += '

'; } - html += itemGroupTitle; + html += escapeHtml(itemGroupTitle); html += '

'; html += '
'; diff --git a/src/components/mediaLibraryCreator/mediaLibraryCreator.js b/src/components/mediaLibraryCreator/mediaLibraryCreator.js index 889804bc9d..c1e6826f6e 100644 --- a/src/components/mediaLibraryCreator/mediaLibraryCreator.js +++ b/src/components/mediaLibraryCreator/mediaLibraryCreator.js @@ -5,6 +5,7 @@ * @module components/mediaLibraryCreator/mediaLibraryCreator */ +import escapeHtml from 'escape-html'; import loading from '../loading/loading'; import dialogHelper from '../dialogHelper/dialogHelper'; import dom from '../../scripts/dom'; @@ -120,10 +121,10 @@ import template from './mediaLibraryCreator.template.html'; let html = ''; html += '
'; html += `
`; - html += `
${pathInfo.Path}
`; + html += `
${escapeHtml(pathInfo.Path)}
`; if (pathInfo.NetworkPath) { - html += `
${pathInfo.NetworkPath}
`; + html += `
${escapeHtml(pathInfo.NetworkPath)}
`; } html += '
'; diff --git a/src/components/mediaLibraryEditor/mediaLibraryEditor.js b/src/components/mediaLibraryEditor/mediaLibraryEditor.js index aaf0c1e550..9cbe9b0519 100644 --- a/src/components/mediaLibraryEditor/mediaLibraryEditor.js +++ b/src/components/mediaLibraryEditor/mediaLibraryEditor.js @@ -5,6 +5,7 @@ * @module components/mediaLibraryEditor/mediaLibraryEditor */ +import escapeHtml from 'escape-html'; import 'jquery'; import loading from '../loading/loading'; import dialogHelper from '../dialogHelper/dialogHelper'; @@ -111,11 +112,11 @@ import template from './mediaLibraryEditor.template.html'; html += `
`; html += `
`; html += '

'; - html += pathInfo.Path; + html += escapeHtml(pathInfo.Path); html += '

'; if (pathInfo.NetworkPath) { - html += `
${pathInfo.NetworkPath}
`; + html += `
${escapeHtml(pathInfo.NetworkPath)}
`; } html += '
'; @@ -213,7 +214,7 @@ export class showEditor { dlg.classList.add('background-theme-a'); dlg.classList.add('formDialog'); dlg.innerHTML = globalize.translateHtml(template); - dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name; + dlg.querySelector('.formDialogHeaderTitle').innerText = options.library.Name; initEditor(dlg, options); dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); diff --git a/src/components/mediainfo/mediainfo.js b/src/components/mediainfo/mediainfo.js index 737d8a4624..f21bc8f666 100644 --- a/src/components/mediainfo/mediainfo.js +++ b/src/components/mediainfo/mediainfo.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import datetime from '../../scripts/datetime'; import globalize from '../../scripts/globalize'; import { appRouter } from '../appRouter'; @@ -77,10 +78,10 @@ import '../../elements/emby-button/emby-button'; Name: item.ChannelName, Id: item.ChannelId - })}">${item.ChannelName}` + })}">${escapeHtml(item.ChannelName)}` }); } else { - miscInfo.push(item.ChannelName); + miscInfo.push(escapeHtml(item.ChannelName)); } } @@ -221,7 +222,7 @@ import '../../elements/emby-button/emby-button'; }); if (text) { - miscInfo.push(text); + miscInfo.push(escapeHtml(text)); } } else if (item.IsMovie && item.ProductionYear && options.originalAirDate !== false) { miscInfo.push(item.ProductionYear); diff --git a/src/components/metadataEditor/metadataEditor.js b/src/components/metadataEditor/metadataEditor.js index ce2f27faad..d5e39d45af 100644 --- a/src/components/metadataEditor/metadataEditor.js +++ b/src/components/metadataEditor/metadataEditor.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dom from '../../scripts/dom'; import layoutManager from '../layoutManager'; import dialogHelper from '../dialogHelper/dialogHelper'; @@ -448,12 +449,12 @@ import template from './metadataEditor.template.html'; fullName = idInfo.Name + ' ' + globalize.translate(idInfo.Type); } - const labelText = globalize.translate('LabelDynamicExternalId', fullName); + const labelText = globalize.translate('LabelDynamicExternalId', escapeHtml(fullName)); html += '
'; html += '
'; - const value = providerIds[idInfo.Key] || ''; + const value = escapeHtml(providerIds[idInfo.Key] || ''); html += '
'; html += ''; @@ -860,7 +861,7 @@ import template from './metadataEditor.template.html'; for (let i = 0, length = ratings.length; i < length; i++) { rating = ratings[i]; - html += "'; + html += "'; } select.innerHTML = html; @@ -893,7 +894,7 @@ import template from './metadataEditor.template.html'; html += '
'; html += '
'; - html += items[i]; + html += escapeHtml(items[i]); html += '
'; html += '
'; @@ -923,7 +924,7 @@ import template from './metadataEditor.template.html'; html += ''; li += '
'; @@ -144,7 +145,7 @@ import toast from '../../../components/toast/toast'; let li = '
'; li += ''; li += '
'; - li += '

' + h.Name + ' = ' + (h.Value || '') + '

'; + li += '

' + escapeHtml(h.Name + ' = ' + (h.Value || '')) + '

'; li += '
'; li += ''; return li += '
'; @@ -186,7 +187,7 @@ import toast from '../../../components/toast/toast'; let li = '
'; li += ''; li += '
'; - li += '

' + (h.Format || '') + '

'; + li += '

' + escapeHtml(h.Format || '') + '

'; li += '
'; li += ''; li += '
'; diff --git a/src/controllers/dashboard/dlna/profiles.js b/src/controllers/dashboard/dlna/profiles.js index 40e1b2ee72..63c61aa3c3 100644 --- a/src/controllers/dashboard/dlna/profiles.js +++ b/src/controllers/dashboard/dlna/profiles.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import globalize from '../../../scripts/globalize'; import loading from '../../../components/loading/loading'; @@ -42,7 +43,7 @@ import confirm from '../../../components/confirm/confirm'; html += ''; html += ''; diff --git a/src/controllers/dashboard/dlna/settings.js b/src/controllers/dashboard/dlna/settings.js index 4fa8467f36..7da0746cfe 100644 --- a/src/controllers/dashboard/dlna/settings.js +++ b/src/controllers/dashboard/dlna/settings.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import loading from '../../../components/loading/loading'; import libraryMenu from '../../../scripts/libraryMenu'; @@ -14,7 +15,7 @@ import Dashboard from '../../../scripts/clientUtils'; $('#chkBlastAliveMessages', page).prop('checked', config.BlastAliveMessages); $('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds); const usersHtml = users.map(function (u) { - return ''; + return ''; }).join(''); $('#selectUser', page).html(usersHtml).val(config.DefaultUserId || ''); loading.hide(); diff --git a/src/controllers/dashboard/library.js b/src/controllers/dashboard/library.js index e94b9ee909..38202ccb62 100644 --- a/src/controllers/dashboard/library.js +++ b/src/controllers/dashboard/library.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import taskButton from '../../scripts/taskbutton'; import loading from '../../components/loading/loading'; @@ -297,7 +298,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder'; if (virtualFolder.showNameWithIcon) { html += '
'; - html += virtualFolder.Name; + html += escapeHtml(virtualFolder.Name); html += '
'; } @@ -319,7 +320,7 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder'; if (virtualFolder.showNameWithIcon) { html += ' '; } else { - html += virtualFolder.Name; + html += escapeHtml(virtualFolder.Name); } html += '
'; diff --git a/src/controllers/dashboard/metadatanfo.js b/src/controllers/dashboard/metadatanfo.js index b0af868582..e0da30b5ef 100644 --- a/src/controllers/dashboard/metadatanfo.js +++ b/src/controllers/dashboard/metadatanfo.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import loading from '../../components/loading/loading'; import libraryMenu from '../../scripts/libraryMenu'; @@ -10,7 +11,7 @@ import alert from '../../components/alert'; function loadPage(page, config, users) { let html = ''; html += users.map(function (user) { - return ''; + return ''; }).join(''); $('#selectUser', page).html(html).val(config.UserId || ''); $('#selectReleaseDateFormat', page).val(config.ReleaseDateFormat); diff --git a/src/controllers/dashboard/notifications/notification/index.js b/src/controllers/dashboard/notifications/notification/index.js index 1bd5100c96..2b562ea073 100644 --- a/src/controllers/dashboard/notifications/notification/index.js +++ b/src/controllers/dashboard/notifications/notification/index.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import '../../../../elements/emby-checkbox/emby-checkbox'; import Dashboard from '../../../../scripts/clientUtils'; @@ -7,7 +8,7 @@ function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) html += items.map(function (u) { const isChecked = isEnabledList ? currentList.indexOf(u.Id) != -1 : currentList.indexOf(u.Id) == -1; const checkedHtml = isChecked ? ' checked="checked"' : ''; - return ''; + return ''; }).join(''); html += '
'; elem.html(html).trigger('create'); @@ -37,7 +38,7 @@ function reload(page) { $('.monitorUsers', page).hide(); } - $('.notificationType', page).html(typeInfo.Name || 'Unknown Notification'); + $('.notificationType', page).html(escapeHtml(typeInfo.Name) || 'Unknown Notification'); if (!notificationConfig) { notificationConfig = { diff --git a/src/controllers/dashboard/users/userpasswordpage.js b/src/controllers/dashboard/users/userpasswordpage.js index ab76ce474f..fa9c95ce20 100644 --- a/src/controllers/dashboard/users/userpasswordpage.js +++ b/src/controllers/dashboard/users/userpasswordpage.js @@ -13,7 +13,7 @@ import confirm from '../../../components/confirm/confirm'; ApiClient.getUser(userid).then(function (user) { Dashboard.getCurrentUser().then(function (loggedInUser) { libraryMenu.setTitle(user.Name); - page.querySelector('.username').innerHTML = user.Name; + page.querySelector('.username').innerText = user.Name; let showPasswordSection = true; let showLocalAccessSection = false; diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index 7c3856afb8..445e68aafa 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -1,4 +1,5 @@ import { intervalToDuration } from 'date-fns'; +import escapeHtml from 'escape-html'; import { appHost } from '../../components/apphost'; import loading from '../../components/loading/loading'; import { appRouter } from '../../components/appRouter'; @@ -211,7 +212,7 @@ function renderTrackSelections(page, instance, item, forceReload) { const selectedId = mediaSources[0].Id; select.innerHTML = mediaSources.map(function (v) { const selected = v.Id === selectedId ? ' selected' : ''; - return ''; + return ''; }).join(''); if (mediaSources.length > 1) { @@ -415,7 +416,7 @@ function getArtistLinksHtml(artists, serverId, context) { itemType: 'MusicArtist', serverId: serverId }); - html.push('' + artist.Name + ''); + html.push('' + escapeHtml(artist.Name) + ''); } return html.join(' / '); @@ -438,21 +439,21 @@ function renderName(item, container, context) { parentNameHtml.push(getArtistLinksHtml(item.ArtistItems, item.ServerId, context)); parentNameLast = true; } else if (item.SeriesName && item.Type === 'Episode') { - parentNameHtml.push(`${item.SeriesName}`); + parentNameHtml.push(`${escapeHtml(item.SeriesName)}`); } else if (item.IsSeries || item.EpisodeTitle) { - parentNameHtml.push(item.Name); + parentNameHtml.push(escapeHtml(item.Name)); } if (item.SeriesName && item.Type === 'Season') { - parentNameHtml.push(`${item.SeriesName}`); + parentNameHtml.push(`${escapeHtml(item.SeriesName)}`); } else if (item.ParentIndexNumber != null && item.Type === 'Episode') { - parentNameHtml.push(`${item.SeasonName}`); + parentNameHtml.push(`${escapeHtml(item.SeasonName)}`); } else if (item.ParentIndexNumber != null && item.IsSeries) { - parentNameHtml.push(item.SeasonName || 'S' + item.ParentIndexNumber); + parentNameHtml.push(escapeHtml(item.SeasonName) || 'S' + item.ParentIndexNumber); } else if (item.Album && item.AlbumId && (item.Type === 'MusicVideo' || item.Type === 'Audio')) { - parentNameHtml.push(`${item.Album}`); + parentNameHtml.push(`${escapeHtml(item.Album)}`); } else if (item.Album) { - parentNameHtml.push(item.Album); + parentNameHtml.push(escapeHtml(item.Album)); } // FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022 @@ -473,9 +474,9 @@ function renderName(item, container, context) { } } - const name = itemHelper.getDisplayName(item, { + const name = escapeHtml(itemHelper.getDisplayName(item, { includeParentInfo: false - }); + })); if (html && !parentNameLast) { if (tvSeasonHtml) { @@ -490,7 +491,7 @@ function renderName(item, container, context) { } if (item.OriginalTitle && item.OriginalTitle != item.Name) { - html += '

' + item.OriginalTitle + '

'; + html += '

' + escapeHtml(item.OriginalTitle) + '

'; } container.innerHTML = html; @@ -667,7 +668,7 @@ function reloadFromItem(instance, page, params, item, user) { location = `${location}`; } itemBirthLocation.classList.remove('hide'); - itemBirthLocation.innerHTML = globalize.translate('BirthPlaceValue', location); + itemBirthLocation.innerText = globalize.translate('BirthPlaceValue', location); } else { itemBirthLocation.classList.add('hide'); } @@ -947,7 +948,7 @@ function renderGenres(page, item, context = inferContext(item)) { Id: p.Id }, { context: context - }) + '">' + p.Name + ''; + }) + '">' + escapeHtml(p.Name) + ''; }).join(', '); const genresLabel = page.querySelector('.genresLabel'); @@ -976,7 +977,7 @@ function renderWriter(page, item, context) { Id: person.Id }, { context: context - }) + '">' + person.Name + ''; + }) + '">' + escapeHtml(person.Name) + ''; }).join(', '); const writersLabel = page.querySelector('.writersLabel'); @@ -1005,7 +1006,7 @@ function renderDirector(page, item, context) { Id: person.Id }, { context: context - }) + '">' + person.Name + ''; + }) + '">' + escapeHtml(person.Name) + ''; }).join(', '); const directorsLabel = page.querySelector('.directorsLabel'); @@ -1058,7 +1059,7 @@ function renderTagline(page, item) { if (item.Taglines && item.Taglines.length) { taglineElement.classList.remove('hide'); - taglineElement.innerHTML = item.Taglines[0]; + taglineElement.innerText = item.Taglines[0]; } else { taglineElement.classList.add('hide'); } @@ -1125,7 +1126,7 @@ function renderMoreFromSeason(view, item, apiClient) { } section.classList.remove('hide'); - section.querySelector('h2').innerHTML = globalize.translate('MoreFromValue', item.SeasonName); + section.querySelector('h2').innerText = globalize.translate('MoreFromValue', item.SeasonName); const itemsContainer = section.querySelector('.itemsContainer'); cardBuilder.buildCards(result.Items, { parentContainer: section, @@ -1184,9 +1185,9 @@ function renderMoreFromArtist(view, item, apiClient) { section.classList.remove('hide'); if (item.Type === 'MusicArtist') { - section.querySelector('h2').innerHTML = globalize.translate('HeaderAppearsOn'); + section.querySelector('h2').innerText = globalize.translate('HeaderAppearsOn'); } else { - section.querySelector('h2').innerHTML = globalize.translate('MoreFromValue', item.AlbumArtists[0].Name); + section.querySelector('h2').innerText = globalize.translate('MoreFromValue', item.AlbumArtists[0].Name); } cardBuilder.buildCards(result.Items, { @@ -1276,7 +1277,7 @@ function renderSeriesAirTime(page, item, isStatic) { } if (item.Studios.length) { if (isStatic) { - html += ' on ' + item.Studios[0].Name; + html += ' on ' + escapeHtml(item.Studios[0].Name); } else { const context = inferContext(item); const href = appRouter.getRouteUrl(item.Studios[0], { @@ -1284,7 +1285,7 @@ function renderSeriesAirTime(page, item, isStatic) { itemType: 'Studio', serverId: item.ServerId }); - html += ' on ' + item.Studios[0].Name + ''; + html += ' on ' + escapeHtml(item.Studios[0].Name) + ''; } } if (html) { @@ -1310,7 +1311,7 @@ function renderTags(page, item) { } if (tagElements.length) { - itemTags.innerHTML = globalize.translate('TagsValue', tagElements.join(', ')); + itemTags.innerText = globalize.translate('TagsValue', tagElements.join(', ')); itemTags.classList.remove('hide'); } else { itemTags.innerHTML = ''; diff --git a/src/controllers/movies/moviegenres.js b/src/controllers/movies/moviegenres.js index 0bda9f3af4..62320fa3ab 100644 --- a/src/controllers/movies/moviegenres.js +++ b/src/controllers/movies/moviegenres.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import layoutManager from '../../components/layoutManager'; import loading from '../../components/loading/loading'; import libraryBrowser from '../../scripts/libraryBrowser'; @@ -150,7 +151,7 @@ import '../../elements/emby-button/emby-button'; parentId: params.topParentId }) + '" class="more button-flat button-flat-mini sectionTitleTextButton btnMoreFromGenre' + item.Id + '">'; html += '

'; - html += item.Name; + html += escapeHtml(item.Name); html += '

'; html += ''; html += ''; diff --git a/src/controllers/movies/moviesrecommended.js b/src/controllers/movies/moviesrecommended.js index 31b19a5a2f..b9532e3d8c 100644 --- a/src/controllers/movies/moviesrecommended.js +++ b/src/controllers/movies/moviesrecommended.js @@ -1,4 +1,4 @@ - +import escapeHtml from 'escape-html'; import { Events } from 'jellyfin-apiclient'; import layoutManager from '../../components/layoutManager'; import inputManager from '../../scripts/inputManager'; @@ -127,7 +127,7 @@ import Dashboard from '../../scripts/clientUtils'; } html += '
'; - html += '

' + title + '

'; + html += '

' + escapeHtml(title) + '

'; const allowBottomPadding = true; if (enableScrollX()) { diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 32abe27275..a27e119768 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import { playbackManager } from '../../../components/playback/playbackmanager'; import SyncPlay from '../../../components/syncPlay/core'; import browser from '../../../scripts/browser'; @@ -1236,7 +1237,7 @@ import { appRouter } from '../../../components/appRouter'; html += ''; html += '
'; html += '
'; - html += chapter.Name; + html += escapeHtml(chapter.Name); html += '
'; html += '

'; html += datetime.getDisplayRunningTime(positionTicks); diff --git a/src/controllers/session/selectServer/index.js b/src/controllers/session/selectServer/index.js index 632267558c..3d4cc0c576 100644 --- a/src/controllers/session/selectServer/index.js +++ b/src/controllers/session/selectServer/index.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import loading from '../../../components/loading/loading'; import { appRouter } from '../../../components/appRouter'; import layoutManager from '../../../components/layoutManager'; @@ -71,7 +72,7 @@ import cardBuilder from '../../../components/cardbuilder/cardBuilder'; cardContainer += '

'; cardContainer += '
'; cardContainer += '
'; - cardContainer += '
' + item.name + '
'; + cardContainer += '
' + escapeHtml(item.name) + '
'; cardContainer += '
'; return cardContainer; }).join(''); diff --git a/src/controllers/shows/tvgenres.js b/src/controllers/shows/tvgenres.js index a14d25344a..7db974744b 100644 --- a/src/controllers/shows/tvgenres.js +++ b/src/controllers/shows/tvgenres.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import layoutManager from '../../components/layoutManager'; import loading from '../../components/loading/loading'; import libraryBrowser from '../../scripts/libraryBrowser'; @@ -148,7 +149,7 @@ import '../../elements/emby-button/emby-button'; parentId: params.topParentId }) + '" class="more button-flat button-flat-mini sectionTitleTextButton btnMoreFromGenre' + item.Id + '">'; html += '

'; - html += item.Name; + html += escapeHtml(item.Name); html += '

'; html += ''; html += ''; diff --git a/src/controllers/user/menu/index.js b/src/controllers/user/menu/index.js index f9443c92d1..07d907d2e2 100644 --- a/src/controllers/user/menu/index.js +++ b/src/controllers/user/menu/index.js @@ -55,7 +55,7 @@ export default function (view, params) { console.debug('Failed to get QuickConnect status'); }); ApiClient.getUser(userId).then(function (user) { - page.querySelector('.headerUsername').innerHTML = user.Name; + page.querySelector('.headerUsername').innerText = user.Name; if (user.Policy.IsAdministrator && !layoutManager.tv) { page.querySelector('.adminSection').classList.remove('hide'); } diff --git a/src/controllers/user/profile/index.js b/src/controllers/user/profile/index.js index 750bacab90..c6d23eb2f9 100644 --- a/src/controllers/user/profile/index.js +++ b/src/controllers/user/profile/index.js @@ -12,7 +12,7 @@ function reloadUser(page) { const userId = getParameterByName('userId'); loading.show(); ApiClient.getUser(userId).then(function (user) { - page.querySelector('.username').innerHTML = user.Name; + page.querySelector('.username').innerText = user.Name; libraryMenu.setTitle(user.Name); let imageUrl = 'assets/img/avatar.png'; diff --git a/src/elements/emby-input/emby-input.js b/src/elements/emby-input/emby-input.js index beea22af54..f9ea23f2ea 100644 --- a/src/elements/emby-input/emby-input.js +++ b/src/elements/emby-input/emby-input.js @@ -45,7 +45,7 @@ import 'webcomponents.js/webcomponents-lite'; const parentNode = this.parentNode; const document = this.ownerDocument; const label = document.createElement('label'); - label.innerHTML = this.getAttribute('label') || ''; + label.innerText = this.getAttribute('label') || ''; label.classList.add('inputLabel'); label.classList.add('inputLabelUnfocused'); @@ -114,7 +114,7 @@ import 'webcomponents.js/webcomponents-lite'; }; EmbyInputPrototype.label = function (text) { - this.labelElement.innerHTML = text; + this.labelElement.innerText = text; }; document.registerElement('emby-input', { diff --git a/src/elements/emby-playstatebutton/emby-playstatebutton.js b/src/elements/emby-playstatebutton/emby-playstatebutton.js index 43140e4ec6..63ab3fd660 100644 --- a/src/elements/emby-playstatebutton/emby-playstatebutton.js +++ b/src/elements/emby-playstatebutton/emby-playstatebutton.js @@ -79,7 +79,7 @@ import ServerConnections from '../../components/ServerConnections'; const text = button.querySelector('.button-text'); if (text) { - text.innerHTML = button.title; + text.innerText = button.title; } } diff --git a/src/elements/emby-ratingbutton/emby-ratingbutton.js b/src/elements/emby-ratingbutton/emby-ratingbutton.js index de42531891..dea35f36f3 100644 --- a/src/elements/emby-ratingbutton/emby-ratingbutton.js +++ b/src/elements/emby-ratingbutton/emby-ratingbutton.js @@ -97,7 +97,7 @@ import ServerConnections from '../../components/ServerConnections'; const text = button.querySelector('.button-text'); if (text) { - text.innerHTML = button.title; + text.innerText = button.title; } } diff --git a/src/elements/emby-select/emby-select.js b/src/elements/emby-select/emby-select.js index d1057a86ed..e069687822 100644 --- a/src/elements/emby-select/emby-select.js +++ b/src/elements/emby-select/emby-select.js @@ -135,7 +135,7 @@ import 'webcomponents.js/webcomponents-lite'; this.classList.add('emby-select'); const label = this.ownerDocument.createElement('label'); - label.innerHTML = this.getAttribute('label') || ''; + label.innerText = this.getAttribute('label') || ''; label.classList.add('selectLabel'); label.htmlFor = this.id; this.parentNode?.insertBefore(label, this); @@ -148,7 +148,7 @@ import 'webcomponents.js/webcomponents-lite'; EmbySelectPrototype.setLabel = function (text) { const label = this.parentNode?.querySelector('label'); - label.innerHTML = text; + label.innerText = text; }; document.registerElement('emby-select', { diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index 5c05a393ef..0bb20270e6 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -154,7 +154,7 @@ import '../emby-input/emby-input'; if (topContainer && this.getAttribute('label')) { const label = this.ownerDocument.createElement('label'); - label.innerHTML = this.getAttribute('label'); + label.innerText = this.getAttribute('label'); label.classList.add('sliderLabel'); label.htmlFor = this.id; topContainer.insertBefore(label, topContainer.firstChild); diff --git a/src/elements/emby-textarea/emby-textarea.js b/src/elements/emby-textarea/emby-textarea.js index 309164ddde..27195ab2ab 100644 --- a/src/elements/emby-textarea/emby-textarea.js +++ b/src/elements/emby-textarea/emby-textarea.js @@ -107,7 +107,7 @@ import '../emby-input/emby-input'; const parentNode = this.parentNode; const label = this.ownerDocument.createElement('label'); - label.innerHTML = this.getAttribute('label') || ''; + label.innerText = this.getAttribute('label') || ''; label.classList.add('textareaLabel'); label.htmlFor = this.id; @@ -123,7 +123,7 @@ import '../emby-input/emby-input'; }); this.label = function (text) { - label.innerHTML = text; + label.innerText = text; }; new autoGrow(this); diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index 2fba0fcfd4..55a90f9d04 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import 'jquery'; import globalize from './globalize'; import 'material-design-icons-iconfont'; @@ -62,7 +63,7 @@ import Dashboard from './clientUtils'; if (item.LockData) { htmlName += ''; } - htmlName += name; + htmlName += escapeHtml(name); htmlName += '
'; return htmlName; } diff --git a/src/scripts/libraryMenu.js b/src/scripts/libraryMenu.js index f709acc49c..f4051ea83c 100644 --- a/src/scripts/libraryMenu.js +++ b/src/scripts/libraryMenu.js @@ -1,3 +1,4 @@ +import escapeHtml from 'escape-html'; import dom from './dom'; import layoutManager from '../components/layoutManager'; import inputManager from './inputManager'; @@ -558,7 +559,7 @@ import Headroom from 'headroom.js'; } menuHtml += ''; - menuHtml += item.name; + menuHtml += escapeHtml(item.name); menuHtml += ''; return menuHtml + ''; } @@ -576,7 +577,7 @@ import Headroom from 'headroom.js'; menuHtml += getToolsLinkHtml(item); } else if (item.name) { menuHtml += '

'; - menuHtml += item.name; + menuHtml += escapeHtml(item.name); menuHtml += '

'; } } @@ -700,7 +701,7 @@ import Headroom from 'headroom.js'; return ` - ${i.Name} + ${escapeHtml(i.Name)} `; }).join(''); libraryMenuOptions.innerHTML = html; @@ -751,7 +752,7 @@ import Headroom from 'headroom.js'; if (info && !info.isLocalPlayer) { icon.classList.add('cast_connected'); headerCastButton.classList.add('castButton-active'); - context.querySelector('.headerSelectedPlayer').innerHTML = info.deviceName || info.name; + context.querySelector('.headerSelectedPlayer').innerText = info.deviceName || info.name; } else { icon.classList.add('cast'); headerCastButton.classList.remove('castButton-active'); @@ -973,7 +974,7 @@ import Headroom from 'headroom.js'; pageTitleElement.classList.remove('pageTitleWithLogo'); pageTitleElement.classList.remove('pageTitleWithDefaultLogo'); pageTitleElement.style.backgroundImage = null; - pageTitleElement.innerHTML = html || ''; + pageTitleElement.innerText = html || ''; } document.title = title || 'Jellyfin';