express-init.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import { themesRootPath as presetThemesRootPath } from '@growi/preset-themes';
  2. import csrf from 'csurf';
  3. import qs from 'qs';
  4. import { PLUGIN_EXPRESS_STATIC_DIR, PLUGIN_STORING_PATH } from '~/features/growi-plugin/server/consts';
  5. import loggerFactory from '~/utils/logger';
  6. import { resolveFromRoot } from '~/utils/project-dir-utils';
  7. import registerSafeRedirectFactory from '../middlewares/safe-redirect';
  8. const logger = loggerFactory('growi:crowi:express-init');
  9. /** @param {import('./index').default} crowi Crowi instance */
  10. module.exports = function(crowi, app) {
  11. const express = require('express');
  12. const compression = require('compression');
  13. const helmet = require('helmet');
  14. const bodyParser = require('body-parser');
  15. const cookieParser = require('cookie-parser');
  16. const methodOverride = require('method-override');
  17. const passport = require('passport');
  18. const expressSession = require('express-session');
  19. const flash = require('connect-flash');
  20. const mongoSanitize = require('express-mongo-sanitize');
  21. const registerSafeRedirect = registerSafeRedirectFactory();
  22. const injectCurrentuserToLocalvars = require('../middlewares/inject-currentuser-to-localvars')();
  23. const autoReconnectToS2sMsgServer = require('../middlewares/auto-reconnect-to-s2s-msg-server')(crowi);
  24. const avoidSessionRoutes = require('../routes/avoid-session-routes');
  25. const env = crowi.node_env;
  26. // see: https://qiita.com/nazomikan/items/9458d591a4831480098d
  27. // Cannot set a custom query parser after app.use() has been called: https://github.com/expressjs/express/issues/3454
  28. app.set('query parser', str => qs.parse(str, { arrayLimit: Infinity }));
  29. app.use(compression());
  30. const { configManager } = crowi;
  31. const trustProxyBool = configManager.getConfig('security:trustProxyBool');
  32. const trustProxyCsv = configManager.getConfig('security:trustProxyCsv');
  33. const trustProxyHops = configManager.getConfig('security:trustProxyHops');
  34. const trustProxy = trustProxyBool ?? trustProxyCsv ?? trustProxyHops;
  35. try {
  36. if (trustProxy != null) {
  37. const isNotSpec = [trustProxyBool, trustProxyCsv, trustProxyHops].filter(trustProxy => trustProxy != null).length !== 1;
  38. if (isNotSpec) {
  39. // eslint-disable-next-line max-len
  40. logger.warn(`If more than one TRUST_PROXY_ ~ environment variable is set, the values are set in the following order of inequality size (BOOL > CSV > HOPS) first. Set value: ${trustProxy}`);
  41. }
  42. app.set('trust proxy', trustProxy);
  43. }
  44. }
  45. catch (err) {
  46. logger.error(err);
  47. }
  48. app.use(helmet({
  49. contentSecurityPolicy: false,
  50. expectCt: false,
  51. referrerPolicy: false,
  52. permittedCrossDomainPolicies: false,
  53. }));
  54. app.use((req, res, next) => {
  55. const now = new Date();
  56. // for datez
  57. app.set('tzoffset', crowi.appService.getTzoffset());
  58. res.locals.req = req;
  59. res.locals.baseUrl = crowi.growiInfoService.getSiteUrl();
  60. res.locals.env = env;
  61. res.locals.now = now;
  62. next();
  63. });
  64. app.set('port', crowi.port);
  65. const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
  66. app.use(express.static(crowi.publicDir, staticOption));
  67. app.use('/static/preset-themes', express.static(
  68. resolveFromRoot(`node_modules/@growi/preset-themes/${presetThemesRootPath}`),
  69. ));
  70. app.use(PLUGIN_EXPRESS_STATIC_DIR, express.static(PLUGIN_STORING_PATH));
  71. app.use(methodOverride());
  72. // inject rawBody to req
  73. app.use((req, res, next) => {
  74. if (!req.is('multipart/form-data')) {
  75. req.rawBody = '';
  76. req.on('data', (chunk) => {
  77. req.rawBody += chunk;
  78. });
  79. }
  80. next();
  81. });
  82. app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
  83. app.use(bodyParser.json({ limit: '50mb' }));
  84. app.use(cookieParser());
  85. // configure express-session
  86. const sessionMiddleware = expressSession(crowi.sessionConfig);
  87. app.use((req, res, next) => {
  88. // test whether the route is listed in avoidSessionRoutes
  89. for (const regex of avoidSessionRoutes) {
  90. if (regex.test(req.path)) {
  91. return next();
  92. }
  93. }
  94. sessionMiddleware(req, res, next);
  95. });
  96. // csurf should be initialized after express-session
  97. // default methods + PUT. See: https://expressjs.com/en/resources/middleware/csurf.html#ignoremethods
  98. app.use(csrf({ ignoreMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'DELETE'], cookie: false }));
  99. // passport
  100. logger.debug('initialize Passport');
  101. app.use(passport.initialize());
  102. app.use(passport.session());
  103. app.use(flash());
  104. app.use(mongoSanitize());
  105. app.use(registerSafeRedirect);
  106. app.use(injectCurrentuserToLocalvars);
  107. app.use(autoReconnectToS2sMsgServer);
  108. };