common.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. const express = require('express')
  2. const router = express.Router()
  3. const pageHelper = require('../helpers/page')
  4. const _ = require('lodash')
  5. /* global WIKI */
  6. /**
  7. * Robots.txt
  8. */
  9. router.get('/robots.txt', (req, res, next) => {
  10. res.type('text/plain')
  11. if (_.includes(WIKI.config.seo.robots, 'noindex')) {
  12. res.send('User-agent: *\nDisallow: /')
  13. } else {
  14. res.status(200).end()
  15. }
  16. })
  17. /**
  18. * Health Endpoint
  19. */
  20. router.get('/healthz', (req, res, next) => {
  21. if (WIKI.models.knex.client.pool.numFree() < 1 && WIKI.models.knex.client.pool.numUsed() < 1) {
  22. res.status(503).json({ ok: false }).end()
  23. } else {
  24. res.status(200).json({ ok: true }).end()
  25. }
  26. })
  27. /**
  28. * Administration
  29. */
  30. router.get(['/a', '/a/*'], (req, res, next) => {
  31. _.set(res.locals, 'pageMeta.title', 'Admin')
  32. res.render('admin')
  33. })
  34. /**
  35. * Download Page / Version
  36. */
  37. router.get(['/d', '/d/*'], async (req, res, next) => {
  38. const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
  39. const versionId = (req.query.v) ? _.toSafeInteger(req.query.v) : 0
  40. const page = await WIKI.models.pages.getPageFromDb({
  41. path: pageArgs.path,
  42. locale: pageArgs.locale,
  43. userId: req.user.id,
  44. isPrivate: false
  45. })
  46. pageArgs.tags = _.get(page, 'tags', [])
  47. if (versionId > 0) {
  48. if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
  49. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  50. return res.render('unauthorized', { action: 'downloadVersion' })
  51. }
  52. } else {
  53. if (!WIKI.auth.checkAccess(req.user, ['read:source'], pageArgs)) {
  54. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  55. return res.render('unauthorized', { action: 'download' })
  56. }
  57. }
  58. if (page) {
  59. const fileName = _.last(page.path.split('/')) + '.' + pageHelper.getFileExtension(page.contentType)
  60. res.attachment(fileName)
  61. if (versionId > 0) {
  62. const pageVersion = await WIKI.models.pageHistory.getVersion({ pageId: page.id, versionId })
  63. res.send(pageHelper.injectPageMetadata(pageVersion))
  64. } else {
  65. res.send(pageHelper.injectPageMetadata(page))
  66. }
  67. } else {
  68. res.status(404).end()
  69. }
  70. })
  71. /**
  72. * Create/Edit document
  73. */
  74. router.get(['/e', '/e/*'], async (req, res, next) => {
  75. const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
  76. if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
  77. return res.redirect(`/e/${pageArgs.locale}/${pageArgs.path}`)
  78. }
  79. _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
  80. _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
  81. if (pageHelper.isReservedPath(pageArgs.path)) {
  82. return next(new Error('Cannot create this page because it starts with a system reserved path.'))
  83. }
  84. let page = await WIKI.models.pages.getPageFromDb({
  85. path: pageArgs.path,
  86. locale: pageArgs.locale,
  87. userId: req.user.id,
  88. isPrivate: false
  89. })
  90. pageArgs.tags = _.get(page, 'tags', [])
  91. const injectCode = {
  92. css: WIKI.config.theming.injectCSS,
  93. head: WIKI.config.theming.injectHead,
  94. body: WIKI.config.theming.injectBody
  95. }
  96. if (page) {
  97. if (!WIKI.auth.checkAccess(req.user, ['write:pages', 'manage:pages'], pageArgs)) {
  98. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  99. return res.render('unauthorized', { action: 'edit' })
  100. }
  101. await page.$relatedQuery('tags')
  102. page.tags = _.map(page.tags, 'tag')
  103. _.set(res.locals, 'pageMeta.title', `Edit ${page.title}`)
  104. _.set(res.locals, 'pageMeta.description', page.description)
  105. page.mode = 'update'
  106. page.isPublished = (page.isPublished === true || page.isPublished === 1) ? 'true' : 'false'
  107. page.content = Buffer.from(page.content).toString('base64')
  108. } else {
  109. if (!WIKI.auth.checkAccess(req.user, ['write:pages'], pageArgs)) {
  110. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  111. return res.render('unauthorized', { action: 'create' })
  112. }
  113. _.set(res.locals, 'pageMeta.title', `New Page`)
  114. page = {
  115. path: pageArgs.path,
  116. localeCode: pageArgs.locale,
  117. editorKey: null,
  118. mode: 'create',
  119. content: null
  120. }
  121. }
  122. res.render('editor', { page, injectCode })
  123. })
  124. /**
  125. * History
  126. */
  127. router.get(['/h', '/h/*'], async (req, res, next) => {
  128. const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
  129. if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
  130. return res.redirect(`/h/${pageArgs.locale}/${pageArgs.path}`)
  131. }
  132. _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
  133. _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
  134. const page = await WIKI.models.pages.getPageFromDb({
  135. path: pageArgs.path,
  136. locale: pageArgs.locale,
  137. userId: req.user.id,
  138. isPrivate: false
  139. })
  140. pageArgs.tags = _.get(page, 'tags', [])
  141. if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
  142. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  143. return res.render('unauthorized', { action: 'history' })
  144. }
  145. if (page) {
  146. _.set(res.locals, 'pageMeta.title', page.title)
  147. _.set(res.locals, 'pageMeta.description', page.description)
  148. res.render('history', { page })
  149. } else {
  150. res.redirect(`/${pageArgs.path}`)
  151. }
  152. })
  153. /**
  154. * Page ID redirection
  155. */
  156. router.get(['/i', '/i/:id'], async (req, res, next) => {
  157. const pageId = _.toSafeInteger(req.params.id)
  158. if (pageId <= 0) {
  159. return res.redirect('/')
  160. }
  161. const page = await WIKI.models.pages.query().column(['path', 'localeCode', 'isPrivate', 'privateNS']).findById(pageId)
  162. if (!page) {
  163. _.set(res.locals, 'pageMeta.title', 'Page Not Found')
  164. return res.status(404).render('notfound', { action: 'view' })
  165. }
  166. if (!WIKI.auth.checkAccess(req.user, ['read:pages'], {
  167. locale: page.localeCode,
  168. path: page.path,
  169. private: page.isPrivate,
  170. privateNS: page.privateNS,
  171. explicitLocale: false,
  172. tags: page.tags
  173. })) {
  174. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  175. return res.render('unauthorized', { action: 'view' })
  176. }
  177. if (WIKI.config.lang.namespacing) {
  178. return res.redirect(`/${page.localeCode}/${page.path}`)
  179. } else {
  180. return res.redirect(`/${page.path}`)
  181. }
  182. })
  183. /**
  184. * Profile
  185. */
  186. router.get(['/p', '/p/*'], (req, res, next) => {
  187. _.set(res.locals, 'pageMeta.title', 'User Profile')
  188. res.render('profile')
  189. })
  190. /**
  191. * Source
  192. */
  193. router.get(['/s', '/s/*'], async (req, res, next) => {
  194. const pageArgs = pageHelper.parsePath(req.path, { stripExt: true })
  195. const versionId = (req.query.v) ? _.toSafeInteger(req.query.v) : 0
  196. const page = await WIKI.models.pages.getPageFromDb({
  197. path: pageArgs.path,
  198. locale: pageArgs.locale,
  199. userId: req.user.id,
  200. isPrivate: false
  201. })
  202. pageArgs.tags = _.get(page, 'tags', [])
  203. if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
  204. return res.redirect(`/s/${pageArgs.locale}/${pageArgs.path}`)
  205. }
  206. _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
  207. _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
  208. if (versionId > 0) {
  209. if (!WIKI.auth.checkAccess(req.user, ['read:history'], pageArgs)) {
  210. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  211. return res.render('unauthorized', { action: 'sourceVersion' })
  212. }
  213. } else {
  214. if (!WIKI.auth.checkAccess(req.user, ['read:source'], pageArgs)) {
  215. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  216. return res.render('unauthorized', { action: 'source' })
  217. }
  218. }
  219. if (page) {
  220. if (versionId > 0) {
  221. const pageVersion = await WIKI.models.pageHistory.getVersion({ pageId: page.id, versionId })
  222. _.set(res.locals, 'pageMeta.title', pageVersion.title)
  223. _.set(res.locals, 'pageMeta.description', pageVersion.description)
  224. res.render('source', {
  225. page: {
  226. ...page,
  227. ...pageVersion
  228. }
  229. })
  230. } else {
  231. _.set(res.locals, 'pageMeta.title', page.title)
  232. _.set(res.locals, 'pageMeta.description', page.description)
  233. res.render('source', { page })
  234. }
  235. } else {
  236. res.redirect(`/${pageArgs.path}`)
  237. }
  238. })
  239. /**
  240. * Tags
  241. */
  242. router.get(['/t', '/t/*'], (req, res, next) => {
  243. _.set(res.locals, 'pageMeta.title', 'Tags')
  244. res.render('tags')
  245. })
  246. /**
  247. * View document / asset
  248. */
  249. router.get('/*', async (req, res, next) => {
  250. const stripExt = _.some(WIKI.data.pageExtensions, ext => _.endsWith(req.path, `.${ext}`))
  251. const pageArgs = pageHelper.parsePath(req.path, { stripExt })
  252. const isPage = (stripExt || pageArgs.path.indexOf('.') === -1)
  253. if (isPage) {
  254. if (WIKI.config.lang.namespacing && !pageArgs.explicitLocale) {
  255. return res.redirect(`/${pageArgs.locale}/${pageArgs.path}`)
  256. }
  257. req.i18n.changeLanguage(pageArgs.locale)
  258. try {
  259. const page = await WIKI.models.pages.getPage({
  260. path: pageArgs.path,
  261. locale: pageArgs.locale,
  262. userId: req.user.id,
  263. isPrivate: false
  264. })
  265. pageArgs.tags = _.get(page, 'tags', [])
  266. if (!WIKI.auth.checkAccess(req.user, ['read:pages'], pageArgs)) {
  267. if (req.user.id === 2) {
  268. res.cookie('loginRedirect', req.path, {
  269. maxAge: 15 * 60 * 1000
  270. })
  271. }
  272. if (pageArgs.path === 'home' && req.user.id === 2) {
  273. return res.redirect('/login')
  274. }
  275. _.set(res.locals, 'pageMeta.title', 'Unauthorized')
  276. return res.status(403).render('unauthorized', {
  277. action: 'view'
  278. })
  279. }
  280. _.set(res, 'locals.siteConfig.lang', pageArgs.locale)
  281. _.set(res, 'locals.siteConfig.rtl', req.i18n.dir() === 'rtl')
  282. if (page) {
  283. _.set(res.locals, 'pageMeta.title', page.title)
  284. _.set(res.locals, 'pageMeta.description', page.description)
  285. const sidebar = await WIKI.models.navigation.getTree({ cache: true, locale: pageArgs.locale })
  286. const injectCode = {
  287. css: WIKI.config.theming.injectCSS,
  288. head: WIKI.config.theming.injectHead,
  289. body: WIKI.config.theming.injectBody
  290. }
  291. if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
  292. if (_.isString(page.toc)) {
  293. page.toc = JSON.parse(page.toc)
  294. }
  295. res.render('legacy/page', { page, sidebar, injectCode, isAuthenticated: req.user && req.user.id !== 2 })
  296. } else {
  297. res.render('page', { page, sidebar, injectCode })
  298. }
  299. } else if (pageArgs.path === 'home') {
  300. _.set(res.locals, 'pageMeta.title', 'Welcome')
  301. res.render('welcome', { locale: pageArgs.locale })
  302. } else {
  303. _.set(res.locals, 'pageMeta.title', 'Page Not Found')
  304. if (WIKI.auth.checkAccess(req.user, ['write:pages'], pageArgs)) {
  305. res.status(404).render('new', { path: pageArgs.path, locale: pageArgs.locale })
  306. } else {
  307. res.status(404).render('notfound', { action: 'view' })
  308. }
  309. }
  310. } catch (err) {
  311. next(err)
  312. }
  313. } else {
  314. if (!WIKI.auth.checkAccess(req.user, ['read:assets'], pageArgs)) {
  315. return res.sendStatus(403)
  316. }
  317. await WIKI.models.assets.getAsset(pageArgs.path, res)
  318. }
  319. })
  320. module.exports = router