diff options
author | Chocobozzz <me@florianbigard.com> | 2022-04-22 09:50:20 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-04-22 09:50:20 +0200 |
commit | 961cbe4269e5f34639e29310fb3d90a6cb1bd6bc (patch) | |
tree | 06404c72c25a95238e7ef8a6bdfcb90d40c8649c /server | |
parent | 4ec52d04dcc5d664612331f8e08d7d90da990415 (diff) | |
download | PeerTube-961cbe4269e5f34639e29310fb3d90a6cb1bd6bc.tar.gz PeerTube-961cbe4269e5f34639e29310fb3d90a6cb1bd6bc.tar.zst PeerTube-961cbe4269e5f34639e29310fb3d90a6cb1bd6bc.zip |
Fix getting live by anonymous user
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/videos/live.ts | 18 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-live.ts | 6 | ||||
-rw-r--r-- | server/models/video/video-live.ts | 25 | ||||
-rw-r--r-- | server/tests/api/check-params/live.ts | 28 |
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 | |||
10 | import { VideoLiveModel } from '@server/models/video/video-live' | 10 | import { VideoLiveModel } from '@server/models/video/video-live' |
11 | import { MVideoDetails, MVideoFullLight } from '@server/types/models' | 11 | import { MVideoDetails, MVideoFullLight } from '@server/types/models' |
12 | import { buildUUID, uuidToShort } from '@shared/extra-utils' | 12 | import { buildUUID, uuidToShort } from '@shared/extra-utils' |
13 | import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, VideoState } from '@shared/models' | 13 | import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, UserRight, VideoState } from '@shared/models' |
14 | import { logger } from '../../../helpers/logger' | 14 | import { logger } from '../../../helpers/logger' |
15 | import { sequelizeTypescript } from '../../../initializers/database' | 15 | import { sequelizeTypescript } from '../../../initializers/database' |
16 | import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' | 16 | import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' |
17 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' | 17 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, optionalAuthenticate } from '../../../middlewares' |
18 | import { VideoModel } from '../../../models/video/video' | 18 | import { VideoModel } from '../../../models/video/video' |
19 | 19 | ||
20 | const liveRouter = express.Router() | 20 | const liveRouter = express.Router() |
@@ -29,7 +29,7 @@ liveRouter.post('/live', | |||
29 | ) | 29 | ) |
30 | 30 | ||
31 | liveRouter.get('/live/:videoId', | 31 | liveRouter.get('/live/:videoId', |
32 | authenticate, | 32 | optionalAuthenticate, |
33 | asyncMiddleware(videoLiveGetValidator), | 33 | asyncMiddleware(videoLiveGetValidator), |
34 | getLiveVideo | 34 | getLiveVideo |
35 | ) | 35 | ) |
@@ -52,7 +52,17 @@ export { | |||
52 | function getLiveVideo (req: express.Request, res: express.Response) { | 52 | function 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 | |||
58 | function 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 | ||
58 | async function updateLiveVideo (req: express.Request, res: express.Response) { | 68 | async 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 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | ||
4 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
5 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | 6 | import { buildAbsoluteFixturePath } from '@shared/core-utils' |
6 | import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models' | 7 | import { 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 () { |