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 { HttpStatusCode } from '@shared/models/http/http-error-codes'
6 import { CustomConfig } from '../../../shared/models/server/custom-config.model'
7 import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
8 import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users'
9 import { isThemeRegistered } from '../../lib/plugins/theme-utils'
10 import { areValidationErrors } from './shared'
12 const customConfigUpdateValidator = [
13 body('instance.name').exists(),
14 body('instance.shortDescription').exists(),
15 body('instance.description').exists(),
16 body('instance.terms').exists(),
17 body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid),
18 body('instance.defaultClientRoute').exists(),
19 body('instance.customizations.css').exists(),
20 body('instance.customizations.javascript').exists(),
22 body('services.twitter.username').exists(),
23 body('services.twitter.whitelisted').isBoolean(),
25 body('cache.previews.size').isInt(),
26 body('cache.captions.size').isInt(),
27 body('cache.torrents.size').isInt(),
29 body('signup.enabled').isBoolean(),
30 body('signup.limit').isInt(),
31 body('signup.requiresEmailVerification').isBoolean(),
32 body('signup.requiresApproval').isBoolean(),
33 body('signup.minimumAge').isInt(),
35 body('admin.email').isEmail(),
36 body('contactForm.enabled').isBoolean(),
38 body('user.history.videos.enabled').isBoolean(),
39 body('user.videoQuota').custom(isUserVideoQuotaValid),
40 body('user.videoQuotaDaily').custom(isUserVideoQuotaDailyValid),
42 body('videoChannels.maxPerUser').isInt(),
44 body('transcoding.enabled').isBoolean(),
45 body('transcoding.allowAdditionalExtensions').isBoolean(),
46 body('transcoding.threads').isInt(),
47 body('transcoding.concurrency').isInt({ min: 1 }),
48 body('transcoding.resolutions.0p').isBoolean(),
49 body('transcoding.resolutions.144p').isBoolean(),
50 body('transcoding.resolutions.240p').isBoolean(),
51 body('transcoding.resolutions.360p').isBoolean(),
52 body('transcoding.resolutions.480p').isBoolean(),
53 body('transcoding.resolutions.720p').isBoolean(),
54 body('transcoding.resolutions.1080p').isBoolean(),
55 body('transcoding.resolutions.1440p').isBoolean(),
56 body('transcoding.resolutions.2160p').isBoolean(),
58 body('transcoding.alwaysTranscodeOriginalResolution').isBoolean(),
60 body('transcoding.webtorrent.enabled').isBoolean(),
61 body('transcoding.hls.enabled').isBoolean(),
63 body('videoStudio.enabled').isBoolean(),
65 body('import.videos.concurrency').isInt({ min: 0 }),
66 body('import.videos.http.enabled').isBoolean(),
67 body('import.videos.torrent.enabled').isBoolean(),
69 body('import.videoChannelSynchronization.enabled').isBoolean(),
71 body('trending.videos.algorithms.default').exists(),
72 body('trending.videos.algorithms.enabled').exists(),
74 body('followers.instance.enabled').isBoolean(),
75 body('followers.instance.manualApproval').isBoolean(),
77 body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)),
79 body('broadcastMessage.enabled').isBoolean(),
80 body('broadcastMessage.message').exists(),
81 body('broadcastMessage.level').exists(),
82 body('broadcastMessage.dismissable').isBoolean(),
84 body('live.enabled').isBoolean(),
85 body('live.allowReplay').isBoolean(),
86 body('live.maxDuration').isInt(),
87 body('live.maxInstanceLives').custom(isIntOrNull),
88 body('live.maxUserLives').custom(isIntOrNull),
89 body('live.transcoding.enabled').isBoolean(),
90 body('live.transcoding.threads').isInt(),
91 body('live.transcoding.resolutions.144p').isBoolean(),
92 body('live.transcoding.resolutions.240p').isBoolean(),
93 body('live.transcoding.resolutions.360p').isBoolean(),
94 body('live.transcoding.resolutions.480p').isBoolean(),
95 body('live.transcoding.resolutions.720p').isBoolean(),
96 body('live.transcoding.resolutions.1080p').isBoolean(),
97 body('live.transcoding.resolutions.1440p').isBoolean(),
98 body('live.transcoding.resolutions.2160p').isBoolean(),
99 body('live.transcoding.alwaysTranscodeOriginalResolution').isBoolean(),
101 body('search.remoteUri.users').isBoolean(),
102 body('search.remoteUri.anonymous').isBoolean(),
103 body('search.searchIndex.enabled').isBoolean(),
104 body('search.searchIndex.url').exists(),
105 body('search.searchIndex.disableLocalSearch').isBoolean(),
106 body('search.searchIndex.isDefaultSearch').isBoolean(),
108 (req: express.Request, res: express.Response, next: express.NextFunction) => {
109 if (areValidationErrors(req, res)) return
110 if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return
111 if (!checkInvalidTranscodingConfig(req.body, res)) return
112 if (!checkInvalidSynchronizationConfig(req.body, res)) return
113 if (!checkInvalidLiveConfig(req.body, res)) return
114 if (!checkInvalidVideoStudioConfig(req.body, res)) return
120 function ensureConfigIsEditable (req: express.Request, res: express.Response, next: express.NextFunction) {
121 if (!CONFIG.WEBADMIN.CONFIGURATION.EDITION.ALLOWED) {
123 status: HttpStatusCode.METHOD_NOT_ALLOWED_405,
124 message: 'Server configuration is static and cannot be edited'
131 // ---------------------------------------------------------------------------
134 customConfigUpdateValidator,
135 ensureConfigIsEditable
138 function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) {
139 if (isEmailEnabled()) return true
141 if (customConfig.signup.requiresEmailVerification === true) {
142 res.fail({ message: 'Emailer is disabled but you require signup email verification.' })
149 function checkInvalidTranscodingConfig (customConfig: CustomConfig, res: express.Response) {
150 if (customConfig.transcoding.enabled === false) return true
152 if (customConfig.transcoding.webtorrent.enabled === false && customConfig.transcoding.hls.enabled === false) {
153 res.fail({ message: 'You need to enable at least webtorrent transcoding or hls transcoding' })
160 function checkInvalidSynchronizationConfig (customConfig: CustomConfig, res: express.Response) {
161 if (customConfig.import.videoChannelSynchronization.enabled && !customConfig.import.videos.http.enabled) {
162 res.fail({ message: 'You need to enable HTTP video import in order to enable channel synchronization' })
168 function checkInvalidLiveConfig (customConfig: CustomConfig, res: express.Response) {
169 if (customConfig.live.enabled === false) return true
171 if (customConfig.live.allowReplay === true && customConfig.transcoding.enabled === false) {
172 res.fail({ message: 'You cannot allow live replay if transcoding is not enabled' })
179 function checkInvalidVideoStudioConfig (customConfig: CustomConfig, res: express.Response) {
180 if (customConfig.videoStudio.enabled === false) return true
182 if (customConfig.videoStudio.enabled === true && customConfig.transcoding.enabled === false) {
183 res.fail({ message: 'You cannot enable video studio if transcoding is not enabled' })