]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/tests/api/object-storage/video-static-file-privacy.ts
Feature/Add replay privacy (#5692)
[github/Chocobozzz/PeerTube.git] / server / tests / api / object-storage / video-static-file-privacy.ts
index c6d7a1a2cc8847a5d1004fc208e59c9d0c1c6f94..930c88543ba680a1e26273be084d226732e16103 100644 (file)
@@ -2,7 +2,7 @@
 
 import { expect } from 'chai'
 import { basename } from 'path'
-import { expectStartWith } from '@server/tests/shared'
+import { checkVideoFileTokenReinjection, expectStartWith } from '@server/tests/shared'
 import { areScalewayObjectStorageTestsDisabled, getAllFiles, getHLS } from '@shared/core-utils'
 import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@shared/models'
 import {
@@ -19,6 +19,12 @@ import {
   waitJobs
 } from '@shared/server-commands'
 
+function extractFilenameFromUrl (url: string) {
+  const parts = basename(url).split(':')
+
+  return parts[parts.length - 1]
+}
+
 describe('Object storage for video static file privacy', function () {
   // We need real world object storage to check ACL
   if (areScalewayObjectStorageTestsDisabled()) return
@@ -26,75 +32,81 @@ describe('Object storage for video static file privacy', function () {
   let server: PeerTubeServer
   let userToken: string
 
-  before(async function () {
-    this.timeout(120000)
+  // ---------------------------------------------------------------------------
 
-    server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig(1))
-    await setAccessTokensToServers([ server ])
-    await setDefaultVideoChannel([ server ])
+  async function checkPrivateVODFiles (uuid: string) {
+    const video = await server.videos.getWithToken({ id: uuid })
 
-    await server.config.enableMinimumTranscoding()
+    for (const file of video.files) {
+      expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/webseed/private/')
 
-    userToken = await server.users.generateUserAndToken('user1')
-  })
+      await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
+    }
 
-  describe('VOD', function () {
-    let privateVideoUUID: string
-    let publicVideoUUID: string
-    let userPrivateVideoUUID: string
+    for (const file of getAllFiles(video)) {
+      const internalFileUrl = await server.sql.getInternalFileUrl(file.id)
+      expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl())
+      await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
+    }
 
-    async function checkPrivateFiles (uuid: string) {
-      const video = await server.videos.getWithToken({ id: uuid })
+    const hls = getHLS(video)
 
-      for (const file of video.files) {
-        expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/webseed/private/')
+    if (hls) {
+      for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) {
+        expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
+      }
+
+      await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
+      await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
+
+      for (const file of hls.files) {
+        expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
 
         await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
       }
+    }
+  }
 
-      for (const file of getAllFiles(video)) {
-        const internalFileUrl = await server.sql.getInternalFileUrl(file.id)
-        expectStartWith(internalFileUrl, ObjectStorageCommand.getScalewayBaseUrl())
-        await makeRawRequest({ url: internalFileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.FORBIDDEN_403 })
-      }
+  async function checkPublicVODFiles (uuid: string) {
+    const video = await server.videos.getWithToken({ id: uuid })
 
-      const hls = getHLS(video)
+    for (const file of getAllFiles(video)) {
+      expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl())
 
-      if (hls) {
-        for (const url of [ hls.playlistUrl, hls.segmentsSha256Url ]) {
-          expectStartWith(url, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
-        }
+      await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
+    }
 
-        await makeRawRequest({ url: hls.playlistUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
-        await makeRawRequest({ url: hls.segmentsSha256Url, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
+    const hls = getHLS(video)
 
-        for (const file of hls.files) {
-          expectStartWith(file.fileUrl, server.url + '/object-storage-proxy/streaming-playlists/hls/private/')
+    if (hls) {
+      expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl())
+      expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl())
 
-          await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
-        }
-      }
+      await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
+      await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
     }
+  }
 
-    async function checkPublicFiles (uuid: string) {
-      const video = await server.videos.getWithToken({ id: uuid })
+  // ---------------------------------------------------------------------------
 
-      for (const file of getAllFiles(video)) {
-        expectStartWith(file.fileUrl, ObjectStorageCommand.getScalewayBaseUrl())
+  before(async function () {
+    this.timeout(120000)
 
-        await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
-      }
+    server = await createSingleServer(1, ObjectStorageCommand.getDefaultScalewayConfig({ serverNumber: 1 }))
+    await setAccessTokensToServers([ server ])
+    await setDefaultVideoChannel([ server ])
 
-      const hls = getHLS(video)
+    await server.config.enableMinimumTranscoding()
 
-      if (hls) {
-        expectStartWith(hls.playlistUrl, ObjectStorageCommand.getScalewayBaseUrl())
-        expectStartWith(hls.segmentsSha256Url, ObjectStorageCommand.getScalewayBaseUrl())
+    userToken = await server.users.generateUserAndToken('user1')
+  })
 
-        await makeRawRequest({ url: hls.playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
-        await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
-      }
-    }
+  describe('VOD', function () {
+    let privateVideoUUID: string
+    let publicVideoUUID: string
+    let userPrivateVideoUUID: string
+
+    // ---------------------------------------------------------------------------
 
     async function getSampleFileUrls (videoId: string) {
       const video = await server.videos.getWithToken({ id: videoId })
@@ -105,8 +117,10 @@ describe('Object storage for video static file privacy', function () {
       }
     }
 
+    // ---------------------------------------------------------------------------
+
     it('Should upload a private video and have appropriate object storage ACL', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       {
         const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE })
@@ -120,18 +134,18 @@ describe('Object storage for video static file privacy', function () {
 
       await waitJobs([ server ])
 
-      await checkPrivateFiles(privateVideoUUID)
+      await checkPrivateVODFiles(privateVideoUUID)
     })
 
     it('Should upload a public video and have appropriate object storage ACL', async function () {
-      this.timeout(60000)
+      this.timeout(120000)
 
       const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED })
       await waitJobs([ server ])
 
       publicVideoUUID = uuid
 
-      await checkPublicFiles(publicVideoUUID)
+      await checkPublicVODFiles(publicVideoUUID)
     })
 
     it('Should not get files without appropriate OAuth token', async function () {
@@ -177,12 +191,26 @@ describe('Object storage for video static file privacy', function () {
       }
     })
 
+    it('Should reinject video file token', async function () {
+      this.timeout(120000)
+
+      const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: privateVideoUUID })
+
+      await checkVideoFileTokenReinjection({
+        server,
+        videoUUID: privateVideoUUID,
+        videoFileToken,
+        resolutions: [ 240, 720 ],
+        isLive: false
+      })
+    })
+
     it('Should update public video to private', async function () {
       this.timeout(60000)
 
       await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.INTERNAL } })
 
-      await checkPrivateFiles(publicVideoUUID)
+      await checkPrivateVODFiles(publicVideoUUID)
     })
 
     it('Should update private video to public', async function () {
@@ -190,7 +218,7 @@ describe('Object storage for video static file privacy', function () {
 
       await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } })
 
-      await checkPublicFiles(publicVideoUUID)
+      await checkPublicVODFiles(publicVideoUUID)
     })
   })
 
@@ -203,6 +231,8 @@ describe('Object storage for video static file privacy', function () {
 
     let unrelatedFileToken: string
 
+    // ---------------------------------------------------------------------------
+
     async function checkLiveFiles (live: LiveVideo, liveId: string) {
       const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
       await server.live.waitUntilPublished({ videoId: liveId })
@@ -260,6 +290,8 @@ describe('Object storage for video static file privacy', function () {
       }
     }
 
+    // ---------------------------------------------------------------------------
+
     before(async function () {
       await server.config.enableMinimumTranscoding()
 
@@ -273,13 +305,21 @@ describe('Object storage for video static file privacy', function () {
       })
 
       {
-        const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: false, privacy: VideoPrivacy.PRIVATE })
+        const { video, live } = await server.live.quickCreate({
+          saveReplay: true,
+          permanentLive: false,
+          privacy: VideoPrivacy.PRIVATE
+        })
         normalLiveId = video.uuid
         normalLive = live
       }
 
       {
-        const { video, live } = await server.live.quickCreate({ saveReplay: true, permanentLive: true, privacy: VideoPrivacy.PRIVATE })
+        const { video, live } = await server.live.quickCreate({
+          saveReplay: true,
+          permanentLive: true,
+          privacy: VideoPrivacy.PRIVATE
+        })
         permanentLiveId = video.uuid
         permanentLive = live
       }
@@ -297,6 +337,26 @@ describe('Object storage for video static file privacy', function () {
       await checkLiveFiles(permanentLive, permanentLiveId)
     })
 
+    it('Should reinject video file token in permanent live', async function () {
+      this.timeout(240000)
+
+      const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: permanentLive.rtmpUrl, streamKey: permanentLive.streamKey })
+      await server.live.waitUntilPublished({ videoId: permanentLiveId })
+
+      const video = await server.videos.getWithToken({ id: permanentLiveId })
+      const videoFileToken = await server.videoToken.getVideoFileToken({ videoId: video.uuid })
+
+      await checkVideoFileTokenReinjection({
+        server,
+        videoUUID: permanentLiveId,
+        videoFileToken,
+        resolutions: [ 720 ],
+        isLive: true
+      })
+
+      await stopFfmpeg(ffmpegCommand)
+    })
+
     it('Should have created a replay of the normal live with a private static path', async function () {
       this.timeout(240000)
 
@@ -320,8 +380,54 @@ describe('Object storage for video static file privacy', function () {
     })
   })
 
+  describe('With private files proxy disabled and public ACL for private files', function () {
+    let videoUUID: string
+
+    before(async function () {
+      this.timeout(240000)
+
+      await server.kill()
+
+      const config = ObjectStorageCommand.getDefaultScalewayConfig({
+        serverNumber: 1,
+        enablePrivateProxy: false,
+        privateACL: 'public-read'
+      })
+      await server.run(config)
+
+      const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE })
+      videoUUID = uuid
+
+      await waitJobs([ server ])
+    })
+
+    it('Should display object storage path for a private video and be able to access them', async function () {
+      this.timeout(60000)
+
+      await checkPublicVODFiles(videoUUID)
+    })
+
+    it('Should not be able to access object storage proxy', async function () {
+      const privateVideo = await server.videos.getWithToken({ id: videoUUID })
+      const webtorrentFilename = extractFilenameFromUrl(privateVideo.files[0].fileUrl)
+      const hlsFilename = extractFilenameFromUrl(getHLS(privateVideo).files[0].fileUrl)
+
+      await makeRawRequest({
+        url: server.url + '/object-storage-proxy/webseed/private/' + webtorrentFilename,
+        token: server.accessToken,
+        expectedStatus: HttpStatusCode.BAD_REQUEST_400
+      })
+
+      await makeRawRequest({
+        url: server.url + '/object-storage-proxy/streaming-playlists/hls/private/' + videoUUID + '/' + hlsFilename,
+        token: server.accessToken,
+        expectedStatus: HttpStatusCode.BAD_REQUEST_400
+      })
+    })
+  })
+
   after(async function () {
-    this.timeout(60000)
+    this.timeout(240000)
 
     const { data } = await server.videos.listAllForAdmin()
 
@@ -330,7 +436,7 @@ describe('Object storage for video static file privacy', function () {
     }
 
     for (const v of data) {
-      await server.servers.waitUntilLog('Removed files of video ' + v.url, 1, true)
+      await server.servers.waitUntilLog('Removed files of video ' + v.url)
     }
 
     await cleanupTests([ server ])