Feat: adds async local storage to admin server

This commit is contained in:
csrapr 2021-05-24 21:57:39 +01:00 committed by Sérgio Salgado
parent 8128f05ffb
commit cb2e1b3907
5 changed files with 47 additions and 8 deletions

View file

@ -1,3 +1,5 @@
const T = require('./time')
const anonymousCustomer = { const anonymousCustomer = {
uuid: '47ac1184-8102-11e7-9079-8f13a7117867', uuid: '47ac1184-8102-11e7-9079-8f13a7117867',
name: 'anonymous' name: 'anonymous'
@ -8,6 +10,8 @@ const cassetteMaxCapacity = 500
const AUTHENTICATOR_ISSUER_ENTITY = 'Lamassu' const AUTHENTICATOR_ISSUER_ENTITY = 'Lamassu'
const AUTH_TOKEN_EXPIRATION_TIME = '30 minutes' const AUTH_TOKEN_EXPIRATION_TIME = '30 minutes'
const REGISTRATION_TOKEN_EXPIRATION_TIME = '30 minutes' const REGISTRATION_TOKEN_EXPIRATION_TIME = '30 minutes'
const USER_SESSIONS_TABLE_NAME = 'user_sessions'
const USER_SESSIONS_CLEAR_INTERVAL = 1 * T.hour
const AUTOMATIC = 'automatic' const AUTOMATIC = 'automatic'
const MANUAL = 'manual' const MANUAL = 'manual'
@ -19,5 +23,7 @@ module.exports = {
AUTH_TOKEN_EXPIRATION_TIME, AUTH_TOKEN_EXPIRATION_TIME,
REGISTRATION_TOKEN_EXPIRATION_TIME, REGISTRATION_TOKEN_EXPIRATION_TIME,
AUTOMATIC, AUTOMATIC,
MANUAL MANUAL,
USER_SESSIONS_TABLE_NAME,
USER_SESSIONS_CLEAR_INTERVAL
} }

View file

@ -19,6 +19,9 @@ const logger = require('../logger')
const session = require('./middlewares/session') const session = require('./middlewares/session')
const { AuthDirective } = require('./graphql/directives') const { AuthDirective } = require('./graphql/directives')
const { typeDefs, resolvers } = require('./graphql/schema') const { typeDefs, resolvers } = require('./graphql/schema')
const computeSchema = require('../compute-schema')
const cleanUserSessions = require('./middlewares/cleanUserSessions')
const { USER_SESSIONS_CLEAR_INTERVAL } = require('../constants')
const devMode = require('minimist')(process.argv.slice(2)).dev const devMode = require('minimist')(process.argv.slice(2)).dev
const idPhotoCardBasedir = _.get('idPhotoCardDir', options) const idPhotoCardBasedir = _.get('idPhotoCardDir', options)
@ -32,6 +35,7 @@ if (!hostname) {
} }
const app = express() const app = express()
app.use(helmet()) app.use(helmet())
app.use(compression()) app.use(compression())
app.use(nocache()) app.use(nocache())
@ -39,6 +43,8 @@ app.use(cookieParser())
app.use(express.json()) app.use(express.json())
app.use(express.urlencoded({ extended: true })) // support encoded bodies app.use(express.urlencoded({ extended: true })) // support encoded bodies
app.use(express.static(path.resolve(__dirname, '..', '..', 'public'))) app.use(express.static(path.resolve(__dirname, '..', '..', 'public')))
app.use(computeSchema)
app.use(cleanUserSessions(USER_SESSIONS_CLEAR_INTERVAL))
app.use(session) app.use(session)
const apolloServer = new ApolloServer({ const apolloServer = new ApolloServer({

View file

@ -30,8 +30,7 @@ const authenticateUser = (username, password) => {
const destroySessionIfSameUser = (context, user) => { const destroySessionIfSameUser = (context, user) => {
const sessionUser = getUserFromCookie(context) const sessionUser = getUserFromCookie(context)
if (sessionUser && user.id === sessionUser.id) if (sessionUser && user.id === sessionUser.id) { context.req.session.destroy() }
context.req.session.destroy()
} }
const destroySessionIfBeingUsed = (sessID, context) => { const destroySessionIfBeingUsed = (sessID, context) => {
@ -60,7 +59,7 @@ const executeProtectedAction = (code, id, context, action) => {
if (user.role !== 'superuser') { if (user.role !== 'superuser') {
return action() return action()
} }
return confirm2FA(code, context) return confirm2FA(code, context)
.then(() => action()) .then(() => action())
}) })

View file

@ -0,0 +1,23 @@
const { asyncLocalStorage } = require('../../async-storage')
const db = require('../../db')
const { USER_SESSIONS_TABLE_NAME } = require('../../constants')
const schemaCache = {}
const cleanUserSessions = (cleanInterval) => (req, res, next) => {
const schema = asyncLocalStorage.getStore() ? asyncLocalStorage.getStore().get('schema') : null
const now = Date.now()
if (!schema) return next()
if (schema && schemaCache.schema + cleanInterval > now) return next()
console.log('Clearing old sessions for schema', schema)
return db.$none('DELETE FROM $1^ WHERE expire < to_timestamp($2)', [USER_SESSIONS_TABLE_NAME, now])
.then(() => {
schemaCache.schema = now
return next()
})
.catch(next)
}
module.exports = cleanUserSessions

View file

@ -3,10 +3,11 @@ const express = require('express')
const router = express.Router() const router = express.Router()
const hkdf = require('futoin-hkdf') const hkdf = require('futoin-hkdf')
const session = require('express-session') const session = require('express-session')
const pgSession = require('connect-pg-simple')(session) const PgSession = require('connect-pg-simple')(session)
const mnemonicHelpers = require('../../mnemonic-helpers') const mnemonicHelpers = require('../../mnemonic-helpers')
const db = require('../../db') const db = require('../../db')
const options = require('../../options') const options = require('../../options')
const { USER_SESSIONS_TABLE_NAME } = require('../../constants')
const getSecret = () => { const getSecret = () => {
const mnemonic = fs.readFileSync(options.mnemonicPath, 'utf8') const mnemonic = fs.readFileSync(options.mnemonicPath, 'utf8')
@ -19,10 +20,14 @@ const getSecret = () => {
const hostname = options.hostname const hostname = options.hostname
const lamaDb = {
query: (query, values, qrm) => db.$query(query, values, qrm, false)
}
router.use('*', session({ router.use('*', session({
store: new pgSession({ store: new PgSession({
pgPromise: db, pgPromise: lamaDb,
tableName: 'user_sessions' tableName: USER_SESSIONS_TABLE_NAME
}), }),
name: 'lid', name: 'lid',
secret: getSecret(), secret: getSecret(),