1 import express from 'express'
2 import { join } from 'path'
3 import { logger } from '@server/helpers/logger'
4 import { optionalAuthenticate } from '@server/middlewares/auth'
5 import { getCompleteLocale, is18nLocale } from '../../shared/core-utils/i18n'
6 import { HttpStatusCode } from '../../shared/models/http/http-error-codes'
7 import { PluginType } from '../../shared/models/plugins/plugin.type'
8 import { isProdInstance } from '../helpers/core-utils'
9 import { PLUGIN_GLOBAL_CSS_PATH } from '../initializers/constants'
10 import { PluginManager, RegisteredPlugin } from '../lib/plugins/plugin-manager'
11 import { getExternalAuthValidator, getPluginValidator, pluginStaticDirectoryValidator } from '../middlewares/validators/plugins'
12 import { serveThemeCSSValidator } from '../middlewares/validators/themes'
14 const sendFileOptions = {
16 immutable: isProdInstance()
19 const pluginsRouter = express.Router()
21 pluginsRouter.get('/plugins/global.css',
25 pluginsRouter.get('/plugins/translations/:locale.json',
29 pluginsRouter.get('/plugins/:pluginName/:pluginVersion/auth/:authName',
30 getPluginValidator(PluginType.PLUGIN),
31 getExternalAuthValidator,
35 pluginsRouter.get('/plugins/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
36 getPluginValidator(PluginType.PLUGIN),
37 pluginStaticDirectoryValidator,
38 servePluginStaticDirectory
41 pluginsRouter.get('/plugins/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
42 getPluginValidator(PluginType.PLUGIN),
43 pluginStaticDirectoryValidator,
44 servePluginClientScripts
47 pluginsRouter.use('/plugins/:pluginName/router',
48 getPluginValidator(PluginType.PLUGIN, false),
50 servePluginCustomRoutes
53 pluginsRouter.use('/plugins/:pluginName/:pluginVersion/router',
54 getPluginValidator(PluginType.PLUGIN),
56 servePluginCustomRoutes
59 pluginsRouter.get('/themes/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
60 getPluginValidator(PluginType.THEME),
61 pluginStaticDirectoryValidator,
62 servePluginStaticDirectory
65 pluginsRouter.get('/themes/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
66 getPluginValidator(PluginType.THEME),
67 pluginStaticDirectoryValidator,
68 servePluginClientScripts
71 pluginsRouter.get('/themes/:themeName/:themeVersion/css/:staticEndpoint(*)',
72 serveThemeCSSValidator,
73 serveThemeCSSDirectory
76 // ---------------------------------------------------------------------------
82 // ---------------------------------------------------------------------------
84 function servePluginGlobalCSS (req: express.Request, res: express.Response) {
85 // Only cache requests that have a ?hash=... query param
86 const globalCSSOptions = req.query.hash
90 return res.sendFile(PLUGIN_GLOBAL_CSS_PATH, globalCSSOptions)
93 function getPluginTranslations (req: express.Request, res: express.Response) {
94 const locale = req.params.locale
96 if (is18nLocale(locale)) {
97 const completeLocale = getCompleteLocale(locale)
98 const json = PluginManager.Instance.getTranslations(completeLocale)
100 return res.json(json)
103 return res.status(HttpStatusCode.NOT_FOUND_404).end()
106 function servePluginStaticDirectory (req: express.Request, res: express.Response) {
107 const plugin: RegisteredPlugin = res.locals.registeredPlugin
108 const staticEndpoint = req.params.staticEndpoint
110 const [ directory, ...file ] = staticEndpoint.split('/')
112 const staticPath = plugin.staticDirs[directory]
113 if (!staticPath) return res.status(HttpStatusCode.NOT_FOUND_404).end()
115 const filepath = file.join('/')
116 return res.sendFile(join(plugin.path, staticPath, filepath), sendFileOptions)
119 function servePluginCustomRoutes (req: express.Request, res: express.Response, next: express.NextFunction) {
120 const plugin: RegisteredPlugin = res.locals.registeredPlugin
121 const router = PluginManager.Instance.getRouter(plugin.npmName)
123 if (!router) return res.status(HttpStatusCode.NOT_FOUND_404).end()
125 return router(req, res, next)
128 function servePluginClientScripts (req: express.Request, res: express.Response) {
129 const plugin: RegisteredPlugin = res.locals.registeredPlugin
130 const staticEndpoint = req.params.staticEndpoint
132 const file = plugin.clientScripts[staticEndpoint]
133 if (!file) return res.status(HttpStatusCode.NOT_FOUND_404).end()
135 return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions)
138 function serveThemeCSSDirectory (req: express.Request, res: express.Response) {
139 const plugin: RegisteredPlugin = res.locals.registeredPlugin
140 const staticEndpoint = req.params.staticEndpoint
142 if (plugin.css.includes(staticEndpoint) === false) {
143 return res.status(HttpStatusCode.NOT_FOUND_404).end()
146 return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions)
149 function handleAuthInPlugin (req: express.Request, res: express.Response) {
150 const authOptions = res.locals.externalAuth
153 logger.debug('Forwarding auth plugin request in %s of plugin %s.', authOptions.authName, res.locals.registeredPlugin.npmName)
154 authOptions.onAuthRequest(req, res)
156 logger.error('Forward request error in auth %s of plugin %s.', authOptions.authName, res.locals.registeredPlugin.npmName, { err })