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 /server/tests/api/object-storage | |
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 'server/tests/api/object-storage')
-rw-r--r-- | server/tests/api/object-storage/video-static-file-privacy.ts | 132 |
1 files changed, 127 insertions, 5 deletions
diff --git a/server/tests/api/object-storage/video-static-file-privacy.ts b/server/tests/api/object-storage/video-static-file-privacy.ts index af9d681b2..2a7c3381d 100644 --- a/server/tests/api/object-storage/video-static-file-privacy.ts +++ b/server/tests/api/object-storage/video-static-file-privacy.ts | |||
@@ -107,8 +107,13 @@ describe('Object storage for video static file privacy', function () { | |||
107 | describe('VOD', function () { | 107 | describe('VOD', function () { |
108 | let privateVideoUUID: string | 108 | let privateVideoUUID: string |
109 | let publicVideoUUID: string | 109 | let publicVideoUUID: string |
110 | let passwordProtectedVideoUUID: string | ||
110 | let userPrivateVideoUUID: string | 111 | let userPrivateVideoUUID: string |
111 | 112 | ||
113 | const correctPassword = 'my super password' | ||
114 | const correctPasswordHeader = { 'x-peertube-video-password': correctPassword } | ||
115 | const incorrectPasswordHeader = { 'x-peertube-video-password': correctPassword + 'toto' } | ||
116 | |||
112 | // --------------------------------------------------------------------------- | 117 | // --------------------------------------------------------------------------- |
113 | 118 | ||
114 | async function getSampleFileUrls (videoId: string) { | 119 | async function getSampleFileUrls (videoId: string) { |
@@ -140,6 +145,22 @@ describe('Object storage for video static file privacy', function () { | |||
140 | await checkPrivateVODFiles(privateVideoUUID) | 145 | await checkPrivateVODFiles(privateVideoUUID) |
141 | }) | 146 | }) |
142 | 147 | ||
148 | it('Should upload a password protected video and have appropriate object storage ACL', async function () { | ||
149 | this.timeout(120000) | ||
150 | |||
151 | { | ||
152 | const { uuid } = await server.videos.quickUpload({ | ||
153 | name: 'video', | ||
154 | privacy: VideoPrivacy.PASSWORD_PROTECTED, | ||
155 | videoPasswords: [ correctPassword ] | ||
156 | }) | ||
157 | passwordProtectedVideoUUID = uuid | ||
158 | } | ||
159 | await waitJobs([ server ]) | ||
160 | |||
161 | await checkPrivateVODFiles(passwordProtectedVideoUUID) | ||
162 | }) | ||
163 | |||
143 | it('Should upload a public video and have appropriate object storage ACL', async function () { | 164 | it('Should upload a public video and have appropriate object storage ACL', async function () { |
144 | this.timeout(120000) | 165 | this.timeout(120000) |
145 | 166 | ||
@@ -163,6 +184,42 @@ describe('Object storage for video static file privacy', function () { | |||
163 | await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | 184 | await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) |
164 | }) | 185 | }) |
165 | 186 | ||
187 | it('Should not get files without appropriate password or appropriate OAuth token', async function () { | ||
188 | this.timeout(60000) | ||
189 | |||
190 | const { webTorrentFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) | ||
191 | |||
192 | await makeRawRequest({ url: webTorrentFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
193 | await makeRawRequest({ | ||
194 | url: webTorrentFile, | ||
195 | token: null, | ||
196 | headers: incorrectPasswordHeader, | ||
197 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
198 | }) | ||
199 | await makeRawRequest({ url: webTorrentFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
200 | await makeRawRequest({ | ||
201 | url: webTorrentFile, | ||
202 | token: null, | ||
203 | headers: correctPasswordHeader, | ||
204 | expectedStatus: HttpStatusCode.OK_200 | ||
205 | }) | ||
206 | |||
207 | await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
208 | await makeRawRequest({ | ||
209 | url: hlsFile, | ||
210 | token: null, | ||
211 | headers: incorrectPasswordHeader, | ||
212 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
213 | }) | ||
214 | await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
215 | await makeRawRequest({ | ||
216 | url: hlsFile, | ||
217 | token: null, | ||
218 | headers: correctPasswordHeader, | ||
219 | expectedStatus: HttpStatusCode.OK_200 | ||
220 | }) | ||
221 | }) | ||
222 | |||
166 | it('Should not get HLS file of another video', async function () { | 223 | it('Should not get HLS file of another video', async function () { |
167 | this.timeout(60000) | 224 | this.timeout(60000) |
168 | 225 | ||
@@ -176,7 +233,7 @@ describe('Object storage for video static file privacy', function () { | |||
176 | await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | 233 | await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) |
177 | }) | 234 | }) |
178 | 235 | ||
179 | it('Should correctly check OAuth or video file token', async function () { | 236 | it('Should correctly check OAuth, video file token of private video', async function () { |
180 | this.timeout(60000) | 237 | this.timeout(60000) |
181 | 238 | ||
182 | const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) | 239 | const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) |
@@ -191,6 +248,35 @@ describe('Object storage for video static file privacy', function () { | |||
191 | 248 | ||
192 | await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 249 | await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
193 | await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) | 250 | await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) |
251 | |||
252 | } | ||
253 | }) | ||
254 | |||
255 | it('Should correctly check OAuth, video file token or video password of password protected video', async function () { | ||
256 | this.timeout(60000) | ||
257 | |||
258 | const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) | ||
259 | const goodVideoFileToken = await server.videoToken.getVideoFileToken({ | ||
260 | videoId: passwordProtectedVideoUUID, | ||
261 | videoPassword: correctPassword | ||
262 | }) | ||
263 | |||
264 | const { webTorrentFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) | ||
265 | |||
266 | for (const url of [ hlsFile, webTorrentFile ]) { | ||
267 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
268 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
269 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
270 | |||
271 | await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
272 | await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
273 | |||
274 | await makeRawRequest({ | ||
275 | url, | ||
276 | headers: incorrectPasswordHeader, | ||
277 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
278 | }) | ||
279 | await makeRawRequest({ url, headers: correctPasswordHeader, expectedStatus: HttpStatusCode.OK_200 }) | ||
194 | } | 280 | } |
195 | }) | 281 | }) |
196 | 282 | ||
@@ -232,16 +318,26 @@ describe('Object storage for video static file privacy', function () { | |||
232 | let permanentLiveId: string | 318 | let permanentLiveId: string |
233 | let permanentLive: LiveVideo | 319 | let permanentLive: LiveVideo |
234 | 320 | ||
321 | let passwordProtectedLiveId: string | ||
322 | let passwordProtectedLive: LiveVideo | ||
323 | |||
324 | const correctPassword = 'my super password' | ||
325 | |||
235 | let unrelatedFileToken: string | 326 | let unrelatedFileToken: string |
236 | 327 | ||
237 | // --------------------------------------------------------------------------- | 328 | // --------------------------------------------------------------------------- |
238 | 329 | ||
239 | async function checkLiveFiles (live: LiveVideo, liveId: string) { | 330 | async function checkLiveFiles (live: LiveVideo, liveId: string, videoPassword?: string) { |
240 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | 331 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) |
241 | await server.live.waitUntilPublished({ videoId: liveId }) | 332 | await server.live.waitUntilPublished({ videoId: liveId }) |
242 | 333 | ||
243 | const video = await server.videos.getWithToken({ id: liveId }) | 334 | const video = videoPassword |
244 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) | 335 | ? await server.videos.getWithPassword({ id: liveId, password: videoPassword }) |
336 | : await server.videos.getWithToken({ id: liveId }) | ||
337 | |||
338 | const fileToken = videoPassword | ||
339 | ? await server.videoToken.getVideoFileToken({ token: null, videoId: video.uuid, videoPassword }) | ||
340 | : await server.videoToken.getVideoFileToken({ videoId: video.uuid }) | ||
245 | 341 | ||
246 | const hls = video.streamingPlaylists[0] | 342 | const hls = video.streamingPlaylists[0] |
247 | 343 | ||
@@ -253,10 +349,19 @@ describe('Object storage for video static file privacy', function () { | |||
253 | 349 | ||
254 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | 350 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) |
255 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | 351 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) |
256 | 352 | if (videoPassword) { | |
353 | await makeRawRequest({ url, headers: { 'x-peertube-video-password': videoPassword }, expectedStatus: HttpStatusCode.OK_200 }) | ||
354 | } | ||
257 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 355 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
258 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 356 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
259 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 357 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) |
358 | if (videoPassword) { | ||
359 | await makeRawRequest({ | ||
360 | url, | ||
361 | headers: { 'x-peertube-video-password': 'incorrectPassword' }, | ||
362 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
363 | }) | ||
364 | } | ||
260 | } | 365 | } |
261 | 366 | ||
262 | await stopFfmpeg(ffmpegCommand) | 367 | await stopFfmpeg(ffmpegCommand) |
@@ -326,6 +431,17 @@ describe('Object storage for video static file privacy', function () { | |||
326 | permanentLiveId = video.uuid | 431 | permanentLiveId = video.uuid |
327 | permanentLive = live | 432 | permanentLive = live |
328 | } | 433 | } |
434 | |||
435 | { | ||
436 | const { video, live } = await server.live.quickCreate({ | ||
437 | saveReplay: false, | ||
438 | permanentLive: false, | ||
439 | privacy: VideoPrivacy.PASSWORD_PROTECTED, | ||
440 | videoPasswords: [ correctPassword ] | ||
441 | }) | ||
442 | passwordProtectedLiveId = video.uuid | ||
443 | passwordProtectedLive = live | ||
444 | } | ||
329 | }) | 445 | }) |
330 | 446 | ||
331 | it('Should create a private normal live and have a private static path', async function () { | 447 | it('Should create a private normal live and have a private static path', async function () { |
@@ -340,6 +456,12 @@ describe('Object storage for video static file privacy', function () { | |||
340 | await checkLiveFiles(permanentLive, permanentLiveId) | 456 | await checkLiveFiles(permanentLive, permanentLiveId) |
341 | }) | 457 | }) |
342 | 458 | ||
459 | it('Should create a password protected live and have a private static path', async function () { | ||
460 | this.timeout(240000) | ||
461 | |||
462 | await checkLiveFiles(passwordProtectedLive, passwordProtectedLiveId, correctPassword) | ||
463 | }) | ||
464 | |||
343 | it('Should reinject video file token in permanent live', async function () { | 465 | it('Should reinject video file token in permanent live', async function () { |
344 | this.timeout(240000) | 466 | this.timeout(240000) |
345 | 467 | ||