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.

184 lines
5.1 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. res.redirect(authResult.redirect)
  68. } catch (err) {
  69. next(err)
  70. }
  71. })
  72. /**
  73. * LEGACY - Login form handling
  74. */
  75. router.post('/login', bruteforce.prevent, async (req, res, next) => {
  76. _.set(res.locals, 'pageMeta.title', 'Login')
  77. if (req.query.legacy || req.get('user-agent').indexOf('Trident') >= 0) {
  78. try {
  79. const authResult = await WIKI.models.users.login({
  80. strategy: req.body.strategy,
  81. username: req.body.user,
  82. password: req.body.pass
  83. }, { req, res })
  84. req.brute.reset()
  85. res.cookie('jwt', authResult.jwt, { expires: moment().add(1, 'y').toDate() })
  86. res.redirect('/')
  87. } catch (err) {
  88. const { formStrategies, socialStrategies } = await WIKI.models.authentication.getStrategiesForLegacyClient()
  89. res.render('legacy/login', {
  90. err,
  91. formStrategies,
  92. socialStrategies
  93. })
  94. }
  95. } else {
  96. res.redirect('/login')
  97. }
  98. })
  99. /**
  100. * Logout
  101. */
  102. router.get('/logout', async (req, res) => {
  103. const redirURL = await WIKI.models.users.logout({ req, res })
  104. req.logout()
  105. res.clearCookie('jwt')
  106. res.redirect(redirURL)
  107. })
  108. /**
  109. * Register form
  110. */
  111. router.get('/register', async (req, res, next) => {
  112. _.set(res.locals, 'pageMeta.title', 'Register')
  113. const localStrg = await WIKI.models.authentication.getStrategy('local')
  114. if (localStrg.selfRegistration) {
  115. res.render('register')
  116. } else {
  117. next(new WIKI.Error.AuthRegistrationDisabled())
  118. }
  119. })
  120. /**
  121. * Verify
  122. */
  123. router.get('/verify/:token', bruteforce.prevent, async (req, res, next) => {
  124. try {
  125. const usr = await WIKI.models.userKeys.validateToken({ kind: 'verify', token: req.params.token })
  126. await WIKI.models.users.query().patch({ isVerified: true }).where('id', usr.id)
  127. req.brute.reset()
  128. if (WIKI.config.auth.enforce2FA) {
  129. res.redirect('/login')
  130. } else {
  131. const result = await WIKI.models.users.refreshToken(usr)
  132. res.cookie('jwt', result.token, { expires: moment().add(1, 'years').toDate() })
  133. res.redirect('/')
  134. }
  135. } catch (err) {
  136. next(err)
  137. }
  138. })
  139. /**
  140. * Reset Password
  141. */
  142. router.get('/login-reset/:token', bruteforce.prevent, async (req, res, next) => {
  143. try {
  144. const usr = await WIKI.models.userKeys.validateToken({ kind: 'resetPwd', token: req.params.token })
  145. if (!usr) {
  146. throw new Error('Invalid Token')
  147. }
  148. req.brute.reset()
  149. const changePwdContinuationToken = await WIKI.models.userKeys.generateToken({
  150. userId: usr.id,
  151. kind: 'changePwd'
  152. })
  153. const bgUrl = !_.isEmpty(WIKI.config.auth.loginBgUrl) ? WIKI.config.auth.loginBgUrl : '/_assets/img/splash/1.jpg'
  154. res.render('login', { bgUrl, hideLocal: WIKI.config.auth.hideLocal, changePwdContinuationToken })
  155. } catch (err) {
  156. next(err)
  157. }
  158. })
  159. /**
  160. * JWT Public Endpoints
  161. */
  162. router.get('/.well-known/jwk.json', function (req, res, next) {
  163. res.json(WIKI.config.certs.jwk)
  164. })
  165. router.get('/.well-known/jwk.pem', function (req, res, next) {
  166. res.send(WIKI.config.certs.public)
  167. })
  168. module.exports = router