aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/api/videos/blacklist.ts6
-rw-r--r--server/controllers/plugins.ts19
-rw-r--r--server/helpers/utils.ts12
-rw-r--r--server/lib/client-html.ts14
-rw-r--r--server/lib/plugins/plugin-manager.ts3
-rw-r--r--shared/models/plugins/server-hook.model.ts2
6 files changed, 36 insertions, 20 deletions
diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts
index 27dcfb761..0ec518e0d 100644
--- a/server/controllers/api/videos/blacklist.ts
+++ b/server/controllers/api/videos/blacklist.ts
@@ -100,13 +100,13 @@ async function updateVideoBlacklistController (req: express.Request, res: expres
100 return res.type('json').status(204).end() 100 return res.type('json').status(204).end()
101} 101}
102 102
103async function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) { 103async function listBlacklist (req: express.Request, res: express.Response) {
104 const resultList = await VideoBlacklistModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.type) 104 const resultList = await VideoBlacklistModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.type)
105 105
106 return res.json(getFormattedObjects<VideoBlacklist, VideoBlacklistModel>(resultList.data, resultList.total)) 106 return res.json(getFormattedObjects(resultList.data, resultList.total))
107} 107}
108 108
109async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { 109async function removeVideoFromBlacklistController (req: express.Request, res: express.Response) {
110 const videoBlacklist = res.locals.videoBlacklist 110 const videoBlacklist = res.locals.videoBlacklist
111 const video = res.locals.video 111 const video = res.locals.video
112 112
diff --git a/server/controllers/plugins.ts b/server/controllers/plugins.ts
index f255d13e8..f5285ba3a 100644
--- a/server/controllers/plugins.ts
+++ b/server/controllers/plugins.ts
@@ -5,6 +5,12 @@ import { RegisteredPlugin } from '../lib/plugins/plugin-manager'
5import { servePluginStaticDirectoryValidator } from '../middlewares/validators/plugins' 5import { servePluginStaticDirectoryValidator } from '../middlewares/validators/plugins'
6import { serveThemeCSSValidator } from '../middlewares/validators/themes' 6import { serveThemeCSSValidator } from '../middlewares/validators/themes'
7import { PluginType } from '../../shared/models/plugins/plugin.type' 7import { PluginType } from '../../shared/models/plugins/plugin.type'
8import { isTestInstance } from '../helpers/core-utils'
9
10const sendFileOptions = {
11 maxAge: '30 days',
12 immutable: !isTestInstance()
13}
8 14
9const pluginsRouter = express.Router() 15const pluginsRouter = express.Router()
10 16
@@ -46,7 +52,12 @@ export {
46// --------------------------------------------------------------------------- 52// ---------------------------------------------------------------------------
47 53
48function servePluginGlobalCSS (req: express.Request, res: express.Response) { 54function servePluginGlobalCSS (req: express.Request, res: express.Response) {
49 return res.sendFile(PLUGIN_GLOBAL_CSS_PATH) 55 // Only cache requests that have a ?hash=... query param
56 const globalCSSOptions = req.query.hash
57 ? sendFileOptions
58 : {}
59
60 return res.sendFile(PLUGIN_GLOBAL_CSS_PATH, globalCSSOptions)
50} 61}
51 62
52function servePluginStaticDirectory (req: express.Request, res: express.Response) { 63function servePluginStaticDirectory (req: express.Request, res: express.Response) {
@@ -61,7 +72,7 @@ function servePluginStaticDirectory (req: express.Request, res: express.Response
61 } 72 }
62 73
63 const filepath = file.join('/') 74 const filepath = file.join('/')
64 return res.sendFile(join(plugin.path, staticPath, filepath)) 75 return res.sendFile(join(plugin.path, staticPath, filepath), sendFileOptions)
65} 76}
66 77
67function servePluginClientScripts (req: express.Request, res: express.Response) { 78function servePluginClientScripts (req: express.Request, res: express.Response) {
@@ -73,7 +84,7 @@ function servePluginClientScripts (req: express.Request, res: express.Response)
73 return res.sendStatus(404) 84 return res.sendStatus(404)
74 } 85 }
75 86
76 return res.sendFile(join(plugin.path, staticEndpoint)) 87 return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions)
77} 88}
78 89
79function serveThemeCSSDirectory (req: express.Request, res: express.Response) { 90function serveThemeCSSDirectory (req: express.Request, res: express.Response) {
@@ -84,5 +95,5 @@ function serveThemeCSSDirectory (req: express.Request, res: express.Response) {
84 return res.sendStatus(404) 95 return res.sendStatus(404)
85 } 96 }
86 97
87 return res.sendFile(join(plugin.path, staticEndpoint)) 98 return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions)
88} 99}
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts
index 94ceb15e0..1464b1477 100644
--- a/server/helpers/utils.ts
+++ b/server/helpers/utils.ts
@@ -19,18 +19,14 @@ async function generateRandomString (size: number) {
19 return raw.toString('hex') 19 return raw.toString('hex')
20} 20}
21 21
22interface FormattableToJSON { toFormattedJSON (args?: any) } 22interface FormattableToJSON<U, V> { toFormattedJSON (args?: U): V }
23function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], objectsTotal: number, formattedArg?: any) { 23function getFormattedObjects<U, V, T extends FormattableToJSON<U, V>> (objects: T[], objectsTotal: number, formattedArg?: U) {
24 const formattedObjects: U[] = [] 24 const formattedObjects = objects.map(o => o.toFormattedJSON(formattedArg))
25
26 objects.forEach(object => {
27 formattedObjects.push(object.toFormattedJSON(formattedArg))
28 })
29 25
30 return { 26 return {
31 total: objectsTotal, 27 total: objectsTotal,
32 data: formattedObjects 28 data: formattedObjects
33 } as ResultList<U> 29 } as ResultList<V>
34} 30}
35 31
36const getServerActor = memoizee(async function () { 32const getServerActor = memoizee(async function () {
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index ccc963514..1e7897220 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -1,8 +1,8 @@
1import * as express from 'express' 1import * as express from 'express'
2import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/models/i18n/i18n' 2import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/models/i18n/i18n'
3import { CUSTOM_HTML_TAG_COMMENTS, EMBED_SIZE, WEBSERVER } from '../initializers/constants' 3import { CUSTOM_HTML_TAG_COMMENTS, EMBED_SIZE, PLUGIN_GLOBAL_CSS_PATH, WEBSERVER } from '../initializers/constants'
4import { join } from 'path' 4import { join } from 'path'
5import { escapeHTML } from '../helpers/core-utils' 5import { escapeHTML, sha256 } from '../helpers/core-utils'
6import { VideoModel } from '../models/video/video' 6import { VideoModel } from '../models/video/video'
7import * as validator from 'validator' 7import * as validator from 'validator'
8import { VideoPrivacy } from '../../shared/models/videos' 8import { VideoPrivacy } from '../../shared/models/videos'
@@ -92,7 +92,7 @@ export class ClientHtml {
92 let html = buffer.toString() 92 let html = buffer.toString()
93 93
94 html = ClientHtml.addCustomCSS(html) 94 html = ClientHtml.addCustomCSS(html)
95 html = ClientHtml.addPluginCSS(html) 95 html = await ClientHtml.addAsyncPluginCSS(html)
96 96
97 ClientHtml.htmlCache[ path ] = html 97 ClientHtml.htmlCache[ path ] = html
98 98
@@ -144,8 +144,12 @@ export class ClientHtml {
144 return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag) 144 return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag)
145 } 145 }
146 146
147 private static addPluginCSS (htmlStringPage: string) { 147 private static async addAsyncPluginCSS (htmlStringPage: string) {
148 const linkTag = `<link rel="stylesheet" href="/plugins/global.css" />` 148 const globalCSSContent = await readFile(PLUGIN_GLOBAL_CSS_PATH)
149 if (!globalCSSContent) return htmlStringPage
150
151 const fileHash = sha256(globalCSSContent)
152 const linkTag = `<link rel="stylesheet" href="/plugins/global.css?hash=${fileHash}" />`
149 153
150 return htmlStringPage.replace('</head>', linkTag + '</head>') 154 return htmlStringPage.replace('</head>', linkTag + '</head>')
151 } 155 }
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts
index cfe63e50d..c0b49c7c7 100644
--- a/server/lib/plugins/plugin-manager.ts
+++ b/server/lib/plugins/plugin-manager.ts
@@ -17,6 +17,7 @@ import { ServerHook, ServerHookName, serverHookObject } from '../../../shared/mo
17import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks' 17import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks'
18import { RegisterOptions } from '../../typings/plugins/register-options.model' 18import { RegisterOptions } from '../../typings/plugins/register-options.model'
19import { PluginLibrary } from '../../typings/plugins' 19import { PluginLibrary } from '../../typings/plugins'
20import { ClientHtml } from '../client-html'
20 21
21export interface RegisteredPlugin { 22export interface RegisteredPlugin {
22 npmName: string 23 npmName: string
@@ -323,6 +324,8 @@ export class PluginManager implements ServerHook {
323 for (const cssPath of cssRelativePaths) { 324 for (const cssPath of cssRelativePaths) {
324 await this.concatFiles(join(pluginPath, cssPath), PLUGIN_GLOBAL_CSS_PATH) 325 await this.concatFiles(join(pluginPath, cssPath), PLUGIN_GLOBAL_CSS_PATH)
325 } 326 }
327
328 ClientHtml.invalidCache()
326 } 329 }
327 330
328 private concatFiles (input: string, output: string) { 331 private concatFiles (input: string, output: string) {
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts
index f53e0ce59..fc4c51160 100644
--- a/shared/models/plugins/server-hook.model.ts
+++ b/shared/models/plugins/server-hook.model.ts
@@ -1,3 +1,5 @@
1// {hookType}:{api?}.{location}.{subLocation?}.{actionType}.{target}
2
1export const serverFilterHookObject = { 3export const serverFilterHookObject = {
2 'filter:api.videos.list.params': true, 4 'filter:api.videos.list.params': true,
3 'filter:api.videos.list.result': true, 5 'filter:api.videos.list.result': true,