Skip to content

Commit

Permalink
Escape HTML
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitrylyzo committed Mar 6, 2022
1 parent 08cbc5a commit 59adbc3
Show file tree
Hide file tree
Showing 60 changed files with 245 additions and 192 deletions.
9 changes: 7 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
11 changes: 6 additions & 5 deletions 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';
Expand Down Expand Up @@ -156,10 +157,10 @@ export function show(options) {
}

if (options.title) {
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
html += '<h1 class="actionSheetTitle">' + escapeHtml(options.title) + '</h1>';
}
if (options.text) {
html += '<p class="actionSheetText">' + options.text + '</p>';
html += '<p class="actionSheetText">' + escapeHtml(options.text) + '</p>';
}

let scrollerClassName = 'actionSheetScroller';
Expand Down Expand Up @@ -212,17 +213,17 @@ export function show(options) {
html += '<div class="listItemBody actionsheetListItemBody">';

html += '<div class="listItemBodyText actionSheetItemText">';
html += (item.name || item.textContent || item.innerText);
html += escapeHtml(item.name || item.textContent || item.innerText);
html += '</div>';

if (item.secondaryText) {
html += `<div class="listItemBodyText secondary">${item.secondaryText}</div>`;
html += `<div class="listItemBodyText secondary">${escapeHtml(item.secondaryText)}</div>`;
}

html += '</div>';

if (item.asideText) {
html += `<div class="listItemAside actionSheetItemAsideText">${item.asideText}</div>`;
html += `<div class="listItemAside actionSheetItemAsideText">${escapeHtml(item.asideText)}</div>`;
}

html += '</button>';
Expand Down
5 changes: 3 additions & 2 deletions 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';
Expand Down Expand Up @@ -33,13 +34,13 @@ import alert from './alert';

html += '<div class="listItemBody three-line">';
html += '<div class="listItemBodyText">';
html += entry.Name;
html += escapeHtml(entry.Name);
html += '</div>';
html += '<div class="listItemBodyText secondary">';
html += datefns.formatRelative(Date.parse(entry.Date), Date.parse(new Date()), { locale: dfnshelper.getLocale() });
html += '</div>';
html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">';
html += entry.ShortOverview || '';
html += escapeHtml(entry.ShortOverview || '');
html += '</div>';
html += '</div>';

Expand Down
27 changes: 15 additions & 12 deletions src/components/cardbuilder/cardBuilder.js
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -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));
}
}
}
Expand Down Expand Up @@ -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 || '')));
}
}

Expand Down Expand Up @@ -948,13 +949,13 @@ import ServerConnections from '../ServerConnections';

}, item.ChannelName));
} else {
lines.push(item.ChannelName || '&nbsp;');
lines.push(escapeHtml(item.ChannelName) || '&nbsp;');
}
}

if (options.showCurrentProgram && item.Type === 'TvChannel') {
if (item.CurrentProgram) {
lines.push(item.CurrentProgram.Name);
lines.push(escapeHtml(item.CurrentProgram.Name));
} else {
lines.push('');
}
Expand All @@ -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)));
}
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -1031,6 +1032,8 @@ import ServerConnections from '../ServerConnections';
text = itemHelper.getDisplayName(item);
}

text = escapeHtml(text);

if (layoutManager.tv) {
return text;
}
Expand Down Expand Up @@ -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() + '"') : '';
Expand All @@ -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 + '</' + tagName + '>';
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 + '</' + tagName + '>';
}

/**
Expand Down Expand Up @@ -1544,7 +1547,7 @@ import ServerConnections from '../ServerConnections';
}

const defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item);
return '<div class="cardText cardDefaultText">' + defaultName + '</div>';
return '<div class="cardText cardDefaultText">' + escapeHtml(defaultName) + '</div>';
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/components/cardbuilder/chaptercardbuilder.js
Expand Up @@ -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';
Expand Down Expand Up @@ -98,7 +99,7 @@ import ServerConnections from '../ServerConnections';
}

let nameHtml = '';
nameHtml += `<div class="cardText">${chapter.Name}</div>`;
nameHtml += `<div class="cardText">${escapeHtml(chapter.Name)}</div>`;
nameHtml += `<div class="cardText">${datetime.getDisplayRunningTime(chapter.StartPositionTicks)}</div>`;

const cardBoxCssClass = 'cardBox';
Expand Down
7 changes: 4 additions & 3 deletions 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';
Expand Down Expand Up @@ -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();
});
}
Expand Down Expand Up @@ -75,12 +76,12 @@ export default class channelMapper {
html += '<span class="material-icons listItemIcon dvr" aria-hidden="true"></span>';
html += '<div class="listItemBody two-line">';
html += '<h3 class="listItemBodyText">';
html += channel.Name;
html += escapeHtml(channel.Name);
html += '</h3>';
html += '<div class="secondary listItemBodyText">';

if (channel.ProviderChannelName) {
html += getMappingSecondaryName(channel, providerName);
html += escapeHtml(getMappingSecondaryName(channel, providerName));
}

html += '</div>';
Expand Down
3 changes: 2 additions & 1 deletion 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';
Expand Down Expand Up @@ -112,7 +113,7 @@ import toast from '../toast/toast';
html += `<option value="">${globalize.translate('OptionNew')}</option>`;

html += result.Items.map(i => {
return `<option value="${i.Id}">${i.Name}</option>`;
return `<option value="${i.Id}">${escapeHtml(i.Name)}</option>`;
});

select.innerHTML = html;
Expand Down
3 changes: 2 additions & 1 deletion 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';

Expand Down Expand Up @@ -26,7 +27,7 @@ type IProps = {
const SelectElement: FunctionComponent<IProps> = ({ className, label, currentProviderId, providers }: IProps) => {
const renderOption = providers.map((provider) => {
const selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : '';
return '<option value="' + provider.Id + '"' + selected + '>' + provider.Name + '</option>';
return '<option value="' + provider.Id + '"' + selected + '>' + escapeHtml(provider.Name) + '</option>';
});

return (
Expand Down
3 changes: 2 additions & 1 deletion 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';

Expand Down Expand Up @@ -27,7 +28,7 @@ const SelectMaxParentalRating: FunctionComponent<IProps> = ({ className, label,
const renderOption = () => {
let content = '';
for (const rating of parentalRatings) {
content += `<option value='${rating.Value}'>${rating.Name}</option>`;
content += `<option value='${rating.Value}'>${escapeHtml(rating.Name)}</option>`;
}
return content;
};
Expand Down
5 changes: 3 additions & 2 deletions 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';
Expand Down Expand Up @@ -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');
}
Expand Down Expand Up @@ -82,7 +83,7 @@ import template from './dialog.template.html';
buttonClass += ' formDialogFooterItem-vertical formDialogFooterItem-nomarginbottom';
}

html += `<button is="emby-button" type="button" class="${buttonClass}" data-id="${item.id}"${autoFocus}>${item.name}</button>`;
html += `<button is="emby-button" type="button" class="${buttonClass}" data-id="${item.id}"${autoFocus}>${escapeHtml(item.name)}</button>`;

if (item.description) {
html += `<div class="formDialogFooterItem formDialogFooterItem-autosize fieldDescription" style="margin-top:.25em!important;margin-bottom:1.25em!important;">${item.description}</div>`;
Expand Down
9 changes: 5 additions & 4 deletions 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';
Expand Down Expand Up @@ -71,10 +72,10 @@ function refreshDirectoryBrowser(page, path, fileOptions, updatePathOnError) {

function getItem(cssClass, type, path, name) {
let html = '';
html += `<div class="listItem listItem-border ${cssClass}" data-type="${type}" data-path="${path}">`;
html += `<div class="listItem listItem-border ${cssClass}" data-type="${type}" data-path="${escapeHtml(path)}">`;
html += '<div class="listItemBody" style="padding-left:0;padding-top:.5em;padding-bottom:.5em;">';
html += '<div class="listItemBodyText">';
html += name;
html += escapeHtml(name);
html += '</div>';
html += '</div>';
html += '<span class="material-icons arrow_forward" aria-hidden="true" style="font-size:inherit;"></span>';
Expand All @@ -87,7 +88,7 @@ function getEditorHtml(options, systemInfo) {
html += '<div class="formDialogContent scrollY">';
html += '<div class="dialogContentInner dialog-content-centered" style="padding-top:2em;">';
if (!options.pathReadOnly) {
const instruction = options.instruction ? `${options.instruction}<br/><br/>` : '';
const instruction = options.instruction ? `${escapeHtml(options.instruction)}<br/><br/>` : '';
html += '<div class="infoBanner" style="margin-bottom:1.5em;">';
html += instruction;
if (systemInfo.OperatingSystem.toLowerCase() === 'bsd') {
Expand Down Expand Up @@ -266,7 +267,7 @@ class DirectoryBrowser {
html += '<div class="formDialogHeader">';
html += `<button is="paper-icon-button-light" class="btnCloseDialog autoSize" tabindex="-1" title="${globalize.translate('ButtonBack')}"><span class="material-icons arrow_back" aria-hidden="true"></span></button>`;
html += '<h3 class="formDialogHeaderTitle">';
html += options.header || globalize.translate('HeaderSelectPath');
html += escapeHtml(options.header) || globalize.translate('HeaderSelectPath');
html += '</h3>';
html += '</div>';
html += getEditorHtml(options, systemInfo);
Expand Down
5 changes: 3 additions & 2 deletions 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';
Expand All @@ -21,7 +22,7 @@ import template from './displaySettings.template.html';
function fillThemes(select, selectedTheme) {
skinManager.getThemes().then(themes => {
select.innerHTML = themes.map(t => {
return `<option value="${t.id}">${t.name}</option>`;
return `<option value="${t.id}">${escapeHtml(t.name)}</option>`;
}).join('');

// get default theme
Expand All @@ -47,7 +48,7 @@ import template from './displaySettings.template.html';
});

selectScreensaver.innerHTML = options.map(o => {
return `<option value="${o.value}">${o.name}</option>`;
return `<option value="${o.value}">${escapeHtml(o.name)}</option>`;
}).join('');

selectScreensaver.value = userSettings.screensaver();
Expand Down
3 changes: 2 additions & 1 deletion 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';
Expand Down Expand Up @@ -37,7 +38,7 @@ function renderOptions(context, selector, cssClass, items, isCheckedFn) {
const checkedHtml = isCheckedFn(filter) ? ' checked' : '';
itemHtml += '<label>';
itemHtml += '<input is="emby-checkbox" type="checkbox"' + checkedHtml + ' data-filter="' + filter.Id + '" class="' + cssClass + '"/>';
itemHtml += '<span>' + filter.Name + '</span>';
itemHtml += '<span>' + escapeHtml(filter.Name) + '</span>';
itemHtml += '</label>';

return itemHtml;
Expand Down

0 comments on commit 59adbc3

Please sign in to comment.