1 import express from 'express'
2 import { body } from 'express-validator'
3 import { isIntOrNull } from '@server/helpers/custom-validators/misc'
4 import { CONFIG, isEmailEnabled } from '@server/initializers/config'
5 import { CustomConfig } from '../../../shared/models/server/custom-config.model'
6 import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
7 import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users'
8 import { logger } from '../../helpers/logger'
9 import { isThemeRegistered } from '../../lib/plugins/theme-utils'
10 import { areValidationErrors } from './shared'
11 import { HttpStatusCode } from '@shared/models/http/http-error-codes'
13 const customConfigUpdateValidator = [
14 body('instance.name').exists(),
15 body('instance.shortDescription').exists(),
16 body('instance.description').exists(),
17 body('instance.terms').exists(),
18 body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid),
19 body('instance.defaultClientRoute').exists(),
20 body('instance.customizations.css').exists(),
21 body('instance.customizations.javascript').exists(),
23 body('services.twitter.username').exists(),
24 body('services.twitter.whitelisted').isBoolean(),
26 body('cache.previews.size').isInt(),
27 body('cache.captions.size').isInt(),
28 body('cache.torrents.size').isInt(),
30 body('signup.enabled').isBoolean(),
31 body('signup.limit').isInt(),
32 body('signup.requiresEmailVerification').isBoolean(),
33 body('signup.minimumAge').isInt(),
35 body('admin.email').isEmail(),
36 body('contactForm.enabled').isBoolean(),
38 body('user.videoQuota').custom(isUserVideoQuotaValid),
39 body('user.videoQuotaDaily').custom(isUserVideoQuotaDailyValid),
41 body('videoChannels.maxPerUser').isInt(),
43 body('transcoding.enabled').isBoolean(),
44 body('transcoding.allowAdditionalExtensions').isBoolean(),
45 body('transcoding.threads').isInt(),
46 body('transcoding.concurrency').isInt({ min: 1 }),
47 body('transcoding.resolutions.0p').isBoolean(),
48 body('transcoding.resolutions.144p').isBoolean(),
49 body('transcoding.resolutions.240p').isBoolean(),
50 body('transcoding.resolutions.360p').isBoolean(),
51 body('transcoding.resolutions.480p').isBoolean(),
52 body('transcoding.resolutions.720p').isBoolean(),
53 body('transcoding.resolutions.1080p').isBoolean(),
54 body('transcoding.resolutions.1440p').isBoolean(),
55 body('transcoding.resolutions.2160p').isBoolean(),
57 body('transcoding.alwaysTranscodeOriginalResolution').isBoolean(),
59 body('transcoding.webtorrent.enabled').isBoolean(),
60 body('transcoding.hls.enabled').isBoolean(),
62 body('videoStudio.enabled').isBoolean(),
64 body('import.videos.concurrency').isInt({ min: 0 }),
65 body('import.videos.http.enabled').isBoolean(),
66 body('import.videos.torrent.enabled').isBoolean(),
68 body('import.videoChannelSynchronization.enabled').isBoolean(),
70 body('trending.videos.algorithms.default').exists(),
71 body('trending.videos.algorithms.enabled').exists(),
73 body('followers.instance.enabled').isBoolean(),
74 body('followers.instance.manualApproval').isBoolean(),
76 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)),
78 body('broadcastMessage.enabled').isBoolean(),
79 body('broadcastMessage.message').exists(),
80 body('broadcastMessage.level').exists(),
81 body('broadcastMessage.dismissable').isBoolean(),
83 body('live.enabled').isBoolean(),
84 body('live.allowReplay').isBoolean(),
85 body('live.maxDuration').isInt(),
86 body('live.maxInstanceLives').custom(isIntOrNull),
87 body('live.maxUserLives').custom(isIntOrNull),
88 body('live.transcoding.enabled').isBoolean(),
89 body('live.transcoding.threads').isInt(),
90 body('live.transcoding.resolutions.144p').isBoolean(),
91 body('live.transcoding.resolutions.240p').isBoolean(),
92 body('live.transcoding.resolutions.360p').isBoolean(),
93 body('live.transcoding.resolutions.480p').isBoolean(),
94 body('live.transcoding.resolutions.720p').isBoolean(),
95 body('live.transcoding.resolutions.1080p').isBoolean(),
96 body('live.transcoding.resolutions.1440p').isBoolean(),
97 body('live.transcoding.resolutions.2160p').isBoolean(),
98 body('live.transcoding.alwaysTranscodeOriginalResolution').isBoolean(),
100 body('search.remoteUri.users').isBoolean(),
101 body('search.remoteUri.anonymous').isBoolean(),
102 body('search.searchIndex.enabled').isBoolean(),
103 body('search.searchIndex.url').exists(),
104 body('search.searchIndex.disableLocalSearch').isBoolean(),
105 body('search.searchIndex.isDefaultSearch').isBoolean(),
107 (req: express.Request, res: express.Response, next: express.NextFunction) => {
108 logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body })
110 if (areValidationErrors(req, res)) return
111 if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return
112 if (!checkInvalidTranscodingConfig(req.body, res)) return
113 if (!checkInvalidSynchronizationConfig(req.body, res)) return
114 if (!checkInvalidLiveConfig(req.body, res)) return
115 if (!checkInvalidVideoStudioConfig(req.body, res)) return
121 function ensureConfigIsEditable (req: express.Request, res: express.Response, next: express.NextFunction) {
122 if (!CONFIG.WEBADMIN.CONFIGURATION.EDITION.ALLOWED) {
124 status: HttpStatusCode.METHOD_NOT_ALLOWED_405,
125 message: 'Server configuration is static and cannot be edited'
132 // ---------------------------------------------------------------------------
135 customConfigUpdateValidator,
136 ensureConfigIsEditable
139 function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) {
140 if (isEmailEnabled()) return true
142 if (customConfig.signup.requiresEmailVerification === true) {
143 res.fail({ message: 'Emailer is disabled but you require signup email verification.' })
150 function checkInvalidTranscodingConfig (customConfig: CustomConfig, res: express.Response) {
151 if (customConfig.transcoding.enabled === false) return true
153 if (customConfig.transcoding.webtorrent.enabled === false && customConfig.transcoding.hls.enabled === false) {
154 res.fail({ message: 'You need to enable at least webtorrent transcoding or hls transcoding' })
161 function checkInvalidSynchronizationConfig (customConfig: CustomConfig, res: express.Response) {
162 if (customConfig.import.videoChannelSynchronization.enabled && !customConfig.import.videos.http.enabled) {
163 res.fail({ message: 'You need to enable HTTP video import in order to enable channel synchronization' })
169 function checkInvalidLiveConfig (customConfig: CustomConfig, res: express.Response) {
170 if (customConfig.live.enabled === false) return true
172 if (customConfig.live.allowReplay === true && customConfig.transcoding.enabled === false) {
173 res.fail({ message: 'You cannot allow live replay if transcoding is not enabled' })
180 function checkInvalidVideoStudioConfig (customConfig: CustomConfig, res: express.Response) {
181 if (customConfig.videoStudio.enabled === false) return true
183 if (customConfig.videoStudio.enabled === true && customConfig.transcoding.enabled === false) {
184 res.fail({ message: 'You cannot enable video studio if transcoding is not enabled' })