express-init.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. module.exports = function(crowi, app) {
  2. const debug = require('debug')('growi:crowi:express-init');
  3. const path = require('path');
  4. const express = require('express');
  5. const helmet = require('helmet');
  6. const bodyParser = require('body-parser');
  7. const cookieParser = require('cookie-parser');
  8. const methodOverride = require('method-override');
  9. const passport = require('passport');
  10. const session = require('express-session');
  11. const sanitizer = require('express-sanitizer');
  12. const basicAuth = require('basic-auth-connect');
  13. const flash = require('connect-flash');
  14. const swig = require('swig-templates');
  15. const webpackAssets = require('express-webpack-assets');
  16. const i18next = require('i18next');
  17. const i18nFsBackend = require('i18next-node-fs-backend');
  18. const i18nSprintf = require('i18next-sprintf-postprocessor');
  19. const i18nMiddleware = require('i18next-express-middleware');
  20. const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
  21. const env = crowi.node_env;
  22. // Old type config API
  23. const Config = crowi.model('Config');
  24. // New type config API
  25. const configManager = crowi.configManager;
  26. const getConfig = configManager.getConfig;
  27. const User = crowi.model('User');
  28. const lngDetector = new i18nMiddleware.LanguageDetector();
  29. lngDetector.addDetector(i18nUserSettingDetector);
  30. i18next
  31. .use(lngDetector)
  32. .use(i18nFsBackend)
  33. .use(i18nSprintf)
  34. .init({
  35. // debug: true,
  36. fallbackLng: [User.LANG_EN_US],
  37. whitelist: Object.keys(User.getLanguageLabels()).map((k) => { return User[k] }),
  38. backend: {
  39. loadPath: `${crowi.localeDir}{{lng}}/translation.json`,
  40. },
  41. detection: {
  42. order: ['userSettingDetector', 'header', 'navigator'],
  43. },
  44. overloadTranslationOptionHandler: i18nSprintf.overloadTranslationOptionHandler,
  45. // change nsSeparator from ':' to '::' because ':' is used in config keys and these are used in i18n keys
  46. nsSeparator: '::',
  47. });
  48. app.use(helmet());
  49. app.use((req, res, next) => {
  50. const now = new Date();
  51. const tzoffset = -(getConfig('crowi', 'app:timezone') || 9) * 60;
  52. // for datez
  53. const Page = crowi.model('Page');
  54. const User = crowi.model('User');
  55. const Config = crowi.model('Config');
  56. app.set('tzoffset', tzoffset);
  57. // req.config = config;
  58. req.csrfToken = null;
  59. res.locals.req = req;
  60. res.locals.baseUrl = crowi.appService.getSiteUrl();
  61. // res.locals.config = config;
  62. res.locals.env = env;
  63. res.locals.now = now;
  64. res.locals.tzoffset = tzoffset;
  65. res.locals.consts = {
  66. pageGrants: Page.getGrantLabels(),
  67. userStatus: User.getUserStatusLabels(),
  68. language: User.getLanguageLabels(),
  69. restrictGuestMode: Config.getRestrictGuestModeLabels(),
  70. registrationMode: Config.getRegistrationModeLabels(),
  71. };
  72. res.locals.local_config = Config.getLocalconfig(); // config for browser context
  73. next();
  74. });
  75. app.set('port', crowi.port);
  76. const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
  77. app.use(express.static(crowi.publicDir, staticOption));
  78. app.engine('html', swig.renderFile);
  79. app.use(webpackAssets(
  80. path.join(crowi.publicDir, 'manifest.json'),
  81. { devMode: (crowi.node_env === 'development') },
  82. ));
  83. // app.set('view cache', false); // Default: true in production, otherwise undefined. -- 2017.07.04 Yuki Takei
  84. app.set('view engine', 'html');
  85. app.set('views', crowi.viewsDir);
  86. app.use(methodOverride());
  87. app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
  88. app.use(bodyParser.json({ limit: '50mb' }));
  89. app.use(sanitizer());
  90. app.use(cookieParser());
  91. app.use(session(crowi.sessionConfig));
  92. // Set basic auth middleware
  93. app.use((req, res, next) => {
  94. if (req.query.access_token || req.body.access_token) {
  95. return next();
  96. }
  97. // FIXME:
  98. // healthcheck endpoint exclude from basic authentication.
  99. // however, hard coding is not desirable.
  100. // need refactoring (ex. setting basic authentication for each routes)
  101. if (req.path === '/_api/v3/healthcheck') {
  102. return next();
  103. }
  104. const basicName = getConfig('crowi', 'security:basicName');
  105. const basicSecret = getConfig('crowi', 'security:basicSecret');
  106. if (basicName && basicSecret) {
  107. return basicAuth(basicName, basicSecret)(req, res, next);
  108. }
  109. next();
  110. });
  111. // passport
  112. if (getConfig('crowi', 'security:isEnabledPassport')) {
  113. debug('initialize Passport');
  114. app.use(passport.initialize());
  115. app.use(passport.session());
  116. }
  117. app.use(flash());
  118. const middlewares = require('../util/middlewares')(crowi, app);
  119. app.use(middlewares.swigFilters(swig));
  120. app.use(middlewares.swigFunctions());
  121. app.use(middlewares.csrfKeyGenerator());
  122. // switch loginChecker
  123. if (getConfig('crowi', 'security:isEnabledPassport')) {
  124. app.use(middlewares.loginCheckerForPassport);
  125. }
  126. else {
  127. app.use(middlewares.loginChecker);
  128. }
  129. app.use(i18nMiddleware.handle(i18next));
  130. };