You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
5.5 KiB

  1. /* global WIKI */
  2. const express = require('express')
  3. const ExpressBrute = require('express-brute')
  4. const BruteKnex = require('../helpers/brute-knex')
  5. const router = express.Router()
  6. const moment = require('moment')
  7. const _ = require('lodash')
  8. const bruteforce = new ExpressBrute(new BruteKnex({
  9. createTable: true,
  10. knex: WIKI.models.knex
  11. }), {
  12. freeRetries: 5,
  13. minWait: 5 * 60 * 1000, // 5 minutes
  14. maxWait: 60 * 60 * 1000, // 1 hour
  15. failCallback: (req, res, next) => {
  16. res.status(401).send('Too many failed attempts. Try again later.')
  17. }
  18. })
  19. /**
  20. * Login form
  21. */
  22. router.get('/login', async (req, res, next) => {
  23. _.set(res.locals, 'pageMeta.title', 'Login')
  24. if (req.query.legacy || (req.get('user-agent') && req.get('user-agent').indexOf('Trident') >= 0)) {
  25. const { formStrategies, socialStrategies } = await WIKI.models.authentication.getStrategiesForLegacyClient()
  26. res.render('legacy/login', {
  27. err: false,
  28. formStrategies,
  29. socialStrategies
  30. })
  31. } else {
  32. // -> Bypass Login
  33. if (WIKI.config.auth.autoLogin && !req.query.all) {
  34. const stg = await WIKI.models.authentication.query().orderBy('order').first()
  35. const stgInfo = _.find(WIKI.data.authentication, ['key', stg.strategyKey])
  36. if (!stgInfo.useForm) {
  37. return res.redirect(`/login/${stg.key}`)
  38. }
  39. }
  40. // -> Show Login
  41. const bgUrl = !_.isEmpty(WIKI.config.auth.loginBgUrl) ? WIKI.config.auth.loginBgUrl : '/_assets/img/splash/1.jpg'
  42. res.render('login', { bgUrl, hideLocal: WIKI.config.auth.hideLocal })
  43. }
  44. })
  45. /**
  46. * Social Strategies Login
  47. */
  48. router.get('/login/:strategy', async (req, res, next) => {
  49. try {
  50. await WIKI.models.users.login({
  51. strategy: req.params.strategy
  52. }, { req, res })
  53. } catch (err) {
  54. next(err)
  55. }
  56. })
  57. /**
  58. * Social Strategies Callback
  59. */
  60. router.all('/login/:strategy/callback', async (req, res, next) => {
  61. if (req.method !== 'GET' && req.method !== 'POST') { return next() }
  62. try {
  63. const authResult = await WIKI.models.users.login({
  64. strategy: req.params.strategy
  65. }, { req, res })
  66. res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
  67. const loginRedirect = req.cookies['loginRedirect']
  68. if (loginRedirect === '/' && authResult.redirect) {
  69. res.clearCookie('loginRedirect')
  70. res.redirect(authResult.redirect)
  71. } else if (loginRedirect) {
  72. res.clearCookie('loginRedirect')
  73. res.redirect(loginRedirect)
  74. } else if (authResult.redirect) {
  75. res.redirect(authResult.redirect)
  76. } else {
  77. res.redirect('/')
  78. }
  79. } catch (err) {
  80. next(err)
  81. }
  82. })
  83. /**
  84. * LEGACY - Login form handling
  85. */
  86. router.post('/login', bruteforce.prevent, async (req, res, next) => {
  87. _.set(res.locals, 'pageMeta.title', 'Login')
  88. if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
  89. try {
  90. const authResult = await WIKI.models.users.login({
  91. strategy: req.body.strategy,
  92. username: req.body.user,
  93. password: req.body.pass
  94. }, { req, res })
  95. req.brute.reset()
  96. res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
  97. res.redirect('/')
  98. } catch (err) {
  99. const { formStrategies, socialStrategies } = await WIKI.models.authentication.getStrategiesForLegacyClient()
  100. res.render('legacy/login', {
  101. err,
  102. formStrategies,
  103. socialStrategies
  104. })
  105. }
  106. } else {
  107. res.redirect('/login')
  108. }
  109. })
  110. /**
  111. * Logout
  112. */
  113. router.get('/logout', async (req, res) => {
  114. const redirURL = await WIKI.models.users.logout({ req, res })
  115. req.logout()
  116. res.clearCookie('jwt')
  117. res.redirect(redirURL)
  118. })
  119. /**
  120. * Register form
  121. */
  122. router.get('/register', async (req, res, next) => {
  123. _.set(res.locals, 'pageMeta.title', 'Register')
  124. const localStrg = await WIKI.models.authentication.getStrategy('local')
  125. if (localStrg.selfRegistration) {
  126. res.render('register')
  127. } else {
  128. next(new WIKI.Error.AuthRegistrationDisabled())
  129. }
  130. })
  131. /**
  132. * Verify
  133. */
  134. router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
  135. try {
  136. const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
  137. await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
  138. req.brute.reset()
  139. if (WIKI.config.auth.enforce2FA) {
  140. res.redirect('/login')
  141. } else {
  142. const result = await WIKI.models.users.refreshToken(usr)
  143. res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
  144. res.redirect('/')
  145. }
  146. } catch (err) {
  147. next(err)
  148. }
  149. })
  150. /**
  151. * Reset Password
  152. */
  153. router.get('/login-reset/:token', bruteforce.prevent, async (req, res, next) => {
  154. try {
  155. const usr = await WIKI.models.userKeys.validateToken({ kind: 'resetPwd', token: req.params.token })
  156. if (!usr) {
  157. throw new Error('Invalid Token')
  158. }
  159. req.brute.reset()
  160. const changePwdContinuationToken = await WIKI.models.userKeys.generateToken({
  161. userId: usr.id,
  162. kind: 'changePwd'
  163. })
  164. const bgUrl = !_.isEmpty(WIKI.config.auth.loginBgUrl) ? WIKI.config.auth.loginBgUrl : '/_assets/img/splash/1.jpg'
  165. res.render('login', { bgUrl, hideLocal: WIKI.config.auth.hideLocal, changePwdContinuationToken })
  166. } catch (err) {
  167. next(err)
  168. }
  169. })
  170. /**
  171. * JWT Public Endpoints
  172. */
  173. router.get('/.well-known/jwk.json', function (req, res, next) {
  174. res.json(WIKI.config.certs.jwk)
  175. })
  176. router.get('/.well-known/jwk.pem', function (req, res, next) {
  177. res.send(WIKI.config.certs.public)
  178. })
  179. module.exports = router