From a93217d2da5d002c99528a6f0951c84c832935b9 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 4 Apr 2024 13:24:41 +0200 Subject: [PATCH] Prefer innerText instead of innerHTML The previous implementation can lead to XSS injection --- client/src/app/modal/confirm.component.ts | 4 ++-- .../shared/control-bar/peertube-link-button.ts | 2 +- .../player/shared/dock/peertube-dock-component.ts | 4 ++-- .../player/shared/playlist/playlist-button.ts | 5 +---- .../player/shared/playlist/playlist-menu-item.ts | 13 ++++++------- .../assets/player/shared/playlist/playlist-menu.ts | 5 ++--- .../player/shared/settings/settings-dialog.ts | 1 - .../player/shared/settings/settings-panel-child.ts | 1 - .../player/shared/settings/settings-panel.ts | 1 - .../src/assets/player/shared/stats/stats-card.ts | 14 +++++++------- client/src/assets/player/shared/upnext/end-card.ts | 2 +- client/src/sass/player/dock.scss | 9 --------- client/src/standalone/videos/shared/player-html.ts | 8 ++++---- .../videos/shared/player-options-builder.ts | 2 +- 14 files changed, 27 insertions(+), 44 deletions(-) diff --git a/client/src/app/modal/confirm.component.ts b/client/src/app/modal/confirm.component.ts index 43369befa..0862d33d4 100644 --- a/client/src/app/modal/confirm.component.ts +++ b/client/src/app/modal/confirm.component.ts @@ -62,8 +62,8 @@ export class ConfirmComponent implements OnInit { this.confirmButtonText = confirmButtonText || $localize`Confirm` this.html.toSafeHtml(message) - .then(message => { - this.message = message + .then(html => { + this.message = html this.showModal() }) diff --git a/client/src/assets/player/shared/control-bar/peertube-link-button.ts b/client/src/assets/player/shared/control-bar/peertube-link-button.ts index f93c265d6..3f4a64236 100644 --- a/client/src/assets/player/shared/control-bar/peertube-link-button.ts +++ b/client/src/assets/player/shared/control-bar/peertube-link-button.ts @@ -29,7 +29,7 @@ class PeerTubeLinkButton extends Component { createEl () { const el = videojs.dom.createEl('a', { href: this.buildLink(), - innerHTML: this.options_.instanceName, + innerText: this.options_.instanceName, title: this.player().localize('Video page (new window)'), className: 'vjs-peertube-link', target: '_blank' diff --git a/client/src/assets/player/shared/dock/peertube-dock-component.ts b/client/src/assets/player/shared/dock/peertube-dock-component.ts index c13ca647b..973db2646 100644 --- a/client/src/assets/player/shared/dock/peertube-dock-component.ts +++ b/client/src/assets/player/shared/dock/peertube-dock-component.ts @@ -37,7 +37,7 @@ class PeerTubeDockComponent extends Component { const title = videojs.dom.createEl('div', { className: 'peertube-dock-title', title: this.options_.title, - innerHTML: this.options_.title + innerText: this.options_.title }) elWrapperTitleDescription.appendChild(title) @@ -47,7 +47,7 @@ class PeerTubeDockComponent extends Component { const description = videojs.dom.createEl('div', { className: 'peertube-dock-description', title: this.options_.description, - innerHTML: this.options_.description + innerText: this.options_.description }) elWrapperTitleDescription.appendChild(description) diff --git a/client/src/assets/player/shared/playlist/playlist-button.ts b/client/src/assets/player/shared/playlist/playlist-button.ts index 45cbb4899..fffa83c7a 100644 --- a/client/src/assets/player/shared/playlist/playlist-button.ts +++ b/client/src/assets/player/shared/playlist/playlist-button.ts @@ -22,19 +22,16 @@ class PlaylistButton extends ClickableComponent { createEl () { this.wrapper = super.createEl('div', { className: 'vjs-playlist-button', - innerHTML: '', tabIndex: -1 }) as HTMLElement const icon = super.createEl('div', { className: 'vjs-playlist-icon', - innerHTML: '', tabIndex: -1 }) this.playlistInfoElement = super.createEl('div', { className: 'vjs-playlist-info', - innerHTML: '', tabIndex: -1 }) as HTMLElement @@ -47,7 +44,7 @@ class PlaylistButton extends ClickableComponent { } update () { - this.playlistInfoElement.innerHTML = this.options_.getCurrentPosition() + '/' + this.options_.playlist.videosLength + this.playlistInfoElement.innerText = this.options_.getCurrentPosition() + '/' + this.options_.playlist.videosLength this.wrapper.title = this.player().localize('Playlist: {1}', [ this.options_.playlist.displayName ]) } diff --git a/client/src/assets/player/shared/playlist/playlist-menu-item.ts b/client/src/assets/player/shared/playlist/playlist-menu-item.ts index 66c92d9e5..dcb31f7f9 100644 --- a/client/src/assets/player/shared/playlist/playlist-menu-item.ts +++ b/client/src/assets/player/shared/playlist/playlist-menu-item.ts @@ -36,8 +36,7 @@ class PlaylistMenuItem extends Component { createEl () { const li = super.createEl('li', { - className: 'vjs-playlist-menu-item', - innerHTML: '' + className: 'vjs-playlist-menu-item' }) as HTMLElement if (!this.options_.element.video) { @@ -50,7 +49,7 @@ class PlaylistMenuItem extends Component { const position = super.createEl('div', { className: 'item-position', - innerHTML: this.options_.element.position + innerText: this.options_.element.position }) positionBlock.appendChild(position) @@ -92,12 +91,12 @@ class PlaylistMenuItem extends Component { }) const title = super.createEl('div', { - innerHTML: videoElement.video.name, + innerText: videoElement.video.name, className: 'title' }) const channel = super.createEl('div', { - innerHTML: videoElement.video.channel.displayName, + innerText: videoElement.video.channel.displayName, className: 'channel' }) @@ -111,7 +110,7 @@ class PlaylistMenuItem extends Component { if (videoElement.stopTimestamp) html += ' - ' + secondsToTime(videoElement.stopTimestamp) const timestamps = super.createEl('div', { - innerHTML: html, + innerText: html, className: 'timestamps' }) @@ -125,7 +124,7 @@ class PlaylistMenuItem extends Component { private buildUnavailableVideo (li: HTMLElement) { const block = super.createEl('div', { className: 'item-unavailable', - innerHTML: this.player().localize('Unavailable video') + innerTExt: this.player().localize('Unavailable video') }) li.appendChild(block) diff --git a/client/src/assets/player/shared/playlist/playlist-menu.ts b/client/src/assets/player/shared/playlist/playlist-menu.ts index f6795390c..437130115 100644 --- a/client/src/assets/player/shared/playlist/playlist-menu.ts +++ b/client/src/assets/player/shared/playlist/playlist-menu.ts @@ -73,7 +73,6 @@ class PlaylistMenu extends Component { const menu = super.createEl('div', { className: 'vjs-playlist-menu', - innerHTML: '', tabIndex: -1 }) @@ -84,13 +83,13 @@ class PlaylistMenu extends Component { const headerLeft = super.createEl('div') const leftTitle = super.createEl('div', { - innerHTML: this.options_.playlist.displayName, + innerText: this.options_.playlist.displayName, className: 'title' }) const playlistChannel = this.options_.playlist.videoChannel const leftSubtitle = super.createEl('div', { - innerHTML: playlistChannel + innerText: playlistChannel ? this.player().localize('By {1}', [ playlistChannel.displayName ]) : '', className: 'channel' diff --git a/client/src/assets/player/shared/settings/settings-dialog.ts b/client/src/assets/player/shared/settings/settings-dialog.ts index ba39d0f45..c0b1e0356 100644 --- a/client/src/assets/player/shared/settings/settings-dialog.ts +++ b/client/src/assets/player/shared/settings/settings-dialog.ts @@ -20,7 +20,6 @@ class SettingsDialog extends Component { return super.createEl('div', { className: 'vjs-settings-dialog vjs-modal-overlay', - innerHTML: '', tabIndex: -1 }, { 'role': 'dialog', diff --git a/client/src/assets/player/shared/settings/settings-panel-child.ts b/client/src/assets/player/shared/settings/settings-panel-child.ts index 161420c38..d4ce5ce3f 100644 --- a/client/src/assets/player/shared/settings/settings-panel-child.ts +++ b/client/src/assets/player/shared/settings/settings-panel-child.ts @@ -7,7 +7,6 @@ class SettingsPanelChild extends Component { createEl () { return super.createEl('div', { className: 'vjs-settings-panel-child', - innerHTML: '', tabIndex: -1 }) } diff --git a/client/src/assets/player/shared/settings/settings-panel.ts b/client/src/assets/player/shared/settings/settings-panel.ts index 28b579bdd..d7c198bbf 100644 --- a/client/src/assets/player/shared/settings/settings-panel.ts +++ b/client/src/assets/player/shared/settings/settings-panel.ts @@ -7,7 +7,6 @@ class SettingsPanel extends Component { createEl () { return super.createEl('div', { className: 'vjs-settings-panel', - innerHTML: '', tabIndex: -1 }) } diff --git a/client/src/assets/player/shared/stats/stats-card.ts b/client/src/assets/player/shared/stats/stats-card.ts index b04e91f99..6c16c6449 100644 --- a/client/src/assets/player/shared/stats/stats-card.ts +++ b/client/src/assets/player/shared/stats/stats-card.ts @@ -285,15 +285,15 @@ class StatsCard extends Component { if (player.muted()) volume += player.localize(' (muted)') const networkActivity = playerNetworkInfo.downloadSpeed - ? `${playerNetworkInfo.downloadSpeed} ⇓ / ${playerNetworkInfo.uploadSpeed} ⇑` + ? `${playerNetworkInfo.downloadSpeed} \u21D3 / ${playerNetworkInfo.uploadSpeed} \u21D1` : undefined let totalTransferred = playerNetworkInfo.totalDownloaded - ? `${playerNetworkInfo.totalDownloaded} ⇓` + ? `${playerNetworkInfo.totalDownloaded} \u21D3` : '' if (playerNetworkInfo.totalUploaded) { - totalTransferred += `/ ${playerNetworkInfo.totalUploaded} ⇑` + totalTransferred += `/ ${playerNetworkInfo.totalUploaded} \u21D1` } const downloadBreakdown = playerNetworkInfo.downloadedFromServer @@ -337,16 +337,16 @@ class StatsCard extends Component { el.root.style.display = 'block' - if (el.value.innerHTML === value) return - el.value.innerHTML = value + if (el.value.innerText === value) return + el.value.innerText = value } - private buildInfoRow (labelText: string, valueHTML?: string) { + private buildInfoRow (labelText: string) { const root = videojs.dom.createEl('div') as HTMLElement root.style.display = 'none' const label = videojs.dom.createEl('div', { innerText: labelText }) as HTMLElement - const value = videojs.dom.createEl('span', { innerHTML: valueHTML }) as HTMLElement + const value = videojs.dom.createEl('span') as HTMLElement root.appendChild(label) root.appendChild(value) diff --git a/client/src/assets/player/shared/upnext/end-card.ts b/client/src/assets/player/shared/upnext/end-card.ts index 798a88db1..268b28ea2 100644 --- a/client/src/assets/player/shared/upnext/end-card.ts +++ b/client/src/assets/player/shared/upnext/end-card.ts @@ -121,7 +121,7 @@ export class EndCard extends Component { this.autoplayRing.setAttribute('stroke-dasharray', `${this.dashOffsetStart}`) this.autoplayRing.setAttribute('stroke-dashoffset', `${-this.dashOffsetStart}`) - this.title.innerHTML = this.options_.getTitle() + this.title.innerText = this.options_.getTitle() if (this.totalTicks === 0) { return cb(false) diff --git a/client/src/sass/player/dock.scss b/client/src/sass/player/dock.scss index 1dce24d30..1c35b8af2 100644 --- a/client/src/sass/player/dock.scss +++ b/client/src/sass/player/dock.scss @@ -60,15 +60,6 @@ .peertube-dock-description { font-size: 11px; line-height: 1.5; - - .text::before { - @include margin-right(4px); - } - - .text::after { - @include margin-left(4px); - transform: scale(-1, 1); - } } @media screen and (max-width: $screen-width-750) { diff --git a/client/src/standalone/videos/shared/player-html.ts b/client/src/standalone/videos/shared/player-html.ts index ada2aaaf7..ffe0261d3 100644 --- a/client/src/standalone/videos/shared/player-html.ts +++ b/client/src/standalone/videos/shared/player-html.ts @@ -69,14 +69,14 @@ export class PlayerHTML { videoPasswordBlock.style.display = 'flex' const videoPasswordTitle = document.getElementById('video-password-title') - videoPasswordTitle.innerHTML = translatedTitle + videoPasswordTitle.innerText = translatedTitle const videoPasswordMessage = document.getElementById('video-password-content') - videoPasswordMessage.innerHTML = translatedMessage + videoPasswordMessage.innerText = translatedMessage if (incorrectPassword) { const videoPasswordError = document.getElementById('video-password-error') - videoPasswordError.innerHTML = peertubeTranslate('Incorrect password, please enter a correct password', translations) + videoPasswordError.innerText = peertubeTranslate('Incorrect password, please enter a correct password', translations) videoPasswordError.style.transform = 'scale(1.2)' setTimeout(() => { @@ -85,7 +85,7 @@ export class PlayerHTML { } const videoPasswordSubmitButton = document.getElementById('video-password-submit') - videoPasswordSubmitButton.innerHTML = peertubeTranslate('Watch Video', translations) + videoPasswordSubmitButton.innerText = peertubeTranslate('Watch Video', translations) const videoPasswordInput = document.getElementById('video-password-input') as HTMLInputElement videoPasswordInput.placeholder = peertubeTranslate('Password', translations) diff --git a/client/src/standalone/videos/shared/player-options-builder.ts b/client/src/standalone/videos/shared/player-options-builder.ts index a38895cd6..570465ad9 100644 --- a/client/src/standalone/videos/shared/player-options-builder.ts +++ b/client/src/standalone/videos/shared/player-options-builder.ts @@ -436,7 +436,7 @@ export class PlayerOptionsBuilder { : undefined const description = this.hasWarningTitle() && this.hasP2PEnabled() - ? '' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '' + ? peertubeTranslate('Watching this video may reveal your IP address to others.') : undefined if (!title && !description) return