From 3545e72c686ff1725bbdfd8d16d693e2f4aa75a3 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 12 Oct 2022 16:09:02 +0200 Subject: Put private videos under a specific subdirectory --- client/src/assets/player/shared/common/utils.ts | 8 +++++- .../shared/manager-options/hls-options-builder.ts | 18 +++++++++++-- .../manager-options/webtorrent-options-builder.ts | 15 +++++++++-- .../shared/p2p-media-loader/segment-validator.ts | 30 ++++++++++++++++++---- .../player/shared/peertube/peertube-plugin.ts | 4 +-- .../player/shared/webtorrent/webtorrent-plugin.ts | 22 +++++++++++++--- client/src/assets/player/types/manager-options.ts | 4 ++- .../player/types/peertube-videojs-typings.ts | 7 ++++- 8 files changed, 91 insertions(+), 17 deletions(-) (limited to 'client/src/assets/player') diff --git a/client/src/assets/player/shared/common/utils.ts b/client/src/assets/player/shared/common/utils.ts index a010d9184..609240626 100644 --- a/client/src/assets/player/shared/common/utils.ts +++ b/client/src/assets/player/shared/common/utils.ts @@ -52,6 +52,10 @@ function getRtcConfig () { } } +function isSameOrigin (current: string, target: string) { + return new URL(current).origin === new URL(target).origin +} + // --------------------------------------------------------------------------- export { @@ -60,5 +64,7 @@ export { videoFileMaxByResolution, videoFileMinByResolution, - bytes + bytes, + + isSameOrigin } diff --git a/client/src/assets/player/shared/manager-options/hls-options-builder.ts b/client/src/assets/player/shared/manager-options/hls-options-builder.ts index 361c76f4b..933c0d595 100644 --- a/client/src/assets/player/shared/manager-options/hls-options-builder.ts +++ b/client/src/assets/player/shared/manager-options/hls-options-builder.ts @@ -5,7 +5,7 @@ import { LiveVideoLatencyMode } from '@shared/models' import { getAverageBandwidthInStore } from '../../peertube-player-local-storage' import { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types' import { PeertubePlayerManagerOptions } from '../../types/manager-options' -import { getRtcConfig } from '../common' +import { getRtcConfig, isSameOrigin } from '../common' import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager' import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder' import { segmentValidatorFactory } from '../p2p-media-loader/segment-validator' @@ -84,7 +84,21 @@ export class HLSOptionsBuilder { simultaneousHttpDownloads: 1, httpFailedSegmentTimeout: 1000, - segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive), + xhrSetup: (xhr, url) => { + if (!this.options.common.requiresAuth) return + if (!isSameOrigin(this.options.common.serverUrl, url)) return + + xhr.setRequestHeader('Authorization', this.options.common.authorizationHeader()) + }, + + segmentValidator: segmentValidatorFactory({ + segmentsSha256Url: this.options.p2pMediaLoader.segmentsSha256Url, + isLive: this.options.common.isLive, + authorizationHeader: this.options.common.authorizationHeader, + requiresAuth: this.options.common.requiresAuth, + serverUrl: this.options.common.serverUrl + }), + segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), useP2P: this.options.common.p2pEnabled, diff --git a/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts b/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts index 257cf1e05..b5bdcd4e6 100644 --- a/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts +++ b/client/src/assets/player/shared/manager-options/webtorrent-options-builder.ts @@ -1,4 +1,5 @@ -import { PeertubePlayerManagerOptions } from '../../types' +import { addQueryParams } from '../../../../../../shared/core-utils' +import { PeertubePlayerManagerOptions, WebtorrentPluginOptions } from '../../types' export class WebTorrentOptionsBuilder { @@ -16,13 +17,23 @@ export class WebTorrentOptionsBuilder { const autoplay = this.autoPlayValue === 'play' - const webtorrent = { + const webtorrent: WebtorrentPluginOptions = { autoplay, playerRefusedP2P: commonOptions.p2pEnabled === false, videoDuration: commonOptions.videoDuration, playerElement: commonOptions.playerElement, + videoFileToken: commonOptions.videoFileToken, + + requiresAuth: commonOptions.requiresAuth, + + buildWebSeedUrls: file => { + if (!commonOptions.requiresAuth) return [] + + return [ addQueryParams(file.fileUrl, { videoFileToken: commonOptions.videoFileToken() }) ] + }, + videoFiles: webtorrentOptions.videoFiles.length !== 0 ? webtorrentOptions.videoFiles // The WebTorrent plugin won't be able to play these files, but it will fallback to HTTP mode diff --git a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts index 18cb6750f..a7ee91950 100644 --- a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts +++ b/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts @@ -2,13 +2,22 @@ import { basename } from 'path' import { Segment } from '@peertube/p2p-media-loader-core' import { logger } from '@root-helpers/logger' import { wait } from '@root-helpers/utils' +import { isSameOrigin } from '../common' type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } } const maxRetries = 3 -function segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) { - let segmentsJSON = fetchSha256Segments(segmentsSha256Url) +function segmentValidatorFactory (options: { + serverUrl: string + segmentsSha256Url: string + isLive: boolean + authorizationHeader: () => string + requiresAuth: boolean +}) { + const { serverUrl, segmentsSha256Url, isLive, authorizationHeader, requiresAuth } = options + + let segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) const regex = /bytes=(\d+)-(\d+)/ return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) { @@ -28,7 +37,7 @@ function segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) { await wait(1000) - segmentsJSON = fetchSha256Segments(segmentsSha256Url) + segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) await segmentValidator(segment, _method, _peerId, retry + 1) return @@ -68,8 +77,19 @@ export { // --------------------------------------------------------------------------- -function fetchSha256Segments (url: string) { - return fetch(url) +function fetchSha256Segments (options: { + serverUrl: string + segmentsSha256Url: string + authorizationHeader: () => string + requiresAuth: boolean +}) { + const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options + + const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url) + ? { Authorization: authorizationHeader() } + : {} + + return fetch(segmentsSha256Url, { headers }) .then(res => res.json() as Promise) .catch(err => { logger.error('Cannot get sha256 segments', err) diff --git a/client/src/assets/player/shared/peertube/peertube-plugin.ts b/client/src/assets/player/shared/peertube/peertube-plugin.ts index a5d712d70..4bd038bb1 100644 --- a/client/src/assets/player/shared/peertube/peertube-plugin.ts +++ b/client/src/assets/player/shared/peertube/peertube-plugin.ts @@ -22,7 +22,7 @@ const Plugin = videojs.getPlugin('plugin') class PeerTubePlugin extends Plugin { private readonly videoViewUrl: string - private readonly authorizationHeader: string + private readonly authorizationHeader: () => string private readonly videoUUID: string private readonly startTime: number @@ -228,7 +228,7 @@ class PeerTubePlugin extends Plugin { 'Content-type': 'application/json; charset=UTF-8' }) - if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader) + if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader()) return fetch(this.videoViewUrl, { method: 'POST', body: JSON.stringify(body), headers }) } diff --git a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts index fa3f48a9a..658b7c867 100644 --- a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts @@ -2,7 +2,7 @@ import videojs from 'video.js' import * as WebTorrent from 'webtorrent' import { logger } from '@root-helpers/logger' import { isIOS } from '@root-helpers/web-browser' -import { timeToInt } from '@shared/core-utils' +import { addQueryParams, timeToInt } from '@shared/core-utils' import { VideoFile } from '@shared/models' import { getAverageBandwidthInStore, getStoredMute, getStoredVolume, saveAverageBandwidth } from '../../peertube-player-local-storage' import { PeerTubeResolution, PlayerNetworkInfo, WebtorrentPluginOptions } from '../../types' @@ -38,6 +38,8 @@ class WebTorrentPlugin extends Plugin { BANDWIDTH_AVERAGE_NUMBER_OF_VALUES: 5 // Last 5 seconds to build average bandwidth } + private readonly buildWebSeedUrls: (file: VideoFile) => string[] + private readonly webtorrent = new WebTorrent({ tracker: { rtcConfig: getRtcConfig() @@ -57,6 +59,9 @@ class WebTorrentPlugin extends Plugin { private isAutoResolutionObservation = false private playerRefusedP2P = false + private requiresAuth: boolean + private videoFileToken: () => string + private torrentInfoInterval: any private autoQualityInterval: any private addTorrentDelay: any @@ -81,6 +86,11 @@ class WebTorrentPlugin extends Plugin { this.savePlayerSrcFunction = this.player.src this.playerElement = options.playerElement + this.requiresAuth = options.requiresAuth + this.videoFileToken = options.videoFileToken + + this.buildWebSeedUrls = options.buildWebSeedUrls + this.player.ready(() => { const playerOptions = this.player.options_ @@ -268,7 +278,8 @@ class WebTorrentPlugin extends Plugin { return new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), { max: 100 }) - } + }, + urlList: this.buildWebSeedUrls(this.currentVideoFile) } this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => { @@ -533,7 +544,12 @@ class WebTorrentPlugin extends Plugin { // Enable error display now this is our last fallback this.player.one('error', () => this.player.peertube().displayFatalError()) - const httpUrl = this.currentVideoFile.fileUrl + let httpUrl = this.currentVideoFile.fileUrl + + if (this.requiresAuth && this.videoFileToken) { + httpUrl = addQueryParams(httpUrl, { videoFileToken: this.videoFileToken() }) + } + this.player.src = this.savePlayerSrcFunction this.player.src(httpUrl) diff --git a/client/src/assets/player/types/manager-options.ts b/client/src/assets/player/types/manager-options.ts index b4d9374c3..9da8fedf8 100644 --- a/client/src/assets/player/types/manager-options.ts +++ b/client/src/assets/player/types/manager-options.ts @@ -57,7 +57,7 @@ export interface CommonOptions extends CustomizationOptions { captions: boolean videoViewUrl: string - authorizationHeader?: string + authorizationHeader?: () => string metricsUrl: string @@ -77,6 +77,8 @@ export interface CommonOptions extends CustomizationOptions { videoShortUUID: string serverUrl: string + requiresAuth: boolean + videoFileToken: () => string errorNotifier: (message: string) => void } diff --git a/client/src/assets/player/types/peertube-videojs-typings.ts b/client/src/assets/player/types/peertube-videojs-typings.ts index 6df94992c..037c4b74b 100644 --- a/client/src/assets/player/types/peertube-videojs-typings.ts +++ b/client/src/assets/player/types/peertube-videojs-typings.ts @@ -95,7 +95,7 @@ type PeerTubePluginOptions = { videoDuration: number videoViewUrl: string - authorizationHeader?: string + authorizationHeader?: () => string subtitle?: string @@ -151,6 +151,11 @@ type WebtorrentPluginOptions = { startTime: number | string playerRefusedP2P: boolean + + requiresAuth: boolean + videoFileToken: () => string + + buildWebSeedUrls: (file: VideoFile) => string[] } type P2PMediaLoaderPluginOptions = { -- cgit v1.2.3