diff options
author | Wicklow <123956049+wickloww@users.noreply.github.com> | 2023-06-29 07:48:55 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-29 09:48:55 +0200 |
commit | 40346ead2b0b7afa475aef057d3673b6c7574b7a (patch) | |
tree | 24ffdc23c3a9d987334842e0d400b5bd44500cf7 /client/src/assets/player/shared | |
parent | ae22c59f14d0d553f60b281948b6c232c2aca178 (diff) | |
download | PeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.tar.gz PeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.tar.zst PeerTube-40346ead2b0b7afa475aef057d3673b6c7574b7a.zip |
Feature/password protected videos (#5836)
* Add server endpoints
* Refactoring test suites
* Update server and add openapi documentation
* fix compliation and tests
* upload/import password protected video on client
* add server error code
* Add video password to update resolver
* add custom message when sharing pw protected video
* improve confirm component
* Add new alert in component
* Add ability to watch protected video on client
* Cannot have password protected replay privacy
* Add migration
* Add tests
* update after review
* Update check params tests
* Add live videos test
* Add more filter test
* Update static file privacy test
* Update object storage tests
* Add test on feeds
* Add missing word
* Fix tests
* Fix tests on live videos
* add embed support on password protected videos
* fix style
* Correcting data leaks
* Unable to add password protected privacy on replay
* Updated code based on review comments
* fix validator and command
* Updated code based on review comments
Diffstat (limited to 'client/src/assets/player/shared')
4 files changed, 47 insertions, 20 deletions
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 194991fa4..8091110bc 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 | |||
@@ -31,7 +31,7 @@ export class HLSOptionsBuilder { | |||
31 | const loader = new this.p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() as P2PMediaLoader | 31 | const loader = new this.p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() as P2PMediaLoader |
32 | 32 | ||
33 | const p2pMediaLoader: P2PMediaLoaderPluginOptions = { | 33 | const p2pMediaLoader: P2PMediaLoaderPluginOptions = { |
34 | requiresAuth: commonOptions.requiresAuth, | 34 | requiresUserAuth: commonOptions.requiresUserAuth, |
35 | videoFileToken: commonOptions.videoFileToken, | 35 | videoFileToken: commonOptions.videoFileToken, |
36 | 36 | ||
37 | redundancyUrlManager, | 37 | redundancyUrlManager, |
@@ -88,17 +88,24 @@ export class HLSOptionsBuilder { | |||
88 | httpFailedSegmentTimeout: 1000, | 88 | httpFailedSegmentTimeout: 1000, |
89 | 89 | ||
90 | xhrSetup: (xhr, url) => { | 90 | xhrSetup: (xhr, url) => { |
91 | if (!this.options.common.requiresAuth) return | 91 | const { requiresUserAuth, requiresPassword } = this.options.common |
92 | |||
93 | if (!(requiresUserAuth || requiresPassword)) return | ||
94 | |||
92 | if (!isSameOrigin(this.options.common.serverUrl, url)) return | 95 | if (!isSameOrigin(this.options.common.serverUrl, url)) return |
93 | 96 | ||
94 | xhr.setRequestHeader('Authorization', this.options.common.authorizationHeader()) | 97 | if (requiresPassword) xhr.setRequestHeader('x-peertube-video-password', this.options.common.videoPassword()) |
98 | |||
99 | else xhr.setRequestHeader('Authorization', this.options.common.authorizationHeader()) | ||
95 | }, | 100 | }, |
96 | 101 | ||
97 | segmentValidator: segmentValidatorFactory({ | 102 | segmentValidator: segmentValidatorFactory({ |
98 | segmentsSha256Url: this.options.p2pMediaLoader.segmentsSha256Url, | 103 | segmentsSha256Url: this.options.p2pMediaLoader.segmentsSha256Url, |
99 | authorizationHeader: this.options.common.authorizationHeader, | 104 | authorizationHeader: this.options.common.authorizationHeader, |
100 | requiresAuth: this.options.common.requiresAuth, | 105 | requiresUserAuth: this.options.common.requiresUserAuth, |
101 | serverUrl: this.options.common.serverUrl | 106 | serverUrl: this.options.common.serverUrl, |
107 | requiresPassword: this.options.common.requiresPassword, | ||
108 | videoPassword: this.options.common.videoPassword | ||
102 | }), | 109 | }), |
103 | 110 | ||
104 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), | 111 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), |
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 b5bdcd4e6..80eec02cf 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 | |||
@@ -26,10 +26,10 @@ export class WebTorrentOptionsBuilder { | |||
26 | 26 | ||
27 | videoFileToken: commonOptions.videoFileToken, | 27 | videoFileToken: commonOptions.videoFileToken, |
28 | 28 | ||
29 | requiresAuth: commonOptions.requiresAuth, | 29 | requiresUserAuth: commonOptions.requiresUserAuth, |
30 | 30 | ||
31 | buildWebSeedUrls: file => { | 31 | buildWebSeedUrls: file => { |
32 | if (!commonOptions.requiresAuth) return [] | 32 | if (!commonOptions.requiresUserAuth && !commonOptions.requiresPassword) return [] |
33 | 33 | ||
34 | return [ addQueryParams(file.fileUrl, { videoFileToken: commonOptions.videoFileToken() }) ] | 34 | return [ addQueryParams(file.fileUrl, { videoFileToken: commonOptions.videoFileToken() }) ] |
35 | }, | 35 | }, |
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 44a31bfb4..e86d3d159 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 | |||
@@ -13,11 +13,20 @@ function segmentValidatorFactory (options: { | |||
13 | serverUrl: string | 13 | serverUrl: string |
14 | segmentsSha256Url: string | 14 | segmentsSha256Url: string |
15 | authorizationHeader: () => string | 15 | authorizationHeader: () => string |
16 | requiresAuth: boolean | 16 | requiresUserAuth: boolean |
17 | requiresPassword: boolean | ||
18 | videoPassword: () => string | ||
17 | }) { | 19 | }) { |
18 | const { serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth } = options | 20 | const { serverUrl, segmentsSha256Url, authorizationHeader, requiresUserAuth, requiresPassword, videoPassword } = options |
19 | 21 | ||
20 | let segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) | 22 | let segmentsJSON = fetchSha256Segments({ |
23 | serverUrl, | ||
24 | segmentsSha256Url, | ||
25 | authorizationHeader, | ||
26 | requiresUserAuth, | ||
27 | requiresPassword, | ||
28 | videoPassword | ||
29 | }) | ||
21 | const regex = /bytes=(\d+)-(\d+)/ | 30 | const regex = /bytes=(\d+)-(\d+)/ |
22 | 31 | ||
23 | return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) { | 32 | return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) { |
@@ -34,7 +43,14 @@ function segmentValidatorFactory (options: { | |||
34 | 43 | ||
35 | await wait(500) | 44 | await wait(500) |
36 | 45 | ||
37 | segmentsJSON = fetchSha256Segments({ serverUrl, segmentsSha256Url, authorizationHeader, requiresAuth }) | 46 | segmentsJSON = fetchSha256Segments({ |
47 | serverUrl, | ||
48 | segmentsSha256Url, | ||
49 | authorizationHeader, | ||
50 | requiresUserAuth, | ||
51 | requiresPassword, | ||
52 | videoPassword | ||
53 | }) | ||
38 | await segmentValidator(segment, _method, _peerId, retry + 1) | 54 | await segmentValidator(segment, _method, _peerId, retry + 1) |
39 | 55 | ||
40 | return | 56 | return |
@@ -78,13 +94,17 @@ function fetchSha256Segments (options: { | |||
78 | serverUrl: string | 94 | serverUrl: string |
79 | segmentsSha256Url: string | 95 | segmentsSha256Url: string |
80 | authorizationHeader: () => string | 96 | authorizationHeader: () => string |
81 | requiresAuth: boolean | 97 | requiresUserAuth: boolean |
98 | requiresPassword: boolean | ||
99 | videoPassword: () => string | ||
82 | }): Promise<SegmentsJSON> { | 100 | }): Promise<SegmentsJSON> { |
83 | const { serverUrl, segmentsSha256Url, requiresAuth, authorizationHeader } = options | 101 | const { serverUrl, segmentsSha256Url, requiresUserAuth, authorizationHeader, requiresPassword, videoPassword } = options |
84 | 102 | ||
85 | const headers = requiresAuth && isSameOrigin(serverUrl, segmentsSha256Url) | 103 | let headers: { [ id: string ]: string } = {} |
86 | ? { Authorization: authorizationHeader() } | 104 | if (isSameOrigin(serverUrl, segmentsSha256Url)) { |
87 | : {} | 105 | if (requiresPassword) headers = { 'x-peertube-video-password': videoPassword() } |
106 | else if (requiresUserAuth) headers = { Authorization: authorizationHeader() } | ||
107 | } | ||
88 | 108 | ||
89 | return fetch(segmentsSha256Url, { headers }) | 109 | return fetch(segmentsSha256Url, { headers }) |
90 | .then(res => res.json() as Promise<SegmentsJSON>) | 110 | .then(res => res.json() as Promise<SegmentsJSON>) |
diff --git a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts index 3dde44a60..e2e220c03 100644 --- a/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/shared/webtorrent/webtorrent-plugin.ts | |||
@@ -59,7 +59,7 @@ class WebTorrentPlugin extends Plugin { | |||
59 | private isAutoResolutionObservation = false | 59 | private isAutoResolutionObservation = false |
60 | private playerRefusedP2P = false | 60 | private playerRefusedP2P = false |
61 | 61 | ||
62 | private requiresAuth: boolean | 62 | private requiresUserAuth: boolean |
63 | private videoFileToken: () => string | 63 | private videoFileToken: () => string |
64 | 64 | ||
65 | private torrentInfoInterval: any | 65 | private torrentInfoInterval: any |
@@ -86,7 +86,7 @@ class WebTorrentPlugin extends Plugin { | |||
86 | this.savePlayerSrcFunction = this.player.src | 86 | this.savePlayerSrcFunction = this.player.src |
87 | this.playerElement = options.playerElement | 87 | this.playerElement = options.playerElement |
88 | 88 | ||
89 | this.requiresAuth = options.requiresAuth | 89 | this.requiresUserAuth = options.requiresUserAuth |
90 | this.videoFileToken = options.videoFileToken | 90 | this.videoFileToken = options.videoFileToken |
91 | 91 | ||
92 | this.buildWebSeedUrls = options.buildWebSeedUrls | 92 | this.buildWebSeedUrls = options.buildWebSeedUrls |
@@ -546,7 +546,7 @@ class WebTorrentPlugin extends Plugin { | |||
546 | 546 | ||
547 | let httpUrl = this.currentVideoFile.fileUrl | 547 | let httpUrl = this.currentVideoFile.fileUrl |
548 | 548 | ||
549 | if (this.requiresAuth && this.videoFileToken) { | 549 | if (this.videoFileToken) { |
550 | httpUrl = addQueryParams(httpUrl, { videoFileToken: this.videoFileToken() }) | 550 | httpUrl = addQueryParams(httpUrl, { videoFileToken: this.videoFileToken() }) |
551 | } | 551 | } |
552 | 552 | ||