Yuki Takei 3 лет назад
Родитель
Сommit
2eed64c0fe
39 измененных файлов с 158 добавлено и 258 удалено
  1. 1 1
      packages/app/package.json
  2. 2 20
      packages/app/src/client/util/apiv1-client.ts
  3. 3 23
      packages/app/src/client/util/apiv3-client.ts
  4. 1 2
      packages/app/src/components/LoginForm.jsx
  5. 3 0
      packages/app/src/interfaces/crowi-request.ts
  6. 2 1
      packages/app/src/pages/[[...path]].page.tsx
  7. 2 0
      packages/app/src/pages/commons.ts
  8. 5 3
      packages/app/src/server/crowi/express-init.js
  9. 0 8
      packages/app/src/server/crowi/index.js
  10. 1 2
      packages/app/src/server/middlewares/access-token-parser.js
  11. 0 27
      packages/app/src/server/middlewares/csrf.js
  12. 8 9
      packages/app/src/server/routes/apiv3/app-settings.js
  13. 1 2
      packages/app/src/server/routes/apiv3/bookmarks.js
  14. 8 9
      packages/app/src/server/routes/apiv3/customize-setting.js
  15. 2 3
      packages/app/src/server/routes/apiv3/export.js
  16. 1 2
      packages/app/src/server/routes/apiv3/forgot-password.js
  17. 3 4
      packages/app/src/server/routes/apiv3/import.js
  18. 3 4
      packages/app/src/server/routes/apiv3/in-app-notification.ts
  19. 4 5
      packages/app/src/server/routes/apiv3/markdown-setting.js
  20. 7 8
      packages/app/src/server/routes/apiv3/notification-setting.js
  21. 3 4
      packages/app/src/server/routes/apiv3/page.js
  22. 8 9
      packages/app/src/server/routes/apiv3/pages.js
  23. 8 9
      packages/app/src/server/routes/apiv3/personal-setting.js
  24. 1 2
      packages/app/src/server/routes/apiv3/search.js
  25. 11 12
      packages/app/src/server/routes/apiv3/security-setting.js
  26. 4 5
      packages/app/src/server/routes/apiv3/share-links.js
  27. 1 2
      packages/app/src/server/routes/apiv3/slack-integration-legacy-settings.js
  28. 11 12
      packages/app/src/server/routes/apiv3/slack-integration-settings.js
  29. 3 4
      packages/app/src/server/routes/apiv3/user-group.js
  30. 1 2
      packages/app/src/server/routes/apiv3/user-ui-settings.ts
  31. 9 10
      packages/app/src/server/routes/apiv3/users.js
  32. 28 26
      packages/app/src/server/routes/index.js
  33. 0 13
      packages/app/src/server/util/middlewares.js
  34. 0 5
      packages/app/src/server/util/swigFunctions.js
  35. 0 1
      packages/app/src/server/views/installer.html
  36. 1 1
      packages/app/src/server/views/invited.html
  37. 0 1
      packages/app/src/server/views/layout/layout.html
  38. 0 5
      packages/app/test/integration/middlewares/access-token-parser.test.js
  39. 12 2
      yarn.lock

+ 1 - 1
packages/app/package.json

@@ -89,7 +89,7 @@
     "connect-mongo": "^4.6.0",
     "connect-mongo": "^4.6.0",
     "connect-redis": "^4.0.4",
     "connect-redis": "^4.0.4",
     "cookie-parser": "^1.4.5",
     "cookie-parser": "^1.4.5",
-    "csrf": "^3.1.0",
+    "csurf": "^1.11.0",
     "date-fns": "^2.23.0",
     "date-fns": "^2.23.0",
     "detect-indent": "^7.0.0",
     "detect-indent": "^7.0.0",
     "diff": "^5.0.0",
     "diff": "^5.0.0",

+ 2 - 20
packages/app/src/client/util/apiv1-client.ts

@@ -4,15 +4,6 @@ import axios from '~/utils/axios';
 
 
 const apiv1Root = '/_api';
 const apiv1Root = '/_api';
 
 
-// get csrf token from body element
-const body = document.querySelector('body');
-const csrfToken = body?.dataset.csrftoken;
-
-
-type ParamWithCsrfKey = {
-  _csrf: string,
-}
-
 class Apiv1ErrorHandler extends Error {
 class Apiv1ErrorHandler extends Error {
 
 
   code;
   code;
@@ -51,24 +42,15 @@ export async function apiGet<T>(path: string, params: unknown = {}): Promise<T>
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-export async function apiPost<T>(path: string, params: any & ParamWithCsrfKey = {}): Promise<T> {
-  if (params._csrf == null) {
-    params._csrf = csrfToken;
-  }
+export async function apiPost<T>(path: string, params: any): Promise<T> {
   return apiRequest<T>('post', path, params);
   return apiRequest<T>('post', path, params);
 }
 }
 
 
 export async function apiPostForm<T>(path: string, formData: FormData): Promise<T> {
 export async function apiPostForm<T>(path: string, formData: FormData): Promise<T> {
-  if (formData.get('_csrf') == null && csrfToken != null) {
-    formData.append('_csrf', csrfToken);
-  }
   return apiPost<T>(path, formData);
   return apiPost<T>(path, formData);
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-export async function apiDelete<T>(path: string, params: any & ParamWithCsrfKey = {}): Promise<T> {
-  if (params._csrf == null) {
-    params._csrf = csrfToken;
-  }
+export async function apiDelete<T>(path: string, params: any): Promise<T> {
   return apiRequest<T>('delete', path, { data: params });
   return apiRequest<T>('delete', path, { data: params });
 }
 }

+ 3 - 23
packages/app/src/client/util/apiv3-client.ts

@@ -12,14 +12,6 @@ const apiv3Root = '/_api/v3';
 
 
 const logger = loggerFactory('growi:apiv3');
 const logger = loggerFactory('growi:apiv3');
 
 
-// get csrf token from body element
-const body = document.querySelector('body');
-const csrfToken = body?.dataset.csrftoken;
-
-
-type ParamWithCsrfKey = {
-  _csrf: string,
-}
 
 
 const apiv3ErrorHandler = (_err) => {
 const apiv3ErrorHandler = (_err) => {
   // extract api errors from general 400 err
   // extract api errors from general 400 err
@@ -51,33 +43,21 @@ export async function apiv3Get<T = any>(path: string, params: unknown = {}): Pro
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-export async function apiv3Post<T = any>(path: string, params: any & ParamWithCsrfKey = {}): Promise<AxiosResponse<T>> {
-  if (params._csrf == null) {
-    params._csrf = csrfToken;
-  }
+export async function apiv3Post<T = any>(path: string, params: any): Promise<AxiosResponse<T>> {
   return apiv3Request('post', path, params);
   return apiv3Request('post', path, params);
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 export async function apiv3PostForm<T = any>(path: string, formData: FormData): Promise<AxiosResponse<T>> {
 export async function apiv3PostForm<T = any>(path: string, formData: FormData): Promise<AxiosResponse<T>> {
-  if (formData.get('_csrf') == null && csrfToken != null) {
-    formData.append('_csrf', csrfToken);
-  }
   return apiv3Post<T>(path, formData);
   return apiv3Post<T>(path, formData);
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-export async function apiv3Put<T = any>(path: string, params: any & ParamWithCsrfKey = {}): Promise<AxiosResponse<T>> {
-  if (params._csrf == null) {
-    params._csrf = csrfToken;
-  }
+export async function apiv3Put<T = any>(path: string, params: any): Promise<AxiosResponse<T>> {
   return apiv3Request('put', path, params);
   return apiv3Request('put', path, params);
 }
 }
 
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-export async function apiv3Delete<T = any>(path: string, params: any & ParamWithCsrfKey = {}): Promise<AxiosResponse<T>> {
-  if (params._csrf == null) {
-    params._csrf = csrfToken;
-  }
+export async function apiv3Delete<T = any>(path: string, params: any): Promise<AxiosResponse<T>> {
   return apiv3Request('delete', path, { params });
   return apiv3Request('delete', path, { params });
 }
 }

+ 1 - 2
packages/app/src/components/LoginForm.jsx

@@ -37,8 +37,7 @@ class LoginForm extends React.Component {
 
 
   handleLoginWithExternalAuth(e) {
   handleLoginWithExternalAuth(e) {
     const auth = e.currentTarget.id;
     const auth = e.currentTarget.id;
-    const { csrfToken } = this.props;
-    window.location.href = `/passport/${auth}?_csrf=${csrfToken}`;
+    window.location.href = `/passport/${auth}`;
   }
   }
 
 
   renderLocalOrLdapLoginForm() {
   renderLocalOrLdapLoginForm() {

+ 3 - 0
packages/app/src/interfaces/crowi-request.ts

@@ -9,4 +9,7 @@ export interface CrowiRequest extends Request {
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   crowi: any,
   crowi: any,
 
 
+  // provided by csurf
+  csrfToken: () => string,
+
 }
 }

+ 2 - 1
packages/app/src/pages/[[...path]].page.tsx

@@ -37,7 +37,7 @@ import {
   useIsForbidden, useIsNotFound, useIsTrashPage, useShared, useShareLinkId, useIsSharedUser, useIsAbleToDeleteCompletely,
   useIsForbidden, useIsNotFound, useIsTrashPage, useShared, useShareLinkId, useIsSharedUser, useIsAbleToDeleteCompletely,
   useAppTitle, useSiteUrl, useConfidential, useIsEnabledStaleNotification,
   useAppTitle, useSiteUrl, useConfidential, useIsEnabledStaleNotification,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsMailerSetup,
   useIsSearchServiceConfigured, useIsSearchServiceReachable, useIsMailerSetup,
-  useAclEnabled, useHasSlackConfig, useDrawioUri, useHackmdUri, useMathJax, useNoCdn, useEditorConfig,
+  useAclEnabled, useHasSlackConfig, useDrawioUri, useHackmdUri, useMathJax, useNoCdn, useEditorConfig, useCsrfToken,
 } from '../stores/context';
 } from '../stores/context';
 
 
 import { CommonProps, getServerSideCommonProps, useCustomTitle } from './commons';
 import { CommonProps, getServerSideCommonProps, useCustomTitle } from './commons';
@@ -93,6 +93,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   useSiteUrl(props.siteUrl);
   useSiteUrl(props.siteUrl);
   // useEditorConfig(props.editorConfig);
   // useEditorConfig(props.editorConfig);
   useConfidential(props.confidential);
   useConfidential(props.confidential);
+  useCsrfToken(props.csrfToken);
 
 
   // page
   // page
   useCurrentPagePath(props.currentPathname);
   useCurrentPagePath(props.currentPathname);

+ 2 - 0
packages/app/src/pages/commons.ts

@@ -11,6 +11,7 @@ export type CommonProps = {
   siteUrl: string,
   siteUrl: string,
   confidential: string,
   confidential: string,
   customTitleTemplate: string,
   customTitleTemplate: string,
+  csrfToken: string,
   growiVersion: string,
   growiVersion: string,
 }
 }
 
 
@@ -33,6 +34,7 @@ export const getServerSideCommonProps: GetServerSideProps<CommonProps> = async(c
     siteUrl: appService.getSiteUrl(),
     siteUrl: appService.getSiteUrl(),
     confidential: appService.getAppConfidential() || '',
     confidential: appService.getAppConfidential() || '',
     customTitleTemplate: customizeService.customTitleTemplate,
     customTitleTemplate: customizeService.customTitleTemplate,
+    csrfToken: req.csrfToken(),
     growiVersion: crowi.version,
     growiVersion: crowi.version,
   };
   };
 
 

+ 5 - 3
packages/app/src/server/crowi/express-init.js

@@ -1,5 +1,7 @@
 import mongoose from 'mongoose';
 import mongoose from 'mongoose';
 
 
+import csrf from 'csurf';
+
 import { allLocales, localePath } from '~/next-i18next.config';
 import { allLocales, localePath } from '~/next-i18next.config';
 
 
 module.exports = function(crowi, app) {
 module.exports = function(crowi, app) {
@@ -73,8 +75,6 @@ module.exports = function(crowi, app) {
     const Config = mongoose.model('Config');
     const Config = mongoose.model('Config');
     app.set('tzoffset', crowi.appService.getTzoffset());
     app.set('tzoffset', crowi.appService.getTzoffset());
 
 
-    req.csrfToken = null;
-
     res.locals.req = req;
     res.locals.req = req;
     res.locals.baseUrl = crowi.appService.getSiteUrl();
     res.locals.baseUrl = crowi.appService.getSiteUrl();
     res.locals.env = env;
     res.locals.env = env;
@@ -132,6 +132,9 @@ module.exports = function(crowi, app) {
     sessionMiddleware(req, res, next);
     sessionMiddleware(req, res, next);
   });
   });
 
 
+  // csurf should be initialized after express-session
+  app.use(csrf({ cookie: false }));
+
   // passport
   // passport
   debug('initialize Passport');
   debug('initialize Passport');
   app.use(passport.initialize());
   app.use(passport.initialize());
@@ -148,7 +151,6 @@ module.exports = function(crowi, app) {
   const middlewares = require('../util/middlewares')(crowi, app);
   const middlewares = require('../util/middlewares')(crowi, app);
   app.use(middlewares.swigFilters(swig));
   app.use(middlewares.swigFilters(swig));
   app.use(middlewares.swigFunctions());
   app.use(middlewares.swigFunctions());
-  app.use(middlewares.csrfKeyGenerator());
 
 
   app.use(i18nMiddleware.handle(i18next));
   app.use(i18nMiddleware.handle(i18next));
 };
 };

+ 0 - 8
packages/app/src/server/crowi/index.js

@@ -121,7 +121,6 @@ Crowi.prototype.init = async function() {
     this.setupSearcher(),
     this.setupSearcher(),
     this.setupMailer(),
     this.setupMailer(),
     this.setupSlackIntegrationService(),
     this.setupSlackIntegrationService(),
-    this.setupCsrf(),
     this.setUpFileUpload(),
     this.setUpFileUpload(),
     this.setUpFileUploaderSwitchService(),
     this.setUpFileUploaderSwitchService(),
     this.setupAttachmentService(),
     this.setupAttachmentService(),
@@ -379,13 +378,6 @@ Crowi.prototype.setupMailer = async function() {
   }
   }
 };
 };
 
 
-Crowi.prototype.setupCsrf = async function() {
-  const Tokens = require('csrf');
-  this.tokens = new Tokens();
-
-  return Promise.resolve();
-};
-
 Crowi.prototype.autoInstall = function() {
 Crowi.prototype.autoInstall = function() {
   const isInstalled = this.configManager.getConfig('crowi', 'app:installed');
   const isInstalled = this.configManager.getConfig('crowi', 'app:installed');
   const username = this.configManager.getConfig('crowi', 'autoInstall:adminUsername');
   const username = this.configManager.getConfig('crowi', 'autoInstall:adminUsername');

+ 1 - 2
packages/app/src/server/middlewares/access-token-parser.js

@@ -26,9 +26,8 @@ module.exports = (crowi) => {
 
 
     // transforming attributes
     // transforming attributes
     req.user = serializeUserSecurely(user);
     req.user = serializeUserSecurely(user);
-    req.skipCsrfVerify = true;
 
 
-    logger.debug('Access token parsed: skipCsrfVerify');
+    logger.debug('Access token parsed.');
 
 
     return next();
     return next();
   };
   };

+ 0 - 27
packages/app/src/server/middlewares/csrf.js

@@ -1,27 +0,0 @@
-import loggerFactory from '~/utils/logger';
-
-const logger = loggerFactory('growi:middleware:csrf');
-
-module.exports = (crowi) => {
-
-  return async(req, res, next) => {
-    const token = req.body._csrf || req.query._csrf || null;
-    const csrfKey = (req.session && req.session.id) || 'anon';
-
-    logger.debug('req.skipCsrfVerify', req.skipCsrfVerify);
-
-    if (req.skipCsrfVerify) {
-      logger.debug('csrf verify skipped');
-      return next();
-    }
-
-    if (crowi.getTokens().verify(csrfKey, token)) {
-      logger.debug('csrf successfully verified');
-      return next();
-    }
-
-    logger.warn('csrf verification failed. return 403', csrfKey, token);
-    return res.sendStatus(403);
-  };
-
-};

+ 8 - 9
packages/app/src/server/routes/apiv3/app-settings.js

@@ -150,7 +150,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const validator = {
   const validator = {
     appSetting: [
     appSetting: [
@@ -294,7 +293,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/AppSettingParams'
    *                  $ref: '#/components/schemas/AppSettingParams'
    */
    */
-  router.put('/app-setting', loginRequiredStrictly, adminRequired, csrf, validator.appSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/app-setting', loginRequiredStrictly, adminRequired, validator.appSetting, apiV3FormValidator, async(req, res) => {
     const requestAppSettingParams = {
     const requestAppSettingParams = {
       'app:title': req.body.title,
       'app:title': req.body.title,
       'app:confidential': req.body.confidential,
       'app:confidential': req.body.confidential,
@@ -345,7 +344,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SiteUrlSettingParams'
    *                  $ref: '#/components/schemas/SiteUrlSettingParams'
    */
    */
-  router.put('/site-url-setting', loginRequiredStrictly, adminRequired, csrf, validator.siteUrlSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/site-url-setting', loginRequiredStrictly, adminRequired, validator.siteUrlSetting, apiV3FormValidator, async(req, res) => {
 
 
     const requestSiteUrlSettingParams = {
     const requestSiteUrlSettingParams = {
       'app:siteUrl': pathUtils.removeTrailingSlash(req.body.siteUrl),
       'app:siteUrl': pathUtils.removeTrailingSlash(req.body.siteUrl),
@@ -477,7 +476,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SmtpSettingParams'
    *                  $ref: '#/components/schemas/SmtpSettingParams'
    */
    */
-  router.put('/smtp-setting', loginRequiredStrictly, adminRequired, csrf, validator.smtpSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/smtp-setting', loginRequiredStrictly, adminRequired, validator.smtpSetting, apiV3FormValidator, async(req, res) => {
     const requestMailSettingParams = {
     const requestMailSettingParams = {
       'mail:from': req.body.fromAddress,
       'mail:from': req.body.fromAddress,
       'mail:transmissionMethod': req.body.transmissionMethod,
       'mail:transmissionMethod': req.body.transmissionMethod,
@@ -547,7 +546,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SesSettingParams'
    *                  $ref: '#/components/schemas/SesSettingParams'
    */
    */
-  router.put('/ses-setting', loginRequiredStrictly, adminRequired, csrf, validator.sesSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/ses-setting', loginRequiredStrictly, adminRequired, validator.sesSetting, apiV3FormValidator, async(req, res) => {
     const { mailService } = crowi;
     const { mailService } = crowi;
 
 
     const requestSesSettingParams = {
     const requestSesSettingParams = {
@@ -596,7 +595,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/FileUploadSettingParams'
    *                  $ref: '#/components/schemas/FileUploadSettingParams'
    */
    */
-  router.put('/file-upload-setting', loginRequiredStrictly, adminRequired, csrf, validator.fileUploadSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/file-upload-setting', loginRequiredStrictly, adminRequired, validator.fileUploadSetting, apiV3FormValidator, async(req, res) => {
     const { fileUploadType } = req.body;
     const { fileUploadType } = req.body;
 
 
     const requestParams = {
     const requestParams = {
@@ -677,7 +676,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/PluginSettingParams'
    *                  $ref: '#/components/schemas/PluginSettingParams'
    */
    */
-  router.put('/plugin-setting', loginRequiredStrictly, adminRequired, csrf, validator.pluginSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/plugin-setting', loginRequiredStrictly, adminRequired, validator.pluginSetting, apiV3FormValidator, async(req, res) => {
     const requestPluginSettingParams = {
     const requestPluginSettingParams = {
       'plugin:isEnabledPlugins': req.body.isEnabledPlugins,
       'plugin:isEnabledPlugins': req.body.isEnabledPlugins,
     };
     };
@@ -697,7 +696,7 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  router.post('/v5-schema-migration', accessTokenParser, loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.post('/v5-schema-migration', accessTokenParser, loginRequiredStrictly, adminRequired, async(req, res) => {
     const isMaintenanceMode = crowi.appService.isMaintenanceMode();
     const isMaintenanceMode = crowi.appService.isMaintenanceMode();
     if (!isMaintenanceMode) {
     if (!isMaintenanceMode) {
       return res.apiv3Err(new ErrorV3('GROWI is not maintenance mode. To import data, please activate the maintenance mode first.', 'not_maintenance_mode'));
       return res.apiv3Err(new ErrorV3('GROWI is not maintenance mode. To import data, please activate the maintenance mode first.', 'not_maintenance_mode'));
@@ -719,7 +718,7 @@ module.exports = (crowi) => {
   });
   });
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/maintenance-mode', accessTokenParser, loginRequiredStrictly, adminRequired, csrf, validator.maintenanceMode, apiV3FormValidator, async(req, res) => {
+  router.post('/maintenance-mode', accessTokenParser, loginRequiredStrictly, adminRequired, validator.maintenanceMode, apiV3FormValidator, async(req, res) => {
     const { flag } = req.body;
     const { flag } = req.body;
 
 
     try {
     try {

+ 1 - 2
packages/app/src/server/routes/apiv3/bookmarks.js

@@ -70,7 +70,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const { Page, Bookmark, User } = crowi.models;
   const { Page, Bookmark, User } = crowi.models;
 
 
@@ -257,7 +256,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/Bookmark'
    *                  $ref: '#/components/schemas/Bookmark'
    */
    */
-  router.put('/', accessTokenParser, loginRequiredStrictly, csrf, validator.bookmarks, apiV3FormValidator, async(req, res) => {
+  router.put('/', accessTokenParser, loginRequiredStrictly, validator.bookmarks, apiV3FormValidator, async(req, res) => {
     const { pageId, bool } = req.body;
     const { pageId, bool } = req.body;
     const userId = req.user?._id;
     const userId = req.user?._id;
 
 

+ 8 - 9
packages/app/src/server/routes/apiv3/customize-setting.js

@@ -91,7 +91,6 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const { customizeService } = crowi;
   const { customizeService } = crowi;
 
 
@@ -235,7 +234,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeLayout'
    *                  $ref: '#/components/schemas/CustomizeLayout'
    */
    */
-  router.put('/layout', loginRequiredStrictly, adminRequired, csrf, validator.layout, apiV3FormValidator, async(req, res) => {
+  router.put('/layout', loginRequiredStrictly, adminRequired, validator.layout, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:isContainerFluid': req.body.isContainerFluid,
       'customize:isContainerFluid': req.body.isContainerFluid,
     };
     };
@@ -315,7 +314,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeTheme'
    *                  $ref: '#/components/schemas/CustomizeTheme'
    */
    */
-  router.put('/theme', loginRequiredStrictly, adminRequired, csrf, validator.theme, apiV3FormValidator, async(req, res) => {
+  router.put('/theme', loginRequiredStrictly, adminRequired, validator.theme, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:theme': req.body.themeType,
       'customize:theme': req.body.themeType,
     };
     };
@@ -357,7 +356,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeFunction'
    *                  $ref: '#/components/schemas/CustomizeFunction'
    */
    */
-  router.put('/function', loginRequiredStrictly, adminRequired, csrf, validator.function, apiV3FormValidator, async(req, res) => {
+  router.put('/function', loginRequiredStrictly, adminRequired, validator.function, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:isEnabledTimeline': req.body.isEnabledTimeline,
       'customize:isEnabledTimeline': req.body.isEnabledTimeline,
       'customize:isSavedStatesOfTabChanges': req.body.isSavedStatesOfTabChanges,
       'customize:isSavedStatesOfTabChanges': req.body.isSavedStatesOfTabChanges,
@@ -417,7 +416,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeHighlight'
    *                  $ref: '#/components/schemas/CustomizeHighlight'
    */
    */
-  router.put('/highlight', loginRequiredStrictly, adminRequired, csrf, validator.highlight, apiV3FormValidator, async(req, res) => {
+  router.put('/highlight', loginRequiredStrictly, adminRequired, validator.highlight, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:highlightJsStyle': req.body.highlightJsStyle,
       'customize:highlightJsStyle': req.body.highlightJsStyle,
       'customize:highlightJsStyleBorder': req.body.highlightJsStyleBorder,
       'customize:highlightJsStyleBorder': req.body.highlightJsStyleBorder,
@@ -461,7 +460,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeTitle'
    *                  $ref: '#/components/schemas/CustomizeTitle'
    */
    */
-  router.put('/customize-title', loginRequiredStrictly, adminRequired, csrf, validator.customizeTitle, apiV3FormValidator, async(req, res) => {
+  router.put('/customize-title', loginRequiredStrictly, adminRequired, validator.customizeTitle, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:title': req.body.customizeTitle,
       'customize:title': req.body.customizeTitle,
     };
     };
@@ -506,7 +505,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeHeader'
    *                  $ref: '#/components/schemas/CustomizeHeader'
    */
    */
-  router.put('/customize-header', loginRequiredStrictly, adminRequired, csrf, validator.customizeHeader, apiV3FormValidator, async(req, res) => {
+  router.put('/customize-header', loginRequiredStrictly, adminRequired, validator.customizeHeader, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:header': req.body.customizeHeader,
       'customize:header': req.body.customizeHeader,
     };
     };
@@ -547,7 +546,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeCss'
    *                  $ref: '#/components/schemas/CustomizeCss'
    */
    */
-  router.put('/customize-css', loginRequiredStrictly, adminRequired, csrf, validator.customizeCss, apiV3FormValidator, async(req, res) => {
+  router.put('/customize-css', loginRequiredStrictly, adminRequired, validator.customizeCss, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:css': req.body.customizeCss,
       'customize:css': req.body.customizeCss,
     };
     };
@@ -591,7 +590,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/CustomizeScript'
    *                  $ref: '#/components/schemas/CustomizeScript'
    */
    */
-  router.put('/customize-script', loginRequiredStrictly, adminRequired, csrf, validator.customizeScript, apiV3FormValidator, async(req, res) => {
+  router.put('/customize-script', loginRequiredStrictly, adminRequired, validator.customizeScript, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'customize:script': req.body.customizeScript,
       'customize:script': req.body.customizeScript,
     };
     };

+ 2 - 3
packages/app/src/server/routes/apiv3/export.js

@@ -44,7 +44,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const { exportService, socketIoService } = crowi;
   const { exportService, socketIoService } = crowi;
 
 
@@ -118,7 +117,7 @@ module.exports = (crowi) => {
    *                  status:
    *                  status:
    *                    $ref: '#/components/schemas/ExportStatus'
    *                    $ref: '#/components/schemas/ExportStatus'
    */
    */
-  router.post('/', accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {
+  router.post('/', accessTokenParser, loginRequired, adminRequired, async(req, res) => {
     // TODO: add express validator
     // TODO: add express validator
     try {
     try {
       const { collections } = req.body;
       const { collections } = req.body;
@@ -161,7 +160,7 @@ module.exports = (crowi) => {
    *              schema:
    *              schema:
    *                type: object
    *                type: object
    */
    */
-  router.delete('/:fileName', accessTokenParser, loginRequired, adminRequired, validator.deleteFile, apiV3FormValidator, csrf, async(req, res) => {
+  router.delete('/:fileName', accessTokenParser, loginRequired, adminRequired, validator.deleteFile, apiV3FormValidator, async(req, res) => {
     // TODO: add express validator
     // TODO: add express validator
     const { fileName } = req.params;
     const { fileName } = req.params;
 
 

+ 1 - 2
packages/app/src/server/routes/apiv3/forgot-password.js

@@ -24,7 +24,6 @@ module.exports = (crowi) => {
   const { appService, mailService, configManager } = crowi;
   const { appService, mailService, configManager } = crowi;
   const User = crowi.model('User');
   const User = crowi.model('User');
   const path = require('path');
   const path = require('path');
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
   const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
 
 
@@ -95,7 +94,7 @@ module.exports = (crowi) => {
   });
   });
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.put('/', apiLimiter, checkPassportStrategyMiddleware, injectResetOrderByTokenMiddleware, csrf, validator.password, apiV3FormValidator, async(req, res) => {
+  router.put('/', apiLimiter, checkPassportStrategyMiddleware, injectResetOrderByTokenMiddleware, validator.password, apiV3FormValidator, async(req, res) => {
     const { passwordResetOrder } = req;
     const { passwordResetOrder } = req;
     const { email } = passwordResetOrder;
     const { email } = passwordResetOrder;
     const grobalLang = configManager.getConfig('crowi', 'app:globalLang');
     const grobalLang = configManager.getConfig('crowi', 'app:globalLang');

+ 3 - 4
packages/app/src/server/routes/apiv3/import.js

@@ -67,7 +67,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   this.adminEvent = crowi.event('admin');
   this.adminEvent = crowi.event('admin');
 
 
@@ -204,7 +203,7 @@ module.exports = (crowi) => {
    *        200:
    *        200:
    *          description: Import process has requested
    *          description: Import process has requested
    */
    */
-  router.post('/', accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {
+  router.post('/', accessTokenParser, loginRequired, adminRequired, async(req, res) => {
     // TODO: add express validator
     // TODO: add express validator
     const { fileName, collections, optionsMap } = req.body;
     const { fileName, collections, optionsMap } = req.body;
 
 
@@ -321,7 +320,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: the property of each extracted file
    *                      description: the property of each extracted file
    */
    */
-  router.post('/upload', uploads.single('file'), accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {
+  router.post('/upload', uploads.single('file'), accessTokenParser, loginRequired, adminRequired, async(req, res) => {
     const { file } = req;
     const { file } = req;
     const zipFile = importService.getFile(file.filename);
     const zipFile = importService.getFile(file.filename);
     let data = null;
     let data = null;
@@ -359,7 +358,7 @@ module.exports = (crowi) => {
    *        200:
    *        200:
    *          description: all files are deleted
    *          description: all files are deleted
    */
    */
-  router.delete('/all', accessTokenParser, loginRequired, adminRequired, csrf, async(req, res) => {
+  router.delete('/all', accessTokenParser, loginRequired, adminRequired, async(req, res) => {
     try {
     try {
       importService.deleteAllZipFiles();
       importService.deleteAllZipFiles();
 
 

+ 3 - 4
packages/app/src/server/routes/apiv3/in-app-notification.ts

@@ -9,7 +9,6 @@ const router = express.Router();
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
   const inAppNotificationService = crowi.inAppNotificationService;
   const inAppNotificationService = crowi.inAppNotificationService;
   const User = crowi.model('User');
   const User = crowi.model('User');
 
 
@@ -75,7 +74,7 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
-  router.post('/read', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
+  router.post('/read', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const user = req.user;
     const user = req.user;
 
 
     try {
     try {
@@ -87,7 +86,7 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
-  router.post('/open', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
+  router.post('/open', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const user = req.user;
     const user = req.user;
     const id = req.body.id;
     const id = req.body.id;
 
 
@@ -101,7 +100,7 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
-  router.put('/all-statuses-open', accessTokenParser, loginRequiredStrictly, csrf, async(req, res) => {
+  router.put('/all-statuses-open', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const user = req.user;
     const user = req.user;
 
 
     try {
     try {

+ 4 - 5
packages/app/src/server/routes/apiv3/markdown-setting.js

@@ -90,7 +90,6 @@ const validator = {
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -152,7 +151,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
   *                   $ref: '#/components/schemas/LineBreakParams'
   *                   $ref: '#/components/schemas/LineBreakParams'
    */
    */
-  router.put('/lineBreak', loginRequiredStrictly, adminRequired, csrf, validator.lineBreak, apiV3FormValidator, async(req, res) => {
+  router.put('/lineBreak', loginRequiredStrictly, adminRequired, validator.lineBreak, apiV3FormValidator, async(req, res) => {
 
 
     const requestLineBreakParams = {
     const requestLineBreakParams = {
       'markdown:isEnabledLinebreaks': req.body.isEnabledLinebreaks,
       'markdown:isEnabledLinebreaks': req.body.isEnabledLinebreaks,
@@ -175,7 +174,7 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  router.put('/indent', loginRequiredStrictly, adminRequired, csrf, validator.indent, apiV3FormValidator, async(req, res) => {
+  router.put('/indent', loginRequiredStrictly, adminRequired, validator.indent, apiV3FormValidator, async(req, res) => {
 
 
     const requestIndentParams = {
     const requestIndentParams = {
       'markdown:adminPreferredIndentSize': req.body.adminPreferredIndentSize,
       'markdown:adminPreferredIndentSize': req.body.adminPreferredIndentSize,
@@ -221,7 +220,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/PresentationParams'
    *                  $ref: '#/components/schemas/PresentationParams'
    */
    */
-  router.put('/presentation', loginRequiredStrictly, adminRequired, csrf, validator.presentationSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/presentation', loginRequiredStrictly, adminRequired, validator.presentationSetting, apiV3FormValidator, async(req, res) => {
     if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
     if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
       return res.apiv3Err(new ErrorV3('customRegularExpression is required'));
       return res.apiv3Err(new ErrorV3('customRegularExpression is required'));
     }
     }
@@ -270,7 +269,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/XssParams'
    *                  $ref: '#/components/schemas/XssParams'
    */
    */
-  router.put('/xss', loginRequiredStrictly, adminRequired, csrf, validator.xssSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/xss', loginRequiredStrictly, adminRequired, validator.xssSetting, apiV3FormValidator, async(req, res) => {
     if (req.body.isEnabledXss && req.body.xssOption == null) {
     if (req.body.isEnabledXss && req.body.xssOption == null) {
       return res.apiv3Err(new ErrorV3('xss option is required'));
       return res.apiv3Err(new ErrorV3('xss option is required'));
     }
     }

+ 7 - 8
packages/app/src/server/routes/apiv3/notification-setting.js

@@ -90,7 +90,6 @@ const validator = {
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
   const GlobalNotificationSetting = crowi.model('GlobalNotificationSetting');
 
 
@@ -158,7 +157,7 @@ module.exports = (crowi) => {
   *                      type: object
   *                      type: object
   *                      description: user trigger notifications for updated
   *                      description: user trigger notifications for updated
   */
   */
-  router.post('/user-notification', loginRequiredStrictly, adminRequired, csrf, validator.userNotification, apiV3FormValidator, async(req, res) => {
+  router.post('/user-notification', loginRequiredStrictly, adminRequired, validator.userNotification, apiV3FormValidator, async(req, res) => {
     const { pathPattern, channel } = req.body;
     const { pathPattern, channel } = req.body;
 
 
     try {
     try {
@@ -202,7 +201,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: deleted notification
    *                      description: deleted notification
    */
    */
-  router.delete('/user-notification/:id', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.delete('/user-notification/:id', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {
@@ -242,7 +241,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: notification param created
    *                      description: notification param created
    */
    */
-  router.post('/global-notification', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, apiV3FormValidator, async(req, res) => {
+  router.post('/global-notification', loginRequiredStrictly, adminRequired, validator.globalNotification, apiV3FormValidator, async(req, res) => {
 
 
     const {
     const {
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
@@ -305,7 +304,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: notification param updated
    *                      description: notification param updated
    */
    */
-  router.put('/global-notification/:id', loginRequiredStrictly, adminRequired, csrf, validator.globalNotification, apiV3FormValidator, async(req, res) => {
+  router.put('/global-notification/:id', loginRequiredStrictly, adminRequired, validator.globalNotification, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const {
     const {
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
       notifyToType, toEmail, slackChannels, triggerPath, triggerEvents,
@@ -376,7 +375,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/NotifyForPageGrant'
    *                  $ref: '#/components/schemas/NotifyForPageGrant'
    */
    */
-  router.put('/notify-for-page-grant', loginRequiredStrictly, adminRequired, csrf, validator.notifyForPageGrant, apiV3FormValidator, async(req, res) => {
+  router.put('/notify-for-page-grant', loginRequiredStrictly, adminRequired, validator.notifyForPageGrant, apiV3FormValidator, async(req, res) => {
 
 
     let requestParams = {
     let requestParams = {
       'notification:owner-page:isEnabled': req.body.isNotificationForOwnerPageEnabled,
       'notification:owner-page:isEnabled': req.body.isNotificationForOwnerPageEnabled,
@@ -433,7 +432,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: notification id for updated
    *                      description: notification id for updated
    */
    */
-  router.put('/global-notification/:id/enabled', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/global-notification/:id/enabled', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const { isEnabled } = req.body;
     const { isEnabled } = req.body;
 
 
@@ -481,7 +480,7 @@ module.exports = (crowi) => {
   *                      type: object
   *                      type: object
   *                      description: deleted notification
   *                      description: deleted notification
   */
   */
-  router.delete('/global-notification/:id', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.delete('/global-notification/:id', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {

+ 3 - 4
packages/app/src/server/routes/apiv3/page.js

@@ -160,7 +160,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
   const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
   const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
 
 
   const globalNotificationService = crowi.getGlobalNotificationService();
   const globalNotificationService = crowi.getGlobalNotificationService();
@@ -307,7 +306,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/Page'
    *                  $ref: '#/components/schemas/Page'
    */
    */
-  router.put('/likes', accessTokenParser, loginRequiredStrictly, csrf, validator.likes, apiV3FormValidator, async(req, res) => {
+  router.put('/likes', accessTokenParser, loginRequiredStrictly, validator.likes, apiV3FormValidator, async(req, res) => {
     const { pageId, bool: isLiked } = req.body;
     const { pageId, bool: isLiked } = req.body;
 
 
     let page;
     let page;
@@ -707,7 +706,7 @@ module.exports = (crowi) => {
   //  *                schema:
   //  *                schema:
   //  *                  $ref: '#/components/schemas/Page'
   //  *                  $ref: '#/components/schemas/Page'
   //  */
   //  */
-  // router.post('/archive', accessTokenParser, loginRequired, csrf, validator.archive, apiV3FormValidator, async(req, res) => {
+  // router.post('/archive', accessTokenParser, loginRequired, validator.archive, apiV3FormValidator, async(req, res) => {
   //   const PageArchive = crowi.model('PageArchive');
   //   const PageArchive = crowi.model('PageArchive');
 
 
   //   const {
   //   const {
@@ -771,7 +770,7 @@ module.exports = (crowi) => {
    *          500:
    *          500:
    *            description: Internal server error.
    *            description: Internal server error.
    */
    */
-  router.put('/subscribe', accessTokenParser, loginRequiredStrictly, csrf, validator.subscribe, apiV3FormValidator, async(req, res) => {
+  router.put('/subscribe', accessTokenParser, loginRequiredStrictly, validator.subscribe, apiV3FormValidator, async(req, res) => {
     const { pageId, status } = req.body;
     const { pageId, status } = req.body;
     const userId = req.user._id;
     const userId = req.user._id;
 
 

+ 8 - 9
packages/app/src/server/routes/apiv3/pages.js

@@ -144,7 +144,6 @@ module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const Page = crowi.model('Page');
   const Page = crowi.model('Page');
   const User = crowi.model('User');
   const User = crowi.model('User');
@@ -285,7 +284,7 @@ module.exports = (crowi) => {
    *          409:
    *          409:
    *            description: page path is already existed
    *            description: page path is already existed
    */
    */
-  router.post('/', accessTokenParser, loginRequiredStrictly, csrf, validator.createPage, apiV3FormValidator, async(req, res) => {
+  router.post('/', accessTokenParser, loginRequiredStrictly, validator.createPage, apiV3FormValidator, async(req, res) => {
     const {
     const {
       body, grant, grantUserGroupId, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, pageTags,
       body, grant, grantUserGroupId, overwriteScopesOfDescendants, isSlackEnabled, slackChannels, pageTags,
     } = req.body;
     } = req.body;
@@ -492,7 +491,7 @@ module.exports = (crowi) => {
    *          409:
    *          409:
    *            description: page path is already existed
    *            description: page path is already existed
    */
    */
-  router.put('/rename', accessTokenParser, loginRequiredStrictly, csrf, validator.renamePage, apiV3FormValidator, async(req, res) => {
+  router.put('/rename', accessTokenParser, loginRequiredStrictly, validator.renamePage, apiV3FormValidator, async(req, res) => {
     const { pageId, revisionId } = req.body;
     const { pageId, revisionId } = req.body;
 
 
     let newPagePath = pathUtils.normalizePath(req.body.newPagePath);
     let newPagePath = pathUtils.normalizePath(req.body.newPagePath);
@@ -557,7 +556,7 @@ module.exports = (crowi) => {
     return res.apiv3(result);
     return res.apiv3(result);
   });
   });
 
 
-  router.post('/resume-rename', accessTokenParser, loginRequiredStrictly, csrf, validator.resumeRenamePage, apiV3FormValidator, async(req, res) => {
+  router.post('/resume-rename', accessTokenParser, loginRequiredStrictly, validator.resumeRenamePage, apiV3FormValidator, async(req, res) => {
 
 
     const { pageId } = req.body;
     const { pageId } = req.body;
     const { user } = req;
     const { user } = req;
@@ -591,7 +590,7 @@ module.exports = (crowi) => {
    *          200:
    *          200:
    *            description: Succeeded to remove all trash pages
    *            description: Succeeded to remove all trash pages
    */
    */
-  router.delete('/empty-trash', accessTokenParser, loginRequired, csrf, apiV3FormValidator, async(req, res) => {
+  router.delete('/empty-trash', accessTokenParser, loginRequired, apiV3FormValidator, async(req, res) => {
     const options = {};
     const options = {};
 
 
     const pagesInTrash = await Page.findChildrenByParentPathOrIdAndViewer('/trash', req.user);
     const pagesInTrash = await Page.findChildrenByParentPathOrIdAndViewer('/trash', req.user);
@@ -707,7 +706,7 @@ module.exports = (crowi) => {
    *          500:
    *          500:
    *            description: Internal server error.
    *            description: Internal server error.
    */
    */
-  router.post('/duplicate', accessTokenParser, loginRequiredStrictly, csrf, validator.duplicatePage, apiV3FormValidator, async(req, res) => {
+  router.post('/duplicate', accessTokenParser, loginRequiredStrictly, validator.duplicatePage, apiV3FormValidator, async(req, res) => {
     const { pageId, isRecursively } = req.body;
     const { pageId, isRecursively } = req.body;
 
 
     const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
     const newPagePath = pathUtils.normalizePath(req.body.pageNameInput);
@@ -805,7 +804,7 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  router.post('/delete', accessTokenParser, loginRequiredStrictly, csrf, validator.deletePages, apiV3FormValidator, async(req, res) => {
+  router.post('/delete', accessTokenParser, loginRequiredStrictly, validator.deletePages, apiV3FormValidator, async(req, res) => {
     const { pageIdToRevisionIdMap, isCompletely, isRecursively } = req.body;
     const { pageIdToRevisionIdMap, isCompletely, isRecursively } = req.body;
     const pageIds = Object.keys(pageIdToRevisionIdMap);
     const pageIds = Object.keys(pageIdToRevisionIdMap);
 
 
@@ -854,7 +853,7 @@ module.exports = (crowi) => {
 
 
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/convert-pages-by-path', accessTokenParser, loginRequiredStrictly, adminRequired, csrf, validator.convertPagesByPath, apiV3FormValidator, async(req, res) => {
+  router.post('/convert-pages-by-path', accessTokenParser, loginRequiredStrictly, adminRequired, validator.convertPagesByPath, apiV3FormValidator, async(req, res) => {
     const { convertPath } = req.body;
     const { convertPath } = req.body;
 
 
     // Convert by path
     // Convert by path
@@ -876,7 +875,7 @@ module.exports = (crowi) => {
   });
   });
 
 
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/legacy-pages-migration', accessTokenParser, loginRequired, csrf, validator.legacyPagesMigration, apiV3FormValidator, async(req, res) => {
+  router.post('/legacy-pages-migration', accessTokenParser, loginRequired, validator.legacyPagesMigration, apiV3FormValidator, async(req, res) => {
     const { pageIds: _pageIds, isRecursively } = req.body;
     const { pageIds: _pageIds, isRecursively } = req.body;
 
 
     // Convert by pageIds
     // Convert by pageIds

+ 8 - 9
packages/app/src/server/routes/apiv3/personal-setting.js

@@ -68,7 +68,6 @@ const router = express.Router();
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const { User, ExternalAccount } = crowi.models;
   const { User, ExternalAccount } = crowi.models;
 
 
@@ -226,7 +225,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: personal params
    *                      description: personal params
    */
    */
-  router.put('/', accessTokenParser, loginRequiredStrictly, csrf, validator.personal, apiV3FormValidator, async(req, res) => {
+  router.put('/', accessTokenParser, loginRequiredStrictly, validator.personal, apiV3FormValidator, async(req, res) => {
 
 
     try {
     try {
       const user = await User.findOne({ _id: req.user.id });
       const user = await User.findOne({ _id: req.user.id });
@@ -267,7 +266,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: user data
    *                      description: user data
    */
    */
-  router.put('/image-type', accessTokenParser, loginRequiredStrictly, csrf, validator.imageType, apiV3FormValidator, async(req, res) => {
+  router.put('/image-type', accessTokenParser, loginRequiredStrictly, validator.imageType, apiV3FormValidator, async(req, res) => {
     const { isGravatarEnabled } = req.body;
     const { isGravatarEnabled } = req.body;
 
 
     try {
     try {
@@ -340,7 +339,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: user data updated
    *                      description: user data updated
    */
    */
-  router.put('/password', accessTokenParser, loginRequiredStrictly, csrf, validator.password, apiV3FormValidator, async(req, res) => {
+  router.put('/password', accessTokenParser, loginRequiredStrictly, validator.password, apiV3FormValidator, async(req, res) => {
     const { body, user } = req;
     const { body, user } = req;
     const { oldPassword, newPassword } = body;
     const { oldPassword, newPassword } = body;
 
 
@@ -378,7 +377,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: user data
    *                      description: user data
    */
    */
-  router.put('/api-token', loginRequiredStrictly, csrf, async(req, res) => {
+  router.put('/api-token', loginRequiredStrictly, async(req, res) => {
     const { user } = req;
     const { user } = req;
 
 
     try {
     try {
@@ -418,7 +417,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Ldap account associate to me
    *                      description: Ldap account associate to me
    */
    */
-  router.put('/associate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.associateLdap, apiV3FormValidator, async(req, res) => {
+  router.put('/associate-ldap', accessTokenParser, loginRequiredStrictly, validator.associateLdap, apiV3FormValidator, async(req, res) => {
     const { passportService } = crowi;
     const { passportService } = crowi;
     const { user, body } = req;
     const { user, body } = req;
     const { username } = body;
     const { username } = body;
@@ -466,7 +465,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Ldap account disassociate to me
    *                      description: Ldap account disassociate to me
    */
    */
-  router.put('/disassociate-ldap', accessTokenParser, loginRequiredStrictly, csrf, validator.disassociateLdap, apiV3FormValidator, async(req, res) => {
+  router.put('/disassociate-ldap', accessTokenParser, loginRequiredStrictly, validator.disassociateLdap, apiV3FormValidator, async(req, res) => {
     const { user, body } = req;
     const { user, body } = req;
     const { providerType, accountId } = body;
     const { providerType, accountId } = body;
 
 
@@ -506,7 +505,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: editor settings
    *                      description: editor settings
    */
    */
-  router.put('/editor-settings', accessTokenParser, loginRequiredStrictly, csrf, validator.editorSettings, apiV3FormValidator, async(req, res) => {
+  router.put('/editor-settings', accessTokenParser, loginRequiredStrictly, validator.editorSettings, apiV3FormValidator, async(req, res) => {
     const query = { userId: req.user.id };
     const query = { userId: req.user.id };
     const { body } = req;
     const { body } = req;
 
 
@@ -595,7 +594,7 @@ module.exports = (crowi) => {
    *                      description: in-app-notification-settings
    *                      description: in-app-notification-settings
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.put('/in-app-notification-settings', accessTokenParser, loginRequiredStrictly, csrf, validator.inAppNotificationSettings, apiV3FormValidator, async(req, res) => {
+  router.put('/in-app-notification-settings', accessTokenParser, loginRequiredStrictly, validator.inAppNotificationSettings, apiV3FormValidator, async(req, res) => {
     const query = { userId: req.user.id };
     const query = { userId: req.user.id };
     const subscribeRules = req.body.subscribeRules;
     const subscribeRules = req.body.subscribeRules;
 
 

+ 1 - 2
packages/app/src/server/routes/apiv3/search.js

@@ -22,7 +22,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -114,7 +113,7 @@ module.exports = (crowi) => {
    *        200:
    *        200:
    *          description: Return 200
    *          description: Return 200
    */
    */
-  router.put('/indices', accessTokenParser, loginRequired, adminRequired, csrf, validatorForPutIndices, apiV3FormValidator, async(req, res) => {
+  router.put('/indices', accessTokenParser, loginRequired, adminRequired, validatorForPutIndices, apiV3FormValidator, async(req, res) => {
     const operation = req.body.operation;
     const operation = req.body.operation;
 
 
     const { searchService } = crowi;
     const { searchService } = crowi;

+ 11 - 12
packages/app/src/server/routes/apiv3/security-setting.js

@@ -334,7 +334,6 @@ const validator = {
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   async function updateAndReloadStrategySettings(authId, params) {
   async function updateAndReloadStrategySettings(authId, params) {
     const { configManager, passportService } = crowi;
     const { configManager, passportService } = crowi;
@@ -505,7 +504,7 @@ module.exports = (crowi) => {
    *                  type: object
    *                  type: object
    *                  description: updated param
    *                  description: updated param
    */
    */
-  router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, csrf, validator.authenticationSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, validator.authenticationSetting, apiV3FormValidator, async(req, res) => {
     const { isEnabled, authId } = req.body;
     const { isEnabled, authId } = req.body;
 
 
     let setupStrategies = await crowi.passportService.getSetupStrategies();
     let setupStrategies = await crowi.passportService.getSetupStrategies();
@@ -586,7 +585,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GeneralSetting'
    *                  $ref: '#/components/schemas/GeneralSetting'
    */
    */
-  router.put('/general-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/general-setting', loginRequiredStrictly, adminRequired, validator.generalSetting, apiV3FormValidator, async(req, res) => {
     const updateData = {
     const updateData = {
       'security:sessionMaxAge': parseInt(req.body.sessionMaxAge),
       'security:sessionMaxAge': parseInt(req.body.sessionMaxAge),
       'security:restrictGuestMode': req.body.restrictGuestMode,
       'security:restrictGuestMode': req.body.restrictGuestMode,
@@ -656,7 +655,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/ShareLinkSetting'
    *                  $ref: '#/components/schemas/ShareLinkSetting'
    */
    */
-  router.put('/share-link-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/share-link-setting', loginRequiredStrictly, adminRequired, validator.generalSetting, apiV3FormValidator, async(req, res) => {
     const updateData = {
     const updateData = {
       'security:disableLinkSharing': req.body.disableLinkSharing,
       'security:disableLinkSharing': req.body.disableLinkSharing,
     };
     };
@@ -767,7 +766,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/LocalSetting'
    *                  $ref: '#/components/schemas/LocalSetting'
    */
    */
-  router.put('/local-setting', loginRequiredStrictly, adminRequired, csrf, validator.localSetting, apiV3FormValidator, async(req, res) => {
+  router.put('/local-setting', loginRequiredStrictly, adminRequired, validator.localSetting, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:registrationMode': req.body.registrationMode,
       'security:registrationMode': req.body.registrationMode,
       'security:registrationWhiteList': req.body.registrationWhiteList,
       'security:registrationWhiteList': req.body.registrationWhiteList,
@@ -813,7 +812,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/LdapAuthSetting'
    *                  $ref: '#/components/schemas/LdapAuthSetting'
    */
    */
-  router.put('/ldap', loginRequiredStrictly, adminRequired, csrf, validator.ldapAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/ldap', loginRequiredStrictly, adminRequired, validator.ldapAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-ldap:serverUrl': req.body.serverUrl,
       'security:passport-ldap:serverUrl': req.body.serverUrl,
       'security:passport-ldap:isUserBind': req.body.isUserBind,
       'security:passport-ldap:isUserBind': req.body.isUserBind,
@@ -876,7 +875,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SamlAuthSetting'
    *                  $ref: '#/components/schemas/SamlAuthSetting'
    */
    */
-  router.put('/saml', loginRequiredStrictly, adminRequired, csrf, validator.samlAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/saml', loginRequiredStrictly, adminRequired, validator.samlAuth, apiV3FormValidator, async(req, res) => {
 
 
     //  For the value of each mandatory items,
     //  For the value of each mandatory items,
     //  check whether it from the environment variables is empty and form value to update it is empty
     //  check whether it from the environment variables is empty and form value to update it is empty
@@ -967,7 +966,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/OidcAuthSetting'
    *                  $ref: '#/components/schemas/OidcAuthSetting'
    */
    */
-  router.put('/oidc', loginRequiredStrictly, adminRequired, csrf, validator.oidcAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/oidc', loginRequiredStrictly, adminRequired, validator.oidcAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-oidc:providerName': req.body.oidcProviderName,
       'security:passport-oidc:providerName': req.body.oidcProviderName,
       'security:passport-oidc:issuerHost': req.body.oidcIssuerHost,
       'security:passport-oidc:issuerHost': req.body.oidcIssuerHost,
@@ -1042,7 +1041,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/BasicAuthSetting'
    *                  $ref: '#/components/schemas/BasicAuthSetting'
    */
    */
-  router.put('/basic', loginRequiredStrictly, adminRequired, csrf, validator.basicAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/basic', loginRequiredStrictly, adminRequired, validator.basicAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-basic:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
       'security:passport-basic:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
     };
     };
@@ -1083,7 +1082,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GoogleOAuthSetting'
    *                  $ref: '#/components/schemas/GoogleOAuthSetting'
    */
    */
-  router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/google-oauth', loginRequiredStrictly, adminRequired, validator.googleOAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-google:clientId': req.body.googleClientId,
       'security:passport-google:clientId': req.body.googleClientId,
       'security:passport-google:clientSecret': req.body.googleClientSecret,
       'security:passport-google:clientSecret': req.body.googleClientSecret,
@@ -1129,7 +1128,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/GitHubOAuthSetting'
    *                  $ref: '#/components/schemas/GitHubOAuthSetting'
    */
    */
-  router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/github-oauth', loginRequiredStrictly, adminRequired, validator.githubOAuth, apiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
       'security:passport-github:clientId': req.body.githubClientId,
       'security:passport-github:clientId': req.body.githubClientId,
       'security:passport-github:clientSecret': req.body.githubClientSecret,
       'security:passport-github:clientSecret': req.body.githubClientSecret,
@@ -1176,7 +1175,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    */
    */
-  router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, apiV3FormValidator, async(req, res) => {
+  router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, validator.twitterOAuth, apiV3FormValidator, async(req, res) => {
 
 
     let requestParams = {
     let requestParams = {
       'security:passport-twitter:consumerKey': req.body.twitterConsumerKey,
       'security:passport-twitter:consumerKey': req.body.twitterConsumerKey,

+ 4 - 5
packages/app/src/server/routes/apiv3/share-links.js

@@ -27,7 +27,6 @@ const today = new Date();
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const loginRequired = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
   const ShareLink = crowi.model('ShareLink');
   const ShareLink = crowi.model('ShareLink');
   const Page = crowi.model('Page');
   const Page = crowi.model('Page');
 
 
@@ -129,7 +128,7 @@ module.exports = (crowi) => {
    *            description: Succeeded to create one share link
    *            description: Succeeded to create one share link
    */
    */
 
 
-  router.post('/', loginRequired, linkSharingRequired, csrf, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
+  router.post('/', loginRequired, linkSharingRequired, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
     const { relatedPage, expiredAt, description } = req.body;
     const { relatedPage, expiredAt, description } = req.body;
 
 
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
@@ -178,7 +177,7 @@ module.exports = (crowi) => {
   *          200:
   *          200:
   *            description: Succeeded to delete o all share links related one page
   *            description: Succeeded to delete o all share links related one page
   */
   */
-  router.delete('/', loginRequired, csrf, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
+  router.delete('/', loginRequired, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
     const { relatedPage } = req.query;
     const { relatedPage } = req.query;
 
 
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
     const page = await Page.findByIdAndViewer(relatedPage, req.user);
@@ -211,7 +210,7 @@ module.exports = (crowi) => {
   *          200:
   *          200:
   *            description: Succeeded to remove all share links
   *            description: Succeeded to remove all share links
   */
   */
-  router.delete('/all', loginRequired, adminRequired, csrf, async(req, res) => {
+  router.delete('/all', loginRequired, adminRequired, async(req, res) => {
 
 
     try {
     try {
       const deletedShareLink = await ShareLink.deleteMany({});
       const deletedShareLink = await ShareLink.deleteMany({});
@@ -247,7 +246,7 @@ module.exports = (crowi) => {
   *          200:
   *          200:
   *            description: Succeeded to delete one share link
   *            description: Succeeded to delete one share link
   */
   */
-  router.delete('/:id', loginRequired, csrf, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
+  router.delete('/:id', loginRequired, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const { user } = req;
     const { user } = req;
 
 

+ 1 - 2
packages/app/src/server/routes/apiv3/slack-integration-legacy-settings.js

@@ -48,7 +48,6 @@ const validator = {
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   /**
   /**
    * @swagger
    * @swagger
@@ -100,7 +99,7 @@ module.exports = (crowi) => {
    *                schema:
    *                schema:
    *                  $ref: '#/components/schemas/SlackConfigurationParams'
    *                  $ref: '#/components/schemas/SlackConfigurationParams'
    */
    */
-  router.put('/', loginRequiredStrictly, adminRequired, csrf, validator.slackConfiguration, apiV3FormValidator, async(req, res) => {
+  router.put('/', loginRequiredStrictly, adminRequired, validator.slackConfiguration, apiV3FormValidator, async(req, res) => {
 
 
     const requestParams = {
     const requestParams = {
       'slack:incomingWebhookUrl': req.body.webhookUrl,
       'slack:incomingWebhookUrl': req.body.webhookUrl,

+ 11 - 12
packages/app/src/server/routes/apiv3/slack-integration-settings.js

@@ -53,7 +53,6 @@ module.exports = (crowi) => {
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
   const SlackAppIntegration = crowi.model('SlackAppIntegration');
   const SlackAppIntegration = crowi.model('SlackAppIntegration');
 
 
   const validator = {
   const validator = {
@@ -305,7 +304,7 @@ module.exports = (crowi) => {
    *           200:
    *           200:
    *             description: Succeeded to put botType setting.
    *             description: Succeeded to put botType setting.
    */
    */
-  router.put('/bot-type', accessTokenParser, loginRequiredStrictly, adminRequired, csrf, validator.botType, apiV3FormValidator, async(req, res) => {
+  router.put('/bot-type', accessTokenParser, loginRequiredStrictly, adminRequired, validator.botType, apiV3FormValidator, async(req, res) => {
     const { currentBotType } = req.body;
     const { currentBotType } = req.body;
 
 
     if (currentBotType == null) {
     if (currentBotType == null) {
@@ -340,7 +339,7 @@ module.exports = (crowi) => {
    *           200:
    *           200:
    *             description: Succeeded to delete botType setting.
    *             description: Succeeded to delete botType setting.
    */
    */
-  router.delete('/bot-type', accessTokenParser, loginRequiredStrictly, adminRequired, csrf, apiV3FormValidator, async(req, res) => {
+  router.delete('/bot-type', accessTokenParser, loginRequiredStrictly, adminRequired, apiV3FormValidator, async(req, res) => {
     try {
     try {
       await handleBotTypeChanging(req, res, null);
       await handleBotTypeChanging(req, res, null);
     }
     }
@@ -364,7 +363,7 @@ module.exports = (crowi) => {
    *           200:
    *           200:
    *             description: Succeeded to put CustomBotWithoutProxy setting.
    *             description: Succeeded to put CustomBotWithoutProxy setting.
    */
    */
-  router.put('/without-proxy/update-settings', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/without-proxy/update-settings', loginRequiredStrictly, adminRequired, async(req, res) => {
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
       const msg = 'Not CustomBotWithoutProxy';
       const msg = 'Not CustomBotWithoutProxy';
@@ -402,7 +401,7 @@ module.exports = (crowi) => {
    *             description: Succeeded to put CustomBotWithoutProxy permissions.
    *             description: Succeeded to put CustomBotWithoutProxy permissions.
    */
    */
 
 
-  router.put('/without-proxy/update-permissions', loginRequiredStrictly, adminRequired, csrf, validator.updatePermissionsWithoutProxy, async(req, res) => {
+  router.put('/without-proxy/update-permissions', loginRequiredStrictly, adminRequired, validator.updatePermissionsWithoutProxy, async(req, res) => {
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
       const msg = 'Not CustomBotWithoutProxy';
       const msg = 'Not CustomBotWithoutProxy';
@@ -441,7 +440,7 @@ module.exports = (crowi) => {
    *          200:
    *          200:
    *            description: Succeeded to create slack app integration
    *            description: Succeeded to create slack app integration
    */
    */
-  router.post('/slack-app-integrations', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.post('/slack-app-integrations', loginRequiredStrictly, adminRequired, async(req, res) => {
     const SlackAppIntegrationRecordsNum = await SlackAppIntegration.countDocuments();
     const SlackAppIntegrationRecordsNum = await SlackAppIntegration.countDocuments();
     if (SlackAppIntegrationRecordsNum >= 10) {
     if (SlackAppIntegrationRecordsNum >= 10) {
       const msg = 'Not be able to create more than 10 slack workspace integration settings';
       const msg = 'Not be able to create more than 10 slack workspace integration settings';
@@ -508,7 +507,7 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
-  router.put('/proxy-uri', loginRequiredStrictly, adminRequired, csrf, validator.proxyUri, apiV3FormValidator, async(req, res) => {
+  router.put('/proxy-uri', loginRequiredStrictly, adminRequired, validator.proxyUri, apiV3FormValidator, async(req, res) => {
     const { proxyUri } = req.body;
     const { proxyUri } = req.body;
 
 
     const requestParams = { 'slackbot:proxyUri': proxyUri };
     const requestParams = { 'slackbot:proxyUri': proxyUri };
@@ -540,7 +539,7 @@ module.exports = (crowi) => {
    *            description: Succeeded to make it primary
    *            description: Succeeded to make it primary
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.put('/slack-app-integrations/:id/make-primary', loginRequiredStrictly, adminRequired, csrf, validator.makePrimary, apiV3FormValidator, async(req, res) => {
+  router.put('/slack-app-integrations/:id/make-primary', loginRequiredStrictly, adminRequired, validator.makePrimary, apiV3FormValidator, async(req, res) => {
 
 
     const { id } = req.params;
     const { id } = req.params;
 
 
@@ -585,7 +584,7 @@ module.exports = (crowi) => {
    *            description: Succeeded to regenerate slack app tokens
    *            description: Succeeded to regenerate slack app tokens
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.put('/slack-app-integrations/:id/regenerate-tokens', loginRequiredStrictly, adminRequired, csrf, validator.regenerateTokens, apiV3FormValidator, async(req, res) => {
+  router.put('/slack-app-integrations/:id/regenerate-tokens', loginRequiredStrictly, adminRequired, validator.regenerateTokens, apiV3FormValidator, async(req, res) => {
 
 
     const { id } = req.params;
     const { id } = req.params;
 
 
@@ -616,7 +615,7 @@ module.exports = (crowi) => {
    *            description: Succeeded to update supported commands
    *            description: Succeeded to update supported commands
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.put('/slack-app-integrations/:id/permissions', loginRequiredStrictly, adminRequired, csrf, validator.updatePermissionsWithProxy, apiV3FormValidator, async(req, res) => {
+  router.put('/slack-app-integrations/:id/permissions', loginRequiredStrictly, adminRequired, validator.updatePermissionsWithProxy, apiV3FormValidator, async(req, res) => {
     // TODO: look here 78975
     // TODO: look here 78975
     const { permissionsForBroadcastUseCommands, permissionsForSingleUseCommands, permissionsForSlackEventActions } = req.body;
     const { permissionsForBroadcastUseCommands, permissionsForSingleUseCommands, permissionsForSlackEventActions } = req.body;
     const { id } = req.params;
     const { id } = req.params;
@@ -673,7 +672,7 @@ module.exports = (crowi) => {
    *             description: Succeeded to delete botType setting.
    *             description: Succeeded to delete botType setting.
    */
    */
   // eslint-disable-next-line max-len
   // eslint-disable-next-line max-len
-  router.post('/slack-app-integrations/:id/relation-test', loginRequiredStrictly, adminRequired, csrf, validator.relationTest, apiV3FormValidator, async(req, res) => {
+  router.post('/slack-app-integrations/:id/relation-test', loginRequiredStrictly, adminRequired, validator.relationTest, apiV3FormValidator, async(req, res) => {
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     if (currentBotType === SlackbotType.CUSTOM_WITHOUT_PROXY) {
     if (currentBotType === SlackbotType.CUSTOM_WITHOUT_PROXY) {
       const msg = 'Not Proxy Type';
       const msg = 'Not Proxy Type';
@@ -747,7 +746,7 @@ module.exports = (crowi) => {
    *           200:
    *           200:
    *             description: Succeeded to connect to slack work space.
    *             description: Succeeded to connect to slack work space.
    */
    */
-  router.post('/without-proxy/test', loginRequiredStrictly, adminRequired, csrf, validator.slackChannel, apiV3FormValidator, async(req, res) => {
+  router.post('/without-proxy/test', loginRequiredStrictly, adminRequired, validator.slackChannel, apiV3FormValidator, async(req, res) => {
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     const currentBotType = crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
     if (currentBotType !== SlackbotType.CUSTOM_WITHOUT_PROXY) {
       const msg = 'Select Without Proxy Type';
       const msg = 'Select Without Proxy Type';

+ 3 - 4
packages/app/src/server/routes/apiv3/user-group.js

@@ -30,7 +30,6 @@ const { ObjectId } = mongoose.Types;
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const {
   const {
     UserGroupRelation,
     UserGroupRelation,
@@ -222,7 +221,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: A result of `UserGroup.createGroupByName`
    *                      description: A result of `UserGroup.createGroupByName`
    */
    */
-  router.post('/', loginRequiredStrictly, adminRequired, csrf, validator.create, apiV3FormValidator, async(req, res) => {
+  router.post('/', loginRequiredStrictly, adminRequired, validator.create, apiV3FormValidator, async(req, res) => {
     const { name, description = '', parentId } = req.body;
     const { name, description = '', parentId } = req.body;
 
 
     try {
     try {
@@ -420,7 +419,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: A result of `UserGroup.removeCompletelyById`
    *                      description: A result of `UserGroup.removeCompletelyById`
    */
    */
-  router.delete('/:id', loginRequiredStrictly, adminRequired, csrf, validator.delete, apiV3FormValidator, async(req, res) => {
+  router.delete('/:id', loginRequiredStrictly, adminRequired, validator.delete, apiV3FormValidator, async(req, res) => {
     const { id: deleteGroupId } = req.params;
     const { id: deleteGroupId } = req.params;
     const { actionName, transferToUserGroupId } = req.query;
     const { actionName, transferToUserGroupId } = req.query;
 
 
@@ -464,7 +463,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: A result of `UserGroup.updateName`
    *                      description: A result of `UserGroup.updateName`
    */
    */
-  router.put('/:id', loginRequiredStrictly, adminRequired, csrf, validator.update, apiV3FormValidator, async(req, res) => {
+  router.put('/:id', loginRequiredStrictly, adminRequired, validator.update, apiV3FormValidator, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
     const {
     const {
       name, description, parentId, forceUpdateParents = false,
       name, description, parentId, forceUpdateParents = false,

+ 1 - 2
packages/app/src/server/routes/apiv3/user-ui-settings.ts

@@ -15,7 +15,6 @@ const router = express.Router();
 
 
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const validatorForPut = [
   const validatorForPut = [
     body('settings').exists().withMessage('The body param \'settings\' is required'),
     body('settings').exists().withMessage('The body param \'settings\' is required'),
@@ -27,7 +26,7 @@ module.exports = (crowi) => {
   ];
   ];
 
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  router.put('/', loginRequiredStrictly, csrf, validatorForPut, apiV3FormValidator, async(req: any, res: any) => {
+  router.put('/', loginRequiredStrictly, validatorForPut, apiV3FormValidator, async(req: any, res: any) => {
     const { user } = req;
     const { user } = req;
     const { settings } = req.body;
     const { settings } = req.body;
 
 

+ 9 - 10
packages/app/src/server/routes/apiv3/users.js

@@ -75,7 +75,6 @@ module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequired = require('../../middlewares/login-required')(crowi, true);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
   const adminRequired = require('../../middlewares/admin-required')(crowi);
-  const csrf = require('../../middlewares/csrf')(crowi);
 
 
   const {
   const {
     User,
     User,
@@ -399,7 +398,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Users email that failed to create or send email
    *                      description: Users email that failed to create or send email
    */
    */
-  router.post('/invite', loginRequiredStrictly, adminRequired, csrf, validator.inviteEmail, apiV3FormValidator, async(req, res) => {
+  router.post('/invite', loginRequiredStrictly, adminRequired, validator.inviteEmail, apiV3FormValidator, async(req, res) => {
 
 
     // Delete duplicate email addresses
     // Delete duplicate email addresses
     const emailList = Array.from(new Set(req.body.shapedEmailList));
     const emailList = Array.from(new Set(req.body.shapedEmailList));
@@ -454,7 +453,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: data of admin user
    *                      description: data of admin user
    */
    */
-  router.put('/:id/giveAdmin', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/giveAdmin', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {
@@ -496,7 +495,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: data of removed admin user
    *                      description: data of removed admin user
    */
    */
-  router.put('/:id/removeAdmin', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/removeAdmin', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {
@@ -537,7 +536,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: data of activate user
    *                      description: data of activate user
    */
    */
-  router.put('/:id/activate', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/activate', loginRequiredStrictly, adminRequired, async(req, res) => {
     // check user upper limit
     // check user upper limit
     const isUserCountExceedsUpperLimit = await User.isUserCountExceedsUpperLimit();
     const isUserCountExceedsUpperLimit = await User.isUserCountExceedsUpperLimit();
     if (isUserCountExceedsUpperLimit) {
     if (isUserCountExceedsUpperLimit) {
@@ -586,7 +585,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: data of deactivate user
    *                      description: data of deactivate user
    */
    */
-  router.put('/:id/deactivate', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/:id/deactivate', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {
@@ -627,7 +626,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: data of delete user
    *                      description: data of delete user
    */
    */
-  router.delete('/:id/remove', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.delete('/:id/remove', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.params;
     const { id } = req.params;
 
 
     try {
     try {
@@ -748,7 +747,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: users updated with imageUrlCached
    *                      description: users updated with imageUrlCached
    */
    */
-  router.put('/update.imageUrlCache', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/update.imageUrlCache', loginRequiredStrictly, adminRequired, async(req, res) => {
     try {
     try {
       const userIds = req.body.userIds;
       const userIds = req.body.userIds;
       const users = await User.find({ _id: { $in: userIds }, imageUrlCached: null });
       const users = await User.find({ _id: { $in: userIds }, imageUrlCached: null });
@@ -804,7 +803,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: Target user
    *                      description: Target user
    */
    */
-  router.put('/reset-password', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/reset-password', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.body;
     const { id } = req.body;
 
 
     try {
     try {
@@ -849,7 +848,7 @@ module.exports = (crowi) => {
    *                      type: object
    *                      type: object
    *                      description: email and reasons for email sending failure
    *                      description: email and reasons for email sending failure
    */
    */
-  router.put('/send-invitation-email', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
+  router.put('/send-invitation-email', loginRequiredStrictly, adminRequired, async(req, res) => {
     const { id } = req.body;
     const { id } = req.body;
 
 
     try {
     try {

+ 28 - 26
packages/app/src/server/routes/index.js

@@ -1,4 +1,5 @@
 import express from 'express';
 import express from 'express';
+import csrf from 'csurf';
 
 
 import apiV1FormValidator from '../middlewares/apiv1-form-validator';
 import apiV1FormValidator from '../middlewares/apiv1-form-validator';
 import injectResetOrderByTokenMiddleware from '../middlewares/inject-reset-order-by-token-middleware';
 import injectResetOrderByTokenMiddleware from '../middlewares/inject-reset-order-by-token-middleware';
@@ -20,6 +21,8 @@ const rateLimit = require('express-rate-limit');
 const multer = require('multer');
 const multer = require('multer');
 const autoReap = require('multer-autoreap');
 const autoReap = require('multer-autoreap');
 
 
+const csrfProtection = csrf({ cookie: false });
+
 const apiLimiter = rateLimit({
 const apiLimiter = rateLimit({
   windowMs: 15 * 60 * 1000, // 15 minutes
   windowMs: 15 * 60 * 1000, // 15 minutes
   max: 10, // limit each IP to 10 requests per windowMs
   max: 10, // limit each IP to 10 requests per windowMs
@@ -38,7 +41,6 @@ module.exports = function(crowi, app) {
   const loginRequired = require('../middlewares/login-required')(crowi, true);
   const loginRequired = require('../middlewares/login-required')(crowi, true);
   const adminRequired = require('../middlewares/admin-required')(crowi);
   const adminRequired = require('../middlewares/admin-required')(crowi);
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
-  const csrf = require('../middlewares/csrf')(crowi);
   const injectUserUISettings = require('../middlewares/inject-user-ui-settings-to-localvars')();
   const injectUserUISettings = require('../middlewares/inject-user-ui-settings-to-localvars')();
 
 
   const uploads = multer({ dest: `${crowi.tmpDir}uploads` });
   const uploads = multer({ dest: `${crowi.tmpDir}uploads` });
@@ -81,10 +83,10 @@ module.exports = function(crowi, app) {
   app.get('/login/error/:reason'      , applicationInstalled, login.error);
   app.get('/login/error/:reason'      , applicationInstalled, login.error);
   app.get('/login'                    , applicationInstalled, login.preLogin, login.login);
   app.get('/login'                    , applicationInstalled, login.preLogin, login.login);
   app.get('/login/invited'            , applicationInstalled, login.invited);
   app.get('/login/invited'            , applicationInstalled, login.invited);
-  app.post('/login/activateInvited'   , apiLimiter , applicationInstalled, loginFormValidator.inviteRules(), loginFormValidator.inviteValidation, csrf, login.invited);
-  app.post('/login'                   , apiLimiter , applicationInstalled, loginFormValidator.loginRules(), loginFormValidator.loginValidation, csrf, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
+  app.post('/login/activateInvited'   , apiLimiter , applicationInstalled, loginFormValidator.inviteRules(), loginFormValidator.inviteValidation, csrfProtection, login.invited);
+  app.post('/login'                   , apiLimiter , applicationInstalled, loginFormValidator.loginRules(), loginFormValidator.loginValidation, csrfProtection, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
 
 
-  app.post('/register'                , apiLimiter , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrf, login.register);
+  app.post('/register'                , apiLimiter , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, login.register);
   app.get('/register'                 , applicationInstalled, login.preLogin, login.register);
   app.get('/register'                 , applicationInstalled, login.preLogin, login.register);
 
 
   app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , admin.index);
   app.get('/admin'                    , applicationInstalled, loginRequiredStrictly , adminRequired , admin.index);
@@ -94,7 +96,7 @@ module.exports = function(crowi, app) {
   if (!isInstalled) {
   if (!isInstalled) {
     const installer = require('./installer')(crowi);
     const installer = require('./installer')(crowi);
     app.get('/installer'              , applicationNotInstalled , installer.index);
     app.get('/installer'              , applicationNotInstalled , installer.index);
-    app.post('/installer'             , apiLimiter , applicationNotInstalled , registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrf, installer.install);
+    app.post('/installer'             , apiLimiter , applicationNotInstalled , registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, installer.install);
     return;
     return;
   }
   }
 
 
@@ -144,12 +146,12 @@ module.exports = function(crowi, app) {
 
 
   // importer management for admin
   // importer management for admin
   app.get('/admin/importer'                     , loginRequiredStrictly , adminRequired , admin.importer.index);
   app.get('/admin/importer'                     , loginRequiredStrictly , adminRequired , admin.importer.index);
-  app.post('/_api/admin/settings/importerEsa'   , loginRequiredStrictly , adminRequired , csrf, admin.importer.api.validators.importer.esa(),admin.api.importerSettingEsa);
-  app.post('/_api/admin/settings/importerQiita' , loginRequiredStrictly , adminRequired , csrf , admin.importer.api.validators.importer.qiita(), admin.api.importerSettingQiita);
-  app.post('/_api/admin/import/esa'             , loginRequiredStrictly , adminRequired , admin.api.importDataFromEsa);
-  app.post('/_api/admin/import/testEsaAPI'      , loginRequiredStrictly , adminRequired , csrf, admin.api.testEsaAPI);
-  app.post('/_api/admin/import/qiita'           , loginRequiredStrictly , adminRequired , admin.api.importDataFromQiita);
-  app.post('/_api/admin/import/testQiitaAPI'    , loginRequiredStrictly , adminRequired , csrf, admin.api.testQiitaAPI);
+  app.post('/_api/admin/settings/importerEsa'   , loginRequiredStrictly , adminRequired , csrfProtection, admin.importer.api.validators.importer.esa(),admin.api.importerSettingEsa);
+  app.post('/_api/admin/settings/importerQiita' , loginRequiredStrictly , adminRequired , csrfProtection, admin.importer.api.validators.importer.qiita(), admin.api.importerSettingQiita);
+  app.post('/_api/admin/import/esa'             , loginRequiredStrictly , adminRequired , csrfProtection, admin.api.importDataFromEsa);
+  app.post('/_api/admin/import/testEsaAPI'      , loginRequiredStrictly , adminRequired , csrfProtection, admin.api.testEsaAPI);
+  app.post('/_api/admin/import/qiita'           , loginRequiredStrictly , adminRequired , csrfProtection, admin.api.importDataFromQiita);
+  app.post('/_api/admin/import/testQiitaAPI'    , loginRequiredStrictly , adminRequired , csrfProtection, admin.api.testQiitaAPI);
 
 
   // export management for admin
   // export management for admin
   app.get('/admin/export'                       , loginRequiredStrictly , adminRequired ,admin.export.index);
   app.get('/admin/export'                       , loginRequiredStrictly , adminRequired ,admin.export.index);
@@ -173,26 +175,26 @@ module.exports = function(crowi, app) {
 
 
   // HTTP RPC Styled API (に徐々に移行していいこうと思う)
   // HTTP RPC Styled API (に徐々に移行していいこうと思う)
   apiV1Router.get('/pages.list'          , accessTokenParser , loginRequired , page.api.list);
   apiV1Router.get('/pages.list'          , accessTokenParser , loginRequired , page.api.list);
-  apiV1Router.post('/pages.update'       , accessTokenParser , loginRequiredStrictly , csrf, page.api.update);
+  apiV1Router.post('/pages.update'       , accessTokenParser , loginRequiredStrictly , page.api.update);
   apiV1Router.get('/pages.exist'         , accessTokenParser , loginRequired , page.api.exist);
   apiV1Router.get('/pages.exist'         , accessTokenParser , loginRequired , page.api.exist);
   apiV1Router.get('/pages.updatePost'    , accessTokenParser, loginRequired, page.api.getUpdatePost);
   apiV1Router.get('/pages.updatePost'    , accessTokenParser, loginRequired, page.api.getUpdatePost);
   apiV1Router.get('/pages.getPageTag'    , accessTokenParser , loginRequired , page.api.getPageTag);
   apiV1Router.get('/pages.getPageTag'    , accessTokenParser , loginRequired , page.api.getPageTag);
   // allow posting to guests because the client doesn't know whether the user logged in
   // allow posting to guests because the client doesn't know whether the user logged in
-  apiV1Router.post('/pages.remove'       , loginRequiredStrictly , csrf, page.validator.remove, apiV1FormValidator, page.api.remove); // (Avoid from API Token)
-  apiV1Router.post('/pages.revertRemove' , loginRequiredStrictly , csrf, page.validator.revertRemove, apiV1FormValidator, page.api.revertRemove); // (Avoid from API Token)
-  apiV1Router.post('/pages.unlink'       , loginRequiredStrictly , csrf, page.api.unlink); // (Avoid from API Token)
-  apiV1Router.post('/pages.duplicate'    , accessTokenParser, loginRequiredStrictly, csrf, page.api.duplicate);
+  apiV1Router.post('/pages.remove'       , loginRequiredStrictly , page.validator.remove, apiV1FormValidator, page.api.remove); // (Avoid from API Token)
+  apiV1Router.post('/pages.revertRemove' , loginRequiredStrictly , page.validator.revertRemove, apiV1FormValidator, page.api.revertRemove); // (Avoid from API Token)
+  apiV1Router.post('/pages.unlink'       , loginRequiredStrictly , page.api.unlink); // (Avoid from API Token)
+  apiV1Router.post('/pages.duplicate'    , accessTokenParser, loginRequiredStrictly, page.api.duplicate);
   apiV1Router.get('/tags.list'           , accessTokenParser, loginRequired, tag.api.list);
   apiV1Router.get('/tags.list'           , accessTokenParser, loginRequired, tag.api.list);
   apiV1Router.get('/tags.search'         , accessTokenParser, loginRequired, tag.api.search);
   apiV1Router.get('/tags.search'         , accessTokenParser, loginRequired, tag.api.search);
   apiV1Router.post('/tags.update'        , accessTokenParser, loginRequiredStrictly, tag.api.update);
   apiV1Router.post('/tags.update'        , accessTokenParser, loginRequiredStrictly, tag.api.update);
   apiV1Router.get('/comments.get'        , accessTokenParser , loginRequired , comment.api.get);
   apiV1Router.get('/comments.get'        , accessTokenParser , loginRequired , comment.api.get);
-  apiV1Router.post('/comments.add'       , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.add);
-  apiV1Router.post('/comments.update'    , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.update);
+  apiV1Router.post('/comments.add'       , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , comment.api.add);
+  apiV1Router.post('/comments.update'    , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , comment.api.update);
   apiV1Router.post('/comments.remove'    , accessTokenParser , loginRequiredStrictly , csrf, comment.api.remove);
   apiV1Router.post('/comments.remove'    , accessTokenParser , loginRequiredStrictly , csrf, comment.api.remove);
-  apiV1Router.post('/attachments.add'                  , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.add);
-  apiV1Router.post('/attachments.uploadProfileImage'   , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.uploadProfileImage);
-  apiV1Router.post('/attachments.remove'               , accessTokenParser , loginRequiredStrictly , csrf, attachment.api.remove);
-  apiV1Router.post('/attachments.removeProfileImage'   , accessTokenParser , loginRequiredStrictly , csrf, attachment.api.removeProfileImage);
+  apiV1Router.post('/attachments.add'                  , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly, attachment.api.add);
+  apiV1Router.post('/attachments.uploadProfileImage'   , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly, attachment.api.uploadProfileImage);
+  apiV1Router.post('/attachments.remove'               , accessTokenParser , loginRequiredStrictly , attachment.api.remove);
+  apiV1Router.post('/attachments.removeProfileImage'   , accessTokenParser , loginRequiredStrictly , attachment.api.removeProfileImage);
   apiV1Router.get('/attachments.limit'   , accessTokenParser , loginRequiredStrictly, attachment.api.limit);
   apiV1Router.get('/attachments.limit'   , accessTokenParser , loginRequiredStrictly, attachment.api.limit);
 
 
   // API v1
   // API v1
@@ -223,9 +225,9 @@ module.exports = function(crowi, app) {
 
 
   app.get('/_hackmd/load-agent'          , hackmd.loadAgent);
   app.get('/_hackmd/load-agent'          , hackmd.loadAgent);
   app.get('/_hackmd/load-styles'         , hackmd.loadStyles);
   app.get('/_hackmd/load-styles'         , hackmd.loadStyles);
-  app.post('/_api/hackmd.integrate'      , accessTokenParser , loginRequiredStrictly , csrf, hackmd.validateForApi, hackmd.integrate);
-  app.post('/_api/hackmd.discard'        , accessTokenParser , loginRequiredStrictly , csrf, hackmd.validateForApi, hackmd.discard);
-  app.post('/_api/hackmd.saveOnHackmd'   , accessTokenParser , loginRequiredStrictly , csrf, hackmd.validateForApi, hackmd.saveOnHackmd);
+  app.post('/_api/hackmd.integrate'      , accessTokenParser , loginRequiredStrictly , hackmd.validateForApi, hackmd.integrate);
+  app.post('/_api/hackmd.discard'        , accessTokenParser , loginRequiredStrictly , hackmd.validateForApi, hackmd.discard);
+  app.post('/_api/hackmd.saveOnHackmd'   , accessTokenParser , loginRequiredStrictly , hackmd.validateForApi, hackmd.saveOnHackmd);
 
 
   app.use('/forgot-password', express.Router()
   app.use('/forgot-password', express.Router()
     .use(forgotPassword.checkForgotPasswordEnabledMiddlewareFactory(crowi))
     .use(forgotPassword.checkForgotPasswordEnabledMiddlewareFactory(crowi))
@@ -238,7 +240,7 @@ module.exports = function(crowi, app) {
   app.use('/user-activation', express.Router()
   app.use('/user-activation', express.Router()
     .get('/:token', apiLimiter, applicationInstalled, injectUserRegistrationOrderByTokenMiddleware, userActivation.form)
     .get('/:token', apiLimiter, applicationInstalled, injectUserRegistrationOrderByTokenMiddleware, userActivation.form)
     .use(userActivation.tokenErrorHandlerMiddeware));
     .use(userActivation.tokenErrorHandlerMiddeware));
-  app.post('/user-activation/register', apiLimiter, applicationInstalled, csrf, userActivation.registerRules(), userActivation.validateRegisterForm, userActivation.registerAction(crowi));
+  app.post('/user-activation/register', apiLimiter, applicationInstalled, csrfProtection, userActivation.registerRules(), userActivation.validateRegisterForm, userActivation.registerAction(crowi));
 
 
   app.get('/share/:linkId', page.showSharedPage);
   app.get('/share/:linkId', page.showSharedPage);
 
 

+ 0 - 13
packages/app/src/server/util/middlewares.js

@@ -7,7 +7,6 @@ import loggerFactory from '~/utils/logger';
 const { pathUtils } = require('@growi/core');
 const { pathUtils } = require('@growi/core');
 const { formatDistanceStrict } = require('date-fns');
 const { formatDistanceStrict } = require('date-fns');
 const entities = require('entities');
 const entities = require('entities');
-const md5 = require('md5');
 
 
 // eslint-disable-next-line no-unused-vars
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:lib:middlewares');
 const logger = loggerFactory('growi:lib:middlewares');
@@ -17,18 +16,6 @@ module.exports = (crowi) => {
 
 
   const middlewares = {};
   const middlewares = {};
 
 
-  middlewares.csrfKeyGenerator = function() {
-    return function(req, res, next) {
-      const csrfKey = (req.session && req.session.id) || 'anon';
-
-      if (req.csrfToken === null) {
-        req.csrfToken = crowi.getTokens().create(csrfKey);
-      }
-
-      next();
-    };
-  };
-
   middlewares.swigFunctions = function() {
   middlewares.swigFunctions = function() {
     return function(req, res, next) {
     return function(req, res, next) {
       require('../util/swigFunctions')(crowi, req, res.locals);
       require('../util/swigFunctions')(crowi, req, res.locals);

+ 0 - 5
packages/app/src/server/util/swigFunctions.js

@@ -27,11 +27,6 @@ module.exports = function(crowi, req, locals) {
     return crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version : '-';
     return crowi.runtimeVersions.versions.yarn ? crowi.runtimeVersions.versions.yarn.version : '-';
   };
   };
 
 
-  // token getter
-  locals.csrf = function() {
-    return req.csrfToken;
-  };
-
   locals.getAppTitleFontSize = function(appTitle) {
   locals.getAppTitleFontSize = function(appTitle) {
     const appTitleWidth = stringWidth(appTitle);
     const appTitleWidth = stringWidth(appTitle);
     let fontSize = 22;
     let fontSize = 22;

+ 0 - 1
packages/app/src/server/views/installer.html

@@ -40,7 +40,6 @@
 <body
 <body
   class="installer nologin growi"
   class="installer nologin growi"
   {% block html_base_attr %}{% endblock %}
   {% block html_base_attr %}{% endblock %}
-  data-csrftoken="{{ csrf() }}"
  >
  >
 
 
 <div id="growi-context-extractor"></div>
 <div id="growi-context-extractor"></div>

+ 1 - 1
packages/app/src/server/views/invited.html

@@ -105,7 +105,7 @@
         </div>
         </div>
 
 
         <div class="input-group justify-content-center d-flex mt-5">
         <div class="input-group justify-content-center d-flex mt-5">
-          <input type="hidden" name="_csrf" value="{{ csrf() }}">
+          <input type="hidden" name="_csrf" value="{{ req.csrfToken() }}">
           <button type="submit" class="btn btn-fill" id="register">
           <button type="submit" class="btn btn-fill" id="register">
             <div class="eff"></div>
             <div class="eff"></div>
             <span class="btn-label"><i class="icon-user-follow"></i></span>
             <span class="btn-label"><i class="icon-user-follow"></i></span>

+ 0 - 1
packages/app/src/server/views/layout/layout.html

@@ -68,7 +68,6 @@
   class="{% block html_base_css %}{% endblock %} growi {{ additionalBodyClasses|join(' ') }}"
   class="{% block html_base_css %}{% endblock %} growi {{ additionalBodyClasses|join(' ') }}"
   data-plugin-enabled="{{ getConfig('crowi', 'plugin:isEnabledPlugins') }}"
   data-plugin-enabled="{{ getConfig('crowi', 'plugin:isEnabledPlugins') }}"
   {% block html_base_attr %}{% endblock %}
   {% block html_base_attr %}{% endblock %}
-  data-csrftoken="{{ csrf() }}"
  >
  >
 
 
 <div id="growi-context-extractor"></div>
 <div id="growi-context-extractor"></div>

+ 0 - 5
packages/app/test/integration/middlewares/access-token-parser.test.js

@@ -27,7 +27,6 @@ describe('accessTokenParser', () => {
     model: jest.fn().mockReturnValue(User),
     model: jest.fn().mockReturnValue(User),
   };
   };
   const req = {
   const req = {
-    skipCsrfVerify: false,
     query: {},
     query: {},
     body: {},
     body: {},
     user: {},
     user: {},
@@ -41,7 +40,6 @@ describe('accessTokenParser', () => {
 
 
     expect(next).toHaveBeenCalled();
     expect(next).toHaveBeenCalled();
     expect(result).toBe('next');
     expect(result).toBe('next');
-    expect(req.skipCsrfVerify).toBe(false);
   });
   });
 
 
   test('with invalid accessToken', async() => {
   test('with invalid accessToken', async() => {
@@ -51,7 +49,6 @@ describe('accessTokenParser', () => {
 
 
     expect(next).toHaveBeenCalled();
     expect(next).toHaveBeenCalled();
     expect(result).toBe('next');
     expect(result).toBe('next');
-    expect(req.skipCsrfVerify).toBe(false);
   });
   });
 
 
   test('with accessToken in query', async() => {
   test('with accessToken in query', async() => {
@@ -61,7 +58,6 @@ describe('accessTokenParser', () => {
 
 
     expect(next).toHaveBeenCalled();
     expect(next).toHaveBeenCalled();
     expect(result).toBe('next');
     expect(result).toBe('next');
-    expect(req.skipCsrfVerify).toBe(true);
     expect(req.user._id).toStrictEqual(targetUser._id);
     expect(req.user._id).toStrictEqual(targetUser._id);
   });
   });
 
 
@@ -72,7 +68,6 @@ describe('accessTokenParser', () => {
 
 
     expect(next).toHaveBeenCalled();
     expect(next).toHaveBeenCalled();
     expect(result).toBe('next');
     expect(result).toBe('next');
-    expect(req.skipCsrfVerify).toBe(true);
     expect(req.user._id).toStrictEqual(targetUser._id);
     expect(req.user._id).toStrictEqual(targetUser._id);
   });
   });
 
 

+ 12 - 2
yarn.lock

@@ -7780,7 +7780,7 @@ crypto-random-string@^2.0.0:
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
   integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
   integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
 
 
-csrf@^3.1.0:
+csrf@3.1.0:
   version "3.1.0"
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.1.0.tgz#ec75e9656d004d674b8ef5ba47b41fbfd6cb9c30"
   resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.1.0.tgz#ec75e9656d004d674b8ef5ba47b41fbfd6cb9c30"
   dependencies:
   dependencies:
@@ -7988,6 +7988,16 @@ csstype@^3.0.2:
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33"
   integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
   integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==
 
 
+csurf@^1.11.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/csurf/-/csurf-1.11.0.tgz#ab0c3c6634634192bd3d6f4b861be20800eeb61a"
+  integrity sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==
+  dependencies:
+    cookie "0.4.0"
+    cookie-signature "1.0.6"
+    csrf "3.1.0"
+    http-errors "~1.7.3"
+
 csv-to-markdown-table@^1.0.1:
 csv-to-markdown-table@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/csv-to-markdown-table/-/csv-to-markdown-table-1.0.1.tgz#43da1b0c0c483faa10a23921abc5e47a48e0daba"
   resolved "https://registry.yarnpkg.com/csv-to-markdown-table/-/csv-to-markdown-table-1.0.1.tgz#43da1b0c0c483faa10a23921abc5e47a48e0daba"
@@ -11619,7 +11629,7 @@ http-errors@1.7.2:
     statuses ">= 1.5.0 < 2"
     statuses ">= 1.5.0 < 2"
     toidentifier "1.0.0"
     toidentifier "1.0.0"
 
 
-http-errors@1.7.3, http-errors@~1.7.2:
+http-errors@1.7.3, http-errors@~1.7.2, http-errors@~1.7.3:
   version "1.7.3"
   version "1.7.3"
   resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
   resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
   integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
   integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==