fix: check revalidation timestamp

This commit is contained in:
NGPixel 2020-06-25 19:25:08 -04:00
parent c37b0ad1d7
commit 92b29d1f06
3 changed files with 22 additions and 13 deletions

View File

@ -103,6 +103,7 @@
"klaw": "3.0.0", "klaw": "3.0.0",
"knex": "0.21.1", "knex": "0.21.1",
"lodash": "4.17.15", "lodash": "4.17.15",
"luxon": "1.24.1",
"markdown-it": "11.0.0", "markdown-it": "11.0.0",
"markdown-it-abbr": "1.0.4", "markdown-it-abbr": "1.0.4",
"markdown-it-attrs": "3.0.3", "markdown-it-attrs": "3.0.3",

View File

@ -3,7 +3,7 @@ const passportJWT = require('passport-jwt')
const _ = require('lodash') const _ = require('lodash')
const jwt = require('jsonwebtoken') const jwt = require('jsonwebtoken')
const ms = require('ms') const ms = require('ms')
const moment = require('moment') const { DateTime } = require('luxon')
const Promise = require('bluebird') const Promise = require('bluebird')
const crypto = Promise.promisifyAll(require('crypto')) const crypto = Promise.promisifyAll(require('crypto'))
const pem2jwk = require('pem-jwk').pem2jwk const pem2jwk = require('pem-jwk').pem2jwk
@ -15,7 +15,7 @@ const securityHelper = require('../helpers/security')
module.exports = { module.exports = {
strategies: {}, strategies: {},
guest: { guest: {
cacheExpiration: moment.utc().subtract(1, 'd') cacheExpiration: DateTime.utc().minus({ days: 1 })
}, },
groups: {}, groups: {},
validApiKeys: [], validApiKeys: [],
@ -55,7 +55,7 @@ module.exports = {
/** /**
* Load authentication strategies * Load authentication strategies
*/ */
async activateStrategies() { async activateStrategies () {
try { try {
// Unload any active strategies // Unload any active strategies
WIKI.auth.strategies = {} WIKI.auth.strategies = {}
@ -109,23 +109,25 @@ module.exports = {
* @param {Express Response} res * @param {Express Response} res
* @param {Express Next Callback} next * @param {Express Next Callback} next
*/ */
authenticate(req, res, next) { authenticate (req, res, next) {
WIKI.auth.passport.authenticate('jwt', {session: false}, async (err, user, info) => { WIKI.auth.passport.authenticate('jwt', {session: false}, async (err, user, info) => {
if (err) { return next() } if (err) { return next() }
let mustRevalidate = false let mustRevalidate = false
// Expired but still valid within N days, just renew // Expired but still valid within N days, just renew
if (info instanceof Error && info.name === 'TokenExpiredError' && moment().subtract(ms(WIKI.config.auth.tokenRenewal), 'ms').isBefore(info.expiredAt)) { if (info instanceof Error && info.name === 'TokenExpiredError' && DateTime.utc().minus(ms(WIKI.config.auth.tokenRenewal)) < DateTime.fromSeconds(info.expiredAt)) {
mustRevalidate = true mustRevalidate = true
} }
// Check if user / group is in revokation list // Check if user / group is in revokation list
if (user) { if (user) {
if (WIKI.auth.revokationList.has(`u${_.toString(user.id)}`)) { const uRevalidate = WIKI.auth.revokationList.get(`u${_.toString(user.id)}`)
if (uRevalidate && user.iat < uRevalidate) {
mustRevalidate = true mustRevalidate = true
} }
for (const gid of user.groups) { for (const gid of user.groups) {
if (WIKI.auth.revokationList.has(`g${_.toString(gid)}`)) { const gRevalidate = WIKI.auth.revokationList.get(`g${_.toString(gid)}`)
if (gRevalidate && user.iat < gRevalidate) {
mustRevalidate = true mustRevalidate = true
} }
} }
@ -133,6 +135,7 @@ module.exports = {
// Revalidate and renew token // Revalidate and renew token
if (mustRevalidate) { if (mustRevalidate) {
console.info('MUST REVALIDATE')
const jwtPayload = jwt.decode(securityHelper.extractJWT(req)) const jwtPayload = jwt.decode(securityHelper.extractJWT(req))
try { try {
const newToken = await WIKI.models.users.refreshToken(jwtPayload.id) const newToken = await WIKI.models.users.refreshToken(jwtPayload.id)
@ -145,7 +148,7 @@ module.exports = {
if (req.get('content-type') === 'application/json') { if (req.get('content-type') === 'application/json') {
res.set('new-jwt', newToken.token) res.set('new-jwt', newToken.token)
} else { } else {
res.cookie('jwt', newToken.token, { expires: moment().add(365, 'days').toDate() }) res.cookie('jwt', newToken.token, { expires: DateTime.utc().plus({ days: 365 }).toJSDate() })
} }
} catch (errc) { } catch (errc) {
WIKI.logger.warn(errc) WIKI.logger.warn(errc)
@ -155,9 +158,9 @@ module.exports = {
// JWT is NOT valid, set as guest // JWT is NOT valid, set as guest
if (!user) { if (!user) {
if (WIKI.auth.guest.cacheExpiration.isSameOrBefore(moment.utc())) { if (WIKI.auth.guest.cacheExpiration <= DateTime.utc()) {
WIKI.auth.guest = await WIKI.models.users.getGuestUser() WIKI.auth.guest = await WIKI.models.users.getGuestUser()
WIKI.auth.guest.cacheExpiration = moment.utc().add(1, 'm') WIKI.auth.guest.cacheExpiration = DateTime.utc().plus({ minutes: 1 })
} }
req.user = WIKI.auth.guest req.user = WIKI.auth.guest
return next() return next()
@ -306,14 +309,14 @@ module.exports = {
async reloadGroups () { async reloadGroups () {
const groupsArray = await WIKI.models.groups.query() const groupsArray = await WIKI.models.groups.query()
this.groups = _.keyBy(groupsArray, 'id') this.groups = _.keyBy(groupsArray, 'id')
WIKI.auth.guest.cacheExpiration = moment.utc().subtract(1, 'd') WIKI.auth.guest.cacheExpiration = DateTime.utc().minus({ days: 1 })
}, },
/** /**
* Reload valid API Keys from DB * Reload valid API Keys from DB
*/ */
async reloadApiKeys () { async reloadApiKeys () {
const keys = await WIKI.models.apiKeys.query().select('id').where('isRevoked', false).andWhere('expiration', '>', moment.utc().toISOString()) const keys = await WIKI.models.apiKeys.query().select('id').where('isRevoked', false).andWhere('expiration', '>', DateTime.utc().toISO())
this.validApiKeys = _.map(keys, 'id') this.validApiKeys = _.map(keys, 'id')
}, },
@ -437,6 +440,6 @@ module.exports = {
* Add user / group ID to JWT revokation list, forcing all requests to be validated against the latest permissions * Add user / group ID to JWT revokation list, forcing all requests to be validated against the latest permissions
*/ */
revokeUserTokens ({ id, kind = 'u' }) { revokeUserTokens ({ id, kind = 'u' }) {
WIKI.auth.revokationList.set(`${kind}${_.toString(id)}`, true, Math.ceil(ms(WIKI.config.auth.tokenExpiration) / 1000)) WIKI.auth.revokationList.set(`${kind}${_.toString(id)}`, Math.round(DateTime.utc().minus({ seconds: 5 }).toSeconds()), Math.ceil(ms(WIKI.config.auth.tokenExpiration) / 1000))
} }
} }

View File

@ -11496,6 +11496,11 @@ lru-cache@^5.0.0, lru-cache@^5.1.1:
dependencies: dependencies:
yallist "^3.0.2" yallist "^3.0.2"
luxon@1.24.1:
version "1.24.1"
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.24.1.tgz#a8383266131ed4eaed4b5f430f96f3695403a52a"
integrity sha512-CgnIMKAWT0ghcuWFfCWBnWGOddM0zu6c4wZAWmD0NN7MZTnro0+833DF6tJep+xlxRPg4KtsYEHYLfTMBQKwYg==
make-dir@^2.0.0, make-dir@^2.1.0: make-dir@^2.0.0, make-dir@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"