markdown-setting.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. import { SupportedAction } from '~/interfaces/activity';
  2. import loggerFactory from '~/utils/logger';
  3. import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
  4. import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
  5. const logger = loggerFactory('growi:routes:apiv3:markdown-setting');
  6. const express = require('express');
  7. const router = express.Router();
  8. const { body } = require('express-validator');
  9. const ErrorV3 = require('../../models/vo/error-apiv3');
  10. const validator = {
  11. lineBreak: [
  12. body('isEnabledLinebreaks').isBoolean(),
  13. body('isEnabledLinebreaksInComments').isBoolean(),
  14. ],
  15. indent: [
  16. body('adminPreferredIndentSize').isIn([2, 4]),
  17. body('isIndentSizeForced').isBoolean(),
  18. ],
  19. presentationSetting: [
  20. body('pageBreakSeparator').isInt().not().isEmpty(),
  21. ],
  22. xssSetting: [
  23. body('isEnabledXss').isBoolean(),
  24. body('tagWhiteList').isArray(),
  25. body('attrWhiteList').isArray(),
  26. ],
  27. };
  28. /**
  29. * @swagger
  30. * tags:
  31. * name: MarkDownSetting
  32. */
  33. /**
  34. * @swagger
  35. *
  36. * components:
  37. * schemas:
  38. * LineBreakParams:
  39. * description: LineBreakParams
  40. * type: object
  41. * properties:
  42. * isEnabledLinebreaks:
  43. * type: boolean
  44. * description: enable lineBreak
  45. * isEnabledLinebreaksInComments:
  46. * type: boolean
  47. * description: enable lineBreak in comment
  48. * PresentationParams:
  49. * description: PresentationParams
  50. * type: object
  51. * properties:
  52. * pageBreakSeparator:
  53. * type: number
  54. * description: number of pageBreakSeparator
  55. * pageBreakCustomSeparator:
  56. * type: string
  57. * description: string of pageBreakCustomSeparator
  58. * XssParams:
  59. * description: XssParams
  60. * type: object
  61. * properties:
  62. * isEnabledPrevention:
  63. * type: boolean
  64. * description: enable xss
  65. * xssOption:
  66. * type: number
  67. * description: number of xss option
  68. * tagWhiteList:
  69. * type: array
  70. * description: array of tag whiteList
  71. * items:
  72. * type: string
  73. * description: tag whitelist
  74. * attrWhiteList:
  75. * type: array
  76. * description: array of attr whiteList
  77. * items:
  78. * type: string
  79. * description: attr whitelist
  80. */
  81. module.exports = (crowi) => {
  82. const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
  83. const adminRequired = require('../../middlewares/admin-required')(crowi);
  84. const csrf = require('../../middlewares/csrf')(crowi);
  85. const addActivity = generateAddActivityMiddleware(crowi);
  86. const activityEvent = crowi.event('activity');
  87. /**
  88. * @swagger
  89. *
  90. * /markdown-setting:
  91. * get:
  92. * tags: [MarkDownSetting]
  93. * operationId: getMarkdownSetting
  94. * summary: /markdown-setting
  95. * description: Get markdown parameters
  96. * responses:
  97. * 200:
  98. * description: params of markdown
  99. * content:
  100. * application/json:
  101. * schema:
  102. * properties:
  103. * markdownParams:
  104. * type: object
  105. * description: markdown params
  106. */
  107. router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
  108. const markdownParams = {
  109. isEnabledLinebreaks: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks'),
  110. isEnabledLinebreaksInComments: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
  111. adminPreferredIndentSize: await crowi.configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize'),
  112. isIndentSizeForced: await crowi.configManager.getConfig('markdown', 'markdown:isIndentSizeForced'),
  113. pageBreakSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakSeparator'),
  114. pageBreakCustomSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakCustomSeparator'),
  115. isEnabledXss: await crowi.configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
  116. xssOption: await crowi.configManager.getConfig('markdown', 'markdown:xss:option'),
  117. tagWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:tagWhiteList'),
  118. attrWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:attrWhiteList'),
  119. };
  120. return res.apiv3({ markdownParams });
  121. });
  122. /**
  123. * @swagger
  124. *
  125. * /markdown-setting/lineBreak:
  126. * put:
  127. * tags: [MarkDownSetting]
  128. * operationId: updateLineBreakMarkdownSetting
  129. * summary: /markdown-setting/lineBreak
  130. * description: Update lineBreak setting
  131. * requestBody:
  132. * required: true
  133. * content:
  134. * application/json:
  135. * schema:
  136. * $ref: '#/components/schemas/LineBreakParams'
  137. * responses:
  138. * 200:
  139. * description: Succeeded to update lineBreak setting
  140. * content:
  141. * application/json:
  142. * schema:
  143. * $ref: '#/components/schemas/LineBreakParams'
  144. */
  145. router.put('/lineBreak', loginRequiredStrictly, adminRequired, csrf, addActivity, validator.lineBreak, apiV3FormValidator, async(req, res) => {
  146. const requestLineBreakParams = {
  147. 'markdown:isEnabledLinebreaks': req.body.isEnabledLinebreaks,
  148. 'markdown:isEnabledLinebreaksInComments': req.body.isEnabledLinebreaksInComments,
  149. };
  150. try {
  151. await crowi.configManager.updateConfigsInTheSameNamespace('markdown', requestLineBreakParams);
  152. const lineBreaksParams = {
  153. isEnabledLinebreaks: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks'),
  154. isEnabledLinebreaksInComments: await crowi.configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
  155. };
  156. const parameters = { action: SupportedAction.ACTION_ADMIN_MARKDOWN_LINE_BREAK_UPDATE };
  157. activityEvent.emit('update', res.locals.activity._id, parameters);
  158. return res.apiv3({ lineBreaksParams });
  159. }
  160. catch (err) {
  161. const msg = 'Error occurred in updating lineBreak';
  162. logger.error('Error', err);
  163. return res.apiv3Err(new ErrorV3(msg, 'update-lineBreak-failed'));
  164. }
  165. });
  166. router.put('/indent', loginRequiredStrictly, adminRequired, csrf, addActivity, validator.indent, apiV3FormValidator, async(req, res) => {
  167. const requestIndentParams = {
  168. 'markdown:adminPreferredIndentSize': req.body.adminPreferredIndentSize,
  169. 'markdown:isIndentSizeForced': req.body.isIndentSizeForced,
  170. };
  171. try {
  172. await crowi.configManager.updateConfigsInTheSameNamespace('markdown', requestIndentParams);
  173. const indentParams = {
  174. adminPreferredIndentSize: await crowi.configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize'),
  175. isIndentSizeForced: await crowi.configManager.getConfig('markdown', 'markdown:isIndentSizeForced'),
  176. };
  177. const parameters = { action: SupportedAction.ACTION_ADMIN_MARKDOWN_INDENT_UPDATE };
  178. activityEvent.emit('update', res.locals.activity._id, parameters);
  179. return res.apiv3({ indentParams });
  180. }
  181. catch (err) {
  182. const msg = 'Error occurred in updating indent';
  183. logger.error('Error', err);
  184. return res.apiv3Err(new ErrorV3(msg, 'update-indent-failed'));
  185. }
  186. });
  187. /**
  188. * @swagger
  189. *
  190. * /markdown-setting/presentation:
  191. * put:
  192. * tags: [MarkDownSetting]
  193. * operationId: updatePresentationMarkdownSetting
  194. * summary: /markdown-setting/presentation
  195. * description: Update presentation
  196. * requestBody:
  197. * required: true
  198. * content:
  199. * application/json:
  200. * schema:
  201. * $ref: '#/components/schemas/PresentationParams'
  202. * responses:
  203. * 200:
  204. * description: Succeeded to update presentation setting
  205. * content:
  206. * application/json:
  207. * schema:
  208. * $ref: '#/components/schemas/PresentationParams'
  209. */
  210. router.put('/presentation', loginRequiredStrictly, adminRequired, csrf, addActivity, validator.presentationSetting, apiV3FormValidator, async(req, res) => {
  211. if (req.body.pageBreakSeparator === 3 && req.body.pageBreakCustomSeparator === '') {
  212. return res.apiv3Err(new ErrorV3('customRegularExpression is required'));
  213. }
  214. const requestPresentationParams = {
  215. 'markdown:presentation:pageBreakSeparator': req.body.pageBreakSeparator,
  216. 'markdown:presentation:pageBreakCustomSeparator': req.body.pageBreakCustomSeparator,
  217. };
  218. try {
  219. await crowi.configManager.updateConfigsInTheSameNamespace('markdown', requestPresentationParams);
  220. const presentationParams = {
  221. pageBreakSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakSeparator'),
  222. pageBreakCustomSeparator: await crowi.configManager.getConfig('markdown', 'markdown:presentation:pageBreakCustomSeparator') || '',
  223. };
  224. const parameters = { action: SupportedAction.ACTION_ADMIN_MARKDOWN_PRESENTATION_UPDATE };
  225. activityEvent.emit('update', res.locals.activity._id, parameters);
  226. return res.apiv3({ presentationParams });
  227. }
  228. catch (err) {
  229. const msg = 'Error occurred in updating presentation';
  230. logger.error('Error', err);
  231. return res.apiv3Err(new ErrorV3(msg, 'update-presentation-failed'));
  232. }
  233. });
  234. /**
  235. * @swagger
  236. *
  237. * /markdown-setting/xss:
  238. * put:
  239. * tags: [MarkDownSetting]
  240. * operationId: updateXssMarkdownSetting
  241. * summary: /markdown-setting/xss
  242. * description: Update xss
  243. * requestBody:
  244. * required: true
  245. * content:
  246. * application/json:
  247. * schema:
  248. * $ref: '#/components/schemas/XssParams'
  249. * responses:
  250. * 200:
  251. * description: Succeeded to update xss setting
  252. * content:
  253. * application/json:
  254. * schema:
  255. * $ref: '#/components/schemas/XssParams'
  256. */
  257. router.put('/xss', loginRequiredStrictly, adminRequired, csrf, addActivity, validator.xssSetting, apiV3FormValidator, async(req, res) => {
  258. if (req.body.isEnabledXss && req.body.xssOption == null) {
  259. return res.apiv3Err(new ErrorV3('xss option is required'));
  260. }
  261. const reqestXssParams = {
  262. 'markdown:xss:isEnabledPrevention': req.body.isEnabledXss,
  263. 'markdown:xss:option': req.body.xssOption,
  264. 'markdown:xss:tagWhiteList': req.body.tagWhiteList,
  265. 'markdown:xss:attrWhiteList': req.body.attrWhiteList,
  266. };
  267. try {
  268. await crowi.configManager.updateConfigsInTheSameNamespace('markdown', reqestXssParams);
  269. const xssParams = {
  270. isEnabledXss: await crowi.configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
  271. xssOption: await crowi.configManager.getConfig('markdown', 'markdown:xss:option'),
  272. tagWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:tagWhiteList'),
  273. attrWhiteList: await crowi.configManager.getConfig('markdown', 'markdown:xss:attrWhiteList'),
  274. };
  275. const parameters = { action: SupportedAction.ACTION_ADMIN_MARKDOWN_XSS_UPDATE };
  276. activityEvent.emit('update', res.locals.activity._id, parameters);
  277. return res.apiv3({ xssParams });
  278. }
  279. catch (err) {
  280. const msg = 'Error occurred in updating xss';
  281. logger.error('Error', err);
  282. return res.apiv3Err(new ErrorV3(msg, 'update-xss-failed'));
  283. }
  284. });
  285. return router;
  286. };