]>
Commit | Line | Data |
---|---|---|
41fb13c3 | 1 | import express from 'express' |
b5f919ac | 2 | import { join } from 'path' |
f43db2f4 C |
3 | import { logger } from '@server/helpers/logger' |
4 | import { optionalAuthenticate } from '@server/middlewares/auth' | |
2d53be02 | 5 | import { getCompleteLocale, is18nLocale } from '../../shared/core-utils/i18n' |
c0e8b12e | 6 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' |
b5f919ac | 7 | import { PluginType } from '../../shared/models/plugins/plugin.type' |
9452d4fd | 8 | import { isProdInstance } from '../helpers/core-utils' |
f43db2f4 C |
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' | |
a8b666e9 C |
13 | |
14 | const sendFileOptions = { | |
15 | maxAge: '30 days', | |
9452d4fd | 16 | immutable: isProdInstance() |
a8b666e9 | 17 | } |
345da516 C |
18 | |
19 | const pluginsRouter = express.Router() | |
20 | ||
b5f919ac | 21 | pluginsRouter.get('/plugins/global.css', |
2c053942 | 22 | servePluginGlobalCSS |
345da516 C |
23 | ) |
24 | ||
d75db01f C |
25 | pluginsRouter.get('/plugins/translations/:locale.json', |
26 | getPluginTranslations | |
27 | ) | |
28 | ||
4a8d113b C |
29 | pluginsRouter.get('/plugins/:pluginName/:pluginVersion/auth/:authName', |
30 | getPluginValidator(PluginType.PLUGIN), | |
31 | getExternalAuthValidator, | |
32 | handleAuthInPlugin | |
33 | ) | |
34 | ||
b5f919ac | 35 | pluginsRouter.get('/plugins/:pluginName/:pluginVersion/static/:staticEndpoint(*)', |
5e2b2e27 C |
36 | getPluginValidator(PluginType.PLUGIN), |
37 | pluginStaticDirectoryValidator, | |
345da516 C |
38 | servePluginStaticDirectory |
39 | ) | |
40 | ||
b5f919ac | 41 | pluginsRouter.get('/plugins/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)', |
5e2b2e27 C |
42 | getPluginValidator(PluginType.PLUGIN), |
43 | pluginStaticDirectoryValidator, | |
345da516 C |
44 | servePluginClientScripts |
45 | ) | |
46 | ||
5e2b2e27 C |
47 | pluginsRouter.use('/plugins/:pluginName/router', |
48 | getPluginValidator(PluginType.PLUGIN, false), | |
f17faefb | 49 | optionalAuthenticate, |
5e2b2e27 C |
50 | servePluginCustomRoutes |
51 | ) | |
52 | ||
53 | pluginsRouter.use('/plugins/:pluginName/:pluginVersion/router', | |
54 | getPluginValidator(PluginType.PLUGIN), | |
f17faefb | 55 | optionalAuthenticate, |
5e2b2e27 C |
56 | servePluginCustomRoutes |
57 | ) | |
58 | ||
b5f919ac | 59 | pluginsRouter.get('/themes/:pluginName/:pluginVersion/static/:staticEndpoint(*)', |
5e2b2e27 C |
60 | getPluginValidator(PluginType.THEME), |
61 | pluginStaticDirectoryValidator, | |
b5f919ac C |
62 | servePluginStaticDirectory |
63 | ) | |
64 | ||
65 | pluginsRouter.get('/themes/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)', | |
5e2b2e27 C |
66 | getPluginValidator(PluginType.THEME), |
67 | pluginStaticDirectoryValidator, | |
b5f919ac C |
68 | servePluginClientScripts |
69 | ) | |
70 | ||
71 | pluginsRouter.get('/themes/:themeName/:themeVersion/css/:staticEndpoint(*)', | |
72 | serveThemeCSSValidator, | |
73 | serveThemeCSSDirectory | |
74 | ) | |
75 | ||
345da516 C |
76 | // --------------------------------------------------------------------------- |
77 | ||
78 | export { | |
79 | pluginsRouter | |
80 | } | |
81 | ||
82 | // --------------------------------------------------------------------------- | |
83 | ||
2c053942 | 84 | function servePluginGlobalCSS (req: express.Request, res: express.Response) { |
a8b666e9 C |
85 | // Only cache requests that have a ?hash=... query param |
86 | const globalCSSOptions = req.query.hash | |
87 | ? sendFileOptions | |
88 | : {} | |
89 | ||
90 | return res.sendFile(PLUGIN_GLOBAL_CSS_PATH, globalCSSOptions) | |
2c053942 C |
91 | } |
92 | ||
d75db01f C |
93 | function getPluginTranslations (req: express.Request, res: express.Response) { |
94 | const locale = req.params.locale | |
95 | ||
96 | if (is18nLocale(locale)) { | |
97 | const completeLocale = getCompleteLocale(locale) | |
98 | const json = PluginManager.Instance.getTranslations(completeLocale) | |
99 | ||
100 | return res.json(json) | |
101 | } | |
102 | ||
76148b27 | 103 | return res.status(HttpStatusCode.NOT_FOUND_404).end() |
d75db01f C |
104 | } |
105 | ||
345da516 C |
106 | function servePluginStaticDirectory (req: express.Request, res: express.Response) { |
107 | const plugin: RegisteredPlugin = res.locals.registeredPlugin | |
108 | const staticEndpoint = req.params.staticEndpoint | |
109 | ||
2c053942 C |
110 | const [ directory, ...file ] = staticEndpoint.split('/') |
111 | ||
112 | const staticPath = plugin.staticDirs[directory] | |
76148b27 | 113 | if (!staticPath) return res.status(HttpStatusCode.NOT_FOUND_404).end() |
345da516 | 114 | |
2c053942 | 115 | const filepath = file.join('/') |
a8b666e9 | 116 | return res.sendFile(join(plugin.path, staticPath, filepath), sendFileOptions) |
345da516 C |
117 | } |
118 | ||
5e2b2e27 C |
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) | |
122 | ||
76148b27 | 123 | if (!router) return res.status(HttpStatusCode.NOT_FOUND_404).end() |
5e2b2e27 C |
124 | |
125 | return router(req, res, next) | |
126 | } | |
127 | ||
345da516 C |
128 | function servePluginClientScripts (req: express.Request, res: express.Response) { |
129 | const plugin: RegisteredPlugin = res.locals.registeredPlugin | |
130 | const staticEndpoint = req.params.staticEndpoint | |
131 | ||
2c053942 | 132 | const file = plugin.clientScripts[staticEndpoint] |
76148b27 | 133 | if (!file) return res.status(HttpStatusCode.NOT_FOUND_404).end() |
2c053942 | 134 | |
a8b666e9 | 135 | return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions) |
345da516 | 136 | } |
b5f919ac C |
137 | |
138 | function serveThemeCSSDirectory (req: express.Request, res: express.Response) { | |
139 | const plugin: RegisteredPlugin = res.locals.registeredPlugin | |
140 | const staticEndpoint = req.params.staticEndpoint | |
141 | ||
142 | if (plugin.css.includes(staticEndpoint) === false) { | |
76148b27 | 143 | return res.status(HttpStatusCode.NOT_FOUND_404).end() |
b5f919ac C |
144 | } |
145 | ||
a8b666e9 | 146 | return res.sendFile(join(plugin.path, staticEndpoint), sendFileOptions) |
b5f919ac | 147 | } |
4a8d113b C |
148 | |
149 | function handleAuthInPlugin (req: express.Request, res: express.Response) { | |
150 | const authOptions = res.locals.externalAuth | |
151 | ||
152 | try { | |
153 | logger.debug('Forwarding auth plugin request in %s of plugin %s.', authOptions.authName, res.locals.registeredPlugin.npmName) | |
154 | authOptions.onAuthRequest(req, res) | |
155 | } catch (err) { | |
dadc90bc | 156 | logger.error('Forward request error in auth %s of plugin %s.', authOptions.authName, res.locals.registeredPlugin.npmName, { err }) |
4a8d113b C |
157 | } |
158 | } |