From 1ae4aeee54e25b2db5bc4becb5ee0ba442a39bc4 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Mon, 21 Dec 2020 15:46:18 +0100 Subject: [PATCH] chore: updated how session is stored (uses redis when available, fall back to memory store when not avail) --- deploy/app.js | 91 +++++++++++-------- deploy/lruStore/index.js | 16 +++- deploy/package.json | 2 + package.json | 4 +- .../atlasViewer.pluginService.service.ts | 2 +- 5 files changed, 74 insertions(+), 41 deletions(-) diff --git a/deploy/app.js b/deploy/app.js index 420720e79..ebfa19165 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -3,44 +3,9 @@ const path = require('path') const express = require('express') const app = express.Router() const session = require('express-session') -const MemoryStore = require('memorystore')(session) const crypto = require('crypto') const cookieParser = require('cookie-parser') -/** - * memorystore (or perhaps lru-cache itself) does not properly close when server shuts - * this causes problems during tests - * So when testing app.js, set USE_DEFAULT_MEMORY_STORE to true - * see app.spec.js - */ -const { USE_DEFAULT_MEMORY_STORE } = process.env -const store = USE_DEFAULT_MEMORY_STORE - ? (console.warn(`USE_DEFAULT_MEMORY_STORE is set to true, memleak expected. Do NOT use in prod.`), null) - : new MemoryStore({ - checkPeriod: 86400000 - }) - -const SESSIONSECRET = process.env.SESSIONSECRET || 'this is not really a random session secret' - -/** - * passport application of oidc requires session - */ -app.use(session({ - secret: SESSIONSECRET, - resave: true, - saveUninitialized: true, - store, -})) - -/** - * configure CSP - */ -if (process.env.DISABLE_CSP && process.env.DISABLE_CSP === 'true') { - console.warn(`DISABLE_CSP is set to true, csp will not be enabled`) -} else { - require('./csp')(app) -} - const { router: regionalFeaturesRouter, regionalFeatureIsReady } = require('./regionalFeatures') const { router: datasetRouter, ready: datasetRouteIsReady } = require('./datasets') @@ -81,12 +46,66 @@ app.use((req, _, next) => { const { configureAuth, ready: authReady } = require('./auth') +const store = (() => { + + const { USE_DEFAULT_MEMORY_STORE } = process.env + if (!!USE_DEFAULT_MEMORY_STORE) { + console.warn(`USE_DEFAULT_MEMORY_STORE is set to true, memleak expected. Do NOT use in prod.`) + return null + } + + const { redisURL } = require('./lruStore') + if (!!redisURL) { + const redis = require('redis') + const RedisStore = require('connect-redis')(session) + const client = redis.createClient({ + url: redisURL + }) + return new RedisStore({ + client + }) + } + + /** + * memorystore (or perhaps lru-cache itself) does not properly close when server shuts + * this causes problems during tests + * So when testing app.js, set USE_DEFAULT_MEMORY_STORE to true + * see app.spec.js + */ + const MemoryStore = require('memorystore')(session) + return new MemoryStore({ + checkPeriod: 86400000 + }) + +})() + +const SESSIONSECRET = process.env.SESSIONSECRET || 'this is not really a random session secret' + +/** + * passport application of oidc requires session + */ +app.use(session({ + secret: SESSIONSECRET, + resave: true, + saveUninitialized: false, + store +})) + +/** + * configure CSP + */ +if (process.env.DISABLE_CSP && process.env.DISABLE_CSP === 'true') { + console.warn(`DISABLE_CSP is set to true, csp will not be enabled`) +} else { + require('./csp')(app) +} + /** * configure Auth * async function, but can start server without */ -const _ = (async () => { +(async () => { await configureAuth(app) app.use('/user', require('./user')) })() diff --git a/deploy/lruStore/index.js b/deploy/lruStore/index.js index 564b89566..6a3c8a908 100644 --- a/deploy/lruStore/index.js +++ b/deploy/lruStore/index.js @@ -20,9 +20,20 @@ const redisProto = REDIS_PROTO || REDIS_RATE_LIMITING_DB_EPHEMERAL_PORT_6379_TCP const redisAddr = REDIS_ADDR || REDIS_RATE_LIMITING_DB_EPHEMERAL_PORT_6379_TCP_ADDR || null const redisPort = REDIS_PORT || REDIS_RATE_LIMITING_DB_EPHEMERAL_PORT_6379_TCP_PORT || 6379 -const userPass = `${REDIS_USERNAME || ''}${( REDIS_PASSWORD && (':' + REDIS_PASSWORD)) || ''}${ (REDIS_USERNAME || REDIS_PASSWORD) && '@'}` +const userPass = (() => { + let returnString = '' + if (REDIS_USERNAME) { + returnString += REDIS_USERNAME + } + if (REDIS_PASSWORD) { + returnString += `:${REDIS_PASSWORD}` + } + return returnString === '' + ? '' + : `${returnString}@` +})() -const redisURL = redisAddr && `${redisProto}://${userPass}${redisAddr}:${redisPort}` +const redisURL = redisAddr && `${redisProto || ''}://${userPass}${redisAddr}:${redisPort}` const crypto = require('crypto') @@ -82,6 +93,7 @@ if (redisURL) { } exports.StoreType = `redis` + exports.redisURL = redisURL console.log(`redis`) } else { diff --git a/deploy/package.json b/deploy/package.json index 39df6e6fc..b9eed1b91 100644 --- a/deploy/package.json +++ b/deploy/package.json @@ -14,6 +14,7 @@ "dependencies": { "archiver": "^3.0.0", "body-parser": "^1.19.0", + "connect-redis": "^5.0.0", "cookie-parser": "^1.4.5", "express": "^4.16.4", "express-rate-limit": "^5.1.1", @@ -28,6 +29,7 @@ "openid-client": "^2.4.5", "passport": "^0.4.0", "rate-limit-redis": "^1.7.0", + "redis": "^3.0.2", "request": "^2.88.0", "showdown": "^1.9.1", "soswrap": "^0.0.2", diff --git a/package.json b/package.json index cf99e4aca..e62868a62 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "build-export": "webpack --config webpack.export.js", "build-export-min": "webpack --config webpack.export.min.js", "build-export-aot": "webpack --config webpack.export.aot.js", - "build-aot": "PRODUCTION=true GIT_HASH=`git rev-parse --short HEAD` webpack --config webpack.aot.js && node ./third_party/matomo/processMatomo.js", + "build-aot": "PRODUCTION=true GIT_HASH=`jq -r '.version' package.json` webpack --config webpack.aot.js && node ./third_party/matomo/processMatomo.js", "plugin-server": "node ./src/plugin_examples/server.js", "dev-server": "BACKEND_URL=${BACKEND_URL:-http://localhost:3000/} webpack-dev-server --config webpack.dev.js --mode development", - "dev-server-aot": "BACKEND_URL=${BACKEND_URL:-http://localhost:3000/} PRODUCTION=true GIT_HASH=`git log --pretty=format:'%h' --invert-grep --grep=^.ignore -1` webpack-dev-server --config webpack.dev-aot.js", + "dev-server-aot": "BACKEND_URL=${BACKEND_URL:-http://localhost:3000/} PRODUCTION=true GIT_HASH=`jq -r '.version' package.json` webpack-dev-server --config webpack.dev-aot.js", "dev-server-all-interfaces": "webpack-dev-server --config webpack.dev.js --mode development --hot --host 0.0.0.0", "test": "karma start spec/karma.conf.js", "e2e": "protractor e2e/protractor.conf", diff --git a/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts b/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts index bf6104a32..8299f6cf5 100644 --- a/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts +++ b/src/atlasViewer/pluginUnit/atlasViewer.pluginService.service.ts @@ -15,7 +15,7 @@ import { DialogService } from 'src/services/dialogService.service'; import { DomSanitizer } from '@angular/platform-browser'; import { MatSnackBar } from '@angular/material/snack-bar'; -const requiresReloadMd = `\n\n***\n\n**warning**: interactive atlas viewer needs to be reloaded for the change to take effect.` +const requiresReloadMd = `\n\n***\n\n**warning**: interactive atlas viewer **will** be reloaded in order for the change to take effect.` export const registerPluginFactoryDirectiveFactory = (pSer: PluginServices) => { return (pFactoryDirective: PluginFactoryDirective) => { -- GitLab