1 import config from 'config'
2 import { uniq } from 'lodash'
3 import { URL } from 'url'
4 import { getFFmpegVersion } from '@server/helpers/ffmpeg'
5 import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
6 import { RecentlyAddedStrategy } from '../../shared/models/redundancy'
7 import { isProdInstance, parseSemVersion } from '../helpers/core-utils'
8 import { isArray } from '../helpers/custom-validators/misc'
9 import { logger } from '../helpers/logger'
10 import { ApplicationModel, getServerActor } from '../models/application/application'
11 import { OAuthClientModel } from '../models/oauth/oauth-client'
12 import { UserModel } from '../models/user/user'
13 import { CONFIG, isEmailEnabled } from './config'
14 import { WEBSERVER } from './constants'
16 async function checkActivityPubUrls () {
17 const actor = await getServerActor()
19 const parsed = new URL(actor.url)
20 if (WEBSERVER.HOST !== parsed.host) {
21 const NODE_ENV = config.util.getEnv('NODE_ENV')
22 const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')
25 'It seems PeerTube was started (and created some data) with another domain name. ' +
26 'This means you will not be able to federate! ' +
27 'Please use %s %s npm run update-host to fix this.',
28 NODE_CONFIG_DIR ? `NODE_CONFIG_DIR=${NODE_CONFIG_DIR}` : '',
29 NODE_ENV ? `NODE_ENV=${NODE_ENV}` : ''
34 // Some checks on configuration files or throw if there is an error
35 function checkConfig () {
37 const configFiles = config.util.getConfigSources().map(s => s.name).join(' -> ')
38 logger.info('Using following configuration file hierarchy: %s.', configFiles)
40 // Moved configuration keys
41 if (config.has('services.csp-logger')) {
42 logger.warn('services.csp-logger configuration has been renamed to csp.report_uri. Please update your configuration file.')
46 checkNSFWPolicyConfig()
47 checkLocalRedundancyConfig()
48 checkRemoteRedundancyConfig()
50 checkTranscodingConfig()
51 checkBroadcastMessageConfig()
54 checkObjectStorageConfig()
55 checkVideoStudioConfig()
58 // We get db by param to not import it in this file (import orders)
59 async function clientsExist () {
60 const totalClients = await OAuthClientModel.countTotal()
62 return totalClients !== 0
65 // We get db by param to not import it in this file (import orders)
66 async function usersExist () {
67 const totalUsers = await UserModel.countTotal()
69 return totalUsers !== 0
72 // We get db by param to not import it in this file (import orders)
73 async function applicationExist () {
74 const totalApplication = await ApplicationModel.countTotal()
76 return totalApplication !== 0
79 async function checkFFmpegVersion () {
80 const version = await getFFmpegVersion()
81 const { major, minor } = parseSemVersion(version)
83 if (major < 4 || (major === 4 && minor < 1)) {
84 logger.warn('Your ffmpeg version (%s) is outdated. PeerTube supports ffmpeg >= 4.1. Please upgrade.', version)
88 // ---------------------------------------------------------------------------
99 // ---------------------------------------------------------------------------
101 function checkEmailConfig () {
102 if (!isEmailEnabled()) {
103 if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
104 throw new Error('Emailer is disabled but you require signup email verification.')
107 if (CONFIG.CONTACT_FORM.ENABLED) {
108 logger.warn('Emailer is disabled so the contact form will not work.')
113 function checkNSFWPolicyConfig () {
114 const defaultNSFWPolicy = CONFIG.INSTANCE.DEFAULT_NSFW_POLICY
116 const available = [ 'do_not_list', 'blur', 'display' ]
117 if (available.includes(defaultNSFWPolicy) === false) {
118 throw new Error('NSFW policy setting should be ' + available.join(' or ') + ' instead of ' + defaultNSFWPolicy)
122 function checkLocalRedundancyConfig () {
123 const redundancyVideos = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES
125 if (isArray(redundancyVideos)) {
126 const available = [ 'most-views', 'trending', 'recently-added' ]
128 for (const r of redundancyVideos) {
129 if (available.includes(r.strategy) === false) {
130 throw new Error('Videos redundancy should have ' + available.join(' or ') + ' strategy instead of ' + r.strategy)
133 // Lifetime should not be < 10 hours
134 if (isProdInstance() && r.minLifetime < 1000 * 3600 * 10) {
135 throw new Error('Video redundancy minimum lifetime should be >= 10 hours for strategy ' + r.strategy)
139 const filtered = uniq(redundancyVideos.map(r => r.strategy))
140 if (filtered.length !== redundancyVideos.length) {
141 throw new Error('Redundancy video entries should have unique strategies')
144 const recentlyAddedStrategy = redundancyVideos.find(r => r.strategy === 'recently-added') as RecentlyAddedStrategy
145 if (recentlyAddedStrategy && isNaN(recentlyAddedStrategy.minViews)) {
146 throw new Error('Min views in recently added strategy is not a number')
149 throw new Error('Videos redundancy should be an array (you must uncomment lines containing - too)')
153 function checkRemoteRedundancyConfig () {
154 const acceptFrom = CONFIG.REMOTE_REDUNDANCY.VIDEOS.ACCEPT_FROM
155 const acceptFromValues = new Set<VideoRedundancyConfigFilter>([ 'nobody', 'anybody', 'followings' ])
157 if (acceptFromValues.has(acceptFrom) === false) {
158 throw new Error('remote_redundancy.videos.accept_from has an incorrect value')
162 function checkStorageConfig () {
163 // Check storage directory locations
164 if (isProdInstance()) {
165 const configStorage = config.get('storage')
166 for (const key of Object.keys(configStorage)) {
167 if (configStorage[key].startsWith('storage/')) {
169 'Directory of %s should not be in the production directory of PeerTube. Please check your production configuration file.',
176 if (CONFIG.STORAGE.VIDEOS_DIR === CONFIG.STORAGE.REDUNDANCY_DIR) {
177 logger.warn('Redundancy directory should be different than the videos folder.')
181 function checkTranscodingConfig () {
182 if (CONFIG.TRANSCODING.ENABLED) {
183 if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false && CONFIG.TRANSCODING.HLS.ENABLED === false) {
184 throw new Error('You need to enable at least WebTorrent transcoding or HLS transcoding.')
187 if (CONFIG.TRANSCODING.CONCURRENCY <= 0) {
188 throw new Error('Transcoding concurrency should be > 0')
192 if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED || CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED) {
193 if (CONFIG.IMPORT.VIDEOS.CONCURRENCY <= 0) {
194 throw new Error('Video import concurrency should be > 0')
199 function checkBroadcastMessageConfig () {
200 if (CONFIG.BROADCAST_MESSAGE.ENABLED) {
201 const currentLevel = CONFIG.BROADCAST_MESSAGE.LEVEL
202 const available = [ 'info', 'warning', 'error' ]
204 if (available.includes(currentLevel) === false) {
205 throw new Error('Broadcast message level should be ' + available.join(' or ') + ' instead of ' + currentLevel)
210 function checkSearchConfig () {
211 if (CONFIG.SEARCH.SEARCH_INDEX.ENABLED === true) {
212 if (CONFIG.SEARCH.REMOTE_URI.USERS === false) {
213 throw new Error('You cannot enable search index without enabling remote URI search for users.')
218 function checkLiveConfig () {
219 if (CONFIG.LIVE.ENABLED === true) {
220 if (CONFIG.LIVE.ALLOW_REPLAY === true && CONFIG.TRANSCODING.ENABLED === false) {
221 throw new Error('Live allow replay cannot be enabled if transcoding is not enabled.')
224 if (CONFIG.LIVE.RTMP.ENABLED === false && CONFIG.LIVE.RTMPS.ENABLED === false) {
225 throw new Error('You must enable at least RTMP or RTMPS')
228 if (CONFIG.LIVE.RTMPS.ENABLED) {
229 if (!CONFIG.LIVE.RTMPS.KEY_FILE) {
230 throw new Error('You must specify a key file to enabled RTMPS')
233 if (!CONFIG.LIVE.RTMPS.CERT_FILE) {
234 throw new Error('You must specify a cert file to enable RTMPS')
240 function checkObjectStorageConfig () {
241 if (CONFIG.OBJECT_STORAGE.ENABLED === true) {
243 if (!CONFIG.OBJECT_STORAGE.VIDEOS.BUCKET_NAME) {
244 throw new Error('videos_bucket should be set when object storage support is enabled.')
247 if (!CONFIG.OBJECT_STORAGE.STREAMING_PLAYLISTS.BUCKET_NAME) {
248 throw new Error('streaming_playlists_bucket should be set when object storage support is enabled.')
252 CONFIG.OBJECT_STORAGE.VIDEOS.BUCKET_NAME === CONFIG.OBJECT_STORAGE.STREAMING_PLAYLISTS.BUCKET_NAME &&
253 CONFIG.OBJECT_STORAGE.VIDEOS.PREFIX === CONFIG.OBJECT_STORAGE.STREAMING_PLAYLISTS.PREFIX
255 if (CONFIG.OBJECT_STORAGE.VIDEOS.PREFIX === '') {
256 throw new Error('Object storage bucket prefixes should be set when the same bucket is used for both types of video.')
260 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.'
266 function checkVideoStudioConfig () {
267 if (CONFIG.VIDEO_STUDIO.ENABLED === true && CONFIG.TRANSCODING.ENABLED === false) {
268 throw new Error('Video studio cannot be enabled if transcoding is disabled')