| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- const Metrics = require('@overleaf/metrics')
- const logger = require('@overleaf/logger')
- function computeValidationToken(req) {
- // this should be a deterministic function of the client-side sessionID,
- // prepended with a version number in case we want to change it later
- return 'v1:' + req.sessionID.slice(-4)
- }
- function checkValidationToken(req) {
- if (req.session) {
- const sessionToken = req.session.validationToken
- if (sessionToken) {
- const clientToken = computeValidationToken(req)
- // Reject invalid sessions. If you change the method for computing the
- // token (above) then you need to either check or ignore previous
- // versions of the token.
- if (sessionToken === clientToken) {
- Metrics.inc('security.session', 1, { status: 'ok' })
- return true
- } else {
- logger.error(
- {
- sessionToken: sessionToken,
- clientToken: clientToken,
- },
- 'session token validation failed'
- )
- Metrics.inc('security.session', 1, { status: 'error' })
- return false
- }
- } else {
- Metrics.inc('security.session', 1, { status: 'missing' })
- }
- }
- return true // fallback to allowing session
- }
- module.exports = {
- enableValidationToken(sessionStore) {
- // generate an identifier from the sessionID for every new session
- const originalGenerate = sessionStore.generate
- sessionStore.generate = function (req) {
- originalGenerate(req)
- // add the validation token as a property that cannot be overwritten
- Object.defineProperty(req.session, 'validationToken', {
- value: computeValidationToken(req),
- enumerable: true,
- writable: false,
- })
- Metrics.inc('security.session', 1, { status: 'new' })
- }
- },
- validationMiddleware(req, res, next) {
- if (!req.session.noSessionCallback) {
- if (!checkValidationToken(req)) {
- // the session must exist for it to fail validation
- return req.session.destroy(() => {
- return next(new Error('invalid session'))
- })
- }
- }
- next()
- },
- hasValidationToken(req) {
- if (req && req.session && req.session.validationToken) {
- return true
- } else {
- return false
- }
- },
- }
|