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 {
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
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 })
}
}
+ // ---------------------------------------------------------------------------
+
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 })
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 () {
}
})
+ 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 () {
await server.videos.update({ id: publicVideoUUID, attributes: { privacy: VideoPrivacy.PUBLIC } })
- await checkPublicFiles(publicVideoUUID)
+ await checkPublicVODFiles(publicVideoUUID)
})
})
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 })
}
}
+ // ---------------------------------------------------------------------------
+
before(async function () {
await server.config.enableMinimumTranscoding()
})
{
- 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
}
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)
})
})
+ 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()
}
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 ])