';
- 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 += "
" + rating.Name + ' ';
+ html += "
" + escapeHtml(rating.Name) + ' ';
}
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 += '
';
html += '';
- html += (person.Name || '');
+ html += escapeHtml(person.Name || '');
html += '
';
if (person.Role && person.Role !== lastType) {
diff --git a/src/components/playback/nowplayinghelper.js b/src/components/playback/nowplayinghelper.js
index a2b72ca84f..507e689c7f 100644
--- a/src/components/playback/nowplayinghelper.js
+++ b/src/components/playback/nowplayinghelper.js
@@ -1,3 +1,5 @@
+import escapeHtml from 'escape-html';
+
export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
let topItem = nowPlayingItem;
let bottomItem = null;
@@ -59,13 +61,13 @@ export function getNowPlayingNames(nowPlayingItem, includeNonNameInfo) {
const list = [];
list.push({
- text: topText,
+ text: escapeHtml(topText),
item: topItem
});
if (bottomText) {
list.push({
- text: bottomText,
+ text: escapeHtml(bottomText),
item: bottomItem
});
}
diff --git a/src/components/playlisteditor/playlisteditor.js b/src/components/playlisteditor/playlisteditor.js
index 8dfc26eb5f..440685fd9c 100644
--- a/src/components/playlisteditor/playlisteditor.js
+++ b/src/components/playlisteditor/playlisteditor.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';
@@ -126,7 +127,7 @@ import ServerConnections from '../ServerConnections';
html += `${globalize.translate('OptionNew')} `;
html += result.Items.map(i => {
- return `${i.Name} `;
+ return `${escapeHtml(i.Name)} `;
});
select.innerHTML = html;
diff --git a/src/components/prompt/prompt.js b/src/components/prompt/prompt.js
index c59a6e724f..df93cfbbf2 100644
--- a/src/components/prompt/prompt.js
+++ b/src/components/prompt/prompt.js
@@ -54,10 +54,10 @@ export default (() => {
dialogHelper.close(dlg);
});
- dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.title || '';
+ dlg.querySelector('.formDialogHeaderTitle').innerText = options.title || '';
if (options.description) {
- dlg.querySelector('.fieldDescription').innerHTML = options.description;
+ dlg.querySelector('.fieldDescription').innerText = options.description;
} else {
dlg.querySelector('.fieldDescription').classList.add('hide');
}
@@ -79,7 +79,7 @@ export default (() => {
return false;
});
- dlg.querySelector('.submitText').innerHTML = options.confirmText || globalize.translate('ButtonOk');
+ dlg.querySelector('.submitText').innerText = options.confirmText || globalize.translate('ButtonOk');
dlg.style.minWidth = `${Math.min(400, dom.getWindowSize().innerWidth - 50)}px`;
diff --git a/src/components/recordingcreator/recordingcreator.js b/src/components/recordingcreator/recordingcreator.js
index c3d59ac217..4387b2e09b 100644
--- a/src/components/recordingcreator/recordingcreator.js
+++ b/src/components/recordingcreator/recordingcreator.js
@@ -81,10 +81,10 @@ function renderRecording(context, defaultTimer, program, apiClient, refreshRecor
imageContainer.classList.add('hide');
}
- context.querySelector('.recordingDialog-itemName').innerHTML = program.Name;
- context.querySelector('.formDialogHeaderTitle').innerHTML = program.Name;
- context.querySelector('.itemGenres').innerHTML = (program.Genres || []).join(' / ');
- context.querySelector('.itemOverview').innerHTML = program.Overview || '';
+ context.querySelector('.recordingDialog-itemName').innerText = program.Name;
+ context.querySelector('.formDialogHeaderTitle').innerText = program.Name;
+ context.querySelector('.itemGenres').innerText = (program.Genres || []).join(' / ');
+ context.querySelector('.itemOverview').innerText = program.Overview || '';
const formDialogFooter = context.querySelector('.formDialogFooter');
const now = new Date();
diff --git a/src/components/recordingcreator/seriesrecordingeditor.js b/src/components/recordingcreator/seriesrecordingeditor.js
index b4bbba863b..a649b1231b 100644
--- a/src/components/recordingcreator/seriesrecordingeditor.js
+++ b/src/components/recordingcreator/seriesrecordingeditor.js
@@ -45,7 +45,7 @@ function renderTimer(context, item) {
context.querySelector('.selectKeepUpTo').value = item.KeepUpTo || 0;
if (item.ChannelName || item.ChannelNumber) {
- context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
+ context.querySelector('.optionChannelOnly').innerText = globalize.translate('ChannelNameOnly', item.ChannelName || item.ChannelNumber);
} else {
context.querySelector('.optionChannelOnly').innerHTML = globalize.translate('OneChannel');
}
diff --git a/src/components/remotecontrol/remotecontrol.js b/src/components/remotecontrol/remotecontrol.js
index d6940f632c..5205093610 100644
--- a/src/components/remotecontrol/remotecontrol.js
+++ b/src/components/remotecontrol/remotecontrol.js
@@ -1,3 +1,4 @@
+import escapeHtml from 'escape-html';
import datetime from '../../scripts/datetime';
import backdrop from '../backdrop/backdrop';
import listView from '../listview/listview';
@@ -139,13 +140,13 @@ function updateNowPlayingInfo(context, state, serverId) {
if (item) {
const nowPlayingServerId = (item.ServerId || serverId);
if (item.Type == 'Audio' || item.MediaStreams[0].Type == 'Audio') {
- const songName = item.Name;
+ const songName = escapeHtml(item.Name);
let artistsSeries = '';
let albumName = '';
if (item.Artists != null) {
if (item.ArtistItems != null) {
for (const artist of item.ArtistItems) {
- const artistName = artist.Name;
+ const artistName = escapeHtml(artist.Name);
const artistId = artist.Id;
artistsSeries += `${artistName} `;
if (artist !== item.ArtistItems.slice(-1)[0]) {
@@ -157,7 +158,7 @@ function updateNowPlayingInfo(context, state, serverId) {
// to normal item.Artists item.
// TODO: Normalise fields returned by all the players
for (const artist of item.Artists) {
- artistsSeries += `${artist} `;
+ artistsSeries += `${escapeHtml(artist)} `;
if (artist !== item.Artists.slice(-1)[0]) {
artistsSeries += ', ';
}
@@ -165,27 +166,27 @@ function updateNowPlayingInfo(context, state, serverId) {
}
}
if (item.Album != null) {
- albumName = '` + item.Album + ' ';
+ albumName = '` + escapeHtml(item.Album) + ' ';
}
- context.querySelector('.nowPlayingAlbum').innerHTML = albumName;
- context.querySelector('.nowPlayingArtist').innerHTML = artistsSeries;
- context.querySelector('.nowPlayingSongName').innerHTML = songName;
+ context.querySelector('.nowPlayingAlbum').innerText = albumName;
+ context.querySelector('.nowPlayingArtist').innerText = artistsSeries;
+ context.querySelector('.nowPlayingSongName').innerText = songName;
} else if (item.Type == 'Episode') {
if (item.SeasonName != null) {
const seasonName = item.SeasonName;
- context.querySelector('.nowPlayingSeason').innerHTML = '${seasonName} `;
+ context.querySelector('.nowPlayingSeason').innerHTML = '${escapeHtml(seasonName)} `;
}
if (item.SeriesName != null) {
const seriesName = item.SeriesName;
if (item.SeriesId != null) {
- context.querySelector('.nowPlayingSerie').innerHTML = '${seriesName} `;
+ context.querySelector('.nowPlayingSerie').innerHTML = '${escapeHtml(seriesName)} `;
} else {
- context.querySelector('.nowPlayingSerie').innerHTML = seriesName;
+ context.querySelector('.nowPlayingSerie').innerText = seriesName;
}
}
- context.querySelector('.nowPlayingEpisode').innerHTML = item.Name;
+ context.querySelector('.nowPlayingEpisode').innerText = item.Name;
} else {
- context.querySelector('.nowPlayingPageTitle').innerHTML = displayName;
+ context.querySelector('.nowPlayingPageTitle').innerText = displayName;
}
if (displayName.length > 0 && item.Type != 'Audio' && item.Type != 'Episode') {
diff --git a/src/components/search/SearchSuggestions.tsx b/src/components/search/SearchSuggestions.tsx
index 596ad64518..fee361a162 100644
--- a/src/components/search/SearchSuggestions.tsx
+++ b/src/components/search/SearchSuggestions.tsx
@@ -1,4 +1,5 @@
import { BaseItemDto } from '@thornbill/jellyfin-sdk/dist/generated-client';
+import escapeHtml from 'escape-html';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { appRouter } from '../appRouter';
@@ -16,7 +17,7 @@ const createSuggestionLink = ({ name, href }: { name: string, href: string }) =>
class='button-link'
style='display: inline-block; padding: 0.5em 1em;'
href='${href}'
->${name}`
+>${escapeHtml(name)}`
});
type SearchSuggestionsProps = {
diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js
index 883cc29fbe..ead71f9cee 100644
--- a/src/components/subtitleeditor/subtitleeditor.js
+++ b/src/components/subtitleeditor/subtitleeditor.js
@@ -1,3 +1,4 @@
+import escapeHtml from 'escape-html';
import { appHost } from '../apphost';
import dialogHelper from '../dialogHelper/dialogHelper';
import layoutManager from '../layoutManager';
@@ -103,11 +104,11 @@ function fillSubtitleList(context, item) {
itemHtml += '';
itemHtml += '
';
- itemHtml += s.DisplayTitle || '';
+ itemHtml += escapeHtml(s.DisplayTitle || '');
itemHtml += '
';
if (s.Path) {
- itemHtml += '
' + (s.Path) + '
';
+ itemHtml += '
' + escapeHtml(s.Path) + '
';
}
itemHtml += '';
@@ -199,7 +200,7 @@ function renderSearchResults(context, results) {
html += '
';
- html += '
' + (result.Name) + '
';
+ html += '
' + escapeHtml(result.Name) + '
';
html += '
';
if (result.Format) {
@@ -212,7 +213,7 @@ function renderSearchResults(context, results) {
html += '
';
if (result.Comment) {
- html += '
' + (result.Comment) + '
';
+ html += '
' + escapeHtml(result.Comment) + '
';
}
if (result.IsHashMatch) {
@@ -265,7 +266,7 @@ function reload(context, apiClient, itemId) {
}
if (file) {
- context.querySelector('.pathValue').innerHTML = file;
+ context.querySelector('.pathValue').innerText = file;
context.querySelector('.originalFile').classList.remove('hide');
} else {
context.querySelector('.pathValue').innerHTML = '';
diff --git a/src/components/upnextdialog/upnextdialog.js b/src/components/upnextdialog/upnextdialog.js
index 2284975f13..4eac3eae60 100644
--- a/src/components/upnextdialog/upnextdialog.js
+++ b/src/components/upnextdialog/upnextdialog.js
@@ -80,7 +80,7 @@ import '../../assets/css/flexstyles.scss';
title = item.SeriesName + ' - ' + title;
}
- elem.querySelector('.upNextDialog-title').innerHTML = title || '';
+ elem.querySelector('.upNextDialog-title').innerText = title || '';
instance.itemType = item.Type;
diff --git a/src/controllers/dashboard/dashboard.js b/src/controllers/dashboard/dashboard.js
index b7468c266d..d4110b05ef 100644
--- a/src/controllers/dashboard/dashboard.js
+++ b/src/controllers/dashboard/dashboard.js
@@ -1,3 +1,4 @@
+import escapeHtml from 'escape-html';
import datetime from '../../scripts/datetime';
import { Events } from 'jellyfin-apiclient';
import itemHelper from '../../components/itemHelper';
@@ -199,10 +200,10 @@ import confirm from '../../components/confirm/confirm';
function reloadSystemInfo(view, apiClient) {
apiClient.getSystemInfo().then(function (systemInfo) {
- view.querySelector('#serverName').innerHTML = globalize.translate('DashboardServerName', systemInfo.ServerName);
- view.querySelector('#versionNumber').innerHTML = globalize.translate('DashboardVersionNumber', systemInfo.Version);
- view.querySelector('#operatingSystem').innerHTML = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem);
- view.querySelector('#architecture').innerHTML = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture);
+ view.querySelector('#serverName').innerText = globalize.translate('DashboardServerName', systemInfo.ServerName);
+ view.querySelector('#versionNumber').innerText = globalize.translate('DashboardVersionNumber', systemInfo.Version);
+ view.querySelector('#operatingSystem').innerText = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem);
+ view.querySelector('#architecture').innerText = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture);
if (systemInfo.CanSelfRestart) {
view.querySelector('#btnRestartServer').classList.remove('hide');
@@ -210,11 +211,11 @@ import confirm from '../../components/confirm/confirm';
view.querySelector('#btnRestartServer').classList.add('hide');
}
- view.querySelector('#cachePath').innerHTML = systemInfo.CachePath;
- view.querySelector('#logPath').innerHTML = systemInfo.LogPath;
- view.querySelector('#transcodePath').innerHTML = systemInfo.TranscodingTempPath;
- view.querySelector('#metadataPath').innerHTML = systemInfo.InternalMetadataPath;
- view.querySelector('#webPath').innerHTML = systemInfo.WebPath;
+ view.querySelector('#cachePath').innerText = systemInfo.CachePath;
+ view.querySelector('#logPath').innerText = systemInfo.LogPath;
+ view.querySelector('#transcodePath').innerText = systemInfo.TranscodingTempPath;
+ view.querySelector('#metadataPath').innerText = systemInfo.InternalMetadataPath;
+ view.querySelector('#webPath').innerText = systemInfo.WebPath;
});
}
@@ -279,8 +280,8 @@ import confirm from '../../components/confirm/confirm';
}
html += '
';
- html += '
' + session.DeviceName + '
';
- html += '
' + DashboardPage.getAppSecondaryText(session) + '
';
+ html += '
' + escapeHtml(session.DeviceName) + '
';
+ html += '
' + escapeHtml(DashboardPage.getAppSecondaryText(session)) + '
';
html += '
';
html += '
';
@@ -289,7 +290,7 @@ import confirm from '../../components/confirm/confirm';
html += '
';
html += nowPlayingName.html;
html += '
';
- html += '
' + DashboardPage.getSessionNowPlayingTime(session) + '
';
+ html += '
' + escapeHtml(DashboardPage.getSessionNowPlayingTime(session)) + '
';
html += '
';
let percent = 100 * session?.PlayState?.PositionTicks / nowPlayingItem?.RunTimeTicks;
@@ -480,16 +481,16 @@ import confirm from '../../components/confirm/confirm';
};
}
- let topText = itemHelper.getDisplayName(nowPlayingItem);
+ let topText = escapeHtml(itemHelper.getDisplayName(nowPlayingItem));
let bottomText = '';
if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) {
bottomText = topText;
- topText = nowPlayingItem.Artists[0];
+ topText = escapeHtml(nowPlayingItem.Artists[0]);
} else {
if (nowPlayingItem.SeriesName || nowPlayingItem.Album) {
bottomText = topText;
- topText = nowPlayingItem.SeriesName || nowPlayingItem.Album;
+ topText = escapeHtml(nowPlayingItem.SeriesName || nowPlayingItem.Album);
} else if (nowPlayingItem.ProductionYear) {
bottomText = nowPlayingItem.ProductionYear;
}
@@ -575,9 +576,9 @@ import confirm from '../../components/confirm/confirm';
btnSessionPlayPauseIcon.classList.remove('play_arrow', 'pause');
btnSessionPlayPauseIcon.classList.add(session.PlayState && session.PlayState.IsPaused ? 'play_arrow' : 'pause');
- row.querySelector('.sessionNowPlayingTime').innerHTML = DashboardPage.getSessionNowPlayingTime(session);
- row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session);
- row.querySelector('.sessionAppSecondaryText').innerHTML = DashboardPage.getAppSecondaryText(session);
+ row.querySelector('.sessionNowPlayingTime').innerText = DashboardPage.getSessionNowPlayingTime(session);
+ row.querySelector('.sessionUserName').innerText = DashboardPage.getUsersHtml(session);
+ row.querySelector('.sessionAppSecondaryText').innerText = DashboardPage.getAppSecondaryText(session);
const nowPlayingName = DashboardPage.getNowPlayingName(session);
const nowPlayingInfoElem = row.querySelector('.sessionNowPlayingInfo');
diff --git a/src/controllers/dashboard/devices/device.js b/src/controllers/dashboard/devices/device.js
index ab9b5a664c..607986c7f3 100644
--- a/src/controllers/dashboard/devices/device.js
+++ b/src/controllers/dashboard/devices/device.js
@@ -8,7 +8,7 @@ import Dashboard from '../../../scripts/clientUtils';
function load(page, device, deviceOptions) {
page.querySelector('#txtCustomName', page).value = deviceOptions.CustomName || '';
- page.querySelector('.reportedName', page).innerHTML = device.Name || '';
+ page.querySelector('.reportedName', page).innerText = device.Name || '';
}
function loadData() {
diff --git a/src/controllers/dashboard/devices/devices.js b/src/controllers/dashboard/devices/devices.js
index a75eebce31..9fa75489fa 100644
--- a/src/controllers/dashboard/devices/devices.js
+++ b/src/controllers/dashboard/devices/devices.js
@@ -1,3 +1,4 @@
+import escapeHtml from 'escape-html';
import cardBuilder from '../../../components/cardbuilder/cardBuilder';
import loading from '../../../components/loading/loading';
import dom from '../../../scripts/dom';
@@ -118,15 +119,15 @@ import confirm from '../../../components/confirm/confirm';
}
deviceHtml += "";
- deviceHtml += device.Name;
+ deviceHtml += escapeHtml(device.Name);
deviceHtml += '
';
deviceHtml += "";
- deviceHtml += device.AppName + ' ' + device.AppVersion;
+ deviceHtml += escapeHtml(device.AppName + ' ' + device.AppVersion);
deviceHtml += '
';
deviceHtml += "";
if (device.LastUserName) {
- deviceHtml += device.LastUserName;
+ deviceHtml += escapeHtml(device.LastUserName);
deviceHtml += ', ' + formatDistanceToNow(Date.parse(device.DateLastActivity), localeWithSuffix);
}
diff --git a/src/controllers/dashboard/dlna/profile.js b/src/controllers/dashboard/dlna/profile.js
index 0962f7a592..00088cb6b6 100644
--- a/src/controllers/dashboard/dlna/profile.js
+++ b/src/controllers/dashboard/dlna/profile.js
@@ -1,3 +1,4 @@
+import escapeHtml from 'escape-html';
import 'jquery';
import loading from '../../../components/loading/loading';
import globalize from '../../../scripts/globalize';
@@ -76,7 +77,7 @@ import toast from '../../../components/toast/toast';
profile.CodecProfiles = profile.CodecProfiles || [];
profile.ResponseProfiles = profile.ResponseProfiles || [];
const usersHtml = '
' + users.map(function (u) {
- return '
' + u.Name + ' ';
+ return '
' + escapeHtml(u.Name) + ' ';
}).join('');
$('#selectUser', page).html(usersHtml).val(profile.UserId || '');
renderSubProfiles(page, profile);
@@ -88,8 +89,8 @@ import toast from '../../../components/toast/toast';
let li = '
';
li += '
';
li += '
';
- li += '
' + h.Name + ': ' + (h.Value || '') + ' ';
- li += '
' + (h.Match || '') + '
';
+ li += '
' + escapeHtml(h.Name + ': ' + (h.Value || '')) + ' ';
+ li += '
' + escapeHtml(h.Match || '') + '
';
li += '
';
li += '';
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 '
' + u.Name + ' ';
+ return '
' + escapeHtml(u.Name) + ' ';
}).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 = '' + globalize.translate('None') + ' ';
html += users.map(function (user) {
- return '' + user.Name + ' ';
+ return '' + escapeHtml(user.Name) + ' ';
}).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 '' + u.Name + ' ';
+ return '' + escapeHtml(u.Name) + ' ';
}).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 '
' + v.Name + ' ';
+ return '
' + escapeHtml(v.Name) + ' ';
}).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 += '
';
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 += '';
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 += '