aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/videos/live.ts18
-rw-r--r--server/middlewares/validators/videos/video-live.ts6
-rw-r--r--server/models/video/video-live.ts25
-rw-r--r--server/tests/api/check-params/live.ts28
4 files changed, 54 insertions, 23 deletions
diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts
index c6f038079..e51658927 100644
--- a/server/controllers/api/videos/live.ts
+++ b/server/controllers/api/videos/live.ts
@@ -10,11 +10,11 @@ import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator
10import { VideoLiveModel } from '@server/models/video/video-live' 10import { VideoLiveModel } from '@server/models/video/video-live'
11import { MVideoDetails, MVideoFullLight } from '@server/types/models' 11import { MVideoDetails, MVideoFullLight } from '@server/types/models'
12import { buildUUID, uuidToShort } from '@shared/extra-utils' 12import { buildUUID, uuidToShort } from '@shared/extra-utils'
13import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, VideoState } from '@shared/models' 13import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, UserRight, VideoState } from '@shared/models'
14import { logger } from '../../../helpers/logger' 14import { logger } from '../../../helpers/logger'
15import { sequelizeTypescript } from '../../../initializers/database' 15import { sequelizeTypescript } from '../../../initializers/database'
16import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' 16import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail'
17import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' 17import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, optionalAuthenticate } from '../../../middlewares'
18import { VideoModel } from '../../../models/video/video' 18import { VideoModel } from '../../../models/video/video'
19 19
20const liveRouter = express.Router() 20const liveRouter = express.Router()
@@ -29,7 +29,7 @@ liveRouter.post('/live',
29) 29)
30 30
31liveRouter.get('/live/:videoId', 31liveRouter.get('/live/:videoId',
32 authenticate, 32 optionalAuthenticate,
33 asyncMiddleware(videoLiveGetValidator), 33 asyncMiddleware(videoLiveGetValidator),
34 getLiveVideo 34 getLiveVideo
35) 35)
@@ -52,7 +52,17 @@ export {
52function getLiveVideo (req: express.Request, res: express.Response) { 52function getLiveVideo (req: express.Request, res: express.Response) {
53 const videoLive = res.locals.videoLive 53 const videoLive = res.locals.videoLive
54 54
55 return res.json(videoLive.toFormattedJSON()) 55 return res.json(videoLive.toFormattedJSON(canSeePrivateLiveInformation(res)))
56}
57
58function canSeePrivateLiveInformation (res: express.Response) {
59 const user = res.locals.oauth?.token.User
60 if (!user) return false
61
62 if (user.hasRight(UserRight.GET_ANY_LIVE)) return true
63
64 const video = res.locals.videoAll
65 return video.VideoChannel.Account.userId === user.id
56} 66}
57 67
58async function updateLiveVideo (req: express.Request, res: express.Response) { 68async function updateLiveVideo (req: express.Request, res: express.Response) {
diff --git a/server/middlewares/validators/videos/video-live.ts b/server/middlewares/validators/videos/video-live.ts
index b756c0bf1..8f821c5f9 100644
--- a/server/middlewares/validators/videos/video-live.ts
+++ b/server/middlewares/validators/videos/video-live.ts
@@ -33,15 +33,11 @@ const videoLiveGetValidator = [
33 isValidVideoIdParam('videoId'), 33 isValidVideoIdParam('videoId'),
34 34
35 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 35 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
36 logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params, user: res.locals.oauth.token.User.username }) 36 logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params })
37 37
38 if (areValidationErrors(req, res)) return 38 if (areValidationErrors(req, res)) return
39 if (!await doesVideoExist(req.params.videoId, res, 'all')) return 39 if (!await doesVideoExist(req.params.videoId, res, 'all')) return
40 40
41 // Check if the user who did the request is able to get the live info
42 const user = res.locals.oauth.token.User
43 if (!checkUserCanManageVideo(user, res.locals.videoAll, UserRight.GET_ANY_LIVE, res, false)) return
44
45 const videoLive = await VideoLiveModel.loadByVideoId(res.locals.videoAll.id) 41 const videoLive = await VideoLiveModel.loadByVideoId(res.locals.videoAll.id)
46 if (!videoLive) { 42 if (!videoLive) {
47 return res.fail({ 43 return res.fail({
diff --git a/server/models/video/video-live.ts b/server/models/video/video-live.ts
index 96c0bf7f7..68e381105 100644
--- a/server/models/video/video-live.ts
+++ b/server/models/video/video-live.ts
@@ -101,21 +101,28 @@ export class VideoLiveModel extends Model<Partial<AttributesOnly<VideoLiveModel>
101 return VideoLiveModel.findOne<MVideoLive>(query) 101 return VideoLiveModel.findOne<MVideoLive>(query)
102 } 102 }
103 103
104 toFormattedJSON (): LiveVideo { 104 toFormattedJSON (canSeePrivateInformation: boolean): LiveVideo {
105 let rtmpUrl: string = null 105 let privateInformation: Pick<LiveVideo, 'rtmpUrl' | 'rtmpsUrl' | 'streamKey'> | {} = {}
106 let rtmpsUrl: string = null
107 106
108 // If we don't have a stream key, it means this is a remote live so we don't specify the rtmp URL 107 // If we don't have a stream key, it means this is a remote live so we don't specify the rtmp URL
109 if (this.streamKey) { 108 // We also display these private information only to the live owne/moderators
110 if (CONFIG.LIVE.RTMP.ENABLED) rtmpUrl = WEBSERVER.RTMP_URL 109 if (this.streamKey && canSeePrivateInformation === true) {
111 if (CONFIG.LIVE.RTMPS.ENABLED) rtmpsUrl = WEBSERVER.RTMPS_URL 110 privateInformation = {
111 streamKey: this.streamKey,
112
113 rtmpUrl: CONFIG.LIVE.RTMP.ENABLED
114 ? WEBSERVER.RTMP_URL
115 : null,
116
117 rtmpsUrl: CONFIG.LIVE.RTMPS.ENABLED
118 ? WEBSERVER.RTMPS_URL
119 : null
120 }
112 } 121 }
113 122
114 return { 123 return {
115 rtmpUrl, 124 ...privateInformation,
116 rtmpsUrl,
117 125
118 streamKey: this.streamKey,
119 permanentLive: this.permanentLive, 126 permanentLive: this.permanentLive,
120 saveReplay: this.saveReplay, 127 saveReplay: this.saveReplay,
121 latencyMode: this.latencyMode 128 latencyMode: this.latencyMode
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts
index 2f1c1257e..d4a81c4f6 100644
--- a/server/tests/api/check-params/live.ts
+++ b/server/tests/api/check-params/live.ts
@@ -1,6 +1,7 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import 'mocha' 3import 'mocha'
4import { expect } from 'chai'
4import { omit } from 'lodash' 5import { omit } from 'lodash'
5import { buildAbsoluteFixturePath } from '@shared/core-utils' 6import { buildAbsoluteFixturePath } from '@shared/core-utils'
6import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models' 7import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models'
@@ -340,16 +341,33 @@ describe('Test video lives API validator', function () {
340 341
341 describe('When getting live information', function () { 342 describe('When getting live information', function () {
342 343
343 it('Should fail without access token', async function () {
344 await command.get({ token: '', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
345 })
346 344
347 it('Should fail with a bad access token', async function () { 345 it('Should fail with a bad access token', async function () {
348 await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) 346 await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 })
349 }) 347 })
350 348
351 it('Should fail with access token of another user', async function () { 349 it('Should not display private information without access token', async function () {
352 await command.get({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) 350 const live = await command.get({ token: '', videoId: video.id })
351
352 expect(live.rtmpUrl).to.not.exist
353 expect(live.streamKey).to.not.exist
354 expect(live.latencyMode).to.exist
355 })
356
357 it('Should not display private information with token of another user', async function () {
358 const live = await command.get({ token: userAccessToken, videoId: video.id })
359
360 expect(live.rtmpUrl).to.not.exist
361 expect(live.streamKey).to.not.exist
362 expect(live.latencyMode).to.exist
363 })
364
365 it('Should display private information with appropriate token', async function () {
366 const live = await command.get({ videoId: video.id })
367
368 expect(live.rtmpUrl).to.exist
369 expect(live.streamKey).to.exist
370 expect(live.latencyMode).to.exist
353 }) 371 })
354 372
355 it('Should fail with a bad video id', async function () { 373 it('Should fail with a bad video id', async function () {