From 3cabf3532b9118a19311f14ca3e171d12d554a2f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 6 Nov 2020 13:59:50 +0100 Subject: Add live server hooks --- server/controllers/api/videos/live.ts | 3 ++ server/lib/live-manager.ts | 2 +- server/lib/moderation.ts | 11 +++++- server/middlewares/validators/videos/video-live.ts | 30 +++++++++++++++ server/tests/fixtures/peertube-plugin-test/main.js | 25 +++++++++---- server/tests/plugins/action-hooks.ts | 43 +++++++++++++++++----- server/tests/plugins/filter-hooks.ts | 23 ++++++++++++ 7 files changed, 117 insertions(+), 20 deletions(-) (limited to 'server') diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts index f980c7730..d438b6f3a 100644 --- a/server/controllers/api/videos/live.ts +++ b/server/controllers/api/videos/live.ts @@ -5,6 +5,7 @@ import { CONFIG } from '@server/initializers/config' import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants' import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' import { federateVideoIfNeeded } from '@server/lib/activitypub/videos' +import { Hooks } from '@server/lib/plugins/hooks' import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator } from '@server/middlewares/validators/videos/video-live' import { VideoLiveModel } from '@server/models/video/video-live' @@ -128,6 +129,8 @@ async function addLiveVideo (req: express.Request, res: express.Response) { return { videoCreated } }) + Hooks.runAction('action:api.live-video.created', { video: videoCreated }) + return res.json({ video: { id: videoCreated.id, diff --git a/server/lib/live-manager.ts b/server/lib/live-manager.ts index 9a2914cc5..ef9377e43 100644 --- a/server/lib/live-manager.ts +++ b/server/lib/live-manager.ts @@ -118,7 +118,7 @@ class LiveManager { } run () { - logger.info('Running RTMP server.') + logger.info('Running RTMP server on port %d', config.rtmp.port) this.rtmpServer = new NodeRtmpServer(config) this.rtmpServer.run() diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index 0ef26d53d..0ace2d021 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts @@ -20,7 +20,7 @@ import { import { ActivityCreate } from '../../shared/models/activitypub' import { VideoObject } from '../../shared/models/activitypub/objects' import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object' -import { VideoCreate, VideoImportCreate } from '../../shared/models/videos' +import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos' import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model' import { UserModel } from '../models/account/user' import { ActorModel } from '../models/activitypub/actor' @@ -43,6 +43,13 @@ function isLocalVideoAccepted (object: { return { accepted: true } } +function isLocalLiveVideoAccepted (object: { + liveVideoBody: LiveVideoCreate + user: UserModel +}): AcceptResult { + return { accepted: true } +} + function isLocalVideoThreadAccepted (_object: { commentBody: VideoCommentCreate video: VideoModel @@ -175,6 +182,8 @@ function createAccountAbuse (options: { } export { + isLocalLiveVideoAccepted, + isLocalVideoAccepted, isLocalVideoThreadAccepted, isRemoteVideoAccepted, diff --git a/server/middlewares/validators/videos/video-live.ts b/server/middlewares/validators/videos/video-live.ts index cbc48fe93..ff92db910 100644 --- a/server/middlewares/validators/videos/video-live.ts +++ b/server/middlewares/validators/videos/video-live.ts @@ -11,6 +11,8 @@ import { CONFIG } from '../../../initializers/config' import { areValidationErrors } from '../utils' import { getCommonVideoEditAttributes } from './videos' import { VideoModel } from '@server/models/video/video' +import { Hooks } from '@server/lib/plugins/hooks' +import { isLocalLiveVideoAccepted } from '@server/lib/moderation' const videoLiveGetValidator = [ param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), @@ -97,6 +99,8 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([ } } + if (!await isLiveVideoAccepted(req, res)) return cleanUpReqFiles(req) + return next() } ]) @@ -137,3 +141,29 @@ export { videoLiveUpdateValidator, videoLiveGetValidator } + +// --------------------------------------------------------------------------- + +async function isLiveVideoAccepted (req: express.Request, res: express.Response) { + // Check we accept this video + const acceptParameters = { + liveVideoBody: req.body, + user: res.locals.oauth.token.User + } + const acceptedResult = await Hooks.wrapFun( + isLocalLiveVideoAccepted, + acceptParameters, + 'filter:api.live-video.create.accept.result' + ) + + if (!acceptedResult || acceptedResult.accepted !== true) { + logger.info('Refused local live video.', { acceptedResult, acceptParameters }) + + res.status(403) + .json({ error: acceptedResult.errorMessage || 'Refused local live video' }) + + return false + } + + return true +} diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index a45e98fb5..322c0610c 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js @@ -7,6 +7,8 @@ async function register ({ registerHook, registerSetting, settingsManager, stora 'action:api.video.uploaded', 'action:api.video.viewed', + 'action:api.live-video.created', + 'action:api.video-thread.created', 'action:api.video-comment-reply.created', 'action:api.video-comment.deleted', @@ -46,15 +48,22 @@ async function register ({ registerHook, registerSetting, settingsManager, stora } }) - registerHook({ - target: 'filter:api.video.upload.accept.result', - handler: ({ accepted }, { videoBody }) => { - if (!accepted) return { accepted: false } - if (videoBody.name.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word' } + for (const hook of [ 'filter:api.video.upload.accept.result', 'filter:api.live-video.create.accept.result' ]) { + registerHook({ + target: hook, + handler: ({ accepted }, { videoBody, liveVideoBody }) => { + if (!accepted) return { accepted: false } - return { accepted: true } - } - }) + const name = videoBody + ? videoBody.name + : liveVideoBody.name + + if (name.indexOf('bad word') !== -1) return { accepted: false, errorMessage: 'bad word' } + + return { accepted: true } + } + }) + } registerHook({ target: 'filter:api.video.pre-import-url.accept.result', diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index ca57a4b51..ac9f2cea5 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts @@ -1,18 +1,12 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ import 'mocha' -import { - cleanupTests, - flushAndRunMultipleServers, - killallServers, - reRunServer, - ServerInfo, - waitUntilLog -} from '../../../shared/extra-utils/server/servers' +import { ServerHookName, VideoPrivacy } from '@shared/models' import { addVideoCommentReply, addVideoCommentThread, blockUser, + createLive, createUser, deleteVideoComment, getPluginTestPath, @@ -20,6 +14,7 @@ import { registerUser, removeUser, setAccessTokensToServers, + setDefaultVideoChannel, unblockUser, updateUser, updateVideo, @@ -27,13 +22,21 @@ import { userLogin, viewVideo } from '../../../shared/extra-utils' +import { + cleanupTests, + flushAndRunMultipleServers, + killallServers, + reRunServer, + ServerInfo, + waitUntilLog +} from '../../../shared/extra-utils/server/servers' describe('Test plugin action hooks', function () { let servers: ServerInfo[] let videoUUID: string let threadId: number - function checkHook (hook: string) { + function checkHook (hook: ServerHookName) { return waitUntilLog(servers[0], 'Run hook ' + hook) } @@ -42,6 +45,7 @@ describe('Test plugin action hooks', function () { servers = await flushAndRunMultipleServers(2) await setAccessTokensToServers(servers) + await setDefaultVideoChannel(servers) await installPlugin({ url: servers[0].url, @@ -51,7 +55,11 @@ describe('Test plugin action hooks', function () { killallServers([ servers[0] ]) - await reRunServer(servers[0]) + await reRunServer(servers[0], { + live: { + enabled: true + } + }) }) describe('Application hooks', function () { @@ -81,6 +89,21 @@ describe('Test plugin action hooks', function () { }) }) + describe('Live hooks', function () { + + it('Should run action:api.live-video.created', async function () { + const attributes = { + name: 'live', + privacy: VideoPrivacy.PUBLIC, + channelId: servers[0].videoChannel.id + } + + await createLive(servers[0].url, servers[0].accessToken, attributes) + + await checkHook('action:api.live-video.created') + }) + }) + describe('Comments hooks', function () { it('Should run action:api.video-thread.created', async function () { const res = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'thread') diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 4d354b68e..9939b8e6e 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts @@ -6,6 +6,7 @@ import { ServerConfig } from '@shared/models' import { addVideoCommentReply, addVideoCommentThread, + createLive, doubleFollow, getConfig, getPluginTestPath, @@ -19,6 +20,7 @@ import { registerUser, setAccessTokensToServers, setDefaultVideoChannel, + updateCustomSubConfig, updateVideo, uploadVideo, waitJobs @@ -61,6 +63,17 @@ describe('Test plugin filter hooks', function () { const res = await getVideosList(servers[0].url) videoUUID = res.body.data[0].uuid + + await updateCustomSubConfig(servers[0].url, servers[0].accessToken, { + live: { enabled: true }, + signup: { enabled: true }, + import: { + videos: { + http: { enabled: true }, + torrent: { enabled: true } + } + } + }) }) it('Should run filter:api.videos.list.params', async function () { @@ -87,6 +100,16 @@ describe('Test plugin filter hooks', function () { await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video with bad word' }, 403) }) + it('Should run filter:api.live-video.create.accept.result', async function () { + const attributes = { + name: 'video with bad word', + privacy: VideoPrivacy.PUBLIC, + channelId: servers[0].videoChannel.id + } + + await createLive(servers[0].url, servers[0].accessToken, attributes, 403) + }) + it('Should run filter:api.video.pre-import-url.accept.result', async function () { const baseAttributes = { name: 'normal title', -- cgit v1.2.3