SessionStoreManager.js 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. const Metrics = require('metrics-sharelatex')
  2. const logger = require('logger-sharelatex')
  3. function computeValidationToken(req) {
  4. // this should be a deterministic function of the client-side sessionID,
  5. // prepended with a version number in case we want to change it later
  6. return 'v1:' + req.sessionID.slice(-4)
  7. }
  8. module.exports = {
  9. enableValidationToken(sessionStore) {
  10. // generate an identifier from the sessionID for every new session
  11. const originalGenerate = sessionStore.generate
  12. sessionStore.generate = function(req) {
  13. originalGenerate(req)
  14. // add the validation token as a property that cannot be overwritten
  15. Object.defineProperty(req.session, 'validationToken', {
  16. value: computeValidationToken(req),
  17. enumerable: true,
  18. writable: false
  19. })
  20. Metrics.inc('security.session', 1, { status: 'new' })
  21. }
  22. },
  23. checkValidationToken(req) {
  24. if (req.session) {
  25. const sessionToken = req.session.validationToken
  26. if (sessionToken) {
  27. const clientToken = computeValidationToken(req)
  28. // Reject invalid sessions. If you change the method for computing the
  29. // token (above) then you need to either check or ignore previous
  30. // versions of the token.
  31. if (sessionToken === clientToken) {
  32. Metrics.inc('security.session', 1, { status: 'ok' })
  33. return true
  34. } else {
  35. logger.error(
  36. {
  37. sessionToken: sessionToken,
  38. clientToken: clientToken
  39. },
  40. 'session token validation failed'
  41. )
  42. Metrics.inc('security.session', 1, { status: 'error' })
  43. return false
  44. }
  45. } else {
  46. Metrics.inc('security.session', 1, { status: 'missing' })
  47. }
  48. }
  49. return true // fallback to allowing session
  50. }
  51. }