diff options
author | Chocobozzz <me@florianbigard.com> | 2023-07-31 14:34:36 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-08-11 15:02:33 +0200 |
commit | 3a4992633ee62d5edfbb484d9c6bcb3cf158489d (patch) | |
tree | e4510b39bdac9c318fdb4b47018d08f15368b8f0 /server/tests/api/object-storage/video-static-file-privacy.ts | |
parent | 04d1da5621d25d59bd5fa1543b725c497bf5d9a8 (diff) | |
download | PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.gz PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.tar.zst PeerTube-3a4992633ee62d5edfbb484d9c6bcb3cf158489d.zip |
Migrate server to ESM
Sorry for the very big commit that may lead to git log issues and merge
conflicts, but it's a major step forward:
* Server can be faster at startup because imports() are async and we can
easily lazy import big modules
* Angular doesn't seem to support ES import (with .js extension), so we
had to correctly organize peertube into a monorepo:
* Use yarn workspace feature
* Use typescript reference projects for dependencies
* Shared projects have been moved into "packages", each one is now a
node module (with a dedicated package.json/tsconfig.json)
* server/tools have been moved into apps/ and is now a dedicated app
bundled and published on NPM so users don't have to build peertube
cli tools manually
* server/tests have been moved into packages/ so we don't compile
them every time we want to run the server
* Use isolatedModule option:
* Had to move from const enum to const
(https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums)
* Had to explictely specify "type" imports when used in decorators
* Prefer tsx (that uses esbuild under the hood) instead of ts-node to
load typescript files (tests with mocha or scripts):
* To reduce test complexity as esbuild doesn't support decorator
metadata, we only test server files that do not import server
models
* We still build tests files into js files for a faster CI
* Remove unmaintained peertube CLI import script
* Removed some barrels to speed up execution (less imports)
Diffstat (limited to 'server/tests/api/object-storage/video-static-file-privacy.ts')
-rw-r--r-- | server/tests/api/object-storage/video-static-file-privacy.ts | 570 |
1 files changed, 0 insertions, 570 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 deleted file mode 100644 index 64ab542a5..000000000 --- a/server/tests/api/object-storage/video-static-file-privacy.ts +++ /dev/null | |||
@@ -1,570 +0,0 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { basename } from 'path' | ||
5 | import { checkVideoFileTokenReinjection, expectStartWith, SQLCommand } from '@server/tests/shared' | ||
6 | import { areScalewayObjectStorageTestsDisabled, getAllFiles, getHLS } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models' | ||
8 | import { | ||
9 | cleanupTests, | ||
10 | createSingleServer, | ||
11 | findExternalSavedVideo, | ||
12 | makeRawRequest, | ||
13 | ObjectStorageCommand, | ||
14 | PeerTubeServer, | ||
15 | sendRTMPStream, | ||
16 | setAccessTokensToServers, | ||
17 | setDefaultVideoChannel, | ||
18 | stopFfmpeg, | ||
19 | waitJobs | ||
20 | } from '@shared/server-commands' | ||
21 | |||
22 | function extractFilenameFromUrl (url: string) { | ||
23 | const parts = basename(url).split(':') | ||
24 | |||
25 | return parts[parts.length - 1] | ||
26 | } | ||
27 | |||
28 | describe('Object storage for video static file privacy', function () { | ||
29 | // We need real world object storage to check ACL | ||
30 | if (areScalewayObjectStorageTestsDisabled()) return | ||
31 | |||
32 | let server: PeerTubeServer | ||
33 | let sqlCommand: SQLCommand | ||
34 | let userToken: string | ||
35 | |||
36 | // --------------------------------------------------------------------------- | ||
37 | |||
38 | async function checkPrivateVODFiles (uuid: string) { | ||
39 | const video = await server.videos.getWithToken({ id: uuid }) | ||
40 | |||
41 | for (const file of video.files) { | ||
42 | expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/web-videos/private/') | ||
43 | |||
44 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
45 | } | ||
46 | |||
47 | for (const file of getAllFiles(video)) { | ||
48 | const internalFileUrl = await sqlCommand.getInternalFileUrl(file.id) | ||
49 | expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
50 | await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
51 | } | ||
52 | |||
53 | const hls = getHLS(video) | ||
54 | |||
55 | if (hls) { | ||
56 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
57 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
58 | } | ||
59 | |||
60 | await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
61 | await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
62 | |||
63 | for (const file of hls.files) { | ||
64 | expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
65 | |||
66 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | |||
71 | async function checkPublicVODFiles (uuid: string) { | ||
72 | const video = await server.videos.getWithToken({ id: uuid }) | ||
73 | |||
74 | for (const file of getAllFiles(video)) { | ||
75 | expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
76 | |||
77 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
78 | } | ||
79 | |||
80 | const hls = getHLS(video) | ||
81 | |||
82 | if (hls) { | ||
83 | expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl()) | ||
84 | expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl()) | ||
85 | |||
86 | await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) | ||
87 | await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | // --------------------------------------------------------------------------- | ||
92 | |||
93 | before(async function () { | ||
94 | this.timeout(120000) | ||
95 | |||
96 | server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig({ serverNumber: 1 })) | ||
97 | await setAccessTokensToServers([ server ]) | ||
98 | await setDefaultVideoChannel([ server ]) | ||
99 | |||
100 | await server.config.enableMinimumTranscoding() | ||
101 | |||
102 | userToken = await server.users.generateUserAndToken('user1') | ||
103 | |||
104 | sqlCommand = new SQLCommand(server) | ||
105 | }) | ||
106 | |||
107 | describe('VOD', function () { | ||
108 | let privateVideoUUID: string | ||
109 | let publicVideoUUID: string | ||
110 | let passwordProtectedVideoUUID: string | ||
111 | let userPrivateVideoUUID: string | ||
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 | |||
117 | // --------------------------------------------------------------------------- | ||
118 | |||
119 | async function getSampleFileUrls (videoId: string) { | ||
120 | const video = await server.videos.getWithToken({ id: videoId }) | ||
121 | |||
122 | return { | ||
123 | webVideoFile: video.files[0].fileUrl, | ||
124 | hlsFile: getHLS(video).files[0].fileUrl | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // --------------------------------------------------------------------------- | ||
129 | |||
130 | it('Should upload a private video and have appropriate object storage ACL', async function () { | ||
131 | this.timeout(120000) | ||
132 | |||
133 | { | ||
134 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
135 | privateVideoUUID = uuid | ||
136 | } | ||
137 | |||
138 | { | ||
139 | const { uuid } = await server.videos.quickUpload({ name: 'user video', token: userToken, privacy: VideoPrivacy.PRIVATE }) | ||
140 | userPrivateVideoUUID = uuid | ||
141 | } | ||
142 | |||
143 | await waitJobs([ server ]) | ||
144 | |||
145 | await checkPrivateVODFiles(privateVideoUUID) | ||
146 | }) | ||
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 | |||
164 | it('Should upload a public video and have appropriate object storage ACL', async function () { | ||
165 | this.timeout(120000) | ||
166 | |||
167 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED }) | ||
168 | await waitJobs([ server ]) | ||
169 | |||
170 | publicVideoUUID = uuid | ||
171 | |||
172 | await checkPublicVODFiles(publicVideoUUID) | ||
173 | }) | ||
174 | |||
175 | it('Should not get files without appropriate OAuth token', async function () { | ||
176 | this.timeout(60000) | ||
177 | |||
178 | const { webVideoFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) | ||
179 | |||
180 | await makeRawRequest({ url: webVideoFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
181 | await makeRawRequest({ url: webVideoFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
182 | |||
183 | await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
184 | await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
185 | }) | ||
186 | |||
187 | it('Should not get files without appropriate password or appropriate OAuth token', async function () { | ||
188 | this.timeout(60000) | ||
189 | |||
190 | const { webVideoFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) | ||
191 | |||
192 | await makeRawRequest({ url: webVideoFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
193 | await makeRawRequest({ | ||
194 | url: webVideoFile, | ||
195 | token: null, | ||
196 | headers: incorrectPasswordHeader, | ||
197 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
198 | }) | ||
199 | await makeRawRequest({ url: webVideoFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
200 | await makeRawRequest({ | ||
201 | url: webVideoFile, | ||
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 | |||
223 | it('Should not get HLS file of another video', async function () { | ||
224 | this.timeout(60000) | ||
225 | |||
226 | const privateVideo = await server.videos.getWithToken({ id: privateVideoUUID }) | ||
227 | const hlsFilename = basename(getHLS(privateVideo).files[0].fileUrl) | ||
228 | |||
229 | const badUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + userPrivateVideoUUID + '/' + hlsFilename | ||
230 | const goodUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + privateVideoUUID + '/' + hlsFilename | ||
231 | |||
232 | await makeRawRequest({ url: badUrl, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 }) | ||
233 | await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
234 | }) | ||
235 | |||
236 | it('Should correctly check OAuth, video file token of private video', async function () { | ||
237 | this.timeout(60000) | ||
238 | |||
239 | const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID }) | ||
240 | const goodVideoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID }) | ||
241 | |||
242 | const { webVideoFile, hlsFile } = await getSampleFileUrls(privateVideoUUID) | ||
243 | |||
244 | for (const url of [ webVideoFile, hlsFile ]) { | ||
245 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
246 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
247 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
248 | |||
249 | await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
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 { webVideoFile, hlsFile } = await getSampleFileUrls(passwordProtectedVideoUUID) | ||
265 | |||
266 | for (const url of [ hlsFile, webVideoFile ]) { | ||
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 }) | ||
280 | } | ||
281 | }) | ||
282 | |||
283 | it('Should reinject video file token', async function () { | ||
284 | this.timeout(120000) | ||
285 | |||
286 | const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID }) | ||
287 | |||
288 | await checkVideoFileTokenReinjection({ | ||
289 | server, | ||
290 | videoUUID: privateVideoUUID, | ||
291 | videoFileToken, | ||
292 | resolutions: [ 240, 720 ], | ||
293 | isLive: false | ||
294 | }) | ||
295 | }) | ||
296 | |||
297 | it('Should update public video to private', async function () { | ||
298 | this.timeout(60000) | ||
299 | |||
300 | await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.INTERNAL } }) | ||
301 | |||
302 | await checkPrivateVODFiles(publicVideoUUID) | ||
303 | }) | ||
304 | |||
305 | it('Should update private video to public', async function () { | ||
306 | this.timeout(60000) | ||
307 | |||
308 | await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } }) | ||
309 | |||
310 | await checkPublicVODFiles(publicVideoUUID) | ||
311 | }) | ||
312 | }) | ||
313 | |||
314 | describe('Live', function () { | ||
315 | let normalLiveId: string | ||
316 | let normalLive: LiveVideo | ||
317 | |||
318 | let permanentLiveId: string | ||
319 | let permanentLive: LiveVideo | ||
320 | |||
321 | let passwordProtectedLiveId: string | ||
322 | let passwordProtectedLive: LiveVideo | ||
323 | |||
324 | const correctPassword = 'my super password' | ||
325 | |||
326 | let unrelatedFileToken: string | ||
327 | |||
328 | // --------------------------------------------------------------------------- | ||
329 | |||
330 | async function checkLiveFiles (live: LiveVideo, liveId: string, videoPassword?: string) { | ||
331 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey }) | ||
332 | await server.live.waitUntilPublished({ videoId: liveId }) | ||
333 | |||
334 | const video = videoPassword | ||
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 }) | ||
341 | |||
342 | const hls = video.streamingPlaylists[0] | ||
343 | |||
344 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
345 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
346 | |||
347 | await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
348 | await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
349 | |||
350 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
351 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
352 | if (videoPassword) { | ||
353 | await makeRawRequest({ url, headers: { 'x-peertube-video-password': videoPassword }, expectedStatus: HttpStatusCode.OK_200 }) | ||
354 | } | ||
355 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
356 | await makeRawRequest({ url, 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 | } | ||
365 | } | ||
366 | |||
367 | await stopFfmpeg(ffmpegCommand) | ||
368 | } | ||
369 | |||
370 | async function checkReplay (replay: VideoDetails) { | ||
371 | const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid }) | ||
372 | |||
373 | const hls = replay.streamingPlaylists[0] | ||
374 | expect(hls.files).to.not.have.lengthOf(0) | ||
375 | |||
376 | for (const file of hls.files) { | ||
377 | await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
378 | await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
379 | |||
380 | await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
381 | await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
382 | await makeRawRequest({ | ||
383 | url: file.fileUrl, | ||
384 | query: { videoFileToken: unrelatedFileToken }, | ||
385 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
386 | }) | ||
387 | } | ||
388 | |||
389 | for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) { | ||
390 | expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/') | ||
391 | |||
392 | await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) | ||
393 | await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 }) | ||
394 | |||
395 | await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
396 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
397 | await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // --------------------------------------------------------------------------- | ||
402 | |||
403 | before(async function () { | ||
404 | await server.config.enableMinimumTranscoding() | ||
405 | |||
406 | const { uuid } = await server.videos.quickUpload({ name: 'another video' }) | ||
407 | unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid }) | ||
408 | |||
409 | await server.config.enableLive({ | ||
410 | allowReplay: true, | ||
411 | transcoding: true, | ||
412 | resolutions: 'min' | ||
413 | }) | ||
414 | |||
415 | { | ||
416 | const { video, live } = await server.live.quickCreate({ | ||
417 | saveReplay: true, | ||
418 | permanentLive: false, | ||
419 | privacy: VideoPrivacy.PRIVATE | ||
420 | }) | ||
421 | normalLiveId = video.uuid | ||
422 | normalLive = live | ||
423 | } | ||
424 | |||
425 | { | ||
426 | const { video, live } = await server.live.quickCreate({ | ||
427 | saveReplay: true, | ||
428 | permanentLive: true, | ||
429 | privacy: VideoPrivacy.PRIVATE | ||
430 | }) | ||
431 | permanentLiveId = video.uuid | ||
432 | permanentLive = live | ||
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 | } | ||
445 | }) | ||
446 | |||
447 | it('Should create a private normal live and have a private static path', async function () { | ||
448 | this.timeout(240000) | ||
449 | |||
450 | await checkLiveFiles(normalLive, normalLiveId) | ||
451 | }) | ||
452 | |||
453 | it('Should create a private permanent live and have a private static path', async function () { | ||
454 | this.timeout(240000) | ||
455 | |||
456 | await checkLiveFiles(permanentLive, permanentLiveId) | ||
457 | }) | ||
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 | |||
465 | it('Should reinject video file token in permanent live', async function () { | ||
466 | this.timeout(240000) | ||
467 | |||
468 | const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: permanentLive.rtmpUrl, streamKey: permanentLive.streamKey }) | ||
469 | await server.live.waitUntilPublished({ videoId: permanentLiveId }) | ||
470 | |||
471 | const video = await server.videos.getWithToken({ id: permanentLiveId }) | ||
472 | const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid }) | ||
473 | |||
474 | await checkVideoFileTokenReinjection({ | ||
475 | server, | ||
476 | videoUUID: permanentLiveId, | ||
477 | videoFileToken, | ||
478 | resolutions: [ 720 ], | ||
479 | isLive: true | ||
480 | }) | ||
481 | |||
482 | await stopFfmpeg(ffmpegCommand) | ||
483 | }) | ||
484 | |||
485 | it('Should have created a replay of the normal live with a private static path', async function () { | ||
486 | this.timeout(240000) | ||
487 | |||
488 | await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId }) | ||
489 | |||
490 | const replay = await server.videos.getWithToken({ id: normalLiveId }) | ||
491 | await checkReplay(replay) | ||
492 | }) | ||
493 | |||
494 | it('Should have created a replay of the permanent live with a private static path', async function () { | ||
495 | this.timeout(240000) | ||
496 | |||
497 | await server.live.waitUntilWaiting({ videoId: permanentLiveId }) | ||
498 | await waitJobs([ server ]) | ||
499 | |||
500 | const live = await server.videos.getWithToken({ id: permanentLiveId }) | ||
501 | const replayFromList = await findExternalSavedVideo(server, live) | ||
502 | const replay = await server.videos.getWithToken({ id: replayFromList.id }) | ||
503 | |||
504 | await checkReplay(replay) | ||
505 | }) | ||
506 | }) | ||
507 | |||
508 | describe('With private files proxy disabled and public ACL for private files', function () { | ||
509 | let videoUUID: string | ||
510 | |||
511 | before(async function () { | ||
512 | this.timeout(240000) | ||
513 | |||
514 | await server.kill() | ||
515 | |||
516 | const config = ObjectStorageCommand.getDefaultScalewayConfig({ | ||
517 | serverNumber: 1, | ||
518 | enablePrivateProxy: false, | ||
519 | privateACL: 'public-read' | ||
520 | }) | ||
521 | await server.run(config) | ||
522 | |||
523 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | ||
524 | videoUUID = uuid | ||
525 | |||
526 | await waitJobs([ server ]) | ||
527 | }) | ||
528 | |||
529 | it('Should display object storage path for a private video and be able to access them', async function () { | ||
530 | this.timeout(60000) | ||
531 | |||
532 | await checkPublicVODFiles(videoUUID) | ||
533 | }) | ||
534 | |||
535 | it('Should not be able to access object storage proxy', async function () { | ||
536 | const privateVideo = await server.videos.getWithToken({ id: videoUUID }) | ||
537 | const webVideoFilename = extractFilenameFromUrl(privateVideo.files[0].fileUrl) | ||
538 | const hlsFilename = extractFilenameFromUrl(getHLS(privateVideo).files[0].fileUrl) | ||
539 | |||
540 | await makeRawRequest({ | ||
541 | url: server.url + '/object-storage-proxy/web-videos/private/' + webVideoFilename, | ||
542 | token: server.accessToken, | ||
543 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
544 | }) | ||
545 | |||
546 | await makeRawRequest({ | ||
547 | url: server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + videoUUID + '/' + hlsFilename, | ||
548 | token: server.accessToken, | ||
549 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
550 | }) | ||
551 | }) | ||
552 | }) | ||
553 | |||
554 | after(async function () { | ||
555 | this.timeout(240000) | ||
556 | |||
557 | const { data } = await server.videos.listAllForAdmin() | ||
558 | |||
559 | for (const v of data) { | ||
560 | await server.videos.remove({ id: v.uuid }) | ||
561 | } | ||
562 | |||
563 | for (const v of data) { | ||
564 | await server.servers.waitUntilLog('Removed files of video ' + v.url) | ||
565 | } | ||
566 | |||
567 | await sqlCommand.cleanup() | ||
568 | await cleanupTests([ server ]) | ||
569 | }) | ||
570 | }) | ||