From 961cbe4269e5f34639e29310fb3d90a6cb1bd6bc Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 22 Apr 2022 09:50:20 +0200 Subject: [PATCH] Fix getting live by anonymous user --- server/controllers/api/videos/live.ts | 18 ++++-- .../validators/videos/video-live.ts | 6 +- server/models/video/video-live.ts | 25 ++++++--- server/tests/api/check-params/live.ts | 28 ++++++++-- shared/models/users/user-right.enum.ts | 56 +++++++++---------- shared/models/videos/live/live-video.model.ts | 8 +-- support/doc/api/openapi.yaml | 4 +- 7 files changed, 89 insertions(+), 56 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 import { VideoLiveModel } from '@server/models/video/video-live' import { MVideoDetails, MVideoFullLight } from '@server/types/models' import { buildUUID, uuidToShort } from '@shared/extra-utils' -import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, VideoState } from '@shared/models' +import { HttpStatusCode, LiveVideoCreate, LiveVideoLatencyMode, LiveVideoUpdate, UserRight, VideoState } from '@shared/models' import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers/database' import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' -import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' +import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, optionalAuthenticate } from '../../../middlewares' import { VideoModel } from '../../../models/video/video' const liveRouter = express.Router() @@ -29,7 +29,7 @@ liveRouter.post('/live', ) liveRouter.get('/live/:videoId', - authenticate, + optionalAuthenticate, asyncMiddleware(videoLiveGetValidator), getLiveVideo ) @@ -52,7 +52,17 @@ export { function getLiveVideo (req: express.Request, res: express.Response) { const videoLive = res.locals.videoLive - return res.json(videoLive.toFormattedJSON()) + return res.json(videoLive.toFormattedJSON(canSeePrivateLiveInformation(res))) +} + +function canSeePrivateLiveInformation (res: express.Response) { + const user = res.locals.oauth?.token.User + if (!user) return false + + if (user.hasRight(UserRight.GET_ANY_LIVE)) return true + + const video = res.locals.videoAll + return video.VideoChannel.Account.userId === user.id } 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 = [ isValidVideoIdParam('videoId'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params, user: res.locals.oauth.token.User.username }) + logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params }) if (areValidationErrors(req, res)) return if (!await doesVideoExist(req.params.videoId, res, 'all')) return - // Check if the user who did the request is able to get the live info - const user = res.locals.oauth.token.User - if (!checkUserCanManageVideo(user, res.locals.videoAll, UserRight.GET_ANY_LIVE, res, false)) return - const videoLive = await VideoLiveModel.loadByVideoId(res.locals.videoAll.id) if (!videoLive) { 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 return VideoLiveModel.findOne(query) } - toFormattedJSON (): LiveVideo { - let rtmpUrl: string = null - let rtmpsUrl: string = null + toFormattedJSON (canSeePrivateInformation: boolean): LiveVideo { + let privateInformation: Pick | {} = {} // If we don't have a stream key, it means this is a remote live so we don't specify the rtmp URL - if (this.streamKey) { - if (CONFIG.LIVE.RTMP.ENABLED) rtmpUrl = WEBSERVER.RTMP_URL - if (CONFIG.LIVE.RTMPS.ENABLED) rtmpsUrl = WEBSERVER.RTMPS_URL + // We also display these private information only to the live owne/moderators + if (this.streamKey && canSeePrivateInformation === true) { + privateInformation = { + streamKey: this.streamKey, + + rtmpUrl: CONFIG.LIVE.RTMP.ENABLED + ? WEBSERVER.RTMP_URL + : null, + + rtmpsUrl: CONFIG.LIVE.RTMPS.ENABLED + ? WEBSERVER.RTMPS_URL + : null + } } return { - rtmpUrl, - rtmpsUrl, + ...privateInformation, - streamKey: this.streamKey, permanentLive: this.permanentLive, saveReplay: this.saveReplay, 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 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ import 'mocha' +import { expect } from 'chai' import { omit } from 'lodash' import { buildAbsoluteFixturePath } from '@shared/core-utils' import { HttpStatusCode, LiveVideoLatencyMode, VideoCreateResult, VideoPrivacy } from '@shared/models' @@ -340,16 +341,33 @@ describe('Test video lives API validator', function () { describe('When getting live information', function () { - it('Should fail without access token', async function () { - await command.get({ token: '', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) - }) it('Should fail with a bad access token', async function () { await command.get({ token: 'toto', videoId: video.id, expectedStatus: HttpStatusCode.UNAUTHORIZED_401 }) }) - it('Should fail with access token of another user', async function () { - await command.get({ token: userAccessToken, videoId: video.id, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) + it('Should not display private information without access token', async function () { + const live = await command.get({ token: '', videoId: video.id }) + + expect(live.rtmpUrl).to.not.exist + expect(live.streamKey).to.not.exist + expect(live.latencyMode).to.exist + }) + + it('Should not display private information with token of another user', async function () { + const live = await command.get({ token: userAccessToken, videoId: video.id }) + + expect(live.rtmpUrl).to.not.exist + expect(live.streamKey).to.not.exist + expect(live.latencyMode).to.exist + }) + + it('Should display private information with appropriate token', async function () { + const live = await command.get({ videoId: video.id }) + + expect(live.rtmpUrl).to.exist + expect(live.streamKey).to.exist + expect(live.latencyMode).to.exist }) it('Should fail with a bad video id', async function () { diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts index d3f793d8b..9c6828aa5 100644 --- a/shared/models/users/user-right.enum.ts +++ b/shared/models/users/user-right.enum.ts @@ -1,47 +1,47 @@ export const enum UserRight { - ALL, + ALL = 0, - MANAGE_USERS, + MANAGE_USERS = 1, - MANAGE_SERVER_FOLLOW, + MANAGE_SERVER_FOLLOW = 2, - MANAGE_LOGS, + MANAGE_LOGS = 3, - MANAGE_DEBUG, + MANAGE_DEBUG = 4, - MANAGE_SERVER_REDUNDANCY, + MANAGE_SERVER_REDUNDANCY = 5, - MANAGE_ABUSES, + MANAGE_ABUSES = 6, - MANAGE_JOBS, + MANAGE_JOBS = 7, - MANAGE_CONFIGURATION, - MANAGE_INSTANCE_CUSTOM_PAGE, + MANAGE_CONFIGURATION = 8, + MANAGE_INSTANCE_CUSTOM_PAGE = 9, - MANAGE_ACCOUNTS_BLOCKLIST, - MANAGE_SERVERS_BLOCKLIST, + MANAGE_ACCOUNTS_BLOCKLIST = 10, + MANAGE_SERVERS_BLOCKLIST = 11, - MANAGE_VIDEO_BLACKLIST, - MANAGE_ANY_VIDEO_CHANNEL, + MANAGE_VIDEO_BLACKLIST = 12, + MANAGE_ANY_VIDEO_CHANNEL = 13, - REMOVE_ANY_VIDEO, - REMOVE_ANY_VIDEO_PLAYLIST, - REMOVE_ANY_VIDEO_COMMENT, + REMOVE_ANY_VIDEO = 14, + REMOVE_ANY_VIDEO_PLAYLIST = 15, + REMOVE_ANY_VIDEO_COMMENT = 16, - UPDATE_ANY_VIDEO, - UPDATE_ANY_VIDEO_PLAYLIST, + UPDATE_ANY_VIDEO = 17, + UPDATE_ANY_VIDEO_PLAYLIST = 18, - GET_ANY_LIVE, - SEE_ALL_VIDEOS, - SEE_ALL_COMMENTS, - CHANGE_VIDEO_OWNERSHIP, + GET_ANY_LIVE = 19, + SEE_ALL_VIDEOS = 20, + SEE_ALL_COMMENTS = 21, + CHANGE_VIDEO_OWNERSHIP = 22, - MANAGE_PLUGINS, + MANAGE_PLUGINS = 23, - MANAGE_VIDEOS_REDUNDANCIES, + MANAGE_VIDEOS_REDUNDANCIES = 24, - MANAGE_VIDEO_FILES, - RUN_VIDEO_TRANSCODING, + MANAGE_VIDEO_FILES = 25, + RUN_VIDEO_TRANSCODING = 26, - MANAGE_VIDEO_IMPORTS + MANAGE_VIDEO_IMPORTS = 27 } diff --git a/shared/models/videos/live/live-video.model.ts b/shared/models/videos/live/live-video.model.ts index 2d3169941..d0f57f883 100644 --- a/shared/models/videos/live/live-video.model.ts +++ b/shared/models/videos/live/live-video.model.ts @@ -1,10 +1,10 @@ import { LiveVideoLatencyMode } from './live-video-latency-mode.enum' export interface LiveVideo { - rtmpUrl: string - rtmpsUrl: string - - streamKey: string + // If owner + rtmpUrl?: string + rtmpsUrl?: string + streamKey?: string saveReplay: boolean permanentLive: boolean diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 012f6d135..123e54f47 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml @@ -7657,11 +7657,13 @@ components: properties: rtmpUrl: type: string + description: Included in the response if an appropriate token is provided rtmpsUrl: type: string + description: Included in the response if an appropriate token is provided streamKey: type: string - description: RTMP stream key to use to stream into this live video + description: RTMP stream key to use to stream into this live video. Included in the response if an appropriate token is provided saveReplay: type: boolean permanentLive: -- 2.41.0