express-init.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import csrf from 'csurf';
  2. import mongoose from 'mongoose';
  3. import { i18n, localePath } from '^/config/next-i18next.config';
  4. import loggerFactory from '~/utils/logger';
  5. const logger = loggerFactory('growi:crowi:express-init');
  6. module.exports = function(crowi, app) {
  7. const debug = require('debug')('growi:crowi:express-init');
  8. const path = require('path');
  9. const express = require('express');
  10. const compression = require('compression');
  11. const helmet = require('helmet');
  12. const bodyParser = require('body-parser');
  13. const cookieParser = require('cookie-parser');
  14. const methodOverride = require('method-override');
  15. const passport = require('passport');
  16. const expressSession = require('express-session');
  17. const flash = require('connect-flash');
  18. const mongoSanitize = require('express-mongo-sanitize');
  19. const swig = require('swig-templates');
  20. const webpackAssets = require('express-webpack-assets');
  21. // const i18next = require('i18next');
  22. // const i18nFsBackend = require('i18next-node-fs-backend');
  23. // const i18nSprintf = require('i18next-sprintf-postprocessor');
  24. // const i18nMiddleware = require('i18next-express-middleware');
  25. const promster = require('../middlewares/promster')(crowi, app);
  26. const registerSafeRedirect = require('../middlewares/safe-redirect')();
  27. const injectCurrentuserToLocalvars = require('../middlewares/inject-currentuser-to-localvars')();
  28. const autoReconnectToS2sMsgServer = require('../middlewares/auto-reconnect-to-s2s-msg-server')(crowi);
  29. const avoidSessionRoutes = require('../routes/avoid-session-routes');
  30. // const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
  31. const env = crowi.node_env;
  32. // const lngDetector = new i18nMiddleware.LanguageDetector();
  33. // lngDetector.addDetector(i18nUserSettingDetector);
  34. // i18next
  35. // .use(lngDetector)
  36. // .use(i18nFsBackend)
  37. // .use(i18nSprintf)
  38. // .init({
  39. // // debug: true,
  40. // fallbackLng: ['en_US'],
  41. // whitelist: i18n.locales,
  42. // backend: {
  43. // loadPath: `${localePath}/{{lng}}/translation.json`,
  44. // },
  45. // detection: {
  46. // order: ['userSettingDetector', 'header', 'navigator'],
  47. // },
  48. // overloadTranslationOptionHandler: i18nSprintf.overloadTranslationOptionHandler,
  49. // // change nsSeparator from ':' to '::' because ':' is used in config keys and these are used in i18n keys
  50. // nsSeparator: '::',
  51. // });
  52. app.use(compression());
  53. const { configManager } = crowi;
  54. const trustProxyBool = configManager.getConfig('crowi', 'security:trustProxyBool');
  55. const trustProxyCsv = configManager.getConfig('crowi', 'security:trustProxyCsv');
  56. const trustProxyHops = configManager.getConfig('crowi', 'security:trustProxyHops');
  57. const trustProxy = trustProxyBool ?? trustProxyCsv ?? trustProxyHops;
  58. try {
  59. if (trustProxy != null) {
  60. const isNotSpec = [trustProxyBool, trustProxyCsv, trustProxyHops].filter(trustProxy => trustProxy != null).length !== 1;
  61. if (isNotSpec) {
  62. // eslint-disable-next-line max-len
  63. 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}`);
  64. }
  65. app.set('trust proxy', trustProxy);
  66. }
  67. }
  68. catch (err) {
  69. logger.error(err);
  70. }
  71. app.use(helmet({
  72. contentSecurityPolicy: false,
  73. expectCt: false,
  74. referrerPolicy: false,
  75. permittedCrossDomainPolicies: false,
  76. }));
  77. app.use((req, res, next) => {
  78. const now = new Date();
  79. // for datez
  80. const Page = crowi.model('Page');
  81. const User = crowi.model('User');
  82. const Config = mongoose.model('Config');
  83. app.set('tzoffset', crowi.appService.getTzoffset());
  84. res.locals.req = req;
  85. res.locals.baseUrl = crowi.appService.getSiteUrl();
  86. res.locals.env = env;
  87. res.locals.now = now;
  88. res.locals.local_config = Config.getLocalconfig(crowi); // config for browser context
  89. next();
  90. });
  91. app.set('port', crowi.port);
  92. const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
  93. app.use(express.static(crowi.publicDir, staticOption));
  94. app.use('/plugins', express.static(path.resolve(__dirname, '../../../tmp/plugins')));
  95. app.engine('html', swig.renderFile);
  96. // app.set('view cache', false); // Default: true in production, otherwise undefined. -- 2017.07.04 Yuki Takei
  97. app.set('view engine', 'html');
  98. app.set('views', crowi.viewsDir);
  99. app.use(methodOverride());
  100. // inject rawBody to req
  101. app.use((req, res, next) => {
  102. if (!req.is('multipart/form-data')) {
  103. req.rawBody = '';
  104. req.on('data', (chunk) => {
  105. req.rawBody += chunk;
  106. });
  107. }
  108. next();
  109. });
  110. app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
  111. app.use(bodyParser.json({ limit: '50mb' }));
  112. app.use(cookieParser());
  113. // configure express-session
  114. const sessionMiddleware = expressSession(crowi.sessionConfig);
  115. app.use((req, res, next) => {
  116. // test whether the route is listed in avoidSessionRoutes
  117. for (const regex of avoidSessionRoutes) {
  118. if (regex.test(req.path)) {
  119. return next();
  120. }
  121. }
  122. sessionMiddleware(req, res, next);
  123. });
  124. // csurf should be initialized after express-session
  125. // default methods + PUT. See: https://expressjs.com/en/resources/middleware/csurf.html#ignoremethods
  126. app.use(csrf({ ignoreMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'POST', 'DELETE'], cookie: false }));
  127. // passport
  128. debug('initialize Passport');
  129. app.use(passport.initialize());
  130. app.use(passport.session());
  131. app.use(flash());
  132. app.use(mongoSanitize());
  133. app.use(promster);
  134. app.use(registerSafeRedirect);
  135. app.use(injectCurrentuserToLocalvars);
  136. app.use(autoReconnectToS2sMsgServer);
  137. const middlewares = require('../util/middlewares')(crowi, app);
  138. app.use(middlewares.swigFilters(swig));
  139. app.use(middlewares.swigFunctions());
  140. // app.use(i18nMiddleware.handle(i18next));
  141. // TODO: Remove this workaround implementation when i18n works correctly.
  142. // For now, req.t returns string given to req.t(string)
  143. app.use((req, res, next) => {
  144. req.t = str => (typeof str === 'string' ? str : '');
  145. next();
  146. });
  147. };