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