diff options
author | Chocobozzz <me@florianbigard.com> | 2021-05-14 12:04:44 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-05-14 13:37:23 +0200 |
commit | aea0b0e7cde7495e60fe07b4444067f53d35ce3f (patch) | |
tree | 61d1e161bb32be144d46b9f5f51f1386e6819b0b /server | |
parent | c76ecc3ff746d78519404db4c525fd024f9a51c0 (diff) | |
download | PeerTube-aea0b0e7cde7495e60fe07b4444067f53d35ce3f.tar.gz PeerTube-aea0b0e7cde7495e60fe07b4444067f53d35ce3f.tar.zst PeerTube-aea0b0e7cde7495e60fe07b4444067f53d35ce3f.zip |
Inject server config in HTML
Diffstat (limited to 'server')
-rw-r--r-- | server/initializers/constants.ts | 3 | ||||
-rw-r--r-- | server/lib/client-html.ts | 18 | ||||
-rw-r--r-- | server/lib/config.ts | 31 | ||||
-rw-r--r-- | server/models/abuse/abuse.ts | 3 | ||||
-rw-r--r-- | server/tests/client.ts | 28 |
5 files changed, 62 insertions, 21 deletions
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 6f388420e..4cf7dcf0a 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -702,7 +702,8 @@ const CUSTOM_HTML_TAG_COMMENTS = { | |||
702 | TITLE: '<!-- title tag -->', | 702 | TITLE: '<!-- title tag -->', |
703 | DESCRIPTION: '<!-- description tag -->', | 703 | DESCRIPTION: '<!-- description tag -->', |
704 | CUSTOM_CSS: '<!-- custom css tag -->', | 704 | CUSTOM_CSS: '<!-- custom css tag -->', |
705 | META_TAGS: '<!-- meta tags -->' | 705 | META_TAGS: '<!-- meta tags -->', |
706 | SERVER_CONFIG: '<!-- server config -->' | ||
706 | } | 707 | } |
707 | 708 | ||
708 | // --------------------------------------------------------------------------- | 709 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 203bd3893..85fdc8754 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -2,12 +2,14 @@ import * as express from 'express' | |||
2 | import { readFile } from 'fs-extra' | 2 | import { readFile } from 'fs-extra' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import validator from 'validator' | 4 | import validator from 'validator' |
5 | import { escapeHTML } from '@shared/core-utils/renderer' | ||
6 | import { HTMLServerConfig } from '@shared/models' | ||
5 | import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n' | 7 | import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n' |
6 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' | 8 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' |
7 | import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos' | 9 | import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos' |
8 | import { isTestInstance, sha256 } from '../helpers/core-utils' | 10 | import { isTestInstance, sha256 } from '../helpers/core-utils' |
9 | import { escapeHTML } from '@shared/core-utils/renderer' | ||
10 | import { logger } from '../helpers/logger' | 11 | import { logger } from '../helpers/logger' |
12 | import { mdToPlainText } from '../helpers/markdown' | ||
11 | import { CONFIG } from '../initializers/config' | 13 | import { CONFIG } from '../initializers/config' |
12 | import { | 14 | import { |
13 | ACCEPT_HEADERS, | 15 | ACCEPT_HEADERS, |
@@ -24,7 +26,7 @@ import { VideoChannelModel } from '../models/video/video-channel' | |||
24 | import { getActivityStreamDuration } from '../models/video/video-format-utils' | 26 | import { getActivityStreamDuration } from '../models/video/video-format-utils' |
25 | import { VideoPlaylistModel } from '../models/video/video-playlist' | 27 | import { VideoPlaylistModel } from '../models/video/video-playlist' |
26 | import { MAccountActor, MChannelActor } from '../types/models' | 28 | import { MAccountActor, MChannelActor } from '../types/models' |
27 | import { mdToPlainText } from '../helpers/markdown' | 29 | import { getHTMLServerConfig } from './config' |
28 | 30 | ||
29 | type Tags = { | 31 | type Tags = { |
30 | ogType: string | 32 | ogType: string |
@@ -209,11 +211,14 @@ class ClientHtml { | |||
209 | if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] | 211 | if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] |
210 | 212 | ||
211 | const buffer = await readFile(path) | 213 | const buffer = await readFile(path) |
214 | const serverConfig = await getHTMLServerConfig() | ||
212 | 215 | ||
213 | let html = buffer.toString() | 216 | let html = buffer.toString() |
214 | html = await ClientHtml.addAsyncPluginCSS(html) | 217 | html = await ClientHtml.addAsyncPluginCSS(html) |
215 | html = ClientHtml.addCustomCSS(html) | 218 | html = ClientHtml.addCustomCSS(html) |
216 | html = ClientHtml.addTitleTag(html) | 219 | html = ClientHtml.addTitleTag(html) |
220 | html = ClientHtml.addDescriptionTag(html) | ||
221 | html = ClientHtml.addServerConfig(html, serverConfig) | ||
217 | 222 | ||
218 | ClientHtml.htmlCache[path] = html | 223 | ClientHtml.htmlCache[path] = html |
219 | 224 | ||
@@ -275,6 +280,7 @@ class ClientHtml { | |||
275 | if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] | 280 | if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] |
276 | 281 | ||
277 | const buffer = await readFile(path) | 282 | const buffer = await readFile(path) |
283 | const serverConfig = await getHTMLServerConfig() | ||
278 | 284 | ||
279 | let html = buffer.toString() | 285 | let html = buffer.toString() |
280 | 286 | ||
@@ -283,6 +289,7 @@ class ClientHtml { | |||
283 | html = ClientHtml.addFaviconContentHash(html) | 289 | html = ClientHtml.addFaviconContentHash(html) |
284 | html = ClientHtml.addLogoContentHash(html) | 290 | html = ClientHtml.addLogoContentHash(html) |
285 | html = ClientHtml.addCustomCSS(html) | 291 | html = ClientHtml.addCustomCSS(html) |
292 | html = ClientHtml.addServerConfig(html, serverConfig) | ||
286 | html = await ClientHtml.addAsyncPluginCSS(html) | 293 | html = await ClientHtml.addAsyncPluginCSS(html) |
287 | 294 | ||
288 | ClientHtml.htmlCache[path] = html | 295 | ClientHtml.htmlCache[path] = html |
@@ -355,6 +362,13 @@ class ClientHtml { | |||
355 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag) | 362 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag) |
356 | } | 363 | } |
357 | 364 | ||
365 | private static addServerConfig (htmlStringPage: string, serverConfig: HTMLServerConfig) { | ||
366 | const serverConfigString = JSON.stringify(serverConfig) | ||
367 | const configScriptTag = `<script type="application/javascript">window.PeerTubeServerConfig = '${serverConfigString}'</script>` | ||
368 | |||
369 | return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.SERVER_CONFIG, configScriptTag) | ||
370 | } | ||
371 | |||
358 | private static async addAsyncPluginCSS (htmlStringPage: string) { | 372 | private static async addAsyncPluginCSS (htmlStringPage: string) { |
359 | const globalCSSContent = await readFile(PLUGIN_GLOBAL_CSS_PATH) | 373 | const globalCSSContent = await readFile(PLUGIN_GLOBAL_CSS_PATH) |
360 | if (globalCSSContent.byteLength === 0) return htmlStringPage | 374 | if (globalCSSContent.byteLength === 0) return htmlStringPage |
diff --git a/server/lib/config.ts b/server/lib/config.ts index fed468fe1..18d49f05a 100644 --- a/server/lib/config.ts +++ b/server/lib/config.ts | |||
@@ -2,17 +2,13 @@ import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/si | |||
2 | import { getServerCommit } from '@server/helpers/utils' | 2 | import { getServerCommit } from '@server/helpers/utils' |
3 | import { CONFIG, isEmailEnabled } from '@server/initializers/config' | 3 | import { CONFIG, isEmailEnabled } from '@server/initializers/config' |
4 | import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants' | 4 | import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants' |
5 | import { RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models' | 5 | import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models' |
6 | import { Hooks } from './plugins/hooks' | 6 | import { Hooks } from './plugins/hooks' |
7 | import { PluginManager } from './plugins/plugin-manager' | 7 | import { PluginManager } from './plugins/plugin-manager' |
8 | import { getThemeOrDefault } from './plugins/theme-utils' | 8 | import { getThemeOrDefault } from './plugins/theme-utils' |
9 | import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles' | 9 | import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles' |
10 | 10 | ||
11 | let serverCommit: string | ||
12 | |||
13 | async function getServerConfig (ip?: string): Promise<ServerConfig> { | 11 | async function getServerConfig (ip?: string): Promise<ServerConfig> { |
14 | if (serverCommit === undefined) serverCommit = await getServerCommit() | ||
15 | |||
16 | const { allowed } = await Hooks.wrapPromiseFun( | 12 | const { allowed } = await Hooks.wrapPromiseFun( |
17 | isSignupAllowed, | 13 | isSignupAllowed, |
18 | { | 14 | { |
@@ -22,6 +18,23 @@ async function getServerConfig (ip?: string): Promise<ServerConfig> { | |||
22 | ) | 18 | ) |
23 | 19 | ||
24 | const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip) | 20 | const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip) |
21 | |||
22 | const signup = { | ||
23 | allowed, | ||
24 | allowedForCurrentIP, | ||
25 | requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION | ||
26 | } | ||
27 | |||
28 | const htmlConfig = await getHTMLServerConfig() | ||
29 | |||
30 | return { ...htmlConfig, signup } | ||
31 | } | ||
32 | |||
33 | // Config injected in HTML | ||
34 | let serverCommit: string | ||
35 | async function getHTMLServerConfig (): Promise<HTMLServerConfig> { | ||
36 | if (serverCommit === undefined) serverCommit = await getServerCommit() | ||
37 | |||
25 | const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) | 38 | const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) |
26 | 39 | ||
27 | return { | 40 | return { |
@@ -65,11 +78,6 @@ async function getServerConfig (ip?: string): Promise<ServerConfig> { | |||
65 | }, | 78 | }, |
66 | serverVersion: PEERTUBE_VERSION, | 79 | serverVersion: PEERTUBE_VERSION, |
67 | serverCommit, | 80 | serverCommit, |
68 | signup: { | ||
69 | allowed, | ||
70 | allowedForCurrentIP, | ||
71 | requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION | ||
72 | }, | ||
73 | transcoding: { | 81 | transcoding: { |
74 | hls: { | 82 | hls: { |
75 | enabled: CONFIG.TRANSCODING.HLS.ENABLED | 83 | enabled: CONFIG.TRANSCODING.HLS.ENABLED |
@@ -223,7 +231,8 @@ export { | |||
223 | getServerConfig, | 231 | getServerConfig, |
224 | getRegisteredThemes, | 232 | getRegisteredThemes, |
225 | getEnabledResolutions, | 233 | getEnabledResolutions, |
226 | getRegisteredPlugins | 234 | getRegisteredPlugins, |
235 | getHTMLServerConfig | ||
227 | } | 236 | } |
228 | 237 | ||
229 | // --------------------------------------------------------------------------- | 238 | // --------------------------------------------------------------------------- |
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts index ffe109c2f..3518f5c02 100644 --- a/server/models/abuse/abuse.ts +++ b/server/models/abuse/abuse.ts | |||
@@ -16,8 +16,7 @@ import { | |||
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' | 18 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' |
19 | import { AttributesOnly } from '@shared/core-utils' | 19 | import { abusePredefinedReasonsMap, AttributesOnly } from '@shared/core-utils' |
20 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | ||
21 | import { | 20 | import { |
22 | AbuseFilter, | 21 | AbuseFilter, |
23 | AbuseObject, | 22 | AbuseObject, |
diff --git a/server/tests/client.ts b/server/tests/client.ts index 3c99bcd1f..a385edd26 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -3,7 +3,7 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import * as request from 'supertest' | 5 | import * as request from 'supertest' |
6 | import { Account, VideoPlaylistPrivacy } from '@shared/models' | 6 | import { Account, HTMLServerConfig, ServerConfig, VideoPlaylistPrivacy } from '@shared/models' |
7 | import { | 7 | import { |
8 | addVideoInPlaylist, | 8 | addVideoInPlaylist, |
9 | cleanupTests, | 9 | cleanupTests, |
@@ -11,6 +11,7 @@ import { | |||
11 | doubleFollow, | 11 | doubleFollow, |
12 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
13 | getAccount, | 13 | getAccount, |
14 | getConfig, | ||
14 | getCustomConfig, | 15 | getCustomConfig, |
15 | getVideosList, | 16 | getVideosList, |
16 | makeHTMLRequest, | 17 | makeHTMLRequest, |
@@ -25,13 +26,17 @@ import { | |||
25 | waitJobs | 26 | waitJobs |
26 | } from '../../shared/extra-utils' | 27 | } from '../../shared/extra-utils' |
27 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 28 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
29 | import { omit } from 'lodash' | ||
28 | 30 | ||
29 | const expect = chai.expect | 31 | const expect = chai.expect |
30 | 32 | ||
31 | function checkIndexTags (html: string, title: string, description: string, css: string) { | 33 | function checkIndexTags (html: string, title: string, description: string, css: string, config: ServerConfig) { |
32 | expect(html).to.contain('<title>' + title + '</title>') | 34 | expect(html).to.contain('<title>' + title + '</title>') |
33 | expect(html).to.contain('<meta name="description" content="' + description + '" />') | 35 | expect(html).to.contain('<meta name="description" content="' + description + '" />') |
34 | expect(html).to.contain('<style class="custom-css-style">' + css + '</style>') | 36 | expect(html).to.contain('<style class="custom-css-style">' + css + '</style>') |
37 | |||
38 | const htmlConfig: HTMLServerConfig = omit(config, 'signup') | ||
39 | expect(html).to.contain(`<script type="application/javascript">window.PeerTubeServerConfig = '${JSON.stringify(htmlConfig)}'</script>`) | ||
35 | } | 40 | } |
36 | 41 | ||
37 | describe('Test a client controllers', function () { | 42 | describe('Test a client controllers', function () { |
@@ -296,10 +301,11 @@ describe('Test a client controllers', function () { | |||
296 | describe('Index HTML', function () { | 301 | describe('Index HTML', function () { |
297 | 302 | ||
298 | it('Should have valid index html tags (title, description...)', async function () { | 303 | it('Should have valid index html tags (title, description...)', async function () { |
304 | const resConfig = await getConfig(servers[0].url) | ||
299 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | 305 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') |
300 | 306 | ||
301 | const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' | 307 | const description = 'PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.' |
302 | checkIndexTags(res.text, 'PeerTube', description, '') | 308 | checkIndexTags(res.text, 'PeerTube', description, '', resConfig.body) |
303 | }) | 309 | }) |
304 | 310 | ||
305 | it('Should update the customized configuration and have the correct index html tags', async function () { | 311 | it('Should update the customized configuration and have the correct index html tags', async function () { |
@@ -318,15 +324,17 @@ describe('Test a client controllers', function () { | |||
318 | } | 324 | } |
319 | }) | 325 | }) |
320 | 326 | ||
327 | const resConfig = await getConfig(servers[0].url) | ||
321 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | 328 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') |
322 | 329 | ||
323 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') | 330 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body) |
324 | }) | 331 | }) |
325 | 332 | ||
326 | it('Should have valid index html updated tags (title, description...)', async function () { | 333 | it('Should have valid index html updated tags (title, description...)', async function () { |
334 | const resConfig = await getConfig(servers[0].url) | ||
327 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') | 335 | const res = await makeHTMLRequest(servers[0].url, '/videos/trending') |
328 | 336 | ||
329 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }') | 337 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body) |
330 | }) | 338 | }) |
331 | 339 | ||
332 | it('Should use the original video URL for the canonical tag', async function () { | 340 | it('Should use the original video URL for the canonical tag', async function () { |
@@ -350,6 +358,16 @@ describe('Test a client controllers', function () { | |||
350 | }) | 358 | }) |
351 | }) | 359 | }) |
352 | 360 | ||
361 | describe('Embed HTML', function () { | ||
362 | |||
363 | it('Should have the correct embed html tags', async function () { | ||
364 | const resConfig = await getConfig(servers[0].url) | ||
365 | const res = await makeHTMLRequest(servers[0].url, servers[0].video.embedPath) | ||
366 | |||
367 | checkIndexTags(res.text, 'PeerTube updated', 'my short description', 'body { background-color: red; }', resConfig.body) | ||
368 | }) | ||
369 | }) | ||
370 | |||
353 | after(async function () { | 371 | after(async function () { |
354 | await cleanupTests(servers) | 372 | await cleanupTests(servers) |
355 | }) | 373 | }) |