diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/config.ts | 4 | ||||
-rw-r--r-- | server/initializers/config.ts | 31 | ||||
-rw-r--r-- | server/lib/server-config-manager.ts | 1 | ||||
-rw-r--r-- | server/middlewares/validators/config.ts | 16 | ||||
-rw-r--r-- | server/tests/api/server/config.ts | 364 |
5 files changed, 234 insertions, 182 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index d542f62aa..5ea1f67c9 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -11,7 +11,7 @@ import { objectConverter } from '../../helpers/core-utils' | |||
11 | import { CONFIG, reloadConfig } from '../../initializers/config' | 11 | import { CONFIG, reloadConfig } from '../../initializers/config' |
12 | import { ClientHtml } from '../../lib/client-html' | 12 | import { ClientHtml } from '../../lib/client-html' |
13 | import { asyncMiddleware, authenticate, ensureUserHasRight, openapiOperationDoc } from '../../middlewares' | 13 | import { asyncMiddleware, authenticate, ensureUserHasRight, openapiOperationDoc } from '../../middlewares' |
14 | import { customConfigUpdateValidator } from '../../middlewares/validators/config' | 14 | import { customConfigUpdateValidator, ensureConfigIsEditable } from '../../middlewares/validators/config' |
15 | 15 | ||
16 | const configRouter = express.Router() | 16 | const configRouter = express.Router() |
17 | 17 | ||
@@ -38,6 +38,7 @@ configRouter.put('/custom', | |||
38 | openapiOperationDoc({ operationId: 'putCustomConfig' }), | 38 | openapiOperationDoc({ operationId: 'putCustomConfig' }), |
39 | authenticate, | 39 | authenticate, |
40 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 40 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
41 | ensureConfigIsEditable, | ||
41 | customConfigUpdateValidator, | 42 | customConfigUpdateValidator, |
42 | asyncMiddleware(updateCustomConfig) | 43 | asyncMiddleware(updateCustomConfig) |
43 | ) | 44 | ) |
@@ -46,6 +47,7 @@ configRouter.delete('/custom', | |||
46 | openapiOperationDoc({ operationId: 'delCustomConfig' }), | 47 | openapiOperationDoc({ operationId: 'delCustomConfig' }), |
47 | authenticate, | 48 | authenticate, |
48 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 49 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
50 | ensureConfigIsEditable, | ||
49 | asyncMiddleware(deleteCustomConfig) | 51 | asyncMiddleware(deleteCustomConfig) |
50 | ) | 52 | ) |
51 | 53 | ||
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index be9fc61f0..b2a8e9e19 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -195,6 +195,13 @@ const CONFIG = { | |||
195 | URL: config.get<string>('peertube.check_latest_version.url') | 195 | URL: config.get<string>('peertube.check_latest_version.url') |
196 | } | 196 | } |
197 | }, | 197 | }, |
198 | WEBADMIN: { | ||
199 | CONFIGURATION: { | ||
200 | EDITS: { | ||
201 | ALLOWED: config.get<boolean>('webadmin.configuration.edit.allowed') | ||
202 | } | ||
203 | } | ||
204 | }, | ||
198 | ADMIN: { | 205 | ADMIN: { |
199 | get EMAIL () { return config.get<string>('admin.email') } | 206 | get EMAIL () { return config.get<string>('admin.email') } |
200 | }, | 207 | }, |
@@ -411,14 +418,22 @@ export { | |||
411 | // --------------------------------------------------------------------------- | 418 | // --------------------------------------------------------------------------- |
412 | 419 | ||
413 | function getLocalConfigFilePath () { | 420 | function getLocalConfigFilePath () { |
414 | const configSources = config.util.getConfigSources() | 421 | const localConfigDir = getLocalConfigDir() |
415 | if (configSources.length === 0) throw new Error('Invalid config source.') | ||
416 | 422 | ||
417 | let filename = 'local' | 423 | let filename = 'local' |
418 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` | 424 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` |
419 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` | 425 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` |
420 | 426 | ||
421 | return join(dirname(configSources[0].name), filename + '.json') | 427 | return join(localConfigDir, filename + '.json') |
428 | } | ||
429 | |||
430 | function getLocalConfigDir () { | ||
431 | if (process.env.PEERTUBE_LOCAL_CONFIG) return process.env.PEERTUBE_LOCAL_CONFIG | ||
432 | |||
433 | const configSources = config.util.getConfigSources() | ||
434 | if (configSources.length === 0) throw new Error('Invalid config source.') | ||
435 | |||
436 | return dirname(configSources[0].name) | ||
422 | } | 437 | } |
423 | 438 | ||
424 | function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { | 439 | function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { |
@@ -437,19 +452,19 @@ function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { | |||
437 | 452 | ||
438 | export function reloadConfig () { | 453 | export function reloadConfig () { |
439 | 454 | ||
440 | function getConfigDirectory () { | 455 | function getConfigDirectories () { |
441 | if (process.env.NODE_CONFIG_DIR) { | 456 | if (process.env.NODE_CONFIG_DIR) { |
442 | return process.env.NODE_CONFIG_DIR | 457 | return process.env.NODE_CONFIG_DIR.split(":") |
443 | } | 458 | } |
444 | 459 | ||
445 | return join(root(), 'config') | 460 | return [ join(root(), 'config') ] |
446 | } | 461 | } |
447 | 462 | ||
448 | function purge () { | 463 | function purge () { |
449 | const directory = getConfigDirectory() | 464 | const directories = getConfigDirectories() |
450 | 465 | ||
451 | for (const fileName in require.cache) { | 466 | for (const fileName in require.cache) { |
452 | if (fileName.includes(directory) === false) { | 467 | if (directories.some((dir) => fileName.includes(dir)) === false) { |
453 | continue | 468 | continue |
454 | } | 469 | } |
455 | 470 | ||
diff --git a/server/lib/server-config-manager.ts b/server/lib/server-config-manager.ts index 80d87a9d3..358f47133 100644 --- a/server/lib/server-config-manager.ts +++ b/server/lib/server-config-manager.ts | |||
@@ -42,6 +42,7 @@ class ServerConfigManager { | |||
42 | const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) | 42 | const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) |
43 | 43 | ||
44 | return { | 44 | return { |
45 | allowEdits: CONFIG.WEBADMIN.CONFIGURATION.EDITS.ALLOWED, | ||
45 | instance: { | 46 | instance: { |
46 | name: CONFIG.INSTANCE.NAME, | 47 | name: CONFIG.INSTANCE.NAME, |
47 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, | 48 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 16a840667..5f1ac89bc 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -1,13 +1,14 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body } from 'express-validator' | 2 | import { body } from 'express-validator' |
3 | import { isIntOrNull } from '@server/helpers/custom-validators/misc' | 3 | import { isIntOrNull } from '@server/helpers/custom-validators/misc' |
4 | import { isEmailEnabled } from '@server/initializers/config' | 4 | import { CONFIG, isEmailEnabled } from '@server/initializers/config' |
5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' | 5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' |
6 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' | 6 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' |
7 | import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' | 7 | import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' |
8 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
9 | import { isThemeRegistered } from '../../lib/plugins/theme-utils' | 9 | import { isThemeRegistered } from '../../lib/plugins/theme-utils' |
10 | import { areValidationErrors } from './shared' | 10 | import { areValidationErrors } from './shared' |
11 | import { HttpStatusCode } from '@shared/models/http/http-error-codes' | ||
11 | 12 | ||
12 | const customConfigUpdateValidator = [ | 13 | const customConfigUpdateValidator = [ |
13 | body('instance.name').exists().withMessage('Should have a valid instance name'), | 14 | body('instance.name').exists().withMessage('Should have a valid instance name'), |
@@ -104,10 +105,21 @@ const customConfigUpdateValidator = [ | |||
104 | } | 105 | } |
105 | ] | 106 | ] |
106 | 107 | ||
108 | function ensureConfigIsEditable (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
109 | if (!CONFIG.WEBADMIN.CONFIGURATION.EDITS.ALLOWED) { | ||
110 | return res.fail({ | ||
111 | status: HttpStatusCode.METHOD_NOT_ALLOWED_405, | ||
112 | message: 'Server configuration is static and cannot be edited' | ||
113 | }) | ||
114 | } | ||
115 | return next() | ||
116 | } | ||
117 | |||
107 | // --------------------------------------------------------------------------- | 118 | // --------------------------------------------------------------------------- |
108 | 119 | ||
109 | export { | 120 | export { |
110 | customConfigUpdateValidator | 121 | customConfigUpdateValidator, |
122 | ensureConfigIsEditable | ||
111 | } | 123 | } |
112 | 124 | ||
113 | function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { | 125 | function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { |
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index c4dd882b8..e057ec1a2 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -201,6 +201,199 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
201 | expect(data.broadcastMessage.dismissable).to.be.true | 201 | expect(data.broadcastMessage.dismissable).to.be.true |
202 | } | 202 | } |
203 | 203 | ||
204 | const newCustomConfig: CustomConfig = { | ||
205 | instance: { | ||
206 | name: 'PeerTube updated', | ||
207 | shortDescription: 'my short description', | ||
208 | description: 'my super description', | ||
209 | terms: 'my super terms', | ||
210 | codeOfConduct: 'my super coc', | ||
211 | |||
212 | creationReason: 'my super creation reason', | ||
213 | moderationInformation: 'my super moderation information', | ||
214 | administrator: 'Kuja', | ||
215 | maintenanceLifetime: 'forever', | ||
216 | businessModel: 'my super business model', | ||
217 | hardwareInformation: '2vCore 3GB RAM', | ||
218 | |||
219 | languages: [ 'en', 'es' ], | ||
220 | categories: [ 1, 2 ], | ||
221 | |||
222 | isNSFW: true, | ||
223 | defaultNSFWPolicy: 'blur' as 'blur', | ||
224 | |||
225 | defaultClientRoute: '/videos/recently-added', | ||
226 | |||
227 | customizations: { | ||
228 | javascript: 'alert("coucou")', | ||
229 | css: 'body { background-color: red; }' | ||
230 | } | ||
231 | }, | ||
232 | theme: { | ||
233 | default: 'default' | ||
234 | }, | ||
235 | services: { | ||
236 | twitter: { | ||
237 | username: '@Kuja', | ||
238 | whitelisted: true | ||
239 | } | ||
240 | }, | ||
241 | cache: { | ||
242 | previews: { | ||
243 | size: 2 | ||
244 | }, | ||
245 | captions: { | ||
246 | size: 3 | ||
247 | }, | ||
248 | torrents: { | ||
249 | size: 4 | ||
250 | } | ||
251 | }, | ||
252 | signup: { | ||
253 | enabled: false, | ||
254 | limit: 5, | ||
255 | requiresEmailVerification: false, | ||
256 | minimumAge: 10 | ||
257 | }, | ||
258 | admin: { | ||
259 | email: 'superadmin1@example.com' | ||
260 | }, | ||
261 | contactForm: { | ||
262 | enabled: false | ||
263 | }, | ||
264 | user: { | ||
265 | videoQuota: 5242881, | ||
266 | videoQuotaDaily: 318742 | ||
267 | }, | ||
268 | transcoding: { | ||
269 | enabled: true, | ||
270 | allowAdditionalExtensions: true, | ||
271 | allowAudioFiles: true, | ||
272 | threads: 1, | ||
273 | concurrency: 3, | ||
274 | profile: 'vod_profile', | ||
275 | resolutions: { | ||
276 | '0p': false, | ||
277 | '240p': false, | ||
278 | '360p': true, | ||
279 | '480p': true, | ||
280 | '720p': false, | ||
281 | '1080p': false, | ||
282 | '1440p': false, | ||
283 | '2160p': false | ||
284 | }, | ||
285 | webtorrent: { | ||
286 | enabled: true | ||
287 | }, | ||
288 | hls: { | ||
289 | enabled: false | ||
290 | } | ||
291 | }, | ||
292 | live: { | ||
293 | enabled: true, | ||
294 | allowReplay: true, | ||
295 | maxDuration: 5000, | ||
296 | maxInstanceLives: -1, | ||
297 | maxUserLives: 10, | ||
298 | transcoding: { | ||
299 | enabled: true, | ||
300 | threads: 4, | ||
301 | profile: 'live_profile', | ||
302 | resolutions: { | ||
303 | '240p': true, | ||
304 | '360p': true, | ||
305 | '480p': true, | ||
306 | '720p': true, | ||
307 | '1080p': true, | ||
308 | '1440p': true, | ||
309 | '2160p': true | ||
310 | } | ||
311 | } | ||
312 | }, | ||
313 | import: { | ||
314 | videos: { | ||
315 | concurrency: 4, | ||
316 | http: { | ||
317 | enabled: false | ||
318 | }, | ||
319 | torrent: { | ||
320 | enabled: false | ||
321 | } | ||
322 | } | ||
323 | }, | ||
324 | trending: { | ||
325 | videos: { | ||
326 | algorithms: { | ||
327 | enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ], | ||
328 | default: 'hot' | ||
329 | } | ||
330 | } | ||
331 | }, | ||
332 | autoBlacklist: { | ||
333 | videos: { | ||
334 | ofUsers: { | ||
335 | enabled: true | ||
336 | } | ||
337 | } | ||
338 | }, | ||
339 | followers: { | ||
340 | instance: { | ||
341 | enabled: false, | ||
342 | manualApproval: true | ||
343 | } | ||
344 | }, | ||
345 | followings: { | ||
346 | instance: { | ||
347 | autoFollowBack: { | ||
348 | enabled: true | ||
349 | }, | ||
350 | autoFollowIndex: { | ||
351 | enabled: true, | ||
352 | indexUrl: 'https://updated.example.com' | ||
353 | } | ||
354 | } | ||
355 | }, | ||
356 | broadcastMessage: { | ||
357 | enabled: true, | ||
358 | level: 'error', | ||
359 | message: 'super bad message', | ||
360 | dismissable: true | ||
361 | }, | ||
362 | search: { | ||
363 | remoteUri: { | ||
364 | anonymous: true, | ||
365 | users: true | ||
366 | }, | ||
367 | searchIndex: { | ||
368 | enabled: true, | ||
369 | url: 'https://search.joinpeertube.org', | ||
370 | disableLocalSearch: true, | ||
371 | isDefaultSearch: true | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | describe('Test static config', function () { | ||
377 | let server: PeerTubeServer = null | ||
378 | |||
379 | before(async function () { | ||
380 | this.timeout(30000) | ||
381 | |||
382 | server = await createSingleServer(1, { webadmin: { configuration: { edit: { allowed: false } } } }) | ||
383 | await setAccessTokensToServers([ server ]) | ||
384 | }) | ||
385 | |||
386 | it('Should tell the client that edits are not allowed', async function () { | ||
387 | const data = await server.config.getConfig() | ||
388 | |||
389 | expect(data.allowEdits).to.be.false | ||
390 | }) | ||
391 | |||
392 | it('Should error when client tries to update', async function () { | ||
393 | await server.config.updateCustomConfig({ newCustomConfig, expectedStatus: 405 }) | ||
394 | }) | ||
395 | }) | ||
396 | |||
204 | describe('Test config', function () { | 397 | describe('Test config', function () { |
205 | let server: PeerTubeServer = null | 398 | let server: PeerTubeServer = null |
206 | 399 | ||
@@ -252,177 +445,6 @@ describe('Test config', function () { | |||
252 | }) | 445 | }) |
253 | 446 | ||
254 | it('Should update the customized configuration', async function () { | 447 | it('Should update the customized configuration', async function () { |
255 | const newCustomConfig: CustomConfig = { | ||
256 | instance: { | ||
257 | name: 'PeerTube updated', | ||
258 | shortDescription: 'my short description', | ||
259 | description: 'my super description', | ||
260 | terms: 'my super terms', | ||
261 | codeOfConduct: 'my super coc', | ||
262 | |||
263 | creationReason: 'my super creation reason', | ||
264 | moderationInformation: 'my super moderation information', | ||
265 | administrator: 'Kuja', | ||
266 | maintenanceLifetime: 'forever', | ||
267 | businessModel: 'my super business model', | ||
268 | hardwareInformation: '2vCore 3GB RAM', | ||
269 | |||
270 | languages: [ 'en', 'es' ], | ||
271 | categories: [ 1, 2 ], | ||
272 | |||
273 | isNSFW: true, | ||
274 | defaultNSFWPolicy: 'blur' as 'blur', | ||
275 | |||
276 | defaultClientRoute: '/videos/recently-added', | ||
277 | |||
278 | customizations: { | ||
279 | javascript: 'alert("coucou")', | ||
280 | css: 'body { background-color: red; }' | ||
281 | } | ||
282 | }, | ||
283 | theme: { | ||
284 | default: 'default' | ||
285 | }, | ||
286 | services: { | ||
287 | twitter: { | ||
288 | username: '@Kuja', | ||
289 | whitelisted: true | ||
290 | } | ||
291 | }, | ||
292 | cache: { | ||
293 | previews: { | ||
294 | size: 2 | ||
295 | }, | ||
296 | captions: { | ||
297 | size: 3 | ||
298 | }, | ||
299 | torrents: { | ||
300 | size: 4 | ||
301 | } | ||
302 | }, | ||
303 | signup: { | ||
304 | enabled: false, | ||
305 | limit: 5, | ||
306 | requiresEmailVerification: false, | ||
307 | minimumAge: 10 | ||
308 | }, | ||
309 | admin: { | ||
310 | email: 'superadmin1@example.com' | ||
311 | }, | ||
312 | contactForm: { | ||
313 | enabled: false | ||
314 | }, | ||
315 | user: { | ||
316 | videoQuota: 5242881, | ||
317 | videoQuotaDaily: 318742 | ||
318 | }, | ||
319 | transcoding: { | ||
320 | enabled: true, | ||
321 | allowAdditionalExtensions: true, | ||
322 | allowAudioFiles: true, | ||
323 | threads: 1, | ||
324 | concurrency: 3, | ||
325 | profile: 'vod_profile', | ||
326 | resolutions: { | ||
327 | '0p': false, | ||
328 | '240p': false, | ||
329 | '360p': true, | ||
330 | '480p': true, | ||
331 | '720p': false, | ||
332 | '1080p': false, | ||
333 | '1440p': false, | ||
334 | '2160p': false | ||
335 | }, | ||
336 | webtorrent: { | ||
337 | enabled: true | ||
338 | }, | ||
339 | hls: { | ||
340 | enabled: false | ||
341 | } | ||
342 | }, | ||
343 | live: { | ||
344 | enabled: true, | ||
345 | allowReplay: true, | ||
346 | maxDuration: 5000, | ||
347 | maxInstanceLives: -1, | ||
348 | maxUserLives: 10, | ||
349 | transcoding: { | ||
350 | enabled: true, | ||
351 | threads: 4, | ||
352 | profile: 'live_profile', | ||
353 | resolutions: { | ||
354 | '240p': true, | ||
355 | '360p': true, | ||
356 | '480p': true, | ||
357 | '720p': true, | ||
358 | '1080p': true, | ||
359 | '1440p': true, | ||
360 | '2160p': true | ||
361 | } | ||
362 | } | ||
363 | }, | ||
364 | import: { | ||
365 | videos: { | ||
366 | concurrency: 4, | ||
367 | http: { | ||
368 | enabled: false | ||
369 | }, | ||
370 | torrent: { | ||
371 | enabled: false | ||
372 | } | ||
373 | } | ||
374 | }, | ||
375 | trending: { | ||
376 | videos: { | ||
377 | algorithms: { | ||
378 | enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ], | ||
379 | default: 'hot' | ||
380 | } | ||
381 | } | ||
382 | }, | ||
383 | autoBlacklist: { | ||
384 | videos: { | ||
385 | ofUsers: { | ||
386 | enabled: true | ||
387 | } | ||
388 | } | ||
389 | }, | ||
390 | followers: { | ||
391 | instance: { | ||
392 | enabled: false, | ||
393 | manualApproval: true | ||
394 | } | ||
395 | }, | ||
396 | followings: { | ||
397 | instance: { | ||
398 | autoFollowBack: { | ||
399 | enabled: true | ||
400 | }, | ||
401 | autoFollowIndex: { | ||
402 | enabled: true, | ||
403 | indexUrl: 'https://updated.example.com' | ||
404 | } | ||
405 | } | ||
406 | }, | ||
407 | broadcastMessage: { | ||
408 | enabled: true, | ||
409 | level: 'error', | ||
410 | message: 'super bad message', | ||
411 | dismissable: true | ||
412 | }, | ||
413 | search: { | ||
414 | remoteUri: { | ||
415 | anonymous: true, | ||
416 | users: true | ||
417 | }, | ||
418 | searchIndex: { | ||
419 | enabled: true, | ||
420 | url: 'https://search.joinpeertube.org', | ||
421 | disableLocalSearch: true, | ||
422 | isDefaultSearch: true | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | await server.config.updateCustomConfig({ newCustomConfig }) | 448 | await server.config.updateCustomConfig({ newCustomConfig }) |
427 | 449 | ||
428 | const data = await server.config.getCustomConfig() | 450 | const data = await server.config.getCustomConfig() |