aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/object-storage/video-static-file-privacy.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-10-19 10:43:53 +0200
committerChocobozzz <chocobozzz@cpy.re>2022-10-24 14:48:24 +0200
commit9ab330b90decf4edf152ff8e1d2948c065766b2c (patch)
tree29d924f50f7307e8e828a57ecb9ea78623487ce0 /server/tests/api/object-storage/video-static-file-privacy.ts
parent3545e72c686ff1725bbdfd8d16d693e2f4aa75a3 (diff)
downloadPeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.tar.gz
PeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.tar.zst
PeerTube-9ab330b90decf4edf152ff8e1d2948c065766b2c.zip
Use private ACL for private videos in s3
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.ts336
1 files changed, 336 insertions, 0 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
new file mode 100644
index 000000000..981bbaa16
--- /dev/null
+++ b/server/tests/api/object-storage/video-static-file-privacy.ts
@@ -0,0 +1,336 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { basename } from 'path'
5import { expectStartWith } from '@server/tests/shared'
6import { areScalewayObjectStorageTestsDisabled, getAllFiles, getHLS } from '@shared/core-utils'
7import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models'
8import {
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
22describe('Object storage for video static file privacy', function () {
23 // We need real world object storage to check ACL
24 if (areScalewayObjectStorageTestsDisabled()) return
25
26 let server: PeerTubeServer
27 let userToken: string
28
29 before(async function () {
30 this.timeout(120000)
31
32 server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig(1))
33 await setAccessTokensToServers([ server ])
34 await setDefaultVideoChannel([ server ])
35
36 await server.config.enableMinimumTranscoding()
37
38 userToken = await server.users.generateUserAndToken('user1')
39 })
40
41 describe('VOD', function () {
42 let privateVideoUUID: string
43 let publicVideoUUID: string
44 let userPrivateVideoUUID: string
45
46 async function checkPrivateFiles (uuid: string) {
47 const video = await server.videos.getWithToken({ id: uuid })
48
49 for (const file of video.files) {
50 expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/webseed/private/')
51
52 await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
53 }
54
55 for (const file of getAllFiles(video)) {
56 const internalFileUrl = await server.sql.getInternalFileUrl(file.id)
57 expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl())
58 await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
59 }
60
61 const hls = getHLS(video)
62
63 if (hls) {
64 for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) {
65 expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
66 }
67
68 await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
69 await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
70
71 for (const file of hls.files) {
72 expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
73
74 await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
75 }
76 }
77 }
78
79 async function checkPublicFiles (uuid: string) {
80 const video = await server.videos.getWithToken({ id: uuid })
81
82 for (const file of getAllFiles(video)) {
83 expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl())
84
85 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
86 }
87
88 const hls = getHLS(video)
89
90 if (hls) {
91 expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl())
92 expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl())
93
94 await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
95 await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
96 }
97 }
98
99 async function getSampleFileUrls (videoId: string) {
100 const video = await server.videos.getWithToken({ id: videoId })
101
102 return {
103 webTorrentFile: video.files[0].fileUrl,
104 hlsFile: getHLS(video).files[0].fileUrl
105 }
106 }
107
108 it('Should upload a private video and have appropriate object storage ACL', async function () {
109 this.timeout(60000)
110
111 {
112 const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE })
113 privateVideoUUID = uuid
114 }
115
116 {
117 const { uuid } = await server.videos.quickUpload({ name: 'user video', token: userToken, privacy: VideoPrivacy.PRIVATE })
118 userPrivateVideoUUID = uuid
119 }
120
121 await waitJobs([ server ])
122
123 await checkPrivateFiles(privateVideoUUID)
124 })
125
126 it('Should upload a public video and have appropriate object storage ACL', async function () {
127 this.timeout(60000)
128
129 const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED })
130 await waitJobs([ server ])
131
132 publicVideoUUID = uuid
133
134 await checkPublicFiles(publicVideoUUID)
135 })
136
137 it('Should not get files without appropriate OAuth token', async function () {
138 this.timeout(60000)
139
140 const { webTorrentFile, hlsFile } = await getSampleFileUrls(privateVideoUUID)
141
142 await makeRawRequest({ url: webTorrentFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
143 await makeRawRequest({ url: webTorrentFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
144
145 await makeRawRequest({ url: hlsFile, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
146 await makeRawRequest({ url: hlsFile, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
147 })
148
149 it('Should not get HLS file of another video', async function () {
150 this.timeout(60000)
151
152 const privateVideo = await server.videos.getWithToken({ id: privateVideoUUID })
153 const hlsFilename = basename(getHLS(privateVideo).files[0].fileUrl)
154
155 const badUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + userPrivateVideoUUID + '/' + hlsFilename
156 const goodUrl = server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + privateVideoUUID + '/' + hlsFilename
157
158 await makeRawRequest({ url: badUrl, token: server.accessToken, expectedStatus: HttpStatusCode.NOT_FOUND_404 })
159 await makeRawRequest({ url: goodUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
160 })
161
162 it('Should correctly check OAuth or video file token', async function () {
163 this.timeout(60000)
164
165 const badVideoFileToken = await server.videoToken.getVideoFileToken({ token: userToken, videoId: userPrivateVideoUUID })
166 const goodVideoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID })
167
168 const { webTorrentFile, hlsFile } = await getSampleFileUrls(privateVideoUUID)
169
170 for (const url of [ webTorrentFile, hlsFile ]) {
171 await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
172 await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
173 await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
174
175 await makeRawRequest({ url, query: { videoFileToken: badVideoFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
176 await makeRawRequest({ url, query: { videoFileToken: goodVideoFileToken }, expectedStatus: HttpStatusCode.OK_200 })
177 }
178 })
179
180 it('Should update public video to private', async function () {
181 this.timeout(60000)
182
183 await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.INTERNAL } })
184
185 await checkPrivateFiles(publicVideoUUID)
186 })
187
188 it('Should update private video to public', async function () {
189 this.timeout(60000)
190
191 await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } })
192
193 await checkPublicFiles(publicVideoUUID)
194 })
195
196 after(async function () {
197 this.timeout(30000)
198
199 if (privateVideoUUID) await server.videos.remove({ id: privateVideoUUID })
200 if (publicVideoUUID) await server.videos.remove({ id: publicVideoUUID })
201 if (userPrivateVideoUUID) await server.videos.remove({ id: userPrivateVideoUUID })
202
203 await waitJobs([ server ])
204 })
205 })
206
207 describe('Live', function () {
208 let normalLiveId: string
209 let normalLive: LiveVideo
210
211 let permanentLiveId: string
212 let permanentLive: LiveVideo
213
214 let unrelatedFileToken: string
215
216 async function checkLiveFiles (live: LiveVideo, liveId: string) {
217 const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
218 await server.live.waitUntilPublished({ videoId: liveId })
219
220 const video = await server.videos.getWithToken({ id: liveId })
221 const fileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid })
222
223 const hls = video.streamingPlaylists[0]
224
225 for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) {
226 expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
227
228 await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
229 await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
230
231 await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
232 await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 })
233
234 await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
235 await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
236 await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
237 }
238
239 await stopFfmpeg(ffmpegCommand)
240 }
241
242 async function checkReplay (replay: VideoDetails) {
243 const fileToken = await server.videoToken.getVideoFileToken({ videoId: replay.uuid })
244
245 const hls = replay.streamingPlaylists[0]
246 expect(hls.files).to.not.have.lengthOf(0)
247
248 for (const file of hls.files) {
249 await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
250 await makeRawRequest({ url: file.fileUrl, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 })
251
252 await makeRawRequest({ url: file.fileUrl, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
253 await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
254 await makeRawRequest({
255 url: file.fileUrl,
256 query: { videoFileToken: unrelatedFileToken },
257 expectedStatus: HttpStatusCode.FORBIDDEN_403
258 })
259 }
260
261 for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) {
262 expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
263
264 await makeRawRequest({ url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
265 await makeRawRequest({ url, query: { videoFileToken: fileToken }, expectedStatus: HttpStatusCode.OK_200 })
266
267 await makeRawRequest({ url, token: userToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
268 await makeRawRequest({ url, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
269 await makeRawRequest({ url, query: { videoFileToken: unrelatedFileToken }, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
270 }
271 }
272
273 before(async function () {
274 await server.config.enableMinimumTranscoding()
275
276 const { uuid } = await server.videos.quickUpload({ name: 'another video' })
277 unrelatedFileToken = await server.videoToken.getVideoFileToken({ videoId: uuid })
278
279 await server.config.enableLive({
280 allowReplay: true,
281 transcoding: true,
282 resolutions: 'min'
283 })
284
285 {
286 const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: false, privacy: VideoPrivacy.PRIVATE })
287 normalLiveId = video.uuid
288 normalLive = live
289 }
290
291 {
292 const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: true, privacy: VideoPrivacy.PRIVATE })
293 permanentLiveId = video.uuid
294 permanentLive = live
295 }
296 })
297
298 it('Should create a private normal live and have a private static path', async function () {
299 this.timeout(240000)
300
301 await checkLiveFiles(normalLive, normalLiveId)
302 })
303
304 it('Should create a private permanent live and have a private static path', async function () {
305 this.timeout(240000)
306
307 await checkLiveFiles(permanentLive, permanentLiveId)
308 })
309
310 it('Should have created a replay of the normal live with a private static path', async function () {
311 this.timeout(240000)
312
313 await server.live.waitUntilReplacedByReplay({ videoId: normalLiveId })
314
315 const replay = await server.videos.getWithToken({ id: normalLiveId })
316 await checkReplay(replay)
317 })
318
319 it('Should have created a replay of the permanent live with a private static path', async function () {
320 this.timeout(240000)
321
322 await server.live.waitUntilWaiting({ videoId: permanentLiveId })
323 await waitJobs([ server ])
324
325 const live = await server.videos.getWithToken({ id: permanentLiveId })
326 const replayFromList = await findExternalSavedVideo(server, live)
327 const replay = await server.videos.getWithToken({ id: replayFromList.id })
328
329 await checkReplay(replay)
330 })
331 })
332
333 after(async function () {
334 await cleanupTests([ server ])
335 })
336})